refactor: convert from Android TV to phone/tablet mode
- Replace Theme.Leanback with Theme.AppCompat.DayNight.NoActionBar - Remove leanback dependencies (leanback, leanback-preference) - Remove LEANBACK_LAUNCHER, leanback feature, banner from manifest - PlayerActivity: replace D-pad with touch controls (click to toggle episodes, close button) - SearchFragment: adaptive grid (3 cols phone / 5 cols tablet), remove focus-based history toggle - Fix deprecated adapterPosition -> bindingAdapterPosition
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
package com.videoapp.tv
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.KeyEvent
|
||||
import android.view.View
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import android.widget.Button
|
||||
import android.widget.ImageButton
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
@@ -15,10 +15,7 @@ import androidx.media3.ui.PlayerView
|
||||
import com.videoapp.tv.data.ConfigRepository
|
||||
import com.videoapp.tv.engine.Episode
|
||||
import com.videoapp.tv.engine.VideoExtractor
|
||||
import com.videoapp.tv.engine.WebViewPlayer
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class PlayerActivity : AppCompatActivity() {
|
||||
|
||||
@@ -28,15 +25,14 @@ class PlayerActivity : AppCompatActivity() {
|
||||
private lateinit var episodeList: android.widget.LinearLayout
|
||||
private lateinit var loadingIndicator: View
|
||||
private lateinit var errorText: android.widget.TextView
|
||||
private lateinit var btnClose: ImageButton
|
||||
|
||||
private var exoPlayer: ExoPlayer? = null
|
||||
private val videoExtractor = VideoExtractor()
|
||||
private val configRepo by lazy { ConfigRepository(this) }
|
||||
private val webViewPlayer by lazy { WebViewPlayer(this) }
|
||||
|
||||
private var episodes: List<Episode> = emptyList()
|
||||
private var currentEpisodeIndex = 0
|
||||
private var isPlayerReady = false
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -48,13 +44,16 @@ class PlayerActivity : AppCompatActivity() {
|
||||
episodeList = findViewById(R.id.episode_list)
|
||||
loadingIndicator = findViewById(R.id.loading_indicator)
|
||||
errorText = findViewById(R.id.error_text)
|
||||
btnClose = findViewById(R.id.btn_close)
|
||||
|
||||
val detailUrl = intent.getStringExtra("detail_url") ?: ""
|
||||
val title = intent.getStringExtra("title") ?: ""
|
||||
|
||||
btnClose.setOnClickListener { finish() }
|
||||
|
||||
initExoPlayer()
|
||||
loadVideos(detailUrl, title)
|
||||
setupFullscreenListener()
|
||||
setupTouchListeners()
|
||||
}
|
||||
|
||||
private fun initExoPlayer() {
|
||||
@@ -63,7 +62,7 @@ class PlayerActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadVideos(detailUrl: String, title: String) {
|
||||
private fun loadVideos(detailUrl: String, @Suppress("UNUSED_PARAMETER") title: String) {
|
||||
showLoading(true)
|
||||
val config = configRepo.getConfig()
|
||||
|
||||
@@ -118,13 +117,10 @@ class PlayerActivity : AppCompatActivity() {
|
||||
val (directUrl, iframeUrl) = videoExtractor.extractFromPlayPage(ep.playUrl, config)
|
||||
|
||||
if (directUrl != null) {
|
||||
// Play with ExoPlayer
|
||||
playWithExoPlayer(directUrl)
|
||||
} else if (iframeUrl != null) {
|
||||
// Play iframe in WebView
|
||||
playWithWebView(iframeUrl)
|
||||
} else {
|
||||
// Fallback: load play page in WebView
|
||||
playWithWebView(ep.playUrl)
|
||||
}
|
||||
}
|
||||
@@ -189,28 +185,15 @@ class PlayerActivity : AppCompatActivity() {
|
||||
showLoading(false)
|
||||
}
|
||||
|
||||
private fun setupFullscreenListener() {
|
||||
// Toggle episode panel visibility on dpad up/down
|
||||
private fun setupTouchListeners() {
|
||||
var panelVisible = true
|
||||
playerView.setOnClickListener {
|
||||
panelVisible = !panelVisible
|
||||
episodePanel.visibility = if (panelVisible) View.VISIBLE else View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
|
||||
return when (keyCode) {
|
||||
KeyEvent.KEYCODE_DPAD_UP -> {
|
||||
episodePanel.visibility = View.VISIBLE
|
||||
true
|
||||
}
|
||||
KeyEvent.KEYCODE_DPAD_DOWN -> {
|
||||
if (episodePanel.visibility == View.VISIBLE) {
|
||||
episodePanel.visibility = View.GONE
|
||||
}
|
||||
true
|
||||
}
|
||||
else -> super.onKeyDown(keyCode, event)
|
||||
playerWebView.setOnClickListener {
|
||||
panelVisible = !panelVisible
|
||||
episodePanel.visibility = if (panelVisible) View.VISIBLE else View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,8 @@ class SearchFragment : Fragment() {
|
||||
}
|
||||
|
||||
private fun setupResultsGrid() {
|
||||
resultsGrid.layoutManager = GridLayoutManager(context, 4)
|
||||
val spanCount = if (resources.configuration.screenWidthDp >= 600) 5 else 3
|
||||
resultsGrid.layoutManager = GridLayoutManager(context, spanCount)
|
||||
resultsGrid.adapter = adapter
|
||||
}
|
||||
|
||||
@@ -107,12 +108,6 @@ class SearchFragment : Fragment() {
|
||||
showHistory(emptyList())
|
||||
}
|
||||
}
|
||||
|
||||
searchInput.setOnFocusChangeListener { _, hasFocus ->
|
||||
if (hasFocus) {
|
||||
historyContainer.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun performSearch(keyword: String) {
|
||||
|
||||
@@ -41,7 +41,7 @@ class SearchResultAdapter(
|
||||
|
||||
init {
|
||||
itemView.setOnClickListener {
|
||||
val pos = adapterPosition
|
||||
val pos = bindingAdapterPosition
|
||||
if (pos != RecyclerView.NO_POSITION) {
|
||||
onItemClick(items[pos])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user