V1.3.9: 二维码跟随控制层 + 声音设置精简 + 远程滑杆绑定修复 + 搜索提速
1) 播放界面右上角二维码改为跟随控制层出现/隐藏
setFullScreenChromeVisible() 里同步 fullScreenQrOverlay 可见性,
updateFullScreenQrOverlay() 新建时按 fullScreenChromeVisible 初始化;
删除按"手机是否在点歌"自动隐藏的 qrAutoHideMonitor,
并删除扫码点歌弹窗里的"扫码点歌后自动隐藏播放界面二维码"提示词。
2) 声音设置删除音量调节与均衡器入口
移除「歌曲最大音量」滑杆(及 pendingMusicVolume)与「均衡器入口」按钮,
该弹窗只保留「切到点播歌曲时音量/原伴唱」这类策略选择; 音量与均衡器统一在「调音」弹窗。
3) 远程控制均衡器滑动点未完全绑定的真正原因: 滑杆被 <label> 包裹
<label> 会把内部任意位置的点击转发给 range -> 点轨道/点文字就跳值。
行容器 label -> div(.audio-row / .eq-band), CSS 相应改为类选择器;
滑杆元素高度 4px -> 32px(触控目标), 细轨道改由 ::-webkit-slider-runnable-track 绘制,
滑块 22px+5px 边框; attachThumbOnlyDrag 命中容差按 32px 滑块对齐(第二道防线)。
4) 远程搜歌界面: 歌曲移到左边、歌手移到右边
同步把默认搜索方式改为「歌曲」(否则左侧高亮与实际模式不一致), 初始 placeholder 同步。
5) 搜索提速(基于对 991MB/67 万首 muse.db 的实测)
实测: 中文 contains 热态 2~280ms; 拼音 GLOB 热态 0.2~150ms、冷态 1~15s;
歌手 EXISTS 34~70ms。瓶颈是冷态 I/O 与重复查库, 因此:
- 设备端新增 remoteSearchCache(LRU 24 条=4 查询×6 页, TTL 60s, 曲库刷新即清空),
同一「类型+关键词+页码」直接复用 JSON, 翻页/重复搜索不再查库;
- 手机端: AbortController 取消旧请求、同关键词不重复请求、首页返回后预热第 2 页、
搜索期间暂停 1s 状态轮询避免抢 I/O;
- 实测证明「一次多取几页」更慢(301 行 6.2s vs 21 行 0.7s), 故保持单页 LIMIT;
- 均衡器卡片收起时跳过其 DOM 刷新(展开时补渲染)。
版本号 1.3.8 -> 1.3.9(versionCode 14 -> 15)。按约定本次不发布 Release, 仅本地打包测试。
This commit is contained in:
+2
-2
@@ -11,8 +11,8 @@ android {
|
||||
applicationId "com.local.ktv"
|
||||
minSdk 21
|
||||
targetSdk 25
|
||||
versionCode 14
|
||||
versionName "1.3.8"
|
||||
versionCode 15
|
||||
versionName "1.3.9"
|
||||
ndk {
|
||||
// 双 ABI 打包:兼容 64 位(Exynos 1580 等 arm64-v8a)与 32 位设备(极米 Play 超越版
|
||||
// 的 Amlogic 950X2/S905X2 采用 32 位 Android 用户态,必须包含 armeabi-v7a,否则
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,9 +1,10 @@
|
||||
const $ = (selector) => document.querySelector(selector);
|
||||
const $$ = (selector) => document.querySelectorAll(selector);
|
||||
const uiState = {
|
||||
page: 1, query: "", searchMode: "singer", busy: false,
|
||||
page: 1, query: "", searchMode: "song", busy: false,
|
||||
hotPage: 1, hotPageSize: 10, hotBusy: false,
|
||||
visible: true, connected: false, eqEnabled: false
|
||||
visible: true, connected: false, eqEnabled: false,
|
||||
equalizer: null, searchAbort: null, searchKey: ""
|
||||
};
|
||||
|
||||
function escapeHtml(value) {
|
||||
@@ -81,7 +82,9 @@ async function refresh() {
|
||||
$("#original").classList.toggle("active", data.vocalMode === "original");
|
||||
$("#accompany").classList.toggle("active", data.vocalMode !== "original");
|
||||
$("#nextSong").textContent = data.next?.title || "队列为空";
|
||||
renderEqualizer(data.equalizer);
|
||||
// 均衡器卡片默认收起: 收起时跳过 DOM 更新(避免每秒轮询重绘), 展开时再渲染一次。
|
||||
uiState.equalizer = data.equalizer;
|
||||
if (!$("#eqBody")?.classList.contains("hidden")) renderEqualizer(data.equalizer);
|
||||
} catch (_) {
|
||||
setConnected(false);
|
||||
}
|
||||
@@ -107,7 +110,7 @@ function renderEqualizer(eq) {
|
||||
const bands = Array.isArray(eq.bands) ? eq.bands : [];
|
||||
const container = $("#eqBands");
|
||||
if (container && container.childElementCount !== bands.length) {
|
||||
container.innerHTML = bands.map((band, index) => `<label class="eq-band"><span>${escapeHtml(band.label)}Hz</span><b><em id="eqValue${index}">${Number(band.level).toFixed(1)}</em>dB</b><input id="eqBand${index}" type="range" min="${eq.minDb}" max="${eq.maxDb}" step="1" value="${band.level}"></label>`).join("");
|
||||
container.innerHTML = bands.map((band, index) => `<div class="eq-band"><span>${escapeHtml(band.label)}Hz</span><b><em id="eqValue${index}">${Number(band.level).toFixed(1)}</em>dB</b><input id="eqBand${index}" type="range" min="${eq.minDb}" max="${eq.maxDb}" step="1" value="${band.level}"></div>`).join("");
|
||||
bands.forEach((band, index) => {
|
||||
const input = $("#eqBand" + index);
|
||||
if (!input) return;
|
||||
@@ -160,7 +163,7 @@ function attachThumbOnlyDrag(input) {
|
||||
const x = point.clientX;
|
||||
const y = point.clientY;
|
||||
// 粗略还原轨道几何:控件左右各留半个滑块宽度。
|
||||
const thumb = 22;
|
||||
const thumb = 32;
|
||||
const trackLeft = rect.left + thumb / 2;
|
||||
const trackRight = rect.right - thumb / 2;
|
||||
const span = trackRight - trackLeft;
|
||||
@@ -200,31 +203,52 @@ async function updateAudio(values) {
|
||||
}
|
||||
|
||||
async function search(reset = true) {
|
||||
if (uiState.busy) return;
|
||||
if (reset) {
|
||||
uiState.page = 1;
|
||||
uiState.query = $("#query").value.trim();
|
||||
if (!uiState.query) {
|
||||
const nextQuery = $("#query").value.trim();
|
||||
if (!nextQuery) {
|
||||
toast(`请输入${uiState.searchMode === "singer" ? "歌手" : "歌曲"}名称`);
|
||||
$("#query").focus();
|
||||
return;
|
||||
}
|
||||
// 同一关键词+同一搜索方式且结果已渲染 → 不重复请求设备(设备端也要查 1GB 曲库)。
|
||||
const key = `${uiState.searchMode}|${nextQuery}`;
|
||||
if (key === uiState.searchKey && $("#results").childElementCount) {
|
||||
$("#searchResultBlock").scrollIntoView({ behavior: "smooth", block: "start" });
|
||||
return;
|
||||
}
|
||||
uiState.page = 1;
|
||||
uiState.query = nextQuery;
|
||||
uiState.searchKey = key;
|
||||
$("#results").innerHTML = "";
|
||||
$("#searchResultBlock").classList.remove("hidden");
|
||||
$("#resultTitle").textContent = uiState.searchMode === "singer" ? "歌手搜索结果" : "歌曲搜索结果";
|
||||
$("#resultSummary").textContent = `正在搜索“${uiState.query}”`;
|
||||
$("#more").classList.add("hidden");
|
||||
if (uiState.searchAbort) uiState.searchAbort.abort();
|
||||
uiState.searchAbort = new AbortController();
|
||||
}
|
||||
const signal = uiState.searchAbort ? uiState.searchAbort.signal : undefined;
|
||||
const requestedPage = uiState.page;
|
||||
uiState.busy = true;
|
||||
try {
|
||||
const data = await api(`/api/v1/songs?q=${encodeURIComponent(uiState.query)}&type=${uiState.searchMode}&page=${uiState.page}&pageSize=20`);
|
||||
const rows = (data.songs || []).map((song, index) => songRow(song, false, false, (uiState.page - 1) * 20 + index)).join("");
|
||||
const data = await api(`/api/v1/songs?q=${encodeURIComponent(uiState.query)}&type=${uiState.searchMode}&page=${requestedPage}&pageSize=20`, { signal });
|
||||
const rows = (data.songs || []).map((song, index) => songRow(song, false, false, (requestedPage - 1) * 20 + index)).join("");
|
||||
if (rows) $("#results").insertAdjacentHTML("beforeend", rows);
|
||||
else if (reset) $("#results").innerHTML = '<div class="empty">没有找到相关歌曲<br><small>请更换关键词后重试</small></div>';
|
||||
$("#resultSummary").textContent = `“${uiState.query}”${data.hasMore ? ",还有更多" : ""}`;
|
||||
$("#more").classList.toggle("hidden", !data.hasMore);
|
||||
uiState.page += 1;
|
||||
} catch (error) { toast(error.message); }
|
||||
finally { uiState.busy = false; }
|
||||
uiState.page = requestedPage + 1;
|
||||
// 预热下一页: 设备端会把它缓存下来, 用户点「更多」时基本瞬时。
|
||||
if (requestedPage === 1 && data.hasMore) {
|
||||
window.setTimeout(() => {
|
||||
api(`/api/v1/songs?q=${encodeURIComponent(uiState.query)}&type=${uiState.searchMode}&page=2&pageSize=20`)
|
||||
.catch(() => {});
|
||||
}, 500);
|
||||
}
|
||||
} catch (error) {
|
||||
// 被下一次搜索取消属于正常情况, 不弹提示。
|
||||
if (error && error.name !== "AbortError") toast(error.message);
|
||||
} finally { uiState.busy = false; }
|
||||
}
|
||||
|
||||
async function loadHot(page) {
|
||||
@@ -317,8 +341,11 @@ $("#eqCollapse")?.addEventListener("click", () => {
|
||||
if (!body) return;
|
||||
const collapsed = body.classList.toggle("hidden");
|
||||
$("#eqCollapse").setAttribute("aria-expanded", collapsed ? "false" : "true");
|
||||
// 展开时补一次渲染(收起期间轮询跳过了 EQ 的 DOM 更新)。
|
||||
if (!collapsed) renderEqualizer(uiState.equalizer);
|
||||
});
|
||||
document.addEventListener("visibilitychange", () => { uiState.visible = !document.hidden; if (uiState.visible) refresh(); });
|
||||
window.setInterval(() => { if (uiState.visible) refresh(); }, 1000);
|
||||
// 搜索进行中暂停状态轮询: 避免与设备端 1GB 曲库查询抢 I/O。
|
||||
window.setInterval(() => { if (uiState.visible && !uiState.busy) refresh(); }, 1000);
|
||||
refresh();
|
||||
loadHot(1);
|
||||
|
||||
@@ -36,8 +36,8 @@
|
||||
<article class="glass-card audio-panel">
|
||||
<div class="panel-title"><div><span class="tiny-icon">♪</span><b>声音控制</b></div><small>即时生效</small></div>
|
||||
<div class="seg"><button id="accompany" data-vocal="accompany"><span>伴</span>伴唱</button><button id="original" data-vocal="original"><span>原</span>原唱</button></div>
|
||||
<label><span><i class="volume-icon">♪</i>音乐音量</span><b><em id="musicValue">85</em>%</b><input id="musicVolume" type="range" min="0" max="100" value="85"></label>
|
||||
<label class="mic-hw"><span><i class="volume-icon mic">●</i>麦克风音量</span><small>由功放/混音器硬件调节</small><input id="micVolume" type="range" min="0" max="100" value="70" disabled></label>
|
||||
<div class="audio-row"><span><i class="volume-icon">♪</i>音乐音量</span><b><em id="musicValue">85</em>%</b><input id="musicVolume" type="range" min="0" max="100" value="85"></div>
|
||||
<div class="audio-row mic-hw"><span><i class="volume-icon mic">●</i>麦克风音量</span><small>由功放/混音器硬件调节</small><input id="micVolume" type="range" min="0" max="100" value="70" disabled></div>
|
||||
</article>
|
||||
|
||||
<article class="glass-card eq-panel">
|
||||
@@ -62,10 +62,10 @@
|
||||
<section id="search" class="page">
|
||||
<div class="page-heading"><div><p>SONG LIBRARY</p><h2>想唱什么?</h2></div><span>海量本地曲库</span></div>
|
||||
<div class="search-mode" role="group" aria-label="搜索方式">
|
||||
<button type="button" data-search-mode="singer" class="active">歌手</button>
|
||||
<button type="button" data-search-mode="song">歌曲</button>
|
||||
<button type="button" data-search-mode="song" class="active">歌曲</button>
|
||||
<button type="button" data-search-mode="singer">歌手</button>
|
||||
</div>
|
||||
<form id="searchForm" class="search-box"><span class="search-icon"></span><input id="query" autocomplete="off" placeholder="输入歌手名或拼音"><button type="submit">搜索</button></form>
|
||||
<form id="searchForm" class="search-box"><span class="search-icon"></span><input id="query" autocomplete="off" placeholder="输入歌曲名或拼音"><button type="submit">搜索</button></form>
|
||||
<div id="searchResultBlock" class="search-result-block hidden">
|
||||
<div class="block-title"><h3 id="resultTitle">歌手搜索结果</h3><span id="resultSummary"></span></div>
|
||||
<div id="results" class="list"></div><button id="more" class="more hidden">加载更多歌曲</button>
|
||||
|
||||
@@ -150,6 +150,18 @@ class MainActivity : AppCompatActivity() {
|
||||
private val remoteServer by lazy { LocalRemoteServer(this) }
|
||||
@Volatile private var remoteStateVersion = 1L
|
||||
private val remoteSongCache = Collections.synchronizedMap(LinkedHashMap<String, Song>())
|
||||
|
||||
/**
|
||||
* 远程搜索结果的短期缓存(LRU,最多 24 条 = 最近 4 个查询 × 6 页)。
|
||||
*
|
||||
* 曲库 DB 有 67 万首/约 1GB,搜索是 I/O 密集操作(实测同一查询冷态数秒、热态数十至数百毫秒)。
|
||||
* 同一「类型+关键词+页码」重复请求直接复用上次的 JSON,翻页(「更多」)与重复搜索不再查库。
|
||||
* TTL 60s + 曲库刷新时清空,保证隐藏/删除歌曲后结果及时跟上。
|
||||
*/
|
||||
private val remoteSearchCache = object : LinkedHashMap<String, Pair<String, Long>>(8, 0.75f, true) {
|
||||
override fun removeEldestEntry(eldest: MutableMap.MutableEntry<String, Pair<String, Long>>?): Boolean =
|
||||
size > 24
|
||||
}
|
||||
private var mobileQrOverlay: View? = null
|
||||
private var fullScreenQrOverlay: View? = null
|
||||
private var updateCheckStarted = false
|
||||
@@ -170,25 +182,6 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
/** 全屏右上角扫码点歌二维码显隐控制: 手机连接点歌(页面可见时每秒轮询 state)
|
||||
* 期间自动隐藏, 断开(无请求超过约 4 秒)后恢复显示。 */
|
||||
private val qrAutoHideMonitor = object : Runnable {
|
||||
private var hiddenByClient = false
|
||||
override fun run() {
|
||||
val overlay = fullScreenQrOverlay
|
||||
if (overlay != null && isFullScreen) {
|
||||
val active = remoteServer.hasRecentActivity(4000)
|
||||
if (active && !hiddenByClient) {
|
||||
hiddenByClient = true
|
||||
overlay.visibility = View.GONE
|
||||
} else if (!active && hiddenByClient) {
|
||||
hiddenByClient = false
|
||||
overlay.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
main.postDelayed(this, 1000)
|
||||
}
|
||||
}
|
||||
/** 周期向 hbeat.ktvsky.com 上报设备身份,维持歌曲源对"合法设备"的判定。 */
|
||||
private val ktvHeartbeatRunnable = object : Runnable {
|
||||
override fun run() {
|
||||
@@ -505,7 +498,6 @@ class MainActivity : AppCompatActivity() {
|
||||
startRemoteServer()
|
||||
updateMobileQrOverlay()
|
||||
main.postDelayed(remoteNetworkMonitor, 5000)
|
||||
main.postDelayed(qrAutoHideMonitor, 1000)
|
||||
// 设备心跳:开机立即上报一次(boot=1),之后每 3600s 保活,维持歌曲源合法设备判定。
|
||||
sendDeviceHeartbeat(boot = true)
|
||||
main.postDelayed(ktvHeartbeatRunnable, HEARTBEAT_INTERVAL_MS)
|
||||
@@ -690,7 +682,6 @@ class MainActivity : AppCompatActivity() {
|
||||
main.removeCallbacks(homeBannerRunnable)
|
||||
main.removeCallbacks(autoFullscreenRunnable)
|
||||
main.removeCallbacks(remoteNetworkMonitor)
|
||||
main.removeCallbacks(qrAutoHideMonitor)
|
||||
stopRecording(false)
|
||||
unregisterMicInputWatcher()
|
||||
micActivator.stop()
|
||||
@@ -2419,6 +2410,8 @@ class MainActivity : AppCompatActivity() {
|
||||
fullScreenChromeVisible = visible
|
||||
fullScreenControls?.visibility = if (visible) View.VISIBLE else View.GONE
|
||||
fullScreenProgressRow?.visibility = if (visible) View.VISIBLE else View.GONE
|
||||
// 右上角二维码跟随控制层一起出现/隐藏(不再按"手机是否在点歌"自动隐藏)。
|
||||
fullScreenQrOverlay?.visibility = if (visible) View.VISIBLE else View.GONE
|
||||
main.removeCallbacks(hideFullScreenChromeRunnable)
|
||||
if (visible && isFullScreen) {
|
||||
val controls = fullScreenControls
|
||||
@@ -3156,10 +3149,6 @@ class MainActivity : AppCompatActivity() {
|
||||
addressLine.gravity = Gravity.CENTER
|
||||
box.addView(addressLine, LinearLayout.LayoutParams(-1, dp(32)))
|
||||
}
|
||||
// 提示:扫码连上后播放界面右上角二维码会自动隐藏。
|
||||
val hint = label("扫码点歌后自动隐藏播放界面二维码", 14, Color.rgb(193, 193, 193))
|
||||
hint.gravity = Gravity.CENTER
|
||||
box.addView(hint, LinearLayout.LayoutParams(-1, dp(if (compact) 26 else 30)))
|
||||
val scroll = android.widget.ScrollView(this).apply { addView(box) }
|
||||
val dialog = AlertDialog.Builder(this)
|
||||
.setTitle("扫码点歌")
|
||||
@@ -3254,6 +3243,8 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
container.addView(box, params)
|
||||
box.bringToFront()
|
||||
// 跟随控制层显隐:控制层收起时二维码也不显示(新建时按当前状态初始化)。
|
||||
box.visibility = if (fullScreenChromeVisible) View.VISIBLE else View.GONE
|
||||
// 同手机点歌二维码: 展示型表面不做焦点填充。
|
||||
TvFocusStyler.suppressFill(box)
|
||||
fullScreenQrOverlay = box
|
||||
@@ -3741,12 +3732,22 @@ class MainActivity : AppCompatActivity() {
|
||||
return remoteOk(equalizerJson().put("message", "均衡器已更新"))
|
||||
}
|
||||
|
||||
/** 远程搜索结果缓存有效期。 */
|
||||
private val SEARCH_CACHE_TTL_MS = 60_000L
|
||||
|
||||
private fun remoteSearchJson(query: Map<String, String>): JSONObject {
|
||||
val keyword = query["q"].orEmpty().trim()
|
||||
val type = query["type"].orEmpty().lowercase(Locale.ROOT).let { if (it == "song") "song" else "singer" }
|
||||
val page = (query["page"]?.toIntOrNull() ?: 1).coerceAtLeast(1)
|
||||
val pageSize = (query["pageSize"]?.toIntOrNull() ?: 20).coerceIn(1, 50)
|
||||
val offset = (page - 1) * pageSize
|
||||
// 命中缓存: 不再查 1GB 曲库(翻页/重复搜索基本瞬时)。
|
||||
val cacheKey = "$type|$keyword|$page|$pageSize"
|
||||
remoteSearchCache[cacheKey]?.let { (json, at) ->
|
||||
if (System.currentTimeMillis() - at < SEARCH_CACHE_TTL_MS) {
|
||||
runCatching { JSONObject(json) }.getOrNull()?.let { return it }
|
||||
}
|
||||
}
|
||||
val songs = if (library.muse.isAvailable() && keyword.isNotBlank()) {
|
||||
if (type == "singer") library.muse.searchSongsBySingerKeyword(keyword, offset, pageSize + 1)
|
||||
else library.muse.searchSongs(keyword, offset, pageSize + 1)
|
||||
@@ -3767,8 +3768,10 @@ class MainActivity : AppCompatActivity() {
|
||||
array.put(songJson(song))
|
||||
}
|
||||
while (remoteSongCache.size > 500) remoteSongCache.remove(remoteSongCache.keys.first())
|
||||
return JSONObject().put("songs", array).put("page", page).put("pageSize", pageSize)
|
||||
val payload = JSONObject().put("songs", array).put("page", page).put("pageSize", pageSize)
|
||||
.put("type", type).put("hasMore", hasMore)
|
||||
remoteSearchCache[cacheKey] = payload.toString() to System.currentTimeMillis()
|
||||
return payload
|
||||
}
|
||||
|
||||
private fun remoteHotJson(query: Map<String, String>): JSONObject {
|
||||
@@ -6190,6 +6193,8 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
private fun refreshLibrary(after: Runnable?) {
|
||||
// 曲库变化后远程搜索结果缓存立即失效,避免还搜到已隐藏/已删除的歌。
|
||||
remoteSearchCache.clear()
|
||||
busy(true, "正在扫描曲库...")
|
||||
io.execute(Runnable {
|
||||
val locals = library.scanLocal().size
|
||||
@@ -8956,7 +8961,6 @@ class MainActivity : AppCompatActivity() {
|
||||
var pendingOrderedSongOriginal = orderedSongOriginal
|
||||
var pendingOrderedVolumeMode = orderedVolumeMode
|
||||
var pendingOrderedVocalMode = orderedVocalMode
|
||||
var pendingMusicVolume = musicVolume
|
||||
fun title(text: String) = TextView(this).apply {
|
||||
this.text = text; textSize = 16f; setTextColor(Color.WHITE); setPadding(0, dp(4), 0, 0)
|
||||
}
|
||||
@@ -8979,23 +8983,12 @@ class MainActivity : AppCompatActivity() {
|
||||
changed(index)
|
||||
}
|
||||
}
|
||||
val musicVolumeTitle = title("歌曲最大音量 ${pendingMusicVolume}%")
|
||||
// 说明:音量调节与均衡器入口已从这里移除 —— 它们统一收敛到「调音」弹窗,
|
||||
// 避免同一功能出现两套入口(音量滑杆 + 均衡器开关/预设/频段都在「调音」里)。
|
||||
val left = LinearLayout(this).apply {
|
||||
orientation = LinearLayout.VERTICAL
|
||||
addView(title("切到点播歌曲时音量:"))
|
||||
addView(choices(arrayOf("跟随上首音量", "跟随上首点播歌曲音量"), pendingOrderedVolumeMode) { pendingOrderedVolumeMode = it })
|
||||
addView(musicVolumeTitle)
|
||||
addView(SeekBar(this@MainActivity).apply {
|
||||
max = 100; progress = pendingMusicVolume
|
||||
setOnSeekBarChangeListener(object : OnSeekBarChangeListener {
|
||||
override fun onProgressChanged(bar: SeekBar?, value: Int, fromUser: Boolean) {
|
||||
pendingMusicVolume = value
|
||||
musicVolumeTitle.text = "歌曲最大音量 ${pendingMusicVolume}%"
|
||||
}
|
||||
override fun onStartTrackingTouch(bar: SeekBar?) = Unit
|
||||
override fun onStopTrackingTouch(bar: SeekBar?) = Unit
|
||||
})
|
||||
})
|
||||
}
|
||||
val right = LinearLayout(this).apply {
|
||||
orientation = LinearLayout.VERTICAL
|
||||
@@ -9009,26 +9002,9 @@ class MainActivity : AppCompatActivity() {
|
||||
addView(left, LinearLayout.LayoutParams(0, -2, 1f).apply { marginEnd = dp(28) })
|
||||
addView(right, LinearLayout.LayoutParams(0, -2, 1f))
|
||||
}
|
||||
// 均衡器入口:与播放界面/主页「调音」里的入口等价,修改即时生效。
|
||||
val eqEntry = TextView(this).apply {
|
||||
text = "均衡器入口 ›"
|
||||
textSize = 17f
|
||||
setTextColor(Color.WHITE)
|
||||
gravity = Gravity.CENTER
|
||||
background = getDrawable(R.drawable.bg_btn_glass)
|
||||
isClickable = true
|
||||
isFocusable = true
|
||||
setPadding(dp(12), dp(10), dp(12), dp(10))
|
||||
setOnClickListener { showTuningDialog() }
|
||||
TvFocusStyler.installAction(this)
|
||||
}
|
||||
val body = LinearLayout(this).apply {
|
||||
orientation = LinearLayout.VERTICAL
|
||||
addView(content, LinearLayout.LayoutParams(-1, -2))
|
||||
addView(eqEntry, LinearLayout.LayoutParams(-1, dp(48)).apply {
|
||||
marginStart = dp(28)
|
||||
marginEnd = dp(28)
|
||||
})
|
||||
}
|
||||
val scroll = android.widget.ScrollView(this).apply { addView(body) }
|
||||
val dialog = AlertDialog.Builder(this).setTitle("声音设置")
|
||||
@@ -9038,7 +9014,6 @@ class MainActivity : AppCompatActivity() {
|
||||
orderedSongOriginal = pendingOrderedSongOriginal
|
||||
orderedVolumeMode = pendingOrderedVolumeMode
|
||||
orderedVocalMode = pendingOrderedVocalMode
|
||||
musicVolume = pendingMusicVolume
|
||||
applyPlaybackMode()
|
||||
saveState()
|
||||
}.create()
|
||||
|
||||
Reference in New Issue
Block a user