From ff0ae402efe806e85ec34e91ec3a19d00daaf012 Mon Sep 17 00:00:00 2001 From: zijunchiang Date: Sat, 5 Sep 2026 01:37:58 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96:=20=E5=90=AF=E5=8A=A8?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E9=9A=8F=E6=9C=BA=E6=92=AD=E6=94=BE=E6=9C=AC?= =?UTF-8?q?=E5=9C=B0=E6=AD=8C=E6=9B=B2=20+=20=E6=95=B0=E6=8D=AE=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E7=95=8C=E9=9D=A2=E5=8D=A1=E9=A1=BF=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 启动无恢复播放/空队列时, 曲库就绪后自动随机播放本地已下载歌曲 (playRandomLocalSong 增加 startup 文案, 与播放完毕随机续播同逻辑, 点歌即取消) - 数据设置: 曲库/下载数统计(逐文件校验)从主线程移到 IO 线程, 界面秒开先显示占位, 统计完成后原位回填副标题(updateSubtitle), 不丢焦点 --- .../main/java/com/local/ktv/MainActivity.kt | 43 +++++++++++++++++-- .../java/com/local/ktv/SettingsListAdapter.kt | 12 +++++- 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/local/ktv/MainActivity.kt b/app/src/main/java/com/local/ktv/MainActivity.kt index 723a81e..2f4797e 100644 --- a/app/src/main/java/com/local/ktv/MainActivity.kt +++ b/app/src/main/java/com/local/ktv/MainActivity.kt @@ -300,6 +300,7 @@ class MainActivity : AppCompatActivity() { private val browseDisplayRequests = HashMap() private var searchScope = "song" private var activeSettingsEntries: List = emptyList() + private var activeSettingsAdapter: SettingsListAdapter? = null private var activeSearchQuery = "" private var searchLanguage = "全部" private var searchContextId = "" @@ -459,6 +460,10 @@ class MainActivity : AppCompatActivity() { startupSong?.let { restoredSong -> play(restoredSong) updateBottomBar(restoredSong, true) + } ?: run { + // 启动时没有恢复的播放与已点歌曲: 曲库就绪后自动随机播放本地已下载歌曲 + // (与"点歌列表播放完毕自动随机本地歌曲"同一逻辑), 避免开机后空白等待。 + startupRandomPending = true } // Keep initialization on the loading state until the external catalog is ready. SongApiClient.init(this) // 主线程初始化 JS Bridge @@ -507,6 +512,13 @@ class MainActivity : AppCompatActivity() { showHomePage() if (usedOldDatabase && bootstrapError != null) toast("曲库更新失败,已使用本地曲库") if (catalogRefreshPending) refreshCurrentCatalogPage() + // 启动自动随机播放: 仅当启动时无恢复播放/空队列且允许顺序播放时触发一次。 + if (startupRandomPending) { + startupRandomPending = false + if (autoNext && orderQueue!!.isEmpty() && currentSong == null) { + main.postDelayed({ playRandomLocalSong(startup = true) }, 600L) + } + } } } else { val reason = bootstrapError?.message.orEmpty().ifBlank { "未找到可用曲库" } @@ -5140,10 +5152,10 @@ class MainActivity : AppCompatActivity() { } /** - * 已点队列自然播放完毕后,从本机所有有效歌曲中随机续播。 + * 从本机所有有效歌曲中随机续播(启动自动播放 / 点歌列表播放完毕均走此逻辑)。 * 随机歌曲不写入已点列表;用户此时点歌会立即取消本次随机请求并优先播放已点歌曲。 */ - private fun playRandomLocalSong() { + private fun playRandomLocalSong(startup: Boolean = false) { val previousSongId = currentSong?.let(::stableId) ?: lastRandomLocalSongId val requestSerial = ++randomLocalRequestSerial playbackPreparing = true @@ -5152,7 +5164,7 @@ class MainActivity : AppCompatActivity() { currentSong = null clearLyrics() updateBottomBar(null, false) - status?.text = "已点播放完成,正在随机本地歌曲..." + status?.text = if (startup) "正在随机播放本地歌曲..." else "已点播放完成,正在随机本地歌曲..." persistRuntimeState() io.execute { @@ -6242,6 +6254,8 @@ class MainActivity : AppCompatActivity() { private var fullScreenPreviousVolume = 70 private var randomLocalRequestSerial = 0L private var lastRandomLocalSongId: String? = null + /** 启动时无恢复播放/空队列: 曲库就绪后自动随机播放本地已下载歌曲(仅触发一次)。 */ + private var startupRandomPending = false private var advancingPlayback = false private var lastAutoAdvanceAtMs = 0L private var fullScreenChromeVisible = false @@ -8135,7 +8149,12 @@ class MainActivity : AppCompatActivity() { }, ) 1 -> listOf( - SettingsEntry(R.drawable.ott_ic_data_upgrade, "曲库", "数据库 ${library.muse.songCount()} 首 本地已下载 ${countDownloadedFiles()} 首", "更新") { + SettingsEntry( + R.drawable.ott_ic_data_upgrade, + "曲库", + "统计中…", + "更新", + ) { io.execute { library.muse.close(); library.muse.open(); main.post { showSettingsSection(1, false) } } }, SettingsEntry(R.drawable.ott_ic_data_setting, "U盘加歌", "扫描U盘内按规定命名的歌曲文件,并添加到曲库中", "立即加歌") { toast("未检测到U盘") }, @@ -8164,9 +8183,25 @@ class MainActivity : AppCompatActivity() { songList!!.dividerHeight = dp(12) songList!!.setBackgroundColor(Color.TRANSPARENT) val settingsAdapter = SettingsListAdapter(this, entries, R.id.btn_back) + activeSettingsAdapter = settingsAdapter songList!!.adapter = settingsAdapter btnBack?.nextFocusDownId = settingsAdapter.firstActionId if (requestInitialFocus) settingsAdapter.requestInitialFocus(songList!!) + // 数据设置: 曲库/下载数统计较耗时(逐文件校验), 移到 IO 线程, 避免进入界面卡顿。 + if (section == 1) refreshLibraryStatsAsync(settingsAdapter) + } + + /** IO 线程统计曲库歌曲数与本地已下载数, 完成后原位回填"曲库"条副标题。 */ + private fun refreshLibraryStatsAsync(adapter: SettingsListAdapter) { + io.execute { + val count = runCatching { library.muse.songCount() }.getOrDefault(0) + val downloaded = runCatching { countDownloadedFiles() }.getOrDefault(0) + main.post { + if (activeSettingsAdapter === adapter) { + adapter.updateSubtitle("曲库", "数据库 $count 首 本地已下载 $downloaded 首") + } + } + } } private fun isNetworkConnected(): Boolean { diff --git a/app/src/main/java/com/local/ktv/SettingsListAdapter.kt b/app/src/main/java/com/local/ktv/SettingsListAdapter.kt index 37ac921..5b145cc 100644 --- a/app/src/main/java/com/local/ktv/SettingsListAdapter.kt +++ b/app/src/main/java/com/local/ktv/SettingsListAdapter.kt @@ -15,7 +15,7 @@ import android.widget.Switch data class SettingsEntry( val icon: Int, val title: String, - val subtitle: String = "", + var subtitle: String = "", val actionText: String = "设置", val checked: Boolean? = null, val action: () -> Unit, @@ -112,6 +112,16 @@ class SettingsListAdapter( requestFocusAt(list, 0, onTargetReady) } + /** 原位更新某条目的副标题(如异步统计完成后回填), 不重建列表、不丢焦点。 */ + fun updateSubtitle(title: String, newSubtitle: String) { + val index = entries.indexOfFirst { it.title == title } + if (index < 0) return + val entry = entries[index] + if (entry.subtitle == newSubtitle) return + entry.subtitle = newSubtitle + notifyDataSetChanged() + } + fun positionForMarker(marker: String): Int? { val prefix = "focus:settings:" if (!marker.startsWith(prefix)) return null