v9.0.0 设置页/商店页遥控焦点高亮(获得焦点变蓝)+商店手动导航
This commit is contained in:
1 parent
1798429a2f
commit
6ae217b9cd
3 files changed
+135
-29
No files matched your search
@@ -11,8 +11,8 @@ android {
|
|||||||
applicationId = "com.iptv807.tv"
|
applicationId = "com.iptv807.tv"
|
||||||
minSdk = 21
|
minSdk = 21
|
||||||
targetSdk = 35
|
targetSdk = 35
|
||||||
versionCode = 890
|
versionCode = 900
|
||||||
versionName = "8.9.0"
|
versionName = "9.0.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
|||||||
@@ -27,6 +27,29 @@ class SettingsActivity : Activity() {
|
|||||||
|
|
||||||
private lateinit var statusText: TextView
|
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?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
try {
|
try {
|
||||||
@@ -44,7 +67,12 @@ class SettingsActivity : Activity() {
|
|||||||
setBackgroundColor(Color.parseColor("#12141A"))
|
setBackgroundColor(Color.parseColor("#12141A"))
|
||||||
setPadding(96, 64, 96, 64)
|
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 {
|
root.addView(TextView(this).apply {
|
||||||
text = "设置"
|
text = "设置"
|
||||||
@@ -88,7 +116,9 @@ class SettingsActivity : Activity() {
|
|||||||
isChecked = isBootReceiverEnabled()
|
isChecked = isBootReceiverEnabled()
|
||||||
val pad = (24 * resources.displayMetrics.density).toInt()
|
val pad = (24 * resources.displayMetrics.density).toInt()
|
||||||
setPadding(pad, pad / 2, pad, pad / 2)
|
setPadding(pad, pad / 2, pad, pad / 2)
|
||||||
setBackgroundColor(Color.parseColor("#1C2028"))
|
isFocusable = true
|
||||||
|
isFocusableInTouchMode = true
|
||||||
|
background = focusBg(normal = 0xFF1C2028.toInt())
|
||||||
}
|
}
|
||||||
bootSwitch.setOnCheckedChangeListener { _, checked ->
|
bootSwitch.setOnCheckedChangeListener { _, checked ->
|
||||||
val pm = packageManager
|
val pm = packageManager
|
||||||
@@ -135,20 +165,17 @@ class SettingsActivity : Activity() {
|
|||||||
textSize = 16f
|
textSize = 16f
|
||||||
setTextColor(Color.WHITE)
|
setTextColor(Color.WHITE)
|
||||||
setHintTextColor(Color.parseColor("#888888"))
|
setHintTextColor(Color.parseColor("#888888"))
|
||||||
setBackgroundColor(Color.parseColor("#1C2028"))
|
|
||||||
setPadding(24, 20, 24, 20)
|
setPadding(24, 20, 24, 20)
|
||||||
isSingleLine = true
|
isSingleLine = true
|
||||||
|
isFocusable = true
|
||||||
|
isFocusableInTouchMode = true
|
||||||
|
background = focusBg(normal = 0xFF1C2028.toInt())
|
||||||
inputType = android.text.InputType.TYPE_CLASS_TEXT
|
inputType = android.text.InputType.TYPE_CLASS_TEXT
|
||||||
}
|
}
|
||||||
root.addView(cardInput, LinearLayout.LayoutParams(
|
root.addView(cardInput, LinearLayout.LayoutParams(
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT).apply { bottomMargin = 12 })
|
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT).apply { bottomMargin = 12 })
|
||||||
|
|
||||||
val actBtn = Button(this).apply {
|
val actBtn = mkAction("激活") { doActivate(cardInput.text.toString().trim()) }
|
||||||
text = "激活"
|
|
||||||
textSize = 17f
|
|
||||||
setBackgroundColor(Color.parseColor("#1B6EF3"))
|
|
||||||
setOnClickListener { doActivate(cardInput.text.toString().trim()) }
|
|
||||||
}
|
|
||||||
root.addView(actBtn, LinearLayout.LayoutParams(
|
root.addView(actBtn, LinearLayout.LayoutParams(
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT).apply { bottomMargin = 40 })
|
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)
|
gravity = Gravity.CENTER; setPadding(0, 24, 0, 24)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
val btn = Button(this).apply {
|
val btn = mkAction("支付成为会员(月/季/年)") {
|
||||||
text = "支付成为会员(月/季/年)"
|
startActivity(Intent(this@SettingsActivity, ShopActivity::class.java))
|
||||||
textSize = 17f
|
|
||||||
setBackgroundColor(Color.parseColor("#1B6EF3"))
|
|
||||||
setOnClickListener { startActivity(Intent(this@SettingsActivity, ShopActivity::class.java)) }
|
|
||||||
}
|
}
|
||||||
root.addView(btn, LinearLayout.LayoutParams(
|
root.addView(btn, LinearLayout.LayoutParams(
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT))
|
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT))
|
||||||
|
|||||||
@@ -33,11 +33,44 @@ class ShopActivity : Activity() {
|
|||||||
data class Plan(val id: Int, val name: String, val price: String, val days: Int)
|
data class Plan(val id: Int, val name: String, val price: String, val days: Int)
|
||||||
|
|
||||||
private lateinit var list: ListView
|
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 lateinit var statusText: TextView
|
||||||
private var payType = "alipay"
|
private var payType = "alipay"
|
||||||
private var orderNo = ""
|
private var orderNo = ""
|
||||||
private var machineId = ""
|
private var machineId = ""
|
||||||
private val handler = Handler(Looper.getMainLooper())
|
private val handler = Handler(Looper.getMainLooper())
|
||||||
|
|
||||||
|
/** 高亮自控的行适配器 */
|
||||||
|
private inner class RowAdapter(private var items: List<String>) : android.widget.BaseAdapter() {
|
||||||
|
var selected = 0
|
||||||
|
set(value) { field = value; notifyDataSetChanged() }
|
||||||
|
fun setItems(v: List<String>) { 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 pollTask: Runnable? = null
|
||||||
private var pollCount = 0
|
private var pollCount = 0
|
||||||
|
|
||||||
@@ -76,6 +109,10 @@ class ShopActivity : Activity() {
|
|||||||
|
|
||||||
list = ListView(this).apply {
|
list = ListView(this).apply {
|
||||||
setBackgroundColor(Color.parseColor("#1C1F26"))
|
setBackgroundColor(Color.parseColor("#1C1F26"))
|
||||||
|
setSelector(android.graphics.drawable.ColorDrawable(Color.TRANSPARENT))
|
||||||
|
isFocusable = false
|
||||||
|
isFocusableInTouchMode = false
|
||||||
|
setItemsCanFocus(false)
|
||||||
}
|
}
|
||||||
root.addView(list, LinearLayout.LayoutParams(
|
root.addView(list, LinearLayout.LayoutParams(
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT, 0, 1f
|
ViewGroup.LayoutParams.MATCH_PARENT, 0, 1f
|
||||||
@@ -88,15 +125,16 @@ class ShopActivity : Activity() {
|
|||||||
root.addView(statusText)
|
root.addView(statusText)
|
||||||
|
|
||||||
val row = LinearLayout(this).apply { orientation = LinearLayout.HORIZONTAL }
|
val row = LinearLayout(this).apply { orientation = LinearLayout.HORIZONTAL }
|
||||||
val alipay = Button(this).apply { text = "支付宝"; textSize = 15f }
|
fun mkPay(label: String, t: String) = TextView(this).apply {
|
||||||
val wxpay = Button(this).apply { text = "微信"; textSize = 15f }
|
text = label; textSize = 16f
|
||||||
fun sel(b: Button, t: String) {
|
setTextColor(Color.WHITE); gravity = Gravity.CENTER
|
||||||
val active = payType == t
|
setPadding(24, 26, 24, 26)
|
||||||
b.setBackgroundColor(if (active) Color.parseColor("#1B6EF3") else Color.parseColor("#2A2F3A"))
|
isFocusable = true; isFocusableInTouchMode = true
|
||||||
|
background = focusBg(0xFF2A2F3A.toInt(), 0xFF1B6EF3.toInt())
|
||||||
|
setOnClickListener { payType = t; refreshPayBtns() }
|
||||||
}
|
}
|
||||||
alipay.setOnClickListener { payType = "alipay"; sel(alipay, "alipay"); sel(wxpay, "wxpay") }
|
alipay = mkPay("支付宝", "alipay")
|
||||||
wxpay.setOnClickListener { payType = "wxpay"; sel(alipay, "alipay"); sel(wxpay, "wxpay") }
|
wxpay = mkPay("微信", "wxpay")
|
||||||
sel(alipay, "alipay"); sel(wxpay, "wxpay")
|
|
||||||
row.addView(alipay, LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f).apply { rightMargin = 16 })
|
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))
|
row.addView(wxpay, LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f))
|
||||||
root.addView(row)
|
root.addView(row)
|
||||||
@@ -104,10 +142,20 @@ class ShopActivity : Activity() {
|
|||||||
list.onItemClickListener = AdapterView.OnItemClickListener { _, _, pos, _ ->
|
list.onItemClickListener = AdapterView.OnItemClickListener { _, _, pos, _ ->
|
||||||
if (pos < plans.size) createOrder(plans[pos])
|
if (pos < plans.size) createOrder(plans[pos])
|
||||||
}
|
}
|
||||||
|
refreshPayBtns()
|
||||||
|
|
||||||
loadPlans()
|
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")
|
@SuppressLint("SetTextI18n")
|
||||||
private fun loadPlans() {
|
private fun loadPlans() {
|
||||||
statusText.text = "加载套餐…"
|
statusText.text = "加载套餐…"
|
||||||
@@ -130,11 +178,13 @@ class ShopActivity : Activity() {
|
|||||||
}
|
}
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
plans.sortBy { it.days }
|
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
|
val d = it.days
|
||||||
"📱 ${it.name} ¥${it.price} ${if (d >= 999) "永久" else "${d}天"}"
|
"📱 ${it.name} ¥${it.price} ${if (d >= 999) "永久" else "${d}天"}"
|
||||||
})
|
})
|
||||||
statusText.text = "选择套餐后按 OK 购买"
|
rowAdapterRef = ra
|
||||||
|
list.adapter = ra
|
||||||
|
statusText.text = "上下选择套餐,OK 购买;左右可切支付方式"
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
runOnUiThread { statusText.text = "加载失败: ${e.javaClass.simpleName}: ${e.message?.take(150)}" }
|
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 {
|
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
|
||||||
if (keyCode == KeyEvent.KEYCODE_BACK && pollTask != null) {
|
// 支付中:回归普通处理
|
||||||
// 支付轮询中返回 → 取消轮询
|
if (pollTask != null) {
|
||||||
handler.removeCallbacks(pollTask!!); 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)
|
return super.onKeyDown(keyCode, event)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user