number selection

This commit is contained in:
Li ZongYing
2024-01-17 16:27:25 +08:00
parent 1aade3a48d
commit 46311036d6
11 changed files with 365 additions and 47 deletions
+5
View File
@@ -14,6 +14,11 @@
## 更新日志 ## 更新日志
### v1.4.4(安卓4专用)
* 优化图标显示
* 增加换台反转
### v1.3.3 ### v1.3.3
* 部分错误会提示用户 * 部分错误会提示用户
+1 -1
View File
@@ -9,7 +9,7 @@
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<application <application
android:allowBackup="true" android:allowBackup="true"
android:icon="@mipmap/ic_launcher" android:icon="@drawable/logo"
android:label="@string/app_name" android:label="@string/app_name"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.MyTV"> android:theme="@style/Theme.MyTV">
@@ -0,0 +1,74 @@
package com.lizongying.mytv
import android.os.Bundle
import android.os.Handler
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.lizongying.mytv.databinding.ChannelBinding
import com.lizongying.mytv.models.TVViewModel
class ChannelFragment : Fragment() {
private var _binding: ChannelBinding? = null
private val binding get() = _binding!!
private val handler = Handler()
private val delay: Long = 3000
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = ChannelBinding.inflate(inflater, container, false)
(activity as MainActivity).fragmentReady()
return binding.root
}
fun show(tvViewModel: TVViewModel) {
binding.channelContent.text = tvViewModel.id.value.toString()
handler.removeCallbacks(removeRunnable)
view?.visibility = View.VISIBLE
handler.postDelayed(removeRunnable, delay)
}
fun show(channel: String) {
if (binding.channelContent.text == "") {
binding.channelContent.text = channel
handler.removeCallbacks(removeRunnable)
view?.visibility = View.VISIBLE
handler.postDelayed(removeRunnable, delay)
} else {
val ch = "${binding.channelContent.text}$channel".toInt()
Log.i(TAG, "channel $ch")
(activity as MainActivity).play(ch)
binding.channelContent.text = ""
view?.visibility = View.GONE
}
}
override fun onResume() {
super.onResume()
handler.postDelayed(removeRunnable, delay)
}
override fun onPause() {
super.onPause()
handler.removeCallbacks(removeRunnable)
}
private val removeRunnable = Runnable {
binding.channelContent.text = ""
view?.visibility = View.GONE
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
companion object {
private const val TAG = "ChannelFragment"
}
}
@@ -1,11 +1,11 @@
package com.lizongying.mytv package com.lizongying.mytv
import android.app.AlertDialog import android.content.Context
import android.content.SharedPreferences
import android.content.pm.PackageInfo import android.content.pm.PackageInfo
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.content.pm.Signature import android.content.pm.Signature
import android.content.pm.SigningInfo import android.content.pm.SigningInfo
import android.graphics.Color
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
@@ -16,11 +16,7 @@ import android.view.KeyEvent
import android.view.MotionEvent import android.view.MotionEvent
import android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION import android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
import android.view.WindowManager import android.view.WindowManager
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import com.lizongying.mytv.models.TVViewModel import com.lizongying.mytv.models.TVViewModel
import java.security.MessageDigest import java.security.MessageDigest
@@ -31,6 +27,7 @@ class MainActivity : FragmentActivity() {
var playerFragment = PlayerFragment() var playerFragment = PlayerFragment()
private val mainFragment = MainFragment2() private val mainFragment = MainFragment2()
private val infoFragment = InfoFragment() private val infoFragment = InfoFragment()
private val channelFragment = ChannelFragment()
private var doubleBackToExitPressedOnce = false private var doubleBackToExitPressedOnce = false
@@ -38,6 +35,13 @@ class MainActivity : FragmentActivity() {
private val handler = Handler() private val handler = Handler()
private val delay: Long = 4000 private val delay: Long = 4000
private val delayHideHelp: Long = 10000
private lateinit var sharedPref: SharedPreferences
private var channelReversal = false
private var versionName = ""
private lateinit var dialogFragment: MyDialogFragment
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@@ -51,17 +55,26 @@ class MainActivity : FragmentActivity() {
supportFragmentManager.beginTransaction() supportFragmentManager.beginTransaction()
.add(R.id.main_browse_fragment, playerFragment) .add(R.id.main_browse_fragment, playerFragment)
.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, mainFragment) .add(R.id.main_browse_fragment, mainFragment)
.hide(infoFragment) .hide(infoFragment)
.hide(channelFragment)
.hide(mainFragment) .hide(mainFragment)
.commit() .commit()
mainFragment.view?.requestFocus() mainFragment.view?.requestFocus()
} }
gestureDetector = GestureDetector(this, GestureListener()) gestureDetector = GestureDetector(this, GestureListener())
sharedPref = getPreferences(Context.MODE_PRIVATE)
channelReversal = sharedPref.getBoolean(CHANNEL_REVERSAL, false)
versionName = getPackageInfo().versionName
dialogFragment = MyDialogFragment(versionName, channelReversal)
} }
fun showInfoFragment(tvViewModel: TVViewModel) { fun showInfoFragment(tvViewModel: TVViewModel) {
infoFragment.show(tvViewModel) infoFragment.show(tvViewModel)
channelFragment.show(tvViewModel)
} }
fun play(tvViewModel: TVViewModel) { fun play(tvViewModel: TVViewModel) {
@@ -69,6 +82,10 @@ class MainActivity : FragmentActivity() {
mainFragment.view?.requestFocus() mainFragment.view?.requestFocus()
} }
fun play(itemPosition: Int) {
mainFragment.play(itemPosition)
}
fun prev() { fun prev() {
mainFragment.prev() mainFragment.prev()
} }
@@ -105,7 +122,9 @@ class MainActivity : FragmentActivity() {
} }
private val hideRunnable = Runnable { private val hideRunnable = Runnable {
supportFragmentManager.beginTransaction().hide(mainFragment).commit() if (!mainFragment.isHidden) {
supportFragmentManager.beginTransaction().hide(mainFragment).commit()
}
} }
private fun mainFragmentIsHidden(): Boolean { private fun mainFragmentIsHidden(): Boolean {
@@ -172,42 +191,42 @@ class MainActivity : FragmentActivity() {
} }
} }
fun saveChannelReversal(channelReversal: Boolean) {
with(sharedPref.edit()) {
putBoolean(CHANNEL_REVERSAL, channelReversal)
apply()
}
this.channelReversal = channelReversal
}
private fun showHelp() { private fun showHelp() {
val versionName = getPackageInfo().versionName if (!mainFragment.isHidden) {
return
}
val textView = TextView(this) Log.i(TAG, "dialogFragment ${dialogFragment.isVisible}")
textView.text = if (!dialogFragment.isVisible) {
"当前版本: $versionName\n获取最新: https://github.com/lizongying/my-tv/releases/" dialogFragment.show(supportFragmentManager, "settings_dialog")
textView.setBackgroundColor(0xFF263238.toInt()) handler.removeCallbacks(hideHelp)
textView.setPadding(20, 50, 20, 20) handler.postDelayed(hideHelp, delayHideHelp)
} else {
handler.removeCallbacks(hideHelp)
dialogFragment.dismiss()
}
}
val imageView = ImageView(this) private val hideHelp = Runnable {
val drawable = ContextCompat.getDrawable(this, R.drawable.appreciate) if (dialogFragment.isVisible) {
imageView.setImageDrawable(drawable) dialogFragment.dismiss()
imageView.setBackgroundColor(Color.WHITE) }
val linearLayout = LinearLayout(this)
linearLayout.orientation = LinearLayout.VERTICAL
linearLayout.addView(textView)
linearLayout.addView(imageView)
val layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
)
imageView.layoutParams = layoutParams
textView.layoutParams = layoutParams
val builder: AlertDialog.Builder = AlertDialog.Builder(this)
builder
.setView(linearLayout)
val dialog: AlertDialog = builder.create()
dialog.show()
} }
private fun channelUp() { private fun channelUp() {
if (mainFragment.isHidden) { if (mainFragment.isHidden) {
if (channelReversal) {
next()
return
}
prev() prev()
} else { } else {
// if (mainFragment.selectedPosition == 0) { // if (mainFragment.selectedPosition == 0) {
@@ -221,6 +240,10 @@ class MainActivity : FragmentActivity() {
private fun channelDown() { private fun channelDown() {
if (mainFragment.isHidden) { if (mainFragment.isHidden) {
if (channelReversal) {
prev()
return
}
next() next()
} else { } else {
// if (mainFragment.selectedPosition == mainFragment.tvListViewModel.maxNum.size - 1) { // if (mainFragment.selectedPosition == mainFragment.tvListViewModel.maxNum.size - 1) {
@@ -250,30 +273,100 @@ 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 {
// Toast.makeText(this, "keyCode ${keyCodeToString(keyCode)}", Toast.LENGTH_SHORT).show()
when (keyCode) { when (keyCode) {
KeyEvent.KEYCODE_0 -> {
showChannel("0")
return true
}
KeyEvent.KEYCODE_1 -> {
showChannel("1")
return true
}
KeyEvent.KEYCODE_2 -> {
showChannel("2")
return true
}
KeyEvent.KEYCODE_3 -> {
showChannel("3")
return true
}
KeyEvent.KEYCODE_4 -> {
showChannel("4")
return true
}
KeyEvent.KEYCODE_5 -> {
showChannel("5")
return true
}
KeyEvent.KEYCODE_6 -> {
showChannel("6")
return true
}
KeyEvent.KEYCODE_7 -> {
showChannel("7")
return true
}
KeyEvent.KEYCODE_8 -> {
showChannel("8")
return true
}
KeyEvent.KEYCODE_9 -> {
showChannel("9")
return true
}
KeyEvent.KEYCODE_ESCAPE -> { KeyEvent.KEYCODE_ESCAPE -> {
back() back()
return true return true
} }
KeyEvent.KEYCODE_BACK -> { KeyEvent.KEYCODE_BACK -> {
back() back()
return true return true
} }
KeyEvent.KEYCODE_BOOKMARK -> {
showHelp()
return true
}
KeyEvent.KEYCODE_UNKNOWN -> { KeyEvent.KEYCODE_UNKNOWN -> {
showHelp() showHelp()
return true return true
} }
KeyEvent.KEYCODE_HELP -> { KeyEvent.KEYCODE_HELP -> {
showHelp() showHelp()
return true return true
} }
KeyEvent.KEYCODE_SETTINGS -> { KeyEvent.KEYCODE_SETTINGS -> {
showHelp() showHelp()
return true return true
} }
KeyEvent.KEYCODE_MENU -> { KeyEvent.KEYCODE_MENU -> {
showHelp() showHelp()
return true return true
@@ -282,6 +375,7 @@ class MainActivity : FragmentActivity() {
KeyEvent.KEYCODE_ENTER -> { KeyEvent.KEYCODE_ENTER -> {
switchMainFragment() switchMainFragment()
} }
KeyEvent.KEYCODE_DPAD_CENTER -> { KeyEvent.KEYCODE_DPAD_CENTER -> {
switchMainFragment() switchMainFragment()
} }
@@ -289,6 +383,7 @@ class MainActivity : FragmentActivity() {
KeyEvent.KEYCODE_DPAD_UP -> { KeyEvent.KEYCODE_DPAD_UP -> {
channelUp() channelUp()
} }
KeyEvent.KEYCODE_CHANNEL_UP -> { KeyEvent.KEYCODE_CHANNEL_UP -> {
channelUp() channelUp()
} }
@@ -296,6 +391,7 @@ class MainActivity : FragmentActivity() {
KeyEvent.KEYCODE_DPAD_DOWN -> { KeyEvent.KEYCODE_DPAD_DOWN -> {
channelDown() channelDown()
} }
KeyEvent.KEYCODE_CHANNEL_DOWN -> { KeyEvent.KEYCODE_CHANNEL_DOWN -> {
channelDown() channelDown()
} }
@@ -382,5 +478,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"
} }
} }
@@ -97,7 +97,7 @@ class MainFragment2 : Fragment(), CardAdapter.ItemListener {
mUpdateProgramRunnable = UpdateProgramRunnable() mUpdateProgramRunnable = UpdateProgramRunnable()
handler.post(mUpdateProgramRunnable) handler.post(mUpdateProgramRunnable)
itemPosition = sharedPref?.getInt("position", 0)!! itemPosition = sharedPref?.getInt(POSITION, 0)!!
if (itemPosition >= tvListViewModel.size()) { if (itemPosition >= tvListViewModel.size()) {
itemPosition = 0 itemPosition = 0
} }
@@ -108,7 +108,8 @@ class MainFragment2 : Fragment(), CardAdapter.ItemListener {
if (tvViewModel.errInfo.value != null if (tvViewModel.errInfo.value != null
&& tvViewModel.id.value == itemPosition && tvViewModel.id.value == itemPosition
) { ) {
Toast.makeText(context, tvViewModel.errInfo.value, Toast.LENGTH_SHORT).show() Toast.makeText(context, tvViewModel.errInfo.value, Toast.LENGTH_SHORT)
.show()
} }
} }
tvViewModel.ready.observe(viewLifecycleOwner) { _ -> tvViewModel.ready.observe(viewLifecycleOwner) { _ ->
@@ -213,12 +214,22 @@ class MainFragment2 : Fragment(), CardAdapter.ItemListener {
fun fragmentReady() { fun fragmentReady() {
ready++ ready++
Log.i(TAG, "ready $ready") Log.i(TAG, "ready $ready")
if (ready == 3) { if (ready == 4) {
// request.fetchPage() // request.fetchPage()
tvListViewModel.getTVViewModel(itemPosition)?.changed() 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() { fun prev() {
view?.post { view?.post {
itemPosition-- itemPosition--
@@ -268,13 +279,26 @@ class MainFragment2 : Fragment(), CardAdapter.ItemListener {
} }
} }
override fun onDestroy() { override fun onStop() {
super.onDestroy() Log.i(TAG, "onStop")
handler.removeCallbacks(mUpdateProgramRunnable) super.onStop()
with(sharedPref!!.edit()) { with(sharedPref!!.edit()) {
putInt("position", itemPosition) putInt(POSITION, itemPosition)
apply() 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() { override fun onResume() {
@@ -284,5 +308,6 @@ class MainFragment2 : Fragment(), CardAdapter.ItemListener {
companion object { companion object {
private const val TAG = "MainFragment" private const val TAG = "MainFragment"
private const val POSITION = "position"
} }
} }
@@ -0,0 +1,49 @@
package com.lizongying.mytv
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import com.lizongying.mytv.databinding.DialogBinding
class MyDialogFragment(private val versionName: String, private val channelReversal: Boolean) :
DialogFragment() {
private var _binding: DialogBinding? = null
private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(STYLE_NO_TITLE, 0)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = DialogBinding.inflate(inflater, container, false)
_binding?.version?.text =
"当前版本: $versionName\n获取最新: https://github.com/lizongying/my-tv/releases/"
val switchView = _binding?.switchView
switchView?.isChecked = channelReversal
switchView?.setOnCheckedChangeListener { _, isChecked ->
(activity as MainActivity).saveChannelReversal(isChecked)
}
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
companion object {
const val TAG = "MyDialogFragment"
}
}
@@ -103,6 +103,11 @@ class PlayerFragment : Fragment() {
} }
} }
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
companion object { companion object {
private const val TAG = "PlaybackVideoFragment" private const val TAG = "PlaybackVideoFragment"
} }
+20
View File
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/channel_fragment"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_gravity="end|top"
android:layout_marginTop="20dp"
android:layout_marginEnd="50dp">
<TextView
android:id="@+id/channel_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginTop="0dp"
android:text="99"
android:textColor="#FFEEEEEE"
android:textStyle="bold"
android:textSize="50sp" />
</FrameLayout>
+44
View File
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/dialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="300dp"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingTop="20dp"
android:paddingLeft="7dp"
android:paddingRight="7dp"
android:background="#FF263238"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/app_name"
android:textSize="16sp" />
<TextView
android:id="@+id/version"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:text="当前版本: $versionName\n获取最新: https://github.com/lizongying/my-tv/releases/"
></TextView>
<Switch
android:id="@+id/switch_view"
android:text="@string/title_channel_reversal"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<ImageView
android:layout_width="300dp"
android:layout_height="wrap_content"
android:src="@drawable/appreciate"
android:background="@color/white" />
</LinearLayout>
</FrameLayout>
-1
View File
@@ -12,7 +12,6 @@
android:layout_width="100dp" android:layout_width="100dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:contentDescription="@string/logo"
android:padding="10dp" /> android:padding="10dp" />
<LinearLayout <LinearLayout
+1 -1
View File
@@ -1,4 +1,4 @@
<resources> <resources>
<string name="app_name">我的电视</string> <string name="app_name">我的电视</string>
<string name="logo">logo</string> <string name="title_channel_reversal">频道反转</string>
</resources> </resources>