麦动KTV: 移除Gitee数据库(改官方Muse同步), 歌曲源切w.w345.my, 远程日志+广告屏蔽
- DatabaseBootstrapper: 删除 Gitee 分片/manifest/blob 下载逻辑, 曲库只走官方 MuseDbSync - build.gradle: 移除 GITEE_DATABASE_* 构建参数 - MainActivity: 重置数据库文案改为官方同步 - ktv_api.js: 歌曲源仅 w.w345.my, 缓存标记 7, 广告/错号资源拦截+重试 - 远程日志: 点歌记录 编号/标题/请求源/状态
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
package com.local.ktv
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.Outline
|
||||
import android.view.Gravity
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewOutlineProvider
|
||||
import android.widget.BaseAdapter
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import kotlin.math.ceil
|
||||
|
||||
/** Four-column singer grid matching the original OTT singer page. */
|
||||
class SingerGridAdapter(
|
||||
private val context: Context,
|
||||
private val singers: List<Array<String?>>,
|
||||
private val onSingerClick: (Array<String?>) -> Unit,
|
||||
) : BaseAdapter() {
|
||||
private val density = context.resources.displayMetrics.density
|
||||
|
||||
override fun getCount(): Int = ceil(singers.size / COLUMN_COUNT.toDouble()).toInt()
|
||||
override fun getItem(position: Int): Any = position
|
||||
override fun getItemId(position: Int): Long = position.toLong()
|
||||
|
||||
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||
val row = (convertView as? LinearLayout) ?: LinearLayout(context).apply {
|
||||
orientation = LinearLayout.HORIZONTAL
|
||||
gravity = Gravity.CENTER
|
||||
layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dp(145))
|
||||
}
|
||||
row.removeAllViews()
|
||||
repeat(COLUMN_COUNT) { column ->
|
||||
val index = position * COLUMN_COUNT + column
|
||||
val singer = singers.getOrNull(index)
|
||||
row.addView(
|
||||
singer?.let(::createSingerTile) ?: View(context),
|
||||
LinearLayout.LayoutParams(0, dp(145), 1f),
|
||||
)
|
||||
}
|
||||
return row
|
||||
}
|
||||
|
||||
private fun createSingerTile(singer: Array<String?>): View {
|
||||
val name = singer.getOrNull(1).orEmpty()
|
||||
return LinearLayout(context).apply {
|
||||
orientation = LinearLayout.VERTICAL
|
||||
gravity = Gravity.TOP or Gravity.CENTER_HORIZONTAL
|
||||
isFocusable = true
|
||||
isClickable = true
|
||||
setAccessibleFocus("focus:singer:${singer.getOrNull(0) ?: name}", "歌星,$name")
|
||||
|
||||
val avatar = ImageView(context).apply {
|
||||
importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO
|
||||
scaleType = ImageView.ScaleType.CENTER_CROP
|
||||
SingerAvatarLoader.load(this, singer.getOrNull(5), R.drawable.ic_singer_placeholder)
|
||||
outlineProvider = object : ViewOutlineProvider() {
|
||||
override fun getOutline(view: View, outline: Outline) {
|
||||
outline.setOval(0, 0, view.width, view.height)
|
||||
}
|
||||
}
|
||||
clipToOutline = true
|
||||
}
|
||||
addView(avatar, LinearLayout.LayoutParams(dp(88), dp(88)).apply { topMargin = dp(21) })
|
||||
|
||||
addView(TextView(context).apply {
|
||||
text = name
|
||||
textSize = 16f
|
||||
setTextColor(Color.WHITE)
|
||||
gravity = Gravity.CENTER
|
||||
isSingleLine = true
|
||||
ellipsize = android.text.TextUtils.TruncateAt.END
|
||||
importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO
|
||||
}, LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dp(30)).apply { topMargin = dp(4) })
|
||||
|
||||
setOnTouchListener { view, event ->
|
||||
when (event.action) {
|
||||
MotionEvent.ACTION_DOWN -> view.animate().scaleX(0.94f).scaleY(0.94f).setDuration(90L).start()
|
||||
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL ->
|
||||
view.animate().scaleX(1f).scaleY(1f).setDuration(120L).start()
|
||||
}
|
||||
false
|
||||
}
|
||||
setOnClickListener { onSingerClick(singer) }
|
||||
TvFocusStyler.install(this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun dp(value: Int): Int = (value * density + 0.5f).toInt()
|
||||
|
||||
companion object {
|
||||
private const val COLUMN_COUNT = 4
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user