diff --git a/README.md b/README.md index 3f5a6e01..0295f82c 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,11 @@ ## 更新日志 +### v1.4.4(安卓4专用) + +* 优化图标显示 +* 增加换台反转 + ### v1.3.3 * 部分错误会提示用户 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f76b90f5..b38f4862 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -9,7 +9,7 @@ diff --git a/app/src/main/java/com/lizongying/mytv/ChannelFragment.kt b/app/src/main/java/com/lizongying/mytv/ChannelFragment.kt new file mode 100644 index 00000000..4e51b57d --- /dev/null +++ b/app/src/main/java/com/lizongying/mytv/ChannelFragment.kt @@ -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" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lizongying/mytv/MainActivity.kt b/app/src/main/java/com/lizongying/mytv/MainActivity.kt index 88e5887b..563c2356 100644 --- a/app/src/main/java/com/lizongying/mytv/MainActivity.kt +++ b/app/src/main/java/com/lizongying/mytv/MainActivity.kt @@ -1,11 +1,11 @@ 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.PackageManager import android.content.pm.Signature import android.content.pm.SigningInfo -import android.graphics.Color import android.os.Build import android.os.Bundle import android.os.Handler @@ -16,11 +16,7 @@ import android.view.KeyEvent import android.view.MotionEvent import android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION import android.view.WindowManager -import android.widget.ImageView -import android.widget.LinearLayout -import android.widget.TextView import android.widget.Toast -import androidx.core.content.ContextCompat import androidx.fragment.app.FragmentActivity import com.lizongying.mytv.models.TVViewModel import java.security.MessageDigest @@ -31,6 +27,7 @@ class MainActivity : FragmentActivity() { var playerFragment = PlayerFragment() private val mainFragment = MainFragment2() private val infoFragment = InfoFragment() + private val channelFragment = ChannelFragment() private var doubleBackToExitPressedOnce = false @@ -38,6 +35,13 @@ class MainActivity : FragmentActivity() { private val handler = Handler() 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?) { super.onCreate(savedInstanceState) @@ -51,17 +55,26 @@ class MainActivity : FragmentActivity() { supportFragmentManager.beginTransaction() .add(R.id.main_browse_fragment, playerFragment) .add(R.id.main_browse_fragment, infoFragment) + .add(R.id.main_browse_fragment, channelFragment) .add(R.id.main_browse_fragment, mainFragment) .hide(infoFragment) + .hide(channelFragment) .hide(mainFragment) .commit() mainFragment.view?.requestFocus() } 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) { infoFragment.show(tvViewModel) + channelFragment.show(tvViewModel) } fun play(tvViewModel: TVViewModel) { @@ -69,6 +82,10 @@ class MainActivity : FragmentActivity() { mainFragment.view?.requestFocus() } + fun play(itemPosition: Int) { + mainFragment.play(itemPosition) + } + fun prev() { mainFragment.prev() } @@ -105,7 +122,9 @@ class MainActivity : FragmentActivity() { } private val hideRunnable = Runnable { - supportFragmentManager.beginTransaction().hide(mainFragment).commit() + if (!mainFragment.isHidden) { + supportFragmentManager.beginTransaction().hide(mainFragment).commit() + } } 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() { - val versionName = getPackageInfo().versionName - - val textView = TextView(this) - textView.text = - "当前版本: $versionName\n获取最新: https://github.com/lizongying/my-tv/releases/" - textView.setBackgroundColor(0xFF263238.toInt()) - textView.setPadding(20, 50, 20, 20) - - val imageView = ImageView(this) - val drawable = ContextCompat.getDrawable(this, R.drawable.appreciate) - imageView.setImageDrawable(drawable) - 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() + if (!mainFragment.isHidden) { + return + } + + Log.i(TAG, "dialogFragment ${dialogFragment.isVisible}") + if (!dialogFragment.isVisible) { + dialogFragment.show(supportFragmentManager, "settings_dialog") + handler.removeCallbacks(hideHelp) + handler.postDelayed(hideHelp, delayHideHelp) + } else { + handler.removeCallbacks(hideHelp) + dialogFragment.dismiss() + } + } + + private val hideHelp = Runnable { + if (dialogFragment.isVisible) { + dialogFragment.dismiss() + } } private fun channelUp() { if (mainFragment.isHidden) { + if (channelReversal) { + next() + return + } prev() } else { // if (mainFragment.selectedPosition == 0) { @@ -221,6 +240,10 @@ class MainActivity : FragmentActivity() { private fun channelDown() { if (mainFragment.isHidden) { + if (channelReversal) { + prev() + return + } next() } else { // if (mainFragment.selectedPosition == mainFragment.tvListViewModel.maxNum.size - 1) { @@ -250,30 +273,100 @@ class MainActivity : FragmentActivity() { }, 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 { -// Toast.makeText(this, "keyCode ${keyCodeToString(keyCode)}", Toast.LENGTH_SHORT).show() 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 -> { back() return true } + KeyEvent.KEYCODE_BACK -> { back() return true } + KeyEvent.KEYCODE_BOOKMARK -> { + showHelp() + return true + } + KeyEvent.KEYCODE_UNKNOWN -> { showHelp() return true } + KeyEvent.KEYCODE_HELP -> { showHelp() return true } + KeyEvent.KEYCODE_SETTINGS -> { showHelp() return true } + KeyEvent.KEYCODE_MENU -> { showHelp() return true @@ -282,6 +375,7 @@ class MainActivity : FragmentActivity() { KeyEvent.KEYCODE_ENTER -> { switchMainFragment() } + KeyEvent.KEYCODE_DPAD_CENTER -> { switchMainFragment() } @@ -289,6 +383,7 @@ class MainActivity : FragmentActivity() { KeyEvent.KEYCODE_DPAD_UP -> { channelUp() } + KeyEvent.KEYCODE_CHANNEL_UP -> { channelUp() } @@ -296,6 +391,7 @@ class MainActivity : FragmentActivity() { KeyEvent.KEYCODE_DPAD_DOWN -> { channelDown() } + KeyEvent.KEYCODE_CHANNEL_DOWN -> { channelDown() } @@ -382,5 +478,6 @@ class MainActivity : FragmentActivity() { companion object { private const val TAG = "MainActivity" + private const val CHANNEL_REVERSAL = "channel_reversal" } } \ No newline at end of file diff --git a/app/src/main/java/com/lizongying/mytv/MainFragment2.kt b/app/src/main/java/com/lizongying/mytv/MainFragment2.kt index 2f7c372f..42896d19 100644 --- a/app/src/main/java/com/lizongying/mytv/MainFragment2.kt +++ b/app/src/main/java/com/lizongying/mytv/MainFragment2.kt @@ -97,7 +97,7 @@ class MainFragment2 : Fragment(), CardAdapter.ItemListener { mUpdateProgramRunnable = UpdateProgramRunnable() handler.post(mUpdateProgramRunnable) - itemPosition = sharedPref?.getInt("position", 0)!! + itemPosition = sharedPref?.getInt(POSITION, 0)!! if (itemPosition >= tvListViewModel.size()) { itemPosition = 0 } @@ -108,7 +108,8 @@ class MainFragment2 : Fragment(), CardAdapter.ItemListener { if (tvViewModel.errInfo.value != null && 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) { _ -> @@ -213,12 +214,22 @@ class MainFragment2 : Fragment(), CardAdapter.ItemListener { fun fragmentReady() { ready++ Log.i(TAG, "ready $ready") - if (ready == 3) { + 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-- @@ -268,13 +279,26 @@ class MainFragment2 : Fragment(), CardAdapter.ItemListener { } } - override fun onDestroy() { - super.onDestroy() - handler.removeCallbacks(mUpdateProgramRunnable) + override fun onStop() { + Log.i(TAG, "onStop") + super.onStop() with(sharedPref!!.edit()) { - putInt("position", itemPosition) + 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() { @@ -284,5 +308,6 @@ class MainFragment2 : Fragment(), CardAdapter.ItemListener { companion object { private const val TAG = "MainFragment" + private const val POSITION = "position" } } \ No newline at end of file diff --git a/app/src/main/java/com/lizongying/mytv/MyDialogFragment.kt b/app/src/main/java/com/lizongying/mytv/MyDialogFragment.kt new file mode 100644 index 00000000..24a9cb5d --- /dev/null +++ b/app/src/main/java/com/lizongying/mytv/MyDialogFragment.kt @@ -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" + } +} + diff --git a/app/src/main/java/com/lizongying/mytv/PlayerFragment.kt b/app/src/main/java/com/lizongying/mytv/PlayerFragment.kt index 77b5557c..b3218455 100644 --- a/app/src/main/java/com/lizongying/mytv/PlayerFragment.kt +++ b/app/src/main/java/com/lizongying/mytv/PlayerFragment.kt @@ -103,6 +103,11 @@ class PlayerFragment : Fragment() { } } + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + companion object { private const val TAG = "PlaybackVideoFragment" } diff --git a/app/src/main/res/layout/channel.xml b/app/src/main/res/layout/channel.xml new file mode 100644 index 00000000..47c664a8 --- /dev/null +++ b/app/src/main/res/layout/channel.xml @@ -0,0 +1,20 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog.xml b/app/src/main/res/layout/dialog.xml new file mode 100644 index 00000000..45bf1fc1 --- /dev/null +++ b/app/src/main/res/layout/dialog.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/info.xml b/app/src/main/res/layout/info.xml index b3e3e69e..1678e33a 100644 --- a/app/src/main/res/layout/info.xml +++ b/app/src/main/res/layout/info.xml @@ -12,7 +12,6 @@ android:layout_width="100dp" android:layout_height="wrap_content" android:layout_marginTop="8dp" - android:contentDescription="@string/logo" android:padding="10dp" /> 我的电视 - logo + 频道反转 \ No newline at end of file