From 6ae217b9cdad7b648c0972cead50af02fb4479ed Mon Sep 17 00:00:00 2001 From: Hermes Agent Date: Thu, 8 Oct 2026 13:31:40 +0800 Subject: [PATCH] =?UTF-8?q?v9.0.0=20=E8=AE=BE=E7=BD=AE=E9=A1=B5/=E5=95=86?= =?UTF-8?q?=E5=BA=97=E9=A1=B5=E9=81=A5=E6=8E=A7=E7=84=A6=E7=82=B9=E9=AB=98?= =?UTF-8?q?=E4=BA=AE(=E8=8E=B7=E5=BE=97=E7=84=A6=E7=82=B9=E5=8F=98?= =?UTF-8?q?=E8=93=9D)+=E5=95=86=E5=BA=97=E6=89=8B=E5=8A=A8=E5=AF=BC?= =?UTF-8?q?=E8=88=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 4 +- .../java/com/iptv807/tv/SettingsActivity.kt | 52 ++++++--- .../main/java/com/iptv807/tv/ShopActivity.kt | 108 +++++++++++++++--- 3 files changed, 135 insertions(+), 29 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 3e0833f..940e26d 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -11,8 +11,8 @@ android { applicationId = "com.iptv807.tv" minSdk = 21 targetSdk = 35 - versionCode = 890 - versionName = "8.9.0" + versionCode = 900 + versionName = "9.0.0" } buildTypes { diff --git a/app/src/main/java/com/iptv807/tv/SettingsActivity.kt b/app/src/main/java/com/iptv807/tv/SettingsActivity.kt index 31874ac..9f8b5ce 100644 --- a/app/src/main/java/com/iptv807/tv/SettingsActivity.kt +++ b/app/src/main/java/com/iptv807/tv/SettingsActivity.kt @@ -27,6 +27,29 @@ class SettingsActivity : Activity() { private lateinit var statusText: TextView + /** 焦点高亮背景:获得焦点→蓝色,普通→深灰 */ + private fun focusBg(normal: Int = 0xFF2A2F3A.toInt(), focused: Int = 0xFF1B6EF3.toInt()) + : android.graphics.drawable.StateListDrawable { + val sl = android.graphics.drawable.StateListDrawable() + sl.addState(intArrayOf(android.R.attr.state_focused), android.graphics.drawable.ColorDrawable(focused)) + sl.addState(intArrayOf(), android.graphics.drawable.ColorDrawable(normal)) + return sl + } + + /** 可聚焦的操作行(代替固定背景的 Button,保证遥控器上能看到选中) */ + private fun mkAction(label: String, onClick: () -> Unit): TextView = + TextView(this).apply { + text = label + textSize = 17f + setTextColor(Color.WHITE) + gravity = Gravity.CENTER + setPadding(24, 26, 24, 26) + isFocusable = true + isFocusableInTouchMode = true + background = focusBg() + setOnClickListener { onClick() } + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) try { @@ -44,7 +67,12 @@ class SettingsActivity : Activity() { setBackgroundColor(Color.parseColor("#12141A")) setPadding(96, 64, 96, 64) } - setContentView(root) + val scroll = android.widget.ScrollView(this).apply { + setBackgroundColor(Color.parseColor("#12141A")) + isFillViewport = true + } + scroll.addView(root) + setContentView(scroll) root.addView(TextView(this).apply { text = "设置" @@ -88,7 +116,9 @@ class SettingsActivity : Activity() { isChecked = isBootReceiverEnabled() val pad = (24 * resources.displayMetrics.density).toInt() setPadding(pad, pad / 2, pad, pad / 2) - setBackgroundColor(Color.parseColor("#1C2028")) + isFocusable = true + isFocusableInTouchMode = true + background = focusBg(normal = 0xFF1C2028.toInt()) } bootSwitch.setOnCheckedChangeListener { _, checked -> val pm = packageManager @@ -135,20 +165,17 @@ class SettingsActivity : Activity() { textSize = 16f setTextColor(Color.WHITE) setHintTextColor(Color.parseColor("#888888")) - setBackgroundColor(Color.parseColor("#1C2028")) setPadding(24, 20, 24, 20) isSingleLine = true + isFocusable = true + isFocusableInTouchMode = true + background = focusBg(normal = 0xFF1C2028.toInt()) inputType = android.text.InputType.TYPE_CLASS_TEXT } root.addView(cardInput, LinearLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT).apply { bottomMargin = 12 }) - val actBtn = Button(this).apply { - text = "激活" - textSize = 17f - setBackgroundColor(Color.parseColor("#1B6EF3")) - setOnClickListener { doActivate(cardInput.text.toString().trim()) } - } + val actBtn = mkAction("激活") { doActivate(cardInput.text.toString().trim()) } root.addView(actBtn, LinearLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT).apply { bottomMargin = 40 }) @@ -159,11 +186,8 @@ class SettingsActivity : Activity() { gravity = Gravity.CENTER; setPadding(0, 24, 0, 24) }) } else { - val btn = Button(this).apply { - text = "支付成为会员(月/季/年)" - textSize = 17f - setBackgroundColor(Color.parseColor("#1B6EF3")) - setOnClickListener { startActivity(Intent(this@SettingsActivity, ShopActivity::class.java)) } + val btn = mkAction("支付成为会员(月/季/年)") { + startActivity(Intent(this@SettingsActivity, ShopActivity::class.java)) } root.addView(btn, LinearLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)) diff --git a/app/src/main/java/com/iptv807/tv/ShopActivity.kt b/app/src/main/java/com/iptv807/tv/ShopActivity.kt index fd09115..4dbc12d 100644 --- a/app/src/main/java/com/iptv807/tv/ShopActivity.kt +++ b/app/src/main/java/com/iptv807/tv/ShopActivity.kt @@ -33,11 +33,44 @@ class ShopActivity : Activity() { data class Plan(val id: Int, val name: String, val price: String, val days: Int) private lateinit var list: ListView + private var rowAdapterRef: RowAdapter? = null + private lateinit var alipay: TextView + private lateinit var wxpay: TextView + private var shopZone = 0 // 0=套餐列表 1=支付方式 private lateinit var statusText: TextView private var payType = "alipay" private var orderNo = "" private var machineId = "" private val handler = Handler(Looper.getMainLooper()) + + /** 高亮自控的行适配器 */ + private inner class RowAdapter(private var items: List) : android.widget.BaseAdapter() { + var selected = 0 + set(value) { field = value; notifyDataSetChanged() } + fun setItems(v: List) { items = v; notifyDataSetChanged() } + override fun getCount(): Int = items.size + override fun getItem(position: Int): Any = items[position] + override fun getItemId(position: Int): Long = position.toLong() + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val tv = (convertView as? TextView) ?: TextView(this@ShopActivity).apply { + textSize = 18f; setPadding(36, 26, 36, 26) + isSingleLine = true + ellipsize = android.text.TextUtils.TruncateAt.END + } + tv.text = items[position] + val on = position == selected + tv.setBackgroundColor(if (on) Color.parseColor("#1B6EF3") else Color.parseColor("#1C1F26")) + tv.setTextColor(Color.WHITE) + return tv + } + } + + private fun focusBg(normal: Int, focused: Int): android.graphics.drawable.StateListDrawable { + val sl = android.graphics.drawable.StateListDrawable() + sl.addState(intArrayOf(android.R.attr.state_focused), android.graphics.drawable.ColorDrawable(focused)) + sl.addState(intArrayOf(), android.graphics.drawable.ColorDrawable(normal)) + return sl + } private var pollTask: Runnable? = null private var pollCount = 0 @@ -76,6 +109,10 @@ class ShopActivity : Activity() { list = ListView(this).apply { setBackgroundColor(Color.parseColor("#1C1F26")) + setSelector(android.graphics.drawable.ColorDrawable(Color.TRANSPARENT)) + isFocusable = false + isFocusableInTouchMode = false + setItemsCanFocus(false) } root.addView(list, LinearLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, 0, 1f @@ -88,15 +125,16 @@ class ShopActivity : Activity() { root.addView(statusText) val row = LinearLayout(this).apply { orientation = LinearLayout.HORIZONTAL } - val alipay = Button(this).apply { text = "支付宝"; textSize = 15f } - val wxpay = Button(this).apply { text = "微信"; textSize = 15f } - fun sel(b: Button, t: String) { - val active = payType == t - b.setBackgroundColor(if (active) Color.parseColor("#1B6EF3") else Color.parseColor("#2A2F3A")) + fun mkPay(label: String, t: String) = TextView(this).apply { + text = label; textSize = 16f + setTextColor(Color.WHITE); gravity = Gravity.CENTER + setPadding(24, 26, 24, 26) + isFocusable = true; isFocusableInTouchMode = true + background = focusBg(0xFF2A2F3A.toInt(), 0xFF1B6EF3.toInt()) + setOnClickListener { payType = t; refreshPayBtns() } } - alipay.setOnClickListener { payType = "alipay"; sel(alipay, "alipay"); sel(wxpay, "wxpay") } - wxpay.setOnClickListener { payType = "wxpay"; sel(alipay, "alipay"); sel(wxpay, "wxpay") } - sel(alipay, "alipay"); sel(wxpay, "wxpay") + alipay = mkPay("支付宝", "alipay") + wxpay = mkPay("微信", "wxpay") row.addView(alipay, LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f).apply { rightMargin = 16 }) row.addView(wxpay, LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f)) root.addView(row) @@ -104,10 +142,20 @@ class ShopActivity : Activity() { list.onItemClickListener = AdapterView.OnItemClickListener { _, _, pos, _ -> if (pos < plans.size) createOrder(plans[pos]) } + refreshPayBtns() loadPlans() } + /** 当前支付方式:亮蓝 + 焦点时更亮 */ + private fun refreshPayBtns() { + val a = payType == "alipay" + alipay.setBackgroundColor(Color.parseColor(if (a) "#1B6EF3" else "#2A2F3A")) + wxpay.setBackgroundColor(Color.parseColor(if (a) "#2A2F3A" else "#1B6EF3")) + alipay.alpha = if (a) 1f else 0.75f + wxpay.alpha = if (a) 0.75f else 1f + } + @SuppressLint("SetTextI18n") private fun loadPlans() { statusText.text = "加载套餐…" @@ -130,11 +178,13 @@ class ShopActivity : Activity() { } runOnUiThread { plans.sortBy { it.days } - list.adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, plans.map { + val ra = RowAdapter(plans.map { val d = it.days "📱 ${it.name} ¥${it.price} ${if (d >= 999) "永久" else "${d}天"}" }) - statusText.text = "选择套餐后按 OK 购买" + rowAdapterRef = ra + list.adapter = ra + statusText.text = "上下选择套餐,OK 购买;左右可切支付方式" } } catch (e: Exception) { runOnUiThread { statusText.text = "加载失败: ${e.javaClass.simpleName}: ${e.message?.take(150)}" } @@ -237,9 +287,41 @@ class ShopActivity : Activity() { } override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { - if (keyCode == KeyEvent.KEYCODE_BACK && pollTask != null) { - // 支付轮询中返回 → 取消轮询 - handler.removeCallbacks(pollTask!!); pollTask = null + // 支付中:回归普通处理 + if (pollTask != null) { + if (keyCode == KeyEvent.KEYCODE_BACK) { handler.removeCallbacks(pollTask!!); pollTask = null } + return super.onKeyDown(keyCode, event) + } + val ra = rowAdapterRef + when (keyCode) { + KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN -> { + val delta = if (keyCode == KeyEvent.KEYCODE_DPAD_UP) -1 else 1 + if (shopZone == 0 && ra != null && ra.count > 0) { + val np = ra.selected + delta + if (np < 0) { shopZone = 1; refreshPayBtns(); alipay.requestFocus() } + else { ra.selected = np.coerceAtMost(ra.count - 1); list.setSelection(ra.selected) } + } else if (shopZone == 1) { + if (delta > 0) { } else { shopZone = 0; ra?.let { list.setSelection(it.selected) } } + } + return true + } + KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT -> { + if (shopZone == 1) { payType = if (payType == "alipay") "wxpay" else "alipay"; refreshPayBtns() } + else if (ra != null && ra.count > 0) { + // 列表里左右也可切支付方式,方便一步到位 + payType = if (payType == "alipay") "wxpay" else "alipay"; refreshPayBtns() + } + return true + } + KeyEvent.KEYCODE_DPAD_CENTER, KeyEvent.KEYCODE_ENTER, KeyEvent.KEYCODE_NUMPAD_ENTER -> { + if (shopZone == 1) { payType = if (payType == "alipay") "wxpay" else "alipay"; refreshPayBtns() } + else { + val pos = ra?.selected ?: -1 + if (pos in plans.indices) createOrder(plans[pos]) + } + return true + } + KeyEvent.KEYCODE_BACK -> { finish(); return true } } return super.onKeyDown(keyCode, event) }