mirror of
https://github.com/lizongying/my-tv.git
synced 2026-11-01 00:56:29 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f4a33a3fc | ||
|
|
c17d62c698 | ||
|
|
33d3da97e5 | ||
|
|
ba95ce5374 | ||
|
|
e1ee909071 | ||
|
|
1fd0951f92 | ||
|
|
42b072f5ec | ||
|
|
a23b1e11ce | ||
|
|
1ac6d87c3c | ||
|
|
b075a7db81 |
@@ -14,7 +14,16 @@
|
|||||||
|
|
||||||
## 更新日志
|
## 更新日志
|
||||||
|
|
||||||
### v1.4.4(安卓4专用)
|
### v1.4.7(高版本专用)
|
||||||
|
|
||||||
|
* 修复部分用户cctv13播放过程中卡住的问题
|
||||||
|
* 调整cctv的频道顺序
|
||||||
|
|
||||||
|
### v1.4.5(高版本专用)
|
||||||
|
|
||||||
|
* 数字选台配置
|
||||||
|
|
||||||
|
### v1.4.4(通用版)
|
||||||
|
|
||||||
* 优化图标显示
|
* 优化图标显示
|
||||||
* 增加换台反转
|
* 增加换台反转
|
||||||
|
|||||||
+1
-1
@@ -101,7 +101,7 @@ dependencies {
|
|||||||
implementation "androidx.media3:media3-exoplayer-hls:$media3_version"
|
implementation "androidx.media3:media3-exoplayer-hls:$media3_version"
|
||||||
|
|
||||||
// 21:2.9.0 17:2.6.4
|
// 21:2.9.0 17:2.6.4
|
||||||
def retrofit2_version = "2.6.4"
|
def retrofit2_version = "2.9.0"
|
||||||
|
|
||||||
implementation 'com.google.protobuf:protobuf-kotlin:3.25.1'
|
implementation 'com.google.protobuf:protobuf-kotlin:3.25.1'
|
||||||
implementation "com.squareup.retrofit2:converter-gson:$retrofit2_version"
|
implementation "com.squareup.retrofit2:converter-gson:$retrofit2_version"
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -1,112 +0,0 @@
|
|||||||
package com.lizongying.mytv
|
|
||||||
|
|
||||||
import android.graphics.Color
|
|
||||||
import android.util.Log
|
|
||||||
import android.view.ContextThemeWrapper
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.view.animation.ScaleAnimation
|
|
||||||
import android.widget.ImageView
|
|
||||||
import androidx.leanback.widget.ImageCardView
|
|
||||||
import androidx.lifecycle.LifecycleOwner
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import com.bumptech.glide.Glide
|
|
||||||
import com.lizongying.mytv.models.TVListViewModel
|
|
||||||
import com.lizongying.mytv.models.TVViewModel
|
|
||||||
|
|
||||||
|
|
||||||
class CardAdapter(private val owner: LifecycleOwner, private var tvListViewModel: TVListViewModel) :
|
|
||||||
RecyclerView.Adapter<CardAdapter.ViewHolder>() {
|
|
||||||
|
|
||||||
private var listener: ItemListener? = null
|
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
|
||||||
val cardView = object :
|
|
||||||
ImageCardView(ContextThemeWrapper(parent.context, R.style.CustomImageCardTheme)) {}
|
|
||||||
startScaleAnimation(cardView, 1.0f, 0.9f)
|
|
||||||
cardView.isFocusable = true
|
|
||||||
cardView.isFocusableInTouchMode = true
|
|
||||||
|
|
||||||
return ViewHolder(cardView)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun startScaleAnimation(view: View, fromScale: Float, toScale: Float) {
|
|
||||||
val scaleAnimation = ScaleAnimation(
|
|
||||||
fromScale, toScale,
|
|
||||||
fromScale, toScale,
|
|
||||||
ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
|
|
||||||
ScaleAnimation.RELATIVE_TO_SELF, 0.5f
|
|
||||||
)
|
|
||||||
scaleAnimation.duration = 200
|
|
||||||
scaleAnimation.fillAfter = true
|
|
||||||
|
|
||||||
view.startAnimation(scaleAnimation)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
|
|
||||||
val item = tvListViewModel.getTVViewModel(position)
|
|
||||||
|
|
||||||
val tvViewModel = item as TVViewModel
|
|
||||||
val cardView = viewHolder.view as ImageCardView
|
|
||||||
|
|
||||||
cardView.setOnFocusChangeListener { _, hasFocus ->
|
|
||||||
listener?.onItemFocusChange(item, hasFocus)
|
|
||||||
if (hasFocus) {
|
|
||||||
startScaleAnimation(cardView, 0.9f, 1.0f)
|
|
||||||
} else {
|
|
||||||
startScaleAnimation(cardView, 1.0f, 0.9f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cardView.setOnClickListener { _ ->
|
|
||||||
listener?.onItemClicked(item)
|
|
||||||
}
|
|
||||||
|
|
||||||
cardView.titleText = tvViewModel.title.value
|
|
||||||
cardView.tag = tvViewModel.videoUrl.value
|
|
||||||
|
|
||||||
if (tvViewModel.logo.value != null) {
|
|
||||||
if (tvViewModel.title.value == "CCTV8K 超高清") {
|
|
||||||
Glide.with(viewHolder.view.context)
|
|
||||||
.load(R.drawable.cctv8k)
|
|
||||||
.centerInside()
|
|
||||||
.into(cardView.mainImageView)
|
|
||||||
} else {
|
|
||||||
Glide.with(viewHolder.view.context)
|
|
||||||
.load(tvViewModel.logo.value)
|
|
||||||
.centerInside()
|
|
||||||
.into(cardView.mainImageView)
|
|
||||||
}
|
|
||||||
|
|
||||||
cardView.mainImageView.setBackgroundColor(Color.WHITE)
|
|
||||||
cardView.setMainImageScaleType(ImageView.ScaleType.CENTER_INSIDE)
|
|
||||||
}
|
|
||||||
|
|
||||||
tvViewModel.program.observe(owner) { _ ->
|
|
||||||
val program = tvViewModel.getProgramOne()
|
|
||||||
if (program != null) {
|
|
||||||
cardView.contentText = program.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getItemCount() = tvListViewModel.size()
|
|
||||||
|
|
||||||
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
|
||||||
val view = itemView
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ItemListener {
|
|
||||||
fun onItemFocusChange(tvViewModel: TVViewModel, hasFocus: Boolean)
|
|
||||||
fun onItemClicked(tvViewModel: TVViewModel)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setItemListener(listener: ItemListener) {
|
|
||||||
this.listener = listener
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "CardAdapter"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -22,6 +22,7 @@ class ChannelFragment : Fragment() {
|
|||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View {
|
): View {
|
||||||
_binding = ChannelBinding.inflate(inflater, container, false)
|
_binding = ChannelBinding.inflate(inflater, container, false)
|
||||||
|
_binding!!.root.visibility = View.GONE
|
||||||
(activity as MainActivity).fragmentReady()
|
(activity as MainActivity).fragmentReady()
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
@@ -41,7 +42,6 @@ class ChannelFragment : Fragment() {
|
|||||||
handler.postDelayed(removeRunnable, delay)
|
handler.postDelayed(removeRunnable, delay)
|
||||||
} else {
|
} else {
|
||||||
val ch = "${binding.channelContent.text}$channel".toInt()
|
val ch = "${binding.channelContent.text}$channel".toInt()
|
||||||
Log.i(TAG, "channel $ch")
|
|
||||||
(activity as MainActivity).play(ch)
|
(activity as MainActivity).play(ch)
|
||||||
binding.channelContent.text = ""
|
binding.channelContent.text = ""
|
||||||
view?.visibility = View.GONE
|
view?.visibility = View.GONE
|
||||||
|
|||||||
@@ -23,17 +23,11 @@ class InfoFragment : Fragment() {
|
|||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View {
|
): View {
|
||||||
_binding = InfoBinding.inflate(inflater, container, false)
|
_binding = InfoBinding.inflate(inflater, container, false)
|
||||||
|
_binding!!.root.visibility = View.GONE
|
||||||
(activity as MainActivity).fragmentReady()
|
(activity as MainActivity).fragmentReady()
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
|
|
||||||
// Use a Handler to delay the fragment transaction
|
|
||||||
handler.postDelayed(removeRunnable, delay)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun show(tvViewModel: TVViewModel) {
|
fun show(tvViewModel: TVViewModel) {
|
||||||
binding.textView.text = tvViewModel.title.value
|
binding.textView.text = tvViewModel.title.value
|
||||||
if (tvViewModel.title.value == "CCTV8K 超高清") {
|
if (tvViewModel.title.value == "CCTV8K 超高清") {
|
||||||
@@ -56,10 +50,13 @@ class InfoFragment : Fragment() {
|
|||||||
handler.postDelayed(removeRunnable, delay)
|
handler.postDelayed(removeRunnable, delay)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
handler.postDelayed(removeRunnable, delay)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
Log.i(TAG, "onPause")
|
|
||||||
// Cancel the delayed task when the fragment is paused
|
|
||||||
handler.removeCallbacks(removeRunnable)
|
handler.removeCallbacks(removeRunnable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,9 +25,10 @@ import java.security.MessageDigest
|
|||||||
class MainActivity : FragmentActivity() {
|
class MainActivity : FragmentActivity() {
|
||||||
|
|
||||||
var playerFragment = PlayerFragment()
|
var playerFragment = PlayerFragment()
|
||||||
private val mainFragment = MainFragment2()
|
private val mainFragment = MainFragment()
|
||||||
private val infoFragment = InfoFragment()
|
private val infoFragment = InfoFragment()
|
||||||
private val channelFragment = ChannelFragment()
|
private val channelFragment = ChannelFragment()
|
||||||
|
private lateinit var settingFragment: SettingFragment
|
||||||
|
|
||||||
private var doubleBackToExitPressedOnce = false
|
private var doubleBackToExitPressedOnce = false
|
||||||
|
|
||||||
@@ -39,9 +40,9 @@ class MainActivity : FragmentActivity() {
|
|||||||
|
|
||||||
private lateinit var sharedPref: SharedPreferences
|
private lateinit var sharedPref: SharedPreferences
|
||||||
private var channelReversal = false
|
private var channelReversal = false
|
||||||
|
private var channelNum = true
|
||||||
|
|
||||||
private var versionName = ""
|
private var versionName = ""
|
||||||
private lateinit var dialogFragment: MyDialogFragment
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@@ -57,8 +58,6 @@ class MainActivity : FragmentActivity() {
|
|||||||
.add(R.id.main_browse_fragment, infoFragment)
|
.add(R.id.main_browse_fragment, infoFragment)
|
||||||
.add(R.id.main_browse_fragment, channelFragment)
|
.add(R.id.main_browse_fragment, channelFragment)
|
||||||
.add(R.id.main_browse_fragment, mainFragment)
|
.add(R.id.main_browse_fragment, mainFragment)
|
||||||
.hide(infoFragment)
|
|
||||||
.hide(channelFragment)
|
|
||||||
.hide(mainFragment)
|
.hide(mainFragment)
|
||||||
.commit()
|
.commit()
|
||||||
mainFragment.view?.requestFocus()
|
mainFragment.view?.requestFocus()
|
||||||
@@ -66,15 +65,32 @@ class MainActivity : FragmentActivity() {
|
|||||||
gestureDetector = GestureDetector(this, GestureListener())
|
gestureDetector = GestureDetector(this, GestureListener())
|
||||||
|
|
||||||
sharedPref = getPreferences(Context.MODE_PRIVATE)
|
sharedPref = getPreferences(Context.MODE_PRIVATE)
|
||||||
channelReversal = sharedPref.getBoolean(CHANNEL_REVERSAL, false)
|
channelReversal = sharedPref.getBoolean(CHANNEL_REVERSAL, channelReversal)
|
||||||
|
channelNum = sharedPref.getBoolean(CHANNEL_NUM, channelNum)
|
||||||
|
|
||||||
versionName = getPackageInfo().versionName
|
versionName = getPackageInfo().versionName
|
||||||
dialogFragment = MyDialogFragment(versionName, channelReversal)
|
settingFragment = SettingFragment(versionName, channelReversal, channelNum)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun showInfoFragment(tvViewModel: TVViewModel) {
|
fun showInfoFragment(tvViewModel: TVViewModel) {
|
||||||
infoFragment.show(tvViewModel)
|
infoFragment.show(tvViewModel)
|
||||||
channelFragment.show(tvViewModel)
|
if (channelNum) {
|
||||||
|
channelFragment.show(tvViewModel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showChannel(channel: String) {
|
||||||
|
if (!mainFragment.isHidden) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settingFragment.isVisible) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channelNum) {
|
||||||
|
channelFragment.show(channel)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun play(tvViewModel: TVViewModel) {
|
fun play(tvViewModel: TVViewModel) {
|
||||||
@@ -106,7 +122,6 @@ class MainActivity : FragmentActivity() {
|
|||||||
val transaction = supportFragmentManager.beginTransaction()
|
val transaction = supportFragmentManager.beginTransaction()
|
||||||
|
|
||||||
if (mainFragment.isHidden) {
|
if (mainFragment.isHidden) {
|
||||||
mainFragment.setPosition()
|
|
||||||
transaction.show(mainFragment)
|
transaction.show(mainFragment)
|
||||||
keepRunnable()
|
keepRunnable()
|
||||||
} else {
|
} else {
|
||||||
@@ -199,25 +214,33 @@ class MainActivity : FragmentActivity() {
|
|||||||
this.channelReversal = channelReversal
|
this.channelReversal = channelReversal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun saveChannelNum(channelNum: Boolean) {
|
||||||
|
with(sharedPref.edit()) {
|
||||||
|
putBoolean(CHANNEL_NUM, channelNum)
|
||||||
|
apply()
|
||||||
|
}
|
||||||
|
this.channelNum = channelNum
|
||||||
|
}
|
||||||
|
|
||||||
private fun showHelp() {
|
private fun showHelp() {
|
||||||
if (!mainFragment.isHidden) {
|
if (!mainFragment.isHidden) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.i(TAG, "dialogFragment ${dialogFragment.isVisible}")
|
Log.i(TAG, "settingFragment ${settingFragment.isVisible}")
|
||||||
if (!dialogFragment.isVisible) {
|
if (!settingFragment.isVisible) {
|
||||||
dialogFragment.show(supportFragmentManager, "settings_dialog")
|
settingFragment.show(supportFragmentManager, "setting")
|
||||||
handler.removeCallbacks(hideHelp)
|
handler.removeCallbacks(hideHelp)
|
||||||
handler.postDelayed(hideHelp, delayHideHelp)
|
handler.postDelayed(hideHelp, delayHideHelp)
|
||||||
} else {
|
} else {
|
||||||
handler.removeCallbacks(hideHelp)
|
handler.removeCallbacks(hideHelp)
|
||||||
dialogFragment.dismiss()
|
settingFragment.dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val hideHelp = Runnable {
|
private val hideHelp = Runnable {
|
||||||
if (dialogFragment.isVisible) {
|
if (settingFragment.isVisible) {
|
||||||
dialogFragment.dismiss()
|
settingFragment.dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,18 +296,6 @@ class MainActivity : FragmentActivity() {
|
|||||||
}, 2000)
|
}, 2000)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showChannel(channel: String) {
|
|
||||||
if (!mainFragment.isHidden) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dialogFragment.isVisible) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
channelFragment.show(channel)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
|
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
|
||||||
when (keyCode) {
|
when (keyCode) {
|
||||||
KeyEvent.KEYCODE_0 -> {
|
KeyEvent.KEYCODE_0 -> {
|
||||||
@@ -479,5 +490,6 @@ class MainActivity : FragmentActivity() {
|
|||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "MainActivity"
|
private const val TAG = "MainActivity"
|
||||||
private const val CHANNEL_REVERSAL = "channel_reversal"
|
private const val CHANNEL_REVERSAL = "channel_reversal"
|
||||||
|
private const val CHANNEL_NUM = "channel_num"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25,19 +25,19 @@ import com.lizongying.mytv.models.TVViewModel
|
|||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|
||||||
class MainFragment : BrowseSupportFragment() {
|
class MainFragment : BrowseSupportFragment() {
|
||||||
var itemPosition: Int = 0
|
|
||||||
|
|
||||||
private var request: Request = Request()
|
private var itemPosition = 0
|
||||||
|
|
||||||
private var rowsAdapter: ArrayObjectAdapter? = null
|
private var rowsAdapter: ArrayObjectAdapter? = null
|
||||||
|
|
||||||
|
private var request = Request()
|
||||||
|
|
||||||
var tvListViewModel = TVListViewModel()
|
var tvListViewModel = TVListViewModel()
|
||||||
|
|
||||||
private var sharedPref: SharedPreferences? = null
|
private var sharedPref: SharedPreferences? = null
|
||||||
|
|
||||||
private var lastVideoUrl: String = ""
|
private var lastVideoUrl = ""
|
||||||
|
|
||||||
private val handler = Handler(Looper.getMainLooper())
|
private val handler = Handler(Looper.getMainLooper())
|
||||||
private lateinit var mUpdateProgramRunnable: UpdateProgramRunnable
|
private lateinit var mUpdateProgramRunnable: UpdateProgramRunnable
|
||||||
@@ -53,7 +53,6 @@ class MainFragment : BrowseSupportFragment() {
|
|||||||
super.onActivityCreated(savedInstanceState)
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
|
||||||
activity?.let { request.initYSP(it) }
|
activity?.let { request.initYSP(it) }
|
||||||
|
|
||||||
sharedPref = activity?.getPreferences(Context.MODE_PRIVATE)
|
sharedPref = activity?.getPreferences(Context.MODE_PRIVATE)
|
||||||
|
|
||||||
loadRows()
|
loadRows()
|
||||||
@@ -100,7 +99,6 @@ class MainFragment : BrowseSupportFragment() {
|
|||||||
if (check(tvViewModel)) {
|
if (check(tvViewModel)) {
|
||||||
(activity as? MainActivity)?.play(tvViewModel)
|
(activity as? MainActivity)?.play(tvViewModel)
|
||||||
(activity as? MainActivity)?.showInfoFragment(tvViewModel)
|
(activity as? MainActivity)?.showInfoFragment(tvViewModel)
|
||||||
|
|
||||||
setSelectedPosition(
|
setSelectedPosition(
|
||||||
tvViewModel.getRowPosition(), true,
|
tvViewModel.getRowPosition(), true,
|
||||||
SelectItemViewHolderTask(tvViewModel.getItemPosition())
|
SelectItemViewHolderTask(tvViewModel.getItemPosition())
|
||||||
@@ -114,58 +112,6 @@ class MainFragment : BrowseSupportFragment() {
|
|||||||
fragmentReady()
|
fragmentReady()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
|
||||||
super.onDestroy()
|
|
||||||
handler.removeCallbacks(mUpdateProgramRunnable)
|
|
||||||
with(sharedPref!!.edit()) {
|
|
||||||
putInt("position", itemPosition)
|
|
||||||
apply()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateProgram(tvViewModel: TVViewModel) {
|
|
||||||
val timestamp = getDateTimestamp()
|
|
||||||
if (timestamp - tvViewModel.programUpdateTime > 60) {
|
|
||||||
if (tvViewModel.program.value!!.isEmpty()) {
|
|
||||||
tvViewModel.programUpdateTime = timestamp
|
|
||||||
request.fetchProgram(tvViewModel)
|
|
||||||
} else {
|
|
||||||
if (timestamp - tvViewModel.program.value!!.last().et < 600) {
|
|
||||||
tvViewModel.programUpdateTime = timestamp
|
|
||||||
request.fetchProgram(tvViewModel)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class UpdateProgramRunnable : Runnable {
|
|
||||||
override fun run() {
|
|
||||||
tvListViewModel.getTVListViewModel().value?.filter { it.programId.value != null }
|
|
||||||
?.forEach { tvViewModel ->
|
|
||||||
updateProgram(
|
|
||||||
tvViewModel
|
|
||||||
)
|
|
||||||
}
|
|
||||||
handler.postDelayed(this, 60000)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun check(tvViewModel: TVViewModel): Boolean {
|
|
||||||
val title = tvViewModel.title.value
|
|
||||||
val videoUrl = tvViewModel.videoIndex.value?.let { tvViewModel.videoUrl.value?.get(it) }
|
|
||||||
if (videoUrl == null || videoUrl == "") {
|
|
||||||
Log.e(TAG, "$title videoUrl is empty")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (videoUrl == lastVideoUrl) {
|
|
||||||
Log.e(TAG, "$title videoUrl is duplication")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
fun toLastPosition() {
|
fun toLastPosition() {
|
||||||
setSelectedPosition(
|
setSelectedPosition(
|
||||||
selectedPosition, false,
|
selectedPosition, false,
|
||||||
@@ -206,51 +152,13 @@ class MainFragment : BrowseSupportFragment() {
|
|||||||
|
|
||||||
adapter = rowsAdapter
|
adapter = rowsAdapter
|
||||||
|
|
||||||
itemPosition = sharedPref?.getInt("position", 0)!!
|
itemPosition = sharedPref?.getInt(POSITION, 0)!!
|
||||||
if (itemPosition >= tvListViewModel.size()) {
|
if (itemPosition >= tvListViewModel.size()) {
|
||||||
itemPosition = 0
|
itemPosition = 0
|
||||||
}
|
}
|
||||||
tvListViewModel.setItemPosition(itemPosition)
|
tvListViewModel.setItemPosition(itemPosition)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun fragmentReady() {
|
|
||||||
ready++
|
|
||||||
Log.i(TAG, "ready $ready")
|
|
||||||
if (ready == 3) {
|
|
||||||
// request.fetchPage()
|
|
||||||
val tvViewModel = tvListViewModel.getTVViewModel(itemPosition)
|
|
||||||
tvViewModel?.changed()
|
|
||||||
|
|
||||||
(activity as? MainActivity)?.switchMainFragment()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun prev() {
|
|
||||||
view?.post {
|
|
||||||
itemPosition--
|
|
||||||
if (itemPosition == -1) {
|
|
||||||
itemPosition = tvListViewModel.size() - 1
|
|
||||||
}
|
|
||||||
tvListViewModel.setItemPosition(itemPosition)
|
|
||||||
|
|
||||||
val tvViewModel = tvListViewModel.getTVViewModel(itemPosition)
|
|
||||||
tvViewModel?.changed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun next() {
|
|
||||||
view?.post {
|
|
||||||
itemPosition++
|
|
||||||
if (itemPosition == tvListViewModel.size()) {
|
|
||||||
itemPosition = 0
|
|
||||||
}
|
|
||||||
tvListViewModel.setItemPosition(itemPosition)
|
|
||||||
|
|
||||||
val tvViewModel = tvListViewModel.getTVViewModel(itemPosition)
|
|
||||||
tvViewModel?.changed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun prevSource() {
|
fun prevSource() {
|
||||||
view?.post {
|
view?.post {
|
||||||
val tvViewModel = tvListViewModel.getTVViewModel(itemPosition)
|
val tvViewModel = tvListViewModel.getTVViewModel(itemPosition)
|
||||||
@@ -297,9 +205,7 @@ class MainFragment : BrowseSupportFragment() {
|
|||||||
if (itemPosition != item.id.value!!) {
|
if (itemPosition != item.id.value!!) {
|
||||||
itemPosition = item.id.value!!
|
itemPosition = item.id.value!!
|
||||||
tvListViewModel.setItemPosition(itemPosition)
|
tvListViewModel.setItemPosition(itemPosition)
|
||||||
|
tvListViewModel.getTVViewModel(itemPosition)?.changed()
|
||||||
val tvViewModel = tvListViewModel.getTVViewModel(itemPosition)
|
|
||||||
tvViewModel?.changed()
|
|
||||||
}
|
}
|
||||||
(activity as? MainActivity)?.switchMainFragment()
|
(activity as? MainActivity)?.switchMainFragment()
|
||||||
}
|
}
|
||||||
@@ -318,12 +224,113 @@ class MainFragment : BrowseSupportFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun check(tvViewModel: TVViewModel): Boolean {
|
||||||
|
val title = tvViewModel.title.value
|
||||||
|
val videoUrl = tvViewModel.videoIndex.value?.let { tvViewModel.videoUrl.value?.get(it) }
|
||||||
|
if (videoUrl == null || videoUrl == "") {
|
||||||
|
Log.e(TAG, "$title videoUrl is empty")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (videoUrl == lastVideoUrl) {
|
||||||
|
Log.e(TAG, "$title videoUrl is duplication")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun fragmentReady() {
|
||||||
|
ready++
|
||||||
|
Log.i(TAG, "ready $ready")
|
||||||
|
if (ready == 4) {
|
||||||
|
// request.fetchPage()
|
||||||
|
tvListViewModel.getTVViewModel(itemPosition)?.changed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun play(itemPosition: Int) {
|
||||||
|
view?.post {
|
||||||
|
if (itemPosition < tvListViewModel.size()) {
|
||||||
|
this.itemPosition = itemPosition
|
||||||
|
tvListViewModel.setItemPosition(itemPosition)
|
||||||
|
tvListViewModel.getTVViewModel(itemPosition)?.changed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun prev() {
|
||||||
|
view?.post {
|
||||||
|
itemPosition--
|
||||||
|
if (itemPosition == -1) {
|
||||||
|
itemPosition = tvListViewModel.size() - 1
|
||||||
|
}
|
||||||
|
tvListViewModel.setItemPosition(itemPosition)
|
||||||
|
tvListViewModel.getTVViewModel(itemPosition)?.changed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun next() {
|
||||||
|
view?.post {
|
||||||
|
itemPosition++
|
||||||
|
if (itemPosition == tvListViewModel.size()) {
|
||||||
|
itemPosition = 0
|
||||||
|
}
|
||||||
|
tvListViewModel.setItemPosition(itemPosition)
|
||||||
|
tvListViewModel.getTVViewModel(itemPosition)?.changed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateProgram(tvViewModel: TVViewModel) {
|
||||||
|
val timestamp = getDateTimestamp()
|
||||||
|
if (timestamp - tvViewModel.programUpdateTime > 60) {
|
||||||
|
if (tvViewModel.program.value!!.isEmpty()) {
|
||||||
|
tvViewModel.programUpdateTime = timestamp
|
||||||
|
request.fetchProgram(tvViewModel)
|
||||||
|
} else {
|
||||||
|
if (timestamp - tvViewModel.program.value!!.last().et < 600) {
|
||||||
|
tvViewModel.programUpdateTime = timestamp
|
||||||
|
request.fetchProgram(tvViewModel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class UpdateProgramRunnable : Runnable {
|
||||||
|
override fun run() {
|
||||||
|
tvListViewModel.getTVListViewModel().value?.filter { it.programId.value != null }
|
||||||
|
?.forEach { tvViewModel ->
|
||||||
|
updateProgram(
|
||||||
|
tvViewModel
|
||||||
|
)
|
||||||
|
}
|
||||||
|
handler.postDelayed(this, 60000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStop() {
|
||||||
|
Log.i(TAG, "onStop")
|
||||||
|
super.onStop()
|
||||||
|
with(sharedPref!!.edit()) {
|
||||||
|
putInt(POSITION, itemPosition)
|
||||||
|
apply()
|
||||||
|
}
|
||||||
|
Log.i(TAG, "POSITION saved")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
Log.i(TAG, "onDestroy")
|
||||||
|
super.onDestroy()
|
||||||
|
handler.removeCallbacks(mUpdateProgramRunnable)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
view!!.requestFocus()
|
view?.post { view?.requestFocus() }
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "MainFragment"
|
private const val TAG = "MainFragment"
|
||||||
|
private const val POSITION = "position"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,313 +0,0 @@
|
|||||||
package com.lizongying.mytv
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.SharedPreferences
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.os.Handler
|
|
||||||
import android.os.Looper
|
|
||||||
import android.util.Log
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.widget.Toast
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import com.lizongying.mytv.Utils.dpToPx
|
|
||||||
import com.lizongying.mytv.databinding.RowBinding
|
|
||||||
import com.lizongying.mytv.databinding.ShowBinding
|
|
||||||
import com.lizongying.mytv.models.TVListViewModel
|
|
||||||
import com.lizongying.mytv.models.TVViewModel
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
class MainFragment2 : Fragment(), CardAdapter.ItemListener {
|
|
||||||
|
|
||||||
private var itemPosition = 0
|
|
||||||
|
|
||||||
private var rowList: MutableList<View> = mutableListOf()
|
|
||||||
|
|
||||||
private var _binding: ShowBinding? = null
|
|
||||||
private val binding get() = _binding!!
|
|
||||||
|
|
||||||
private var request: Request = Request()
|
|
||||||
|
|
||||||
var tvListViewModel = TVListViewModel()
|
|
||||||
|
|
||||||
private var sharedPref: SharedPreferences? = null
|
|
||||||
|
|
||||||
private var lastVideoUrl: String = ""
|
|
||||||
|
|
||||||
private val handler = Handler(Looper.getMainLooper())
|
|
||||||
private lateinit var mUpdateProgramRunnable: UpdateProgramRunnable
|
|
||||||
|
|
||||||
private var ready = 0
|
|
||||||
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?
|
|
||||||
): View {
|
|
||||||
_binding = ShowBinding.inflate(inflater, container, false)
|
|
||||||
return binding.root
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
|
||||||
super.onActivityCreated(savedInstanceState)
|
|
||||||
|
|
||||||
activity?.let { request.initYSP(it) }
|
|
||||||
sharedPref = activity?.getPreferences(Context.MODE_PRIVATE)
|
|
||||||
|
|
||||||
view?.post {
|
|
||||||
val content = binding.content
|
|
||||||
|
|
||||||
var idx: Long = 0
|
|
||||||
for ((k, v) in TVList.list) {
|
|
||||||
val itemBinding: RowBinding =
|
|
||||||
RowBinding.inflate(layoutInflater, content, false)
|
|
||||||
|
|
||||||
val tvListViewModelCurrent = TVListViewModel()
|
|
||||||
for ((idx2, v1) in v.withIndex()) {
|
|
||||||
val tvViewModel = TVViewModel(v1)
|
|
||||||
tvViewModel.setRowPosition(idx.toInt())
|
|
||||||
tvViewModel.setItemPosition(idx2)
|
|
||||||
tvListViewModelCurrent.addTVViewModel(tvViewModel)
|
|
||||||
tvListViewModel.addTVViewModel(tvViewModel)
|
|
||||||
}
|
|
||||||
tvListViewModel.maxNum.add(v.size)
|
|
||||||
|
|
||||||
val adapter = CardAdapter(viewLifecycleOwner, tvListViewModelCurrent)
|
|
||||||
rowList.add(itemBinding.rowItems)
|
|
||||||
|
|
||||||
adapter.setItemListener(this)
|
|
||||||
|
|
||||||
itemBinding.rowHeader.text = k
|
|
||||||
itemBinding.rowItems.adapter = adapter
|
|
||||||
itemBinding.rowItems.layoutManager =
|
|
||||||
LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
|
|
||||||
|
|
||||||
val layoutParams = itemBinding.row.layoutParams as ViewGroup.MarginLayoutParams
|
|
||||||
layoutParams.topMargin = dpToPx(11F)
|
|
||||||
itemBinding.row.layoutParams = layoutParams
|
|
||||||
content.addView(itemBinding.row)
|
|
||||||
|
|
||||||
idx++
|
|
||||||
}
|
|
||||||
|
|
||||||
mUpdateProgramRunnable = UpdateProgramRunnable()
|
|
||||||
handler.post(mUpdateProgramRunnable)
|
|
||||||
|
|
||||||
itemPosition = sharedPref?.getInt(POSITION, 0)!!
|
|
||||||
if (itemPosition >= tvListViewModel.size()) {
|
|
||||||
itemPosition = 0
|
|
||||||
}
|
|
||||||
setPosition()
|
|
||||||
tvListViewModel.setItemPosition(itemPosition)
|
|
||||||
tvListViewModel.getTVListViewModel().value?.forEach { tvViewModel ->
|
|
||||||
tvViewModel.errInfo.observe(viewLifecycleOwner) { _ ->
|
|
||||||
if (tvViewModel.errInfo.value != null
|
|
||||||
&& tvViewModel.id.value == itemPosition
|
|
||||||
) {
|
|
||||||
Toast.makeText(context, tvViewModel.errInfo.value, Toast.LENGTH_SHORT)
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tvViewModel.ready.observe(viewLifecycleOwner) { _ ->
|
|
||||||
|
|
||||||
// not first time && channel not change
|
|
||||||
if (tvViewModel.ready.value != null
|
|
||||||
&& tvViewModel.id.value == itemPosition
|
|
||||||
&& check(tvViewModel)
|
|
||||||
) {
|
|
||||||
Log.i(TAG, "ready ${tvViewModel.title.value}")
|
|
||||||
(activity as? MainActivity)?.play(tvViewModel)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tvViewModel.change.observe(viewLifecycleOwner) { _ ->
|
|
||||||
if (tvViewModel.change.value != null) {
|
|
||||||
val title = tvViewModel.title.value
|
|
||||||
Log.i(TAG, "switch $title")
|
|
||||||
if (tvViewModel.pid.value != "") {
|
|
||||||
Log.i(TAG, "request $title ${tvViewModel.pid.value}")
|
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
|
||||||
tvViewModel.let { request.fetchData(it) }
|
|
||||||
}
|
|
||||||
(activity as? MainActivity)?.showInfoFragment(tvViewModel)
|
|
||||||
setPosition(
|
|
||||||
tvViewModel.getRowPosition(), tvViewModel.getItemPosition()
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
if (check(tvViewModel)) {
|
|
||||||
(activity as? MainActivity)?.play(tvViewModel)
|
|
||||||
(activity as? MainActivity)?.showInfoFragment(tvViewModel)
|
|
||||||
setPosition(
|
|
||||||
tvViewModel.getRowPosition(), tvViewModel.getItemPosition()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fragmentReady()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onItemFocusChange(tvViewModel: TVViewModel, hasFocus: Boolean) {
|
|
||||||
if (hasFocus) {
|
|
||||||
tvListViewModel.setItemPositionCurrent(tvViewModel.id.value!!)
|
|
||||||
(activity as MainActivity).keepRunnable()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onItemClicked(tvViewModel: TVViewModel) {
|
|
||||||
if (this.isHidden) {
|
|
||||||
(activity as? MainActivity)?.switchMainFragment()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (itemPosition != tvViewModel.id.value!!) {
|
|
||||||
itemPosition = tvViewModel.id.value!!
|
|
||||||
tvListViewModel.setItemPosition(itemPosition)
|
|
||||||
tvListViewModel.getTVViewModel(itemPosition)?.changed()
|
|
||||||
}
|
|
||||||
(activity as? MainActivity)?.switchMainFragment()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setPosition() {
|
|
||||||
val tvViewModel = tvListViewModel.getTVViewModel(itemPosition)
|
|
||||||
rowList[tvViewModel!!.getRowPosition()].post {
|
|
||||||
((rowList[tvViewModel.getRowPosition()] as RecyclerView).layoutManager as LinearLayoutManager).findViewByPosition(
|
|
||||||
tvViewModel.getItemPosition()
|
|
||||||
)?.requestFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setPosition(rowPosition: Int, itemPosition: Int) {
|
|
||||||
rowList[rowPosition].post {
|
|
||||||
((rowList[rowPosition] as RecyclerView).layoutManager as LinearLayoutManager).findViewByPosition(
|
|
||||||
itemPosition
|
|
||||||
)?.requestFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun check(tvViewModel: TVViewModel): Boolean {
|
|
||||||
val title = tvViewModel.title.value
|
|
||||||
val videoUrl = tvViewModel.videoIndex.value?.let { tvViewModel.videoUrl.value?.get(it) }
|
|
||||||
if (videoUrl == null || videoUrl == "") {
|
|
||||||
Log.e(TAG, "$title videoUrl is empty")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (videoUrl == lastVideoUrl) {
|
|
||||||
Log.e(TAG, "$title videoUrl is duplication")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
fun fragmentReady() {
|
|
||||||
ready++
|
|
||||||
Log.i(TAG, "ready $ready")
|
|
||||||
if (ready == 4) {
|
|
||||||
// request.fetchPage()
|
|
||||||
tvListViewModel.getTVViewModel(itemPosition)?.changed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun play(itemPosition: Int) {
|
|
||||||
view?.post {
|
|
||||||
if (itemPosition < tvListViewModel.size()) {
|
|
||||||
this.itemPosition = itemPosition
|
|
||||||
tvListViewModel.setItemPosition(itemPosition)
|
|
||||||
tvListViewModel.getTVViewModel(itemPosition)?.changed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun prev() {
|
|
||||||
view?.post {
|
|
||||||
itemPosition--
|
|
||||||
if (itemPosition == -1) {
|
|
||||||
itemPosition = tvListViewModel.size() - 1
|
|
||||||
}
|
|
||||||
tvListViewModel.setItemPosition(itemPosition)
|
|
||||||
tvListViewModel.getTVViewModel(itemPosition)?.changed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun next() {
|
|
||||||
view?.post {
|
|
||||||
itemPosition++
|
|
||||||
if (itemPosition == tvListViewModel.size()) {
|
|
||||||
itemPosition = 0
|
|
||||||
}
|
|
||||||
tvListViewModel.setItemPosition(itemPosition)
|
|
||||||
tvListViewModel.getTVViewModel(itemPosition)?.changed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateProgram(tvViewModel: TVViewModel) {
|
|
||||||
val timestamp = Utils.getDateTimestamp()
|
|
||||||
if (timestamp - tvViewModel.programUpdateTime > 60) {
|
|
||||||
if (tvViewModel.program.value!!.isEmpty()) {
|
|
||||||
tvViewModel.programUpdateTime = timestamp
|
|
||||||
request.fetchProgram(tvViewModel)
|
|
||||||
} else {
|
|
||||||
if (timestamp - tvViewModel.program.value!!.last().et < 600) {
|
|
||||||
tvViewModel.programUpdateTime = timestamp
|
|
||||||
request.fetchProgram(tvViewModel)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class UpdateProgramRunnable : Runnable {
|
|
||||||
override fun run() {
|
|
||||||
tvListViewModel.getTVListViewModel().value?.filter { it.programId.value != null }
|
|
||||||
?.forEach { tvViewModel ->
|
|
||||||
updateProgram(
|
|
||||||
tvViewModel
|
|
||||||
)
|
|
||||||
}
|
|
||||||
handler.postDelayed(this, 60000)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onStop() {
|
|
||||||
Log.i(TAG, "onStop")
|
|
||||||
super.onStop()
|
|
||||||
with(sharedPref!!.edit()) {
|
|
||||||
putInt(POSITION, itemPosition)
|
|
||||||
apply()
|
|
||||||
}
|
|
||||||
Log.i(TAG, "POSITION saved")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroy() {
|
|
||||||
Log.i(TAG, "onDestroy")
|
|
||||||
super.onDestroy()
|
|
||||||
handler.removeCallbacks(mUpdateProgramRunnable)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroyView() {
|
|
||||||
Log.i(TAG, "onDestroyView")
|
|
||||||
super.onDestroyView()
|
|
||||||
_binding = null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
view!!.requestFocus()
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "MainFragment"
|
|
||||||
private const val POSITION = "position"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -74,10 +74,9 @@ class PlayerFragment : Fragment() {
|
|||||||
@OptIn(UnstableApi::class)
|
@OptIn(UnstableApi::class)
|
||||||
fun play(tvViewModel: TVViewModel) {
|
fun play(tvViewModel: TVViewModel) {
|
||||||
this.tvViewModel = tvViewModel
|
this.tvViewModel = tvViewModel
|
||||||
val videoUrlCurrent =
|
val videoUrlCurrent = tvViewModel.getVideoUrlCurrent()
|
||||||
tvViewModel.videoIndex.value?.let { tvViewModel.videoUrl.value?.get(it) }
|
|
||||||
playerView?.player?.run {
|
playerView?.player?.run {
|
||||||
videoUrlCurrent?.let { setMediaItem(MediaItem.fromUri(it)) }
|
setMediaItem(MediaItem.fromUri(videoUrlCurrent))
|
||||||
prepare()
|
prepare()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-5
@@ -8,7 +8,10 @@ import androidx.fragment.app.DialogFragment
|
|||||||
import com.lizongying.mytv.databinding.DialogBinding
|
import com.lizongying.mytv.databinding.DialogBinding
|
||||||
|
|
||||||
|
|
||||||
class MyDialogFragment(private val versionName: String, private val channelReversal: Boolean) :
|
class SettingFragment(private val versionName: String,
|
||||||
|
private val channelReversal: Boolean,
|
||||||
|
private val channelNum: Boolean,
|
||||||
|
) :
|
||||||
DialogFragment() {
|
DialogFragment() {
|
||||||
|
|
||||||
private var _binding: DialogBinding? = null
|
private var _binding: DialogBinding? = null
|
||||||
@@ -28,12 +31,18 @@ class MyDialogFragment(private val versionName: String, private val channelRever
|
|||||||
_binding?.version?.text =
|
_binding?.version?.text =
|
||||||
"当前版本: $versionName\n获取最新: https://github.com/lizongying/my-tv/releases/"
|
"当前版本: $versionName\n获取最新: https://github.com/lizongying/my-tv/releases/"
|
||||||
|
|
||||||
val switchView = _binding?.switchView
|
val switchChannelReversal = _binding?.switchChannelReversal
|
||||||
switchView?.isChecked = channelReversal
|
switchChannelReversal?.isChecked = channelReversal
|
||||||
switchView?.setOnCheckedChangeListener { _, isChecked ->
|
switchChannelReversal?.setOnCheckedChangeListener { _, isChecked ->
|
||||||
(activity as MainActivity).saveChannelReversal(isChecked)
|
(activity as MainActivity).saveChannelReversal(isChecked)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val switchChannelNum = _binding?.switchChannelNum
|
||||||
|
switchChannelNum?.isChecked = channelNum
|
||||||
|
switchChannelNum?.setOnCheckedChangeListener { _, isChecked ->
|
||||||
|
(activity as MainActivity).saveChannelNum(isChecked)
|
||||||
|
}
|
||||||
|
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,7 +52,7 @@ class MyDialogFragment(private val versionName: String, private val channelRever
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val TAG = "MyDialogFragment"
|
const val TAG = "SettingFragment"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +145,7 @@ object TVList {
|
|||||||
"CCTV10 科教" to arrayOf("600001805", "2000203503"),
|
"CCTV10 科教" to arrayOf("600001805", "2000203503"),
|
||||||
"CCTV11 戏曲" to arrayOf("600001806", "2000204103"),
|
"CCTV11 戏曲" to arrayOf("600001806", "2000204103"),
|
||||||
"CCTV12 社会与法" to arrayOf("600001807", "2000202603"),
|
"CCTV12 社会与法" to arrayOf("600001807", "2000202603"),
|
||||||
// "CCTV13 新闻" to arrayOf("600001811","2000204603"),
|
"CCTV13 新闻" to arrayOf("600001811","2000204603"),
|
||||||
"CCTV14 少儿" to arrayOf("600001809", "2000204403"),
|
"CCTV14 少儿" to arrayOf("600001809", "2000204403"),
|
||||||
"CCTV15 音乐" to arrayOf("600001815", "2000205003"),
|
"CCTV15 音乐" to arrayOf("600001815", "2000205003"),
|
||||||
"CCTV16 奥林匹克" to arrayOf("600098637", "2012375003"),
|
"CCTV16 奥林匹克" to arrayOf("600098637", "2012375003"),
|
||||||
@@ -196,8 +196,6 @@ object TVList {
|
|||||||
private fun setupTV(): Map<String, List<TV>> {
|
private fun setupTV(): Map<String, List<TV>> {
|
||||||
val tvs = """
|
val tvs = """
|
||||||
央视频道
|
央视频道
|
||||||
CCTV4K 超高清,
|
|
||||||
CCTV8K 超高清,
|
|
||||||
CCTV1 综合,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226231/index.m3u8
|
CCTV1 综合,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226231/index.m3u8
|
||||||
CCTV2 财经,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226195/index.m3u8
|
CCTV2 财经,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226195/index.m3u8
|
||||||
CCTV3 综艺,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226397/index.m3u8
|
CCTV3 综艺,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226397/index.m3u8
|
||||||
@@ -216,6 +214,8 @@ CCTV14 少儿,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226193/inde
|
|||||||
CCTV15 音乐,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225785/index.m3u8
|
CCTV15 音乐,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225785/index.m3u8
|
||||||
CCTV16 奥林匹克,http://39.134.24.162/dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226921/index.m3u8;http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226921/index.m3u8
|
CCTV16 奥林匹克,http://39.134.24.162/dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226921/index.m3u8;http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226921/index.m3u8
|
||||||
CCTV17 农业农村,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226198/index.m3u8
|
CCTV17 农业农村,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226198/index.m3u8
|
||||||
|
CCTV4K 超高清,
|
||||||
|
CCTV8K 超高清,
|
||||||
风云剧场,http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226950/index.m3u8
|
风云剧场,http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226950/index.m3u8
|
||||||
第一剧场,http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226959/index.m3u8
|
第一剧场,http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226959/index.m3u8
|
||||||
怀旧剧场,http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226972/index.m3u8
|
怀旧剧场,http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226972/index.m3u8
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class TVViewModel(private var tv: TV) : ViewModel() {
|
|||||||
private var itemPosition: Int = 0
|
private var itemPosition: Int = 0
|
||||||
|
|
||||||
var retryTimes: Int = 0
|
var retryTimes: Int = 0
|
||||||
var retryMaxTimes: Int = 5
|
var retryMaxTimes: Int = 8
|
||||||
var programUpdateTime: Long = 0
|
var programUpdateTime: Long = 0
|
||||||
|
|
||||||
private val _errInfo = MutableLiveData<String>()
|
private val _errInfo = MutableLiveData<String>()
|
||||||
@@ -222,18 +222,25 @@ class TVViewModel(private var tv: TV) : ViewModel() {
|
|||||||
mMinimumLoadableRetryCount = minimumLoadableRetryCount
|
mMinimumLoadableRetryCount = minimumLoadableRetryCount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (playerView?.player as ExoPlayer).setMediaSource(tvViewModel.buildSource())
|
||||||
|
*/
|
||||||
@OptIn(UnstableApi::class)
|
@OptIn(UnstableApi::class)
|
||||||
fun buildSource(videoUrl: String, mHeaders: Map<String, String>?): HlsMediaSource {
|
fun buildSource(): HlsMediaSource {
|
||||||
val httpDataSource = DefaultHttpDataSource.Factory()
|
val httpDataSource = DefaultHttpDataSource.Factory()
|
||||||
mHeaders?.let { httpDataSource.setDefaultRequestProperties(it) }
|
mHeaders?.let { httpDataSource.setDefaultRequestProperties(it) }
|
||||||
|
|
||||||
return HlsMediaSource.Factory(httpDataSource).createMediaSource(
|
return HlsMediaSource.Factory(httpDataSource).createMediaSource(
|
||||||
MediaItem.fromUri(
|
MediaItem.fromUri(
|
||||||
Uri.parse(videoUrl)
|
Uri.parse(getVideoUrlCurrent())
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getVideoUrlCurrent(): String {
|
||||||
|
return _videoUrl.value!![_videoIndex.value!!]
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "TVViewModel"
|
private const val TAG = "TVViewModel"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,12 +26,18 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="10dp"
|
android:layout_marginTop="10dp"
|
||||||
android:layout_marginBottom="10dp"
|
|
||||||
android:text="当前版本: $versionName\n获取最新: https://github.com/lizongying/my-tv/releases/"
|
android:text="当前版本: $versionName\n获取最新: https://github.com/lizongying/my-tv/releases/"
|
||||||
></TextView>
|
></TextView>
|
||||||
<Switch
|
<Switch
|
||||||
android:id="@+id/switch_view"
|
android:id="@+id/switch_channel_reversal"
|
||||||
android:text="@string/title_channel_reversal"
|
android:text="@string/title_channel_reversal"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
<Switch
|
||||||
|
android:id="@+id/switch_channel_num"
|
||||||
|
android:text="@string/title_channel_num"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:id="@+id/row"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/row_header"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="start"
|
|
||||||
android:layout_marginTop="0dp"
|
|
||||||
android:layout_marginStart="10dp"
|
|
||||||
android:layout_marginBottom="5dp"
|
|
||||||
android:gravity="start"
|
|
||||||
android:textColor="#FFEEEEEE"
|
|
||||||
android:textSize="22sp" />
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/row_items"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
</androidx.recyclerview.widget.RecyclerView>
|
|
||||||
</LinearLayout>
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:id="@+id/show_fragment"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
<ScrollView
|
|
||||||
android:id="@+id/scroll_view"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/content"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical">
|
|
||||||
</LinearLayout>
|
|
||||||
</ScrollView>
|
|
||||||
</FrameLayout>
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">我的电视</string>
|
<string name="app_name">我的电视</string>
|
||||||
<string name="title_channel_reversal">频道反转</string>
|
<string name="title_channel_reversal">换台反转</string>
|
||||||
|
<string name="title_channel_num">数字选台</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1,25 +1,10 @@
|
|||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<style name="CustomImageCardViewStyle" parent="Widget.Leanback.ImageCardViewStyle">
|
<style name="CustomImageCardViewStyle" parent="Widget.Leanback.ImageCardViewStyle">
|
||||||
<item name="cardType">infoUnder</item>
|
<item name="lbImageCardViewType">Title|Content</item>
|
||||||
<item name="infoVisibility">always</item>
|
|
||||||
<!-- In order to keep backward compatibility we have to create an icon on right. -->
|
|
||||||
<item name="lbImageCardViewType">Title|Content|IconOnRight</item>
|
|
||||||
<!-- Deprecated. Use 'Widget.Leanback.ImageCardView.InfoAreaStyle' instead. -->
|
|
||||||
<item name="infoAreaBackground">@null</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style name="CustomImageCardViewImageStyle" parent="Widget.Leanback.ImageCardView.ImageStyle">
|
|
||||||
<item name="android:layout_width">143dp</item>
|
|
||||||
<item name="android:layout_height">50dp</item>
|
|
||||||
<item name="android:adjustViewBounds">true</item>
|
|
||||||
<item name="android:contentDescription">@null</item>
|
|
||||||
<item name="android:scaleType">centerCrop</item>
|
|
||||||
<item name="layout_viewType">main</item>
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="CustomImageCardTheme" parent="Theme.Leanback">
|
<style name="CustomImageCardTheme" parent="Theme.Leanback">
|
||||||
<item name="imageCardViewStyle">@style/CustomImageCardViewStyle</item>
|
<item name="imageCardViewStyle">@style/CustomImageCardViewStyle</item>
|
||||||
<item name="imageCardViewImageStyle">@style/CustomImageCardViewImageStyle</item>
|
|
||||||
</style>
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
plugins {
|
plugins {
|
||||||
id 'com.android.application' version '8.2.0' apply false
|
id 'com.android.application' version '8.2.1' apply false
|
||||||
id 'com.android.library' version '8.2.0' apply false
|
id 'com.android.library' version '8.2.1' apply false
|
||||||
id 'org.jetbrains.kotlin.android' version '1.9.21' apply false
|
id 'org.jetbrains.kotlin.android' version '1.9.21' apply false
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user