Skip to content

Commit daa0ce2

Browse files
committed
fix(update): The update pop-up window supports displaying multiple versions of the update content between the latest version and the current version
1 parent 2b1240e commit daa0ce2

File tree

3 files changed

+64
-46
lines changed

3 files changed

+64
-46
lines changed

composeApp/src/commonMain/kotlin/com/jankinwu/fntv/client/ui/component/common/AnimatedScrollbar.kt

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ fun AnimatedScrollbarLazyColumn(
5050
modifier: Modifier = Modifier,
5151
scrollbarWidth: Dp = 6.dp,
5252
scrollbarOffsetX: Dp = (-1).dp,
53+
autoHidden: Boolean = true,
5354
content: LazyListScope.() -> Unit
5455
) {
5556
var isHovered by remember { mutableStateOf(false) }
@@ -74,6 +75,7 @@ fun AnimatedScrollbarLazyColumn(
7475
isHovered = false
7576
}
7677
}
78+
7779
PointerEventType.Exit -> {
7880
hideScrollbarJob?.cancel()
7981
isHovered = false
@@ -91,7 +93,7 @@ fun AnimatedScrollbarLazyColumn(
9193
}
9294

9395
AnimatedVisibility(
94-
visible = listState.isScrollInProgress || isHovered || isDragging || isScrollbarHovered,
96+
visible = if (autoHidden) listState.isScrollInProgress || isHovered || isDragging || isScrollbarHovered else true,
9597
enter = fadeIn(),
9698
exit = fadeOut(),
9799
modifier = Modifier.align(Alignment.CenterEnd)
@@ -103,7 +105,8 @@ fun AnimatedScrollbarLazyColumn(
103105
if (visibleItemsInfo.isNotEmpty() && layoutInfo.totalItemsCount > 0) {
104106
val viewportHeight = layoutInfo.viewportSize.height.toFloat()
105107

106-
val averageItemHeight = visibleItemsInfo.sumOf { it.size } / visibleItemsInfo.size.toFloat()
108+
val averageItemHeight =
109+
visibleItemsInfo.sumOf { it.size } / visibleItemsInfo.size.toFloat()
107110
val totalContentHeight = averageItemHeight * layoutInfo.totalItemsCount
108111

109112
if (totalContentHeight <= viewportHeight) return@AnimatedVisibility
@@ -115,8 +118,10 @@ fun AnimatedScrollbarLazyColumn(
115118
val scrollableDistance = totalContentHeight - viewportHeight
116119
val scrollbarMaxOffset = viewportHeight - scrollbarHeightPx
117120

118-
val currentScrollPosition = listState.firstVisibleItemIndex * averageItemHeight + listState.firstVisibleItemScrollOffset
119-
val scrollbarOffsetPx = if (scrollableDistance > 0) (currentScrollPosition / scrollableDistance * scrollbarMaxOffset) else 0f
121+
val currentScrollPosition =
122+
listState.firstVisibleItemIndex * averageItemHeight + listState.firstVisibleItemScrollOffset
123+
val scrollbarOffsetPx =
124+
if (scrollableDistance > 0) (currentScrollPosition / scrollableDistance * scrollbarMaxOffset) else 0f
120125
val scrollbarOffset = with(density) { scrollbarOffsetPx.toDp() }
121126
// 修改这里的颜色逻辑,根据是否悬浮显示不同颜色
122127
val scrollbarColor = if (isScrollbarHovered || isDragging) {
@@ -138,6 +143,7 @@ fun AnimatedScrollbarLazyColumn(
138143
isScrollbarHovered = true
139144
hideScrollbarJob?.cancel()
140145
}
146+
141147
PointerEventType.Exit -> {
142148
isScrollbarHovered = false
143149
}
@@ -165,7 +171,8 @@ fun AnimatedScrollbarLazyColumn(
165171
change.consume()
166172
coroutineScope.launch {
167173
if (scrollbarMaxOffset > 0) {
168-
val scrollDelta = (dragAmount.y / scrollbarMaxOffset) * scrollableDistance
174+
val scrollDelta =
175+
(dragAmount.y / scrollbarMaxOffset) * scrollableDistance
169176
listState.scrollBy(scrollDelta)
170177
}
171178
}
@@ -229,7 +236,8 @@ fun AnimatedScrollbarColumn(
229236
val scrollableDistance = contentHeight - viewportHeight
230237
val scrollbarMaxOffset = viewportHeight - scrollbarHeightPx
231238

232-
val scrollbarOffsetPx = (scrollState.value.toFloat() / scrollableDistance * scrollbarMaxOffset)
239+
val scrollbarOffsetPx =
240+
(scrollState.value.toFloat() / scrollableDistance * scrollbarMaxOffset)
233241
val scrollbarOffset = with(density) { scrollbarOffsetPx.toDp() }
234242

235243
Box(
@@ -250,7 +258,8 @@ fun AnimatedScrollbarColumn(
250258
change.consume()
251259
coroutineScope.launch {
252260
if (scrollbarMaxOffset > 0) {
253-
val scrollDelta = (dragAmount.y / scrollbarMaxOffset) * scrollableDistance
261+
val scrollDelta =
262+
(dragAmount.y / scrollbarMaxOffset) * scrollableDistance
254263
scrollState.scrollBy(scrollDelta)
255264
}
256265
}

composeApp/src/commonMain/kotlin/com/jankinwu/fntv/client/ui/component/common/dialog/UpdateDialog.kt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,9 @@ fun UpdateDialog(
6767
AnimatedScrollbarLazyColumn(
6868
listState = lazyListState,
6969
modifier = Modifier.height(290.dp),
70-
scrollbarWidth = 2.dp,
71-
scrollbarOffsetX = (-2).dp
70+
scrollbarWidth = 4.dp,
71+
scrollbarOffsetX = (-2).dp,
72+
autoHidden = false
7273
) {
7374
item {
7475
Markdown(
@@ -105,8 +106,9 @@ fun UpdateDialog(
105106
AnimatedScrollbarLazyColumn(
106107
listState = lazyListState,
107108
modifier = Modifier.height(290.dp).padding(horizontal = 8.dp),
108-
scrollbarWidth = 2.dp,
109-
scrollbarOffsetX = (-2).dp
109+
scrollbarWidth = 4.dp,
110+
scrollbarOffsetX = (-2).dp,
111+
autoHidden = false
110112
) {
111113
item {
112114
Markdown(

composeApp/src/jvmMain/kotlin/com/jankinwu/fntv/client/manager/DesktopUpdateManager.kt

Lines changed: 42 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -87,14 +87,14 @@ class DesktopUpdateManager : UpdateManager {
8787
scope.launch {
8888
_status.value = UpdateStatus.Checking
8989
try {
90-
val releases = fetchReleases(includePrerelease)
90+
val releases = fetchReleases()
9191

9292
if (releases.isEmpty()) {
9393
handleNoReleasesFound()
9494
return@launch
9595
}
9696

97-
val bestReleaseInfo = findBestRelease(releases)
97+
val bestReleaseInfo = findBestRelease(releases, includePrerelease)
9898
if (bestReleaseInfo != null) {
9999
processUpdateInfo(bestReleaseInfo, isManual, autoDownload, proxyUrl)
100100
} else {
@@ -107,12 +107,8 @@ class DesktopUpdateManager : UpdateManager {
107107
}
108108
}
109109

110-
private suspend fun fetchReleases(includePrerelease: Boolean): List<GitHubRelease> {
111-
return if (includePrerelease) {
112-
fetchReleasesWithPagination()
113-
} else {
114-
fetchLatestRelease()
115-
}
110+
private suspend fun fetchReleases(): List<GitHubRelease> {
111+
return fetchReleasesWithPagination()
116112
}
117113

118114
private suspend fun fetchReleasesWithPagination(): List<GitHubRelease> {
@@ -167,17 +163,6 @@ class DesktopUpdateManager : UpdateManager {
167163
}
168164
}
169165

170-
private suspend fun fetchLatestRelease(): List<GitHubRelease> {
171-
val targetUrl = "https://api.github.com/repos/FNOSP/fntv-client-multiplatform/releases/latest"
172-
logger.i("Checking update from: $targetUrl")
173-
val response = client.get(targetUrl)
174-
return if (response.status == HttpStatusCode.NotFound) {
175-
emptyList()
176-
} else {
177-
listOf(response.body<GitHubRelease>())
178-
}
179-
}
180-
181166
private fun handleNoReleasesFound() {
182167
logger.i("No releases found")
183168
_status.value = UpdateStatus.UpToDate
@@ -190,7 +175,7 @@ class DesktopUpdateManager : UpdateManager {
190175
_latestVersion.value = null
191176
}
192177

193-
private fun findBestRelease(releases: List<GitHubRelease>): UpdateInfo? {
178+
private fun findBestRelease(releases: List<GitHubRelease>, includePrerelease: Boolean): UpdateInfo? {
194179
val currentVersion = BuildConfig.VERSION_NAME
195180
val arch = getSystemArch()
196181
val osName = getSystemOS()
@@ -202,44 +187,66 @@ class DesktopUpdateManager : UpdateManager {
202187
asset.name.contains(arch, ignoreCase = true) &&
203188
(targetExtension == null || asset.name.endsWith(targetExtension, ignoreCase = true))
204189
}
205-
}
206-
207-
if (validReleases.isEmpty()) return null
208-
209-
val sortedReleases = validReleases.sortedWith { r1, r2 ->
190+
}.sortedWith { r1, r2 ->
210191
val v1 = r1.name.removePrefix("v").trim()
211192
val v2 = r2.name.removePrefix("v").trim()
212193
compareVersions(v2, v1) // Descending
213194
}
214195

196+
if (validReleases.isEmpty()) return null
197+
215198
val skippedVersions = AppSettingsStore.skippedVersions
216-
var bestRelease: GitHubRelease? = null
217-
var remoteVersion = ""
199+
var targetRelease: GitHubRelease? = null
200+
var targetVersionString = ""
218201

219-
for (release in sortedReleases) {
202+
for (release in validReleases) {
220203
val v = release.name.removePrefix("v").trim()
204+
221205
if (skippedVersions.contains(v)) {
222206
logger.i("Skipping version: $v")
223207
continue
224208
}
225-
if (compareVersions(v, currentVersion) > 0) {
226-
bestRelease = release
227-
remoteVersion = v
209+
210+
if (compareVersions(v, currentVersion) <= 0) {
228211
break
229212
}
213+
214+
if (!includePrerelease && release.prerelease) {
215+
continue
216+
}
217+
218+
targetRelease = release
219+
targetVersionString = v
220+
break
221+
}
222+
223+
if (targetRelease == null) return null
224+
225+
val notesBuilder = StringBuilder()
226+
var addedCount = 0
227+
for (release in validReleases) {
228+
val v = release.name.removePrefix("v").trim()
229+
if (compareVersions(v, targetVersionString) <= 0 && compareVersions(v, currentVersion) > 0) {
230+
if (addedCount > 0) {
231+
notesBuilder.append("\n\n")
232+
}
233+
notesBuilder.append("#### ${release.name}\n")
234+
notesBuilder.append(release.body)
235+
addedCount++
236+
}
230237
}
231238

232-
return bestRelease?.let { release ->
233-
logger.i("Current version: $currentVersion, Best remote version: $remoteVersion")
239+
return targetRelease.let { release ->
240+
logger.i("Current version: $currentVersion, Target version: $targetVersionString")
234241
val asset = release.assets.find {
235242
it.name.contains(osName, ignoreCase = true) &&
236243
it.name.contains(arch, ignoreCase = true) &&
237244
(targetExtension == null || it.name.endsWith(targetExtension, ignoreCase = true))
238245
}
239246
asset?.let {
240247
UpdateInfo(
241-
version = remoteVersion,
242-
releaseNotes = release.body,
248+
version = targetVersionString,
249+
releaseNotes = notesBuilder.toString(),
243250
downloadUrl = it.browserDownloadUrl,
244251
hash = it.digest?.removePrefix("sha256:"),
245252
fileName = it.name,

0 commit comments

Comments
 (0)