Compare commits

...
8 Commits
Author SHA1 Message Date
Li ZongYing 0286d118ed fix update 2024-05-07 17:55:08 +08:00
Li ZongYing fc83defe31 optimize version check 2024-05-07 12:56:34 +08:00
Li ZongYing 6fc73efd47 optimize version check 2024-05-07 12:55:11 +08:00
Li ZongYing b157f1eb28 fix time 2024-05-07 11:38:10 +08:00
Li ZongYing 2b172ae615 fix retry bug 2024-05-01 17:00:33 +08:00
Li ZongYing 39e5cc7c1f opitimize request 2024-05-01 16:52:33 +08:00
Li ZongYing df5b006024 optimize style 2024-04-29 12:12:59 +08:00
Li ZongYing fe888c36ac left->start 2024-04-27 19:11:08 +08:00
38 changed files with 719 additions and 371 deletions
+24
View File
@@ -1,5 +1,29 @@
## 更新日志 ## 更新日志
### v1.9.6(通用)
* 优化在线升级
* 优化可能状态错误的问题
### v1.9.4(通用)
* 修复默认时间不显示问题
* 设置页居中
* 频道号和时间对齐
### v1.9.2(通用)
* 修复一个重试的错误
### v1.9.0(通用)
* 减少视频播放失败情况
* 全面屏手机居中显示
### v1.8.8(通用)
* 样式优化
### v1.8.6(通用) ### v1.8.6(通用)
* 增加错误显示 * 增加错误显示
+9 -1
View File
@@ -1,6 +1,6 @@
.PHONY: all .PHONY: all
all: info all: info gen-version
branch := $(shell git rev-parse --abbrev-ref HEAD) branch := $(shell git rev-parse --abbrev-ref HEAD)
commit := $(shell git rev-parse --short HEAD) commit := $(shell git rev-parse --short HEAD)
@@ -9,3 +9,11 @@ info:
@echo 'SHELL='$(SHELL) @echo 'SHELL='$(SHELL)
@echo 'branch='$(branch) @echo 'branch='$(branch)
@echo 'commit='$(commit) @echo 'commit='$(commit)
gen-version:
git describe --tags --always
git describe --tags --always | sed 's/v/ /g' | sed 's/\./ /g' | sed 's/-/ /g' | awk '{print ($$1*16777216)+($$2*65536)+($$3*256)+$$4}'
#make gen v=v1.1.3
gen:
echo $(v) | sed 's/v/ /g' | sed 's/\./ /g' | sed 's/-/ /g' | awk '{print "{\"version_code\": " ($$1*16777216)+($$2*65536)+($$3*256)+$$4 ", \"version_name\": \"" "$(v)" "\"}"}' > version.json
+15
View File
@@ -12,6 +12,7 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<application <application
android:name=".MyTvApplication" android:name=".MyTvApplication"
@@ -36,6 +37,9 @@
<category android:name="android.intent.category.LEANBACK_LAUNCHER" /> <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
<meta-data
android:name="android.windowLayoutInDisplayCutoutMode"
android:value="shortEdges" />
</activity> </activity>
<receiver <receiver
@@ -58,5 +62,16 @@
android:name=".InitializerProvider" android:name=".InitializerProvider"
android:authorities="${applicationId}.InitializerProvider" android:authorities="${applicationId}.InitializerProvider"
android:exported="false" /> android:exported="false" />
<meta-data android:name="android.max_aspect" android:value="2.5" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application> </application>
</manifest> </manifest>
Binary file not shown.
Binary file not shown.
@@ -6,7 +6,7 @@ import android.os.Handler
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.view.marginRight import androidx.core.view.marginEnd
import androidx.core.view.marginTop import androidx.core.view.marginTop
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.lizongying.mytv.databinding.ChannelBinding import com.lizongying.mytv.databinding.ChannelBinding
@@ -30,38 +30,21 @@ class ChannelFragment : Fragment() {
val application = requireActivity().applicationContext as MyTvApplication val application = requireActivity().applicationContext as MyTvApplication
val width = application.getWidth()
val height = application.getHeight()
val ratio = 16f / 9f
if (width.toFloat() / height > ratio) {
val x =
((Resources.getSystem().displayMetrics.widthPixels - height * ratio) / 2).toInt()
val originalLayoutParams =
binding.channel.layoutParams as ViewGroup.MarginLayoutParams
originalLayoutParams.rightMargin += x
binding.channel.layoutParams = originalLayoutParams
}
if (width.toFloat() / height < ratio) {
val y =
((height - Resources.getSystem().displayMetrics.widthPixels / ratio) / 2).toInt()
val originalLayoutParams =
binding.channel.layoutParams as ViewGroup.MarginLayoutParams
originalLayoutParams.topMargin += y
binding.channel.layoutParams = originalLayoutParams
}
binding.channel.layoutParams.width = application.px2Px(binding.channel.layoutParams.width) binding.channel.layoutParams.width = application.px2Px(binding.channel.layoutParams.width)
binding.channel.layoutParams.height = application.px2Px(binding.channel.layoutParams.height) binding.channel.layoutParams.height = application.px2Px(binding.channel.layoutParams.height)
val layoutParams = binding.channel.layoutParams as ViewGroup.MarginLayoutParams val layoutParams = binding.channel.layoutParams as ViewGroup.MarginLayoutParams
layoutParams.topMargin = application.px2Px(binding.channel.marginTop) layoutParams.topMargin = application.px2Px(binding.channel.marginTop)
layoutParams.rightMargin = application.px2Px(binding.channel.marginRight) layoutParams.marginEnd = application.px2Px(binding.channel.marginEnd)
binding.channel.layoutParams = layoutParams binding.channel.layoutParams = layoutParams
binding.content.textSize = application.px2PxFont(binding.content.textSize)
(activity as MainActivity).fragmentReady("ChannelFragment") binding.content.textSize = application.px2PxFont(binding.content.textSize)
binding.time.textSize = application.px2PxFont(binding.time.textSize)
binding.main.layoutParams.width = application.shouldWidthPx()
binding.main.layoutParams.height = application.shouldHeightPx()
(activity as MainActivity).fragmentReady(TAG)
return binding.root return binding.root
} }
@@ -7,24 +7,33 @@ import androidx.fragment.app.DialogFragment
class ConfirmationFragment( class ConfirmationFragment(
private val listener: ConfirmationListener, private val listener: ConfirmationListener,
private val message: String private val message: String,
private val update: Boolean
) : DialogFragment() { ) : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return activity?.let { return activity?.let {
val builder = AlertDialog.Builder(it) val builder = AlertDialog.Builder(it)
builder.setTitle("确定更新吗?") builder.setTitle(message)
.setMessage(message) if (update) {
.setPositiveButton( builder.setMessage("确定更新吗?")
"确定" .setPositiveButton(
) { _, _ -> "确定"
listener.onConfirm() ) { _, _ ->
} listener.onConfirm()
.setNegativeButton( }
"取消" .setNegativeButton(
) { _, _ -> "取消"
listener.onCancel() ) { _, _ ->
} listener.onCancel()
}
} else {
builder.setMessage("")
.setNegativeButton(
"好的"
) { _, _ ->
}
}
builder.create() builder.create()
} ?: throw IllegalStateException("Activity cannot be null") } ?: throw IllegalStateException("Activity cannot be null")
} }
@@ -4,7 +4,7 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.view.marginLeft import androidx.core.view.marginStart
import androidx.core.view.marginTop import androidx.core.view.marginTop
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.lizongying.mytv.databinding.ErrorBinding import com.lizongying.mytv.databinding.ErrorBinding
@@ -24,10 +24,6 @@ class ErrorFragment : Fragment() {
binding.logo.layoutParams.width = application.px2Px(binding.logo.layoutParams.width) binding.logo.layoutParams.width = application.px2Px(binding.logo.layoutParams.width)
binding.logo.layoutParams.height = application.px2Px(binding.logo.layoutParams.height) binding.logo.layoutParams.height = application.px2Px(binding.logo.layoutParams.height)
val layoutParamsMain = binding.main.layoutParams as ViewGroup.MarginLayoutParams
layoutParamsMain.leftMargin = application.px2Px(binding.main.marginLeft)
binding.main.layoutParams = layoutParamsMain
val layoutParams = binding.msg.layoutParams as ViewGroup.MarginLayoutParams val layoutParams = binding.msg.layoutParams as ViewGroup.MarginLayoutParams
layoutParams.topMargin = application.px2Px(binding.msg.marginTop) layoutParams.topMargin = application.px2Px(binding.msg.marginTop)
binding.msg.layoutParams = layoutParams binding.msg.layoutParams = layoutParams
@@ -8,7 +8,7 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.view.marginBottom import androidx.core.view.marginBottom
import androidx.core.view.marginLeft import androidx.core.view.marginStart
import androidx.core.view.marginTop import androidx.core.view.marginTop
import androidx.core.view.setPadding import androidx.core.view.setPadding
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
@@ -30,31 +30,21 @@ class InfoFragment : Fragment() {
_binding = InfoBinding.inflate(inflater, container, false) _binding = InfoBinding.inflate(inflater, container, false)
val application = requireActivity().applicationContext as MyTvApplication val application = requireActivity().applicationContext as MyTvApplication
val width = application.getWidth()
val height = application.getHeight()
val ratio = 16f / 9f
if (width.toFloat() / height < ratio) {
val y =
((height - Resources.getSystem().displayMetrics.widthPixels / ratio) / 2).toInt()
val originalLayoutParams = binding.info.layoutParams as ViewGroup.MarginLayoutParams
originalLayoutParams.bottomMargin += y
binding.info.layoutParams = originalLayoutParams
}
binding.info.layoutParams.width = application.px2Px(binding.info.layoutParams.width) binding.info.layoutParams.width = application.px2Px(binding.info.layoutParams.width)
binding.info.layoutParams.height = application.px2Px(binding.info.layoutParams.height) binding.info.layoutParams.height = application.px2Px(binding.info.layoutParams.height)
val layoutParams = binding.info.layoutParams as ViewGroup.MarginLayoutParams val layoutParams = binding.info.layoutParams as ViewGroup.MarginLayoutParams
layoutParams.bottomMargin = application.px2Px(binding.info.marginBottom) layoutParams.bottomMargin = application.px2Px(binding.info.marginBottom)
binding.info.layoutParams = layoutParams binding.info.layoutParams = layoutParams
binding.logo.layoutParams.width = application.px2Px(binding.logo.layoutParams.width) binding.logo.layoutParams.width = application.px2Px(binding.logo.layoutParams.width)
binding.logo.setPadding(application.px2Px(binding.logo.paddingTop)) binding.logo.setPadding(application.px2Px(binding.logo.paddingTop))
binding.main.layoutParams.width = application.px2Px(binding.main.layoutParams.width) binding.main.layoutParams.width = application.px2Px(binding.main.layoutParams.width)
binding.main.setPadding(application.px2Px(binding.main.paddingTop)) binding.main.setPadding(application.px2Px(binding.main.paddingTop))
val layoutParamsMain = binding.main.layoutParams as ViewGroup.MarginLayoutParams val layoutParamsMain = binding.main.layoutParams as ViewGroup.MarginLayoutParams
layoutParamsMain.leftMargin = application.px2Px(binding.main.marginLeft) layoutParamsMain.marginStart = application.px2Px(binding.main.marginStart)
binding.main.layoutParams = layoutParamsMain binding.main.layoutParams = layoutParamsMain
val layoutParamsDesc = binding.desc.layoutParams as ViewGroup.MarginLayoutParams val layoutParamsDesc = binding.desc.layoutParams as ViewGroup.MarginLayoutParams
@@ -64,13 +54,19 @@ class InfoFragment : Fragment() {
binding.title.textSize = application.px2PxFont(binding.title.textSize) binding.title.textSize = application.px2PxFont(binding.title.textSize)
binding.desc.textSize = application.px2PxFont(binding.desc.textSize) binding.desc.textSize = application.px2PxFont(binding.desc.textSize)
binding.container.layoutParams.width = application.shouldWidthPx()
binding.container.layoutParams.height = application.shouldHeightPx()
_binding!!.root.visibility = View.GONE _binding!!.root.visibility = View.GONE
(activity as MainActivity).fragmentReady("InfoFragment") (activity as MainActivity).fragmentReady(TAG)
return binding.root return binding.root
} }
fun show(tvViewModel: TVViewModel) { fun show(tvViewModel: TVViewModel) {
if (_binding == null) {
return
}
binding.title.text = tvViewModel.getTV().title binding.title.text = tvViewModel.getTV().title
Glide.with(this) Glide.with(this)
@@ -0,0 +1,37 @@
package com.lizongying.mytv
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.lizongying.mytv.databinding.LoadingBinding
class LoadingFragment : Fragment() {
private var _binding: LoadingBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = LoadingBinding.inflate(inflater, container, false)
val application = requireActivity().applicationContext as MyTvApplication
binding.bar.layoutParams.width = application.px2Px(binding.bar.layoutParams.width)
binding.bar.layoutParams.height = application.px2Px(binding.bar.layoutParams.height)
(activity as MainActivity).fragmentReady(TAG)
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
companion object {
private const val TAG = "LoadingFragment"
}
}
@@ -1,8 +1,5 @@
package com.lizongying.mytv package com.lizongying.mytv
import android.content.Context
import android.net.ConnectivityManager
import android.net.Network
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
@@ -11,9 +8,13 @@ import android.util.Log
import android.view.GestureDetector import android.view.GestureDetector
import android.view.KeyEvent import android.view.KeyEvent
import android.view.MotionEvent import android.view.MotionEvent
import android.view.View.SYSTEM_UI_FLAG_FULLSCREEN
import android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION import android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
import android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
import android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
import android.view.WindowManager import android.view.WindowManager
import android.widget.Toast import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.lizongying.mytv.models.TVViewModel import com.lizongying.mytv.models.TVViewModel
@@ -29,6 +30,8 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
private var ready = 0 private var ready = 0
private val playerFragment = PlayerFragment() private val playerFragment = PlayerFragment()
private val errorFragment = ErrorFragment() private val errorFragment = ErrorFragment()
private val loadingFragment = LoadingFragment()
private val mainFragment = MainFragment() private val mainFragment = MainFragment()
private val infoFragment = InfoFragment() private val infoFragment = InfoFragment()
private val channelFragment = ChannelFragment() private val channelFragment = ChannelFragment()
@@ -56,47 +59,69 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) setContentView(R.layout.activity_main)
Request.setRequestListener(this) Request.setRequestListener(this)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
val lp = window.attributes
lp.layoutInDisplayCutoutMode =
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
window.setAttributes(lp)
}
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
window.decorView.systemUiVisibility = SYSTEM_UI_FLAG_HIDE_NAVIGATION window.decorView.systemUiVisibility =
SYSTEM_UI_FLAG_FULLSCREEN or
SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or SYSTEM_UI_FLAG_HIDE_NAVIGATION or
SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
// window.statusBarColor = Color.TRANSPARENT
// window.navigationBarColor = Color.TRANSPARENT
// }
if (savedInstanceState == null) { if (savedInstanceState == null) {
supportFragmentManager.beginTransaction() val transaction = supportFragmentManager.beginTransaction()
.add(R.id.main_browse_fragment, playerFragment) .add(R.id.main_browse_fragment, playerFragment)
.add(R.id.main_browse_fragment, errorFragment) .add(R.id.main_browse_fragment, errorFragment)
// .add(R.id.main_browse_fragment, loadingFragment)
.add(R.id.main_browse_fragment, timeFragment) .add(R.id.main_browse_fragment, timeFragment)
.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(mainFragment) .hide(mainFragment)
.hide(errorFragment) .hide(errorFragment)
.commit()
if (!SP.time) {
transaction.hide(timeFragment)
} else {
transaction.show(timeFragment)
}
transaction.commitNow()
} }
gestureDetector = GestureDetector(this, GestureListener()) gestureDetector = GestureDetector(this, GestureListener())
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val connectivityManager = // val connectivityManager =
getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager // getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
connectivityManager.registerDefaultNetworkCallback(object : // connectivityManager.registerDefaultNetworkCallback(object :
ConnectivityManager.NetworkCallback() { // ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) { // override fun onAvailable(network: Network) {
super.onAvailable(network) // super.onAvailable(network)
Log.i(TAG, "net ${Build.VERSION.SDK_INT}") // Log.i(TAG, "net ${Build.VERSION.SDK_INT}")
if (this@MainActivity.isNetworkConnected) { // if (this@MainActivity.isNetworkConnected) {
Log.i(TAG, "net isNetworkConnected") // Log.i(TAG, "net isNetworkConnected")
ready++ // ready++
} // }
} // }
}) // })
} else { // } else {
Log.i(TAG, "net ${Build.VERSION.SDK_INT}") // Log.i(TAG, "net ${Build.VERSION.SDK_INT}")
ready++ // ready++
} // }
} }
fun showInfoFragment(tvViewModel: TVViewModel) { fun showInfoFragment(tvViewModel: TVViewModel) {
@@ -126,6 +151,14 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
.commit() .commit()
} }
fun showLoadingFragment() {
showFragment(loadingFragment)
}
fun hideLoadingFragment() {
hideFragment(loadingFragment)
}
fun showPlayerFragment() { fun showPlayerFragment() {
if (playerFragment.isVisible) { if (playerFragment.isVisible) {
return return
@@ -196,7 +229,6 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
fun settingDelayHide() { fun settingDelayHide() {
handler.removeCallbacks(hideSetting) handler.removeCallbacks(hideSetting)
handler.postDelayed(hideSetting, delayHideSetting) handler.postDelayed(hideSetting, delayHideSetting)
showTime()
} }
fun settingNeverHide() { fun settingNeverHide() {
@@ -224,20 +256,37 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
fun fragmentReady(tag: String) { fun fragmentReady(tag: String) {
ready++ ready++
Log.i(TAG, "ready $tag $ready ") Log.i(TAG, "ready $tag $ready ")
if (ready == 8) { if (ready == 7) {
mainFragment.fragmentReady() mainFragment.fragmentReady()
showTime()
} }
} }
private fun showTime() { private fun showTime() {
Log.i(TAG, "showTime ${SP.time}")
if (SP.time) { if (SP.time) {
timeFragment.show() showFragment(timeFragment)
} else { } else {
timeFragment.hide() hideFragment(timeFragment)
} }
mainFragment.changeStyle() }
private fun showFragment(fragment: Fragment) {
if (!fragment.isHidden) {
return
}
supportFragmentManager.beginTransaction()
.show(fragment)
.commitNow()
}
private fun hideFragment(fragment: Fragment) {
if (fragment.isHidden) {
return
}
supportFragmentManager.beginTransaction()
.hide(fragment)
.commitNow()
} }
override fun onTouchEvent(event: MotionEvent?): Boolean { override fun onTouchEvent(event: MotionEvent?): Boolean {
@@ -298,20 +347,19 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
return return
} }
Log.i(TAG, "settingFragment ${settingFragment.isVisible}") if (settingFragment.isVisible) {
if (!settingFragment.isVisible) { return
settingFragment.show(supportFragmentManager, "setting")
settingDelayHide()
} else {
handler.removeCallbacks(hideSetting)
settingFragment.dismiss()
} }
settingFragment.show(supportFragmentManager, TAG)
settingDelayHide()
} }
private val hideSetting = Runnable { private val hideSetting = Runnable {
if (settingFragment.isVisible) { if (settingFragment.isVisible) {
settingFragment.dismiss() settingFragment.dismiss()
showTime() showTime()
mainFragment.changeMenu()
} }
} }
@@ -376,6 +424,11 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
}, 2000) }, 2000)
} }
private fun active() {
if (settingFragment.isVisible) {
settingDelayHide()
}
}
fun onKey(keyCode: Int): Boolean { fun onKey(keyCode: Int): Boolean {
Log.i(TAG, "keyCode $keyCode") Log.i(TAG, "keyCode $keyCode")
@@ -466,6 +519,7 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
} }
KeyEvent.KEYCODE_ENTER -> { KeyEvent.KEYCODE_ENTER -> {
active()
switchMainFragment() switchMainFragment()
} }
@@ -474,6 +528,7 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
} }
KeyEvent.KEYCODE_DPAD_UP -> { KeyEvent.KEYCODE_DPAD_UP -> {
active()
channelUp() channelUp()
} }
@@ -482,6 +537,7 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
} }
KeyEvent.KEYCODE_DPAD_DOWN -> { KeyEvent.KEYCODE_DPAD_DOWN -> {
active()
channelDown() channelDown()
} }
@@ -490,6 +546,7 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
} }
KeyEvent.KEYCODE_DPAD_LEFT -> { KeyEvent.KEYCODE_DPAD_LEFT -> {
active()
if (mainFragment.isHidden && !settingFragment.isVisible) { if (mainFragment.isHidden && !settingFragment.isVisible) {
switchMainFragment() switchMainFragment()
return true return true
@@ -497,6 +554,7 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
} }
KeyEvent.KEYCODE_DPAD_RIGHT -> { KeyEvent.KEYCODE_DPAD_RIGHT -> {
active()
if (mainFragment.isHidden && !settingFragment.isVisible) { if (mainFragment.isHidden && !settingFragment.isVisible) {
showSetting() showSetting()
return true return true
@@ -525,6 +583,12 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
override fun onResume() { override fun onResume() {
Log.i(TAG, "onResume") Log.i(TAG, "onResume")
super.onResume() super.onResume()
}
override fun onResumeFragments() {
super.onResumeFragments()
mainFragment.changeMenu()
if (!mainFragment.isHidden) { if (!mainFragment.isHidden) {
handler.postDelayed(hideMain, delayHideMain) handler.postDelayed(hideMain, delayHideMain)
} }
@@ -1,6 +1,5 @@
package com.lizongying.mytv package com.lizongying.mytv
import android.content.res.Resources
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.KeyEvent import android.view.KeyEvent
@@ -9,7 +8,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Toast import android.widget.Toast
import androidx.core.view.marginBottom import androidx.core.view.marginBottom
import androidx.core.view.marginLeft import androidx.core.view.marginStart
import androidx.core.view.marginTop import androidx.core.view.marginTop
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
@@ -51,37 +50,10 @@ class MainFragment : Fragment(), CardAdapter.ItemListener {
application = requireActivity().applicationContext as MyTvApplication application = requireActivity().applicationContext as MyTvApplication
val width = application.getWidth() binding.menu.layoutParams.width = application.shouldWidthPx()
val height = application.getHeight() binding.menu.layoutParams.height = application.shouldHeightPx()
val ratio = 16f / 9f binding.container.setOnClickListener {
if (width.toFloat() / height > ratio) {
val x =
((Resources.getSystem().displayMetrics.widthPixels - height * ratio) / 2).toInt()
val originalLayoutParams =
binding.scroll.layoutParams as ViewGroup.MarginLayoutParams
originalLayoutParams.leftMargin += x
originalLayoutParams.rightMargin += x
binding.scroll.layoutParams = originalLayoutParams
Log.i(
TAG,
"binding.scroll ${Resources.getSystem().displayMetrics.widthPixels} ${height * ratio}"
)
}
if (width.toFloat() / height < ratio) {
val y =
((height - Resources.getSystem().displayMetrics.widthPixels / ratio) / 2).toInt()
val originalLayoutParams =
binding.scroll.layoutParams as ViewGroup.MarginLayoutParams
originalLayoutParams.topMargin += y
originalLayoutParams.bottomMargin += y
binding.scroll.layoutParams = originalLayoutParams
}
binding.menu.setOnClickListener {
hideSelf() hideSelf()
} }
@@ -166,7 +138,7 @@ class MainFragment : Fragment(), CardAdapter.ItemListener {
itemBinding.header.layoutParams as ViewGroup.MarginLayoutParams itemBinding.header.layoutParams as ViewGroup.MarginLayoutParams
layoutParamsHeader.topMargin = application.px2Px(itemBinding.header.marginTop) layoutParamsHeader.topMargin = application.px2Px(itemBinding.header.marginTop)
layoutParamsHeader.bottomMargin = application.px2Px(itemBinding.header.marginBottom) layoutParamsHeader.bottomMargin = application.px2Px(itemBinding.header.marginBottom)
layoutParamsHeader.leftMargin = application.px2Px(itemBinding.header.marginLeft) layoutParamsHeader.marginStart = application.px2Px(itemBinding.header.marginStart)
itemBinding.header.layoutParams = layoutParamsHeader itemBinding.header.layoutParams = layoutParamsHeader
itemBinding.header.textSize = application.px2PxFont(itemBinding.header.textSize) itemBinding.header.textSize = application.px2PxFont(itemBinding.header.textSize)
@@ -188,8 +160,10 @@ class MainFragment : Fragment(), CardAdapter.ItemListener {
if (tvViewModel.errInfo.value == "") { if (tvViewModel.errInfo.value == "") {
(activity as? MainActivity)?.showPlayerFragment() (activity as? MainActivity)?.showPlayerFragment()
(activity as? MainActivity)?.hideErrorFragment() (activity as? MainActivity)?.hideErrorFragment()
(activity as? MainActivity)?.hideLoadingFragment()
} else { } else {
(activity as? MainActivity)?.hidePlayerFragment() (activity as? MainActivity)?.hidePlayerFragment()
(activity as? MainActivity)?.hideLoadingFragment()
(activity as? MainActivity)?.showErrorFragment(tvViewModel.errInfo.value.toString()) (activity as? MainActivity)?.showErrorFragment(tvViewModel.errInfo.value.toString())
} }
} }
@@ -231,11 +205,11 @@ class MainFragment : Fragment(), CardAdapter.ItemListener {
} }
} }
} }
(activity as MainActivity).fragmentReady("MainFragment") (activity as MainActivity).fragmentReady(TAG)
} }
} }
fun changeStyle() { fun changeMenu() {
if (SP.grid) { if (SP.grid) {
for (i in rowList) { for (i in rowList) {
if (i is RecyclerView) { if (i is RecyclerView) {
@@ -278,7 +252,7 @@ class MainFragment : Fragment(), CardAdapter.ItemListener {
for (i in rowList) { for (i in rowList) {
if (i.tag as Int != row) { if (i.tag as Int != row) {
((i as RecyclerView).adapter as CardAdapter).focusable = false ((i as RecyclerView).adapter as CardAdapter).focusable = false
((i as RecyclerView).adapter as CardAdapter).clear() (i.adapter as CardAdapter).clear()
} else { } else {
((i as RecyclerView).adapter as CardAdapter).focusable = true ((i as RecyclerView).adapter as CardAdapter).focusable = true
} }
@@ -435,13 +409,6 @@ class MainFragment : Fragment(), CardAdapter.ItemListener {
super.onResume() super.onResume()
} }
override fun onStop() {
Log.i(TAG, "onStop")
super.onStop()
SP.itemPosition = itemPosition
Log.i(TAG, "$POSITION $itemPosition saved")
}
override fun onDestroy() { override fun onDestroy() {
Log.i(TAG, "onDestroy") Log.i(TAG, "onDestroy")
super.onDestroy() super.onDestroy()
@@ -12,8 +12,12 @@ class MyTvApplication : Application() {
private lateinit var displayMetrics: DisplayMetrics private lateinit var displayMetrics: DisplayMetrics
private lateinit var realDisplayMetrics: DisplayMetrics private lateinit var realDisplayMetrics: DisplayMetrics
private lateinit var windowManager: WindowManager
private var width = 0 private var width = 0
private var height = 0 private var height = 0
private var shouldWidth = 0
private var shouldHeight = 0
private var deviation = 0 private var deviation = 0
private var ratio = 1.0 private var ratio = 1.0
private var density = 2.0f private var density = 2.0f
@@ -24,7 +28,7 @@ class MyTvApplication : Application() {
displayMetrics = DisplayMetrics() displayMetrics = DisplayMetrics()
realDisplayMetrics = DisplayMetrics() realDisplayMetrics = DisplayMetrics()
val windowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager windowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager
windowManager.defaultDisplay.getMetrics(displayMetrics) windowManager.defaultDisplay.getMetrics(displayMetrics)
windowManager.defaultDisplay.getRealMetrics(realDisplayMetrics) windowManager.defaultDisplay.getRealMetrics(realDisplayMetrics)
@@ -44,6 +48,16 @@ class MyTvApplication : Application() {
height * 2 / 1080.0 / density height * 2 / 1080.0 / density
} }
if ((width.toDouble() / height) < (16.0 / 9.0)) {
ratio = width * 2 / 1920.0 / density
shouldWidth = width
shouldHeight = (width * 9.0 / 16.0).toInt()
} else {
ratio = height * 2 / 1080.0 / density
shouldHeight = height
shouldWidth = (height * 16.0 / 9.0).toInt()
}
deviation = width - Resources.getSystem().displayMetrics.widthPixels deviation = width - Resources.getSystem().displayMetrics.widthPixels
scale = Resources.getSystem().displayMetrics.scaledDensity scale = Resources.getSystem().displayMetrics.scaledDensity
} }
@@ -56,18 +70,26 @@ class MyTvApplication : Application() {
return realDisplayMetrics return realDisplayMetrics
} }
fun shouldWidthPx(): Int {
return shouldWidth
}
fun shouldHeightPx(): Int {
return shouldHeight
}
fun getWidth(): Int { fun getWidth(): Int {
return width return width
} }
fun getDeviation(): Int {
return deviation
}
fun getHeight(): Int { fun getHeight(): Int {
return height return height
} }
fun getDeviation(): Int {
return deviation
}
fun getRatio(): Double { fun getRatio(): Double {
return ratio return ratio
} }
@@ -93,7 +93,7 @@ class PlayerFragment : Fragment(), SurfaceHolder.Callback {
}) })
} }
}) })
(activity as MainActivity).fragmentReady("PlayerFragment") (activity as MainActivity).fragmentReady(TAG)
return _binding!!.root return _binding!!.root
} }
@@ -154,7 +154,7 @@ class PlayerFragment : Fragment(), SurfaceHolder.Callback {
} }
companion object { companion object {
private const val TAG = "PlaybackVideoFragment" private const val TAG = "PlayerFragment"
} }
override fun surfaceCreated(holder: SurfaceHolder) { override fun surfaceCreated(holder: SurfaceHolder) {
@@ -1,5 +1,6 @@
package com.lizongying.mytv package com.lizongying.mytv
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@@ -23,6 +24,11 @@ class SettingFragment : DialogFragment() {
dialog?.window?.apply { dialog?.window?.apply {
addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
attributes.layoutInDisplayCutoutMode =
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
setAttributes(attributes)
}
} }
} }
@@ -81,7 +87,7 @@ class SettingFragment : DialogFragment() {
} }
} }
updateManager = UpdateManager(context, this, context.appVersionCode) updateManager = UpdateManager(context, context.appVersionCode)
binding.checkVersion.setOnClickListener( binding.checkVersion.setOnClickListener(
OnClickListenerCheckVersion( OnClickListenerCheckVersion(
activity as MainActivity, activity as MainActivity,
@@ -101,9 +107,9 @@ class SettingFragment : DialogFragment() {
) )
binding.name.textSize = application.px2PxFont(binding.name.textSize) binding.name.textSize = application.px2PxFont(binding.name.textSize)
binding.version.textSize = application.px2PxFont(binding.version.textSize) binding.version.textSize = application.px2PxFont(binding.version.textSize)
val layoutParamsDesc = binding.version.layoutParams as ViewGroup.MarginLayoutParams val layoutParamsVersion = binding.version.layoutParams as ViewGroup.MarginLayoutParams
layoutParamsDesc.topMargin = application.px2Px(binding.version.marginTop) layoutParamsVersion.topMargin = application.px2Px(binding.version.marginTop)
binding.version.layoutParams = layoutParamsDesc binding.version.layoutParams = layoutParamsVersion
binding.checkVersion.textSize = application.px2PxFont(binding.checkVersion.textSize) binding.checkVersion.textSize = application.px2PxFont(binding.checkVersion.textSize)
val layoutParamsCheckVersion = val layoutParamsCheckVersion =
@@ -1,12 +1,11 @@
package com.lizongying.mytv package com.lizongying.mytv
import android.content.res.Resources
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.view.marginRight import androidx.core.view.marginEnd
import androidx.core.view.marginTop import androidx.core.view.marginTop
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.lizongying.mytv.Utils.getDateFormat import com.lizongying.mytv.Utils.getDateFormat
@@ -27,52 +26,41 @@ class TimeFragment : Fragment() {
val application = requireActivity().applicationContext as MyTvApplication val application = requireActivity().applicationContext as MyTvApplication
val width = application.getWidth()
val height = application.getHeight()
val ratio = 16f / 9f
if (width.toFloat() / height > ratio) {
val x =
((Resources.getSystem().displayMetrics.widthPixels - height * ratio) / 2).toInt()
val originalLayoutParams = binding.time.layoutParams as ViewGroup.MarginLayoutParams
originalLayoutParams.rightMargin += x
binding.time.layoutParams = originalLayoutParams
}
if (width.toFloat() / height < ratio) {
val y =
((height - Resources.getSystem().displayMetrics.widthPixels / ratio) / 2).toInt()
val originalLayoutParams = binding.time.layoutParams as ViewGroup.MarginLayoutParams
originalLayoutParams.topMargin += y
binding.time.layoutParams = originalLayoutParams
}
binding.time.layoutParams.width = application.px2Px(binding.time.layoutParams.width) binding.time.layoutParams.width = application.px2Px(binding.time.layoutParams.width)
binding.time.layoutParams.height = application.px2Px(binding.time.layoutParams.height) binding.time.layoutParams.height = application.px2Px(binding.time.layoutParams.height)
val layoutParams = binding.time.layoutParams as ViewGroup.MarginLayoutParams val layoutParams = binding.time.layoutParams as ViewGroup.MarginLayoutParams
layoutParams.topMargin = application.px2Px(binding.time.marginTop) layoutParams.topMargin = application.px2Px(binding.time.marginTop)
layoutParams.rightMargin = application.px2Px(binding.time.marginRight) layoutParams.marginEnd = application.px2Px(binding.time.marginEnd)
binding.time.layoutParams = layoutParams binding.time.layoutParams = layoutParams
binding.content.textSize = application.px2PxFont(binding.content.textSize)
(activity as MainActivity).fragmentReady("TimeFragment") binding.content.textSize = application.px2PxFont(binding.content.textSize)
binding.channel.textSize = application.px2PxFont(binding.channel.textSize)
binding.main.layoutParams.width = application.shouldWidthPx()
binding.main.layoutParams.height = application.shouldHeightPx()
if (SP.time) {
handler.removeCallbacks(showRunnable)
handler.postDelayed(showRunnable, 0)
} else {
handler.removeCallbacks(showRunnable)
}
(activity as MainActivity).fragmentReady(TAG)
return binding.root return binding.root
} }
override fun onResume() { override fun onHiddenChanged(hidden: Boolean) {
super.onResume() super.onHiddenChanged(hidden)
if (view?.visibility == View.VISIBLE) { if (!hidden) {
handler.removeCallbacks(showRunnable) handler.removeCallbacks(showRunnable)
handler.postDelayed(showRunnable, 0) handler.postDelayed(showRunnable, 0)
} else {
handler.removeCallbacks(showRunnable)
} }
} }
override fun onPause() {
super.onPause()
handler.removeCallbacks(showRunnable)
}
private val showRunnable: Runnable = Runnable { private val showRunnable: Runnable = Runnable {
run { run {
if (_binding == null) { if (_binding == null) {
@@ -83,17 +71,6 @@ class TimeFragment : Fragment() {
} }
} }
fun show() {
view?.visibility = View.VISIBLE
handler.removeCallbacks(showRunnable)
handler.postDelayed(showRunnable, 0)
}
fun hide() {
view?.visibility = View.GONE
handler.removeCallbacks(showRunnable)
}
override fun onDestroyView() { override fun onDestroyView() {
handler.removeCallbacks(showRunnable) handler.removeCallbacks(showRunnable)
super.onDestroyView() super.onDestroyView()
@@ -17,8 +17,10 @@ import android.util.Log
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.core.content.PermissionChecker import androidx.core.content.PermissionChecker
import androidx.core.content.PermissionChecker.checkSelfPermission import androidx.core.content.PermissionChecker.checkSelfPermission
import com.lizongying.mytv.api.ReleaseV2 import androidx.fragment.app.FragmentActivity
import com.lizongying.mytv.api.ApiClient
import com.lizongying.mytv.requests.ReleaseRequest import com.lizongying.mytv.requests.ReleaseRequest
import com.lizongying.mytv.requests.ReleaseResponse
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -27,13 +29,12 @@ import java.io.File
class UpdateManager( class UpdateManager(
private var context: Context, private var context: Context,
private var settingFragment: SettingFragment,
private var versionCode: Long private var versionCode: Long
) : ) :
ConfirmationFragment.ConfirmationListener { ConfirmationFragment.ConfirmationListener {
private var myRequest = ReleaseRequest() private var releaseRequest = ReleaseRequest()
private var release: ReleaseV2? = null private var release: ReleaseResponse? = null
private var downloadReceiver: DownloadReceiver? = null private var downloadReceiver: DownloadReceiver? = null
@@ -43,30 +44,32 @@ class UpdateManager(
} }
CoroutineScope(Dispatchers.Main).launch { CoroutineScope(Dispatchers.Main).launch {
var text = "版本获取失败" var text = "版本获取失败"
var update = false
try { try {
release = myRequest.getRelease() release = releaseRequest.getRelease()
Log.i(TAG, "versionCode $versionCode ${release?.c}") Log.i(TAG, "versionCode $versionCode ${release?.version_code}")
if (release?.c != null) { if (release?.version_code != null) {
text = if (release?.c!! > versionCode) { if (release?.version_code!! > versionCode) {
"最新版本:${release?.n}\n${release?.d ?: ""}" text = "最新版本:${release?.version_name}"
update = true
} else { } else {
"已是最新版本,不需要更新" text = "已是最新版本,不需要更新"
} }
} }
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "Error occurred: ${e.message}", e) Log.e(TAG, "Error occurred: ${e.message}", e)
} }
updateUI(text) updateUI(text, update)
} }
} }
private fun updateUI(text: String) { private fun updateUI(text: String, update: Boolean) {
val dialog = ConfirmationFragment(this@UpdateManager, text) val dialog = ConfirmationFragment(this@UpdateManager, text, update)
settingFragment.fragmentManager?.let { dialog.show(it, TAG) } dialog.show((context as FragmentActivity).supportFragmentManager, TAG)
} }
private fun haveStoragePermission(): Boolean { private fun haveStoragePermission(): Boolean {
if (Build.VERSION.SDK_INT >= 23) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(context, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) if (checkSelfPermission(context, android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
=== PermissionChecker.PERMISSION_GRANTED === PermissionChecker.PERMISSION_GRANTED
) { ) {
@@ -88,20 +91,32 @@ class UpdateManager(
} }
private fun startDownload(release: ReleaseV2) { private fun startDownload(release: ReleaseResponse) {
val apkFileName = "my-tv-${release.n}.apk" val packageInstaller = context.packageManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (!packageInstaller.canRequestPackageInstalls()) {
}
}
val apkName = "my-tv"
val apkFileName = "$apkName-${release.version_name}.apk"
Log.i(TAG, "apkFileName $apkFileName") Log.i(TAG, "apkFileName $apkFileName")
val downloadManager = val downloadManager =
context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val request = Request(Uri.parse(release.u)) val request =
Log.i(TAG, "url ${Uri.parse(release.u)}") Request(Uri.parse("${ApiClient.DOWNLOAD_HOST}${release.version_name}/$apkName-${release.version_name}.apk"))
Log.i(
TAG,
"url ${Uri.parse("${ApiClient.DOWNLOAD_HOST}${release.version_name}/$apkName-${release.version_name}.apk")}"
)
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)?.mkdirs() context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)?.mkdirs()
Log.i(TAG, "save dir ${Environment.DIRECTORY_DOWNLOADS}")
request.setDestinationInExternalFilesDir( request.setDestinationInExternalFilesDir(
context, context,
Environment.DIRECTORY_DOWNLOADS, Environment.DIRECTORY_DOWNLOADS,
apkFileName apkFileName
) )
request.setTitle("${settingFragment.resources.getString(R.string.app_name)} ${release.n}") request.setTitle("${context.resources.getString(R.string.app_name)} ${release.version_name}")
request.setNotificationVisibility(Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) request.setNotificationVisibility(Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
request.setAllowedOverRoaming(false) request.setAllowedOverRoaming(false)
request.setMimeType("application/vnd.android.package-archive") request.setMimeType("application/vnd.android.package-archive")
@@ -179,27 +194,73 @@ class UpdateManager(
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {
val reference = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1) val reference = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
Log.i(TAG, "reference $reference") Log.i(TAG, "reference $reference")
val progress = intent.getIntExtra("progress", 0)
Log.i(TAG, "progress $progress")
// 检查是否是我们发起的下载
if (reference == downloadReference) { if (reference == downloadReference) {
// 下载完成,触发安装 val downloadManager =
installNewVersion() context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val query = DownloadManager.Query().setFilterById(downloadReference)
val cursor = downloadManager.query(query)
if (cursor != null && cursor.moveToFirst()) {
val statusIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)
if (statusIndex < 0) {
Log.i(TAG, "Download failure")
return
}
val status = cursor.getInt(statusIndex)
val progressIndex =
cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)
if (progressIndex < 0) {
Log.i(TAG, "Download failure")
return
}
val progress = cursor.getInt(progressIndex)
val totalSizeIndex =
cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)
val totalSize = cursor.getInt(totalSizeIndex)
cursor.close()
when (status) {
DownloadManager.STATUS_SUCCESSFUL -> {
installNewVersion()
}
DownloadManager.STATUS_FAILED -> {
// Handle download failure
Log.i(TAG, "Download failure")
}
else -> {
// Update UI with download progress
val percentage = progress * 100 / totalSize
Log.i(TAG, "Download progress: $percentage%")
}
}
}
} }
} }
private fun installNewVersion() { private fun installNewVersion() {
val installIntent = Intent(Intent.ACTION_VIEW) val apkFile = File(
val apkUri = Uri.fromFile( context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
File( apkFileName
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
apkFileName
)
) )
installIntent.setDataAndType(apkUri, "application/vnd.android.package-archive") Log.i(TAG, "apkFile $apkFile")
installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(installIntent) if (apkFile.exists()) {
val apkUri = Uri.parse("file://$apkFile")
Log.i(TAG, "apkUri $apkUri")
val installIntent = Intent(Intent.ACTION_VIEW).apply {
setDataAndType(apkUri, "application/vnd.android.package-archive")
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK)
}
context.startActivity(installIntent)
} else {
Log.e(TAG, "APK file does not exist!")
}
} }
} }
+20 -1
View File
@@ -2,12 +2,15 @@ package com.lizongying.mytv
import android.content.res.Resources import android.content.res.Resources
import android.os.Build import android.os.Build
import android.util.Log
import android.util.TypedValue import android.util.TypedValue
import com.google.gson.Gson import com.google.gson.Gson
import com.lizongying.mytv.api.TimeResponse import com.lizongying.mytv.api.TimeResponse
import com.lizongying.mytv.requests.Request import com.lizongying.mytv.requests.Request
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import okhttp3.Interceptor
import okhttp3.Response
import java.io.IOException import java.io.IOException
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Date import java.util.Date
@@ -47,6 +50,20 @@ object Utils {
} }
} }
class RetryInterceptor(private val maxRetry: Int) : Interceptor {
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
var response = chain.proceed(request)
var tryCount = 0
while (!response.isSuccessful && tryCount < maxRetry) {
tryCount++
response = chain.proceed(request)
}
return response
}
}
/** /**
* 从服务器获取时间戳 * 从服务器获取时间戳
* @return Long 时间戳 * @return Long 时间戳
@@ -55,7 +72,9 @@ object Utils {
return withContext(Dispatchers.IO) { return withContext(Dispatchers.IO) {
val client = okhttp3.OkHttpClient.Builder() val client = okhttp3.OkHttpClient.Builder()
.connectTimeout(500, java.util.concurrent.TimeUnit.MILLISECONDS) .connectTimeout(500, java.util.concurrent.TimeUnit.MILLISECONDS)
.readTimeout(1, java.util.concurrent.TimeUnit.SECONDS).build() .readTimeout(1, java.util.concurrent.TimeUnit.SECONDS)
.addInterceptor(RetryInterceptor(3))
.build()
val request = okhttp3.Request.Builder() val request = okhttp3.Request.Builder()
.url("https://api.m.taobao.com/rest/api3.do?api=mtop.common.getTimestamp") .url("https://api.m.taobao.com/rest/api3.do?api=mtop.common.getTimestamp")
.build() .build()
@@ -4,6 +4,7 @@ package com.lizongying.mytv.api
import android.os.Build import android.os.Build
import android.util.Log import android.util.Log
import com.lizongying.mytv.jce.JceConverterFactory import com.lizongying.mytv.jce.JceConverterFactory
import com.lizongying.mytv.requests.ReleaseService
import okhttp3.ConnectionSpec import okhttp3.ConnectionSpec
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.TlsVersion import okhttp3.TlsVersion
@@ -47,7 +48,7 @@ class ApiClient {
val releaseService: ReleaseService by lazy { val releaseService: ReleaseService by lazy {
Retrofit.Builder() Retrofit.Builder()
.baseUrl(myUrl) .baseUrl(HOST)
.client(okHttpClient) .client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create())
.build().create(ReleaseService::class.java) .build().create(ReleaseService::class.java)
@@ -170,4 +171,9 @@ class ApiClient {
throw RuntimeException(e) throw RuntimeException(e)
} }
} }
companion object {
const val HOST = "https://gitee.com/lizongying/my-tv/raw/"
const val DOWNLOAD_HOST = "https://gitee.com/lizongying/my-tv/releases/download/"
}
} }
@@ -1,12 +0,0 @@
package com.lizongying.mytv.api
import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Path
interface ReleaseService {
@GET("my-tv/v2/release/{name}")
fun getRelease(
@Path("name") date: String = "2",
): Call<ReleaseV2>
}
@@ -3,6 +3,7 @@ package com.lizongying.mytv.models
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import com.lizongying.mytv.SP
class TVListViewModel : ViewModel() { class TVListViewModel : ViewModel() {
@@ -30,6 +31,7 @@ class TVListViewModel : ViewModel() {
fun setItemPosition(position: Int) { fun setItemPosition(position: Int) {
_itemPosition.value = position _itemPosition.value = position
SP.itemPosition = position
} }
fun size(): Int { fun size(): Int {
@@ -16,6 +16,8 @@ class TVViewModel(private var tv: TV) : ViewModel() {
var retryTimes = 0 var retryTimes = 0
var retryMaxTimes = 8 var retryMaxTimes = 8
var authYSPRetryTimes = 0
var authYSPRetryMaxTimes = 3
var tokenYSPRetryTimes = 0 var tokenYSPRetryTimes = 0
var tokenYSPRetryMaxTimes = 0 var tokenYSPRetryMaxTimes = 0
var tokenFHRetryTimes = 0 var tokenFHRetryTimes = 0
@@ -64,6 +66,10 @@ class TVViewModel(private var tv: TV) : ViewModel() {
} }
fun changed(from: String) { fun changed(from: String) {
retryTimes = 0
authYSPRetryTimes = 0
tokenYSPRetryTimes = 0
tokenFHRetryTimes = 0
_change.value = from _change.value = from
} }
@@ -13,17 +13,20 @@ import kotlin.coroutines.suspendCoroutine
class ReleaseRequest { class ReleaseRequest {
private var releaseService = ApiClient().releaseService private var releaseService = ApiClient().releaseService
suspend fun getRelease(): ReleaseV2? { suspend fun getRelease(): ReleaseResponse? {
return withContext(Dispatchers.IO) { return withContext(Dispatchers.IO) {
fetchRelease() fetchRelease()
} }
} }
private suspend fun fetchRelease(): ReleaseV2? { private suspend fun fetchRelease(): ReleaseResponse? {
return suspendCoroutine { continuation -> return suspendCoroutine { continuation ->
releaseService.getRelease() releaseService.getRelease()
.enqueue(object : Callback<ReleaseV2> { .enqueue(object : Callback<ReleaseResponse> {
override fun onResponse(call: Call<ReleaseV2>, response: Response<ReleaseV2>) { override fun onResponse(
call: Call<ReleaseResponse>,
response: Response<ReleaseResponse>
) {
if (response.isSuccessful) { if (response.isSuccessful) {
continuation.resume(response.body()) continuation.resume(response.body())
} else { } else {
@@ -31,7 +34,7 @@ class ReleaseRequest {
} }
} }
override fun onFailure(call: Call<ReleaseV2>, t: Throwable) { override fun onFailure(call: Call<ReleaseResponse>, t: Throwable) {
continuation.resume(null) continuation.resume(null)
} }
}) })
@@ -0,0 +1,7 @@
package com.lizongying.mytv.requests
data class ReleaseResponse(
val version_code: Int?,
val version_name: String?,
)
@@ -0,0 +1,10 @@
package com.lizongying.mytv.requests
import retrofit2.Call
import retrofit2.http.GET
interface ReleaseService {
@GET("JELLY_BEAN_MR1/version.json")
fun getRelease(
): Call<ReleaseResponse>
}
@@ -119,7 +119,9 @@ object Request {
if (!tvModel.getTV().mustToken) { if (!tvModel.getTV().mustToken) {
fetchAuth(tvModel, cookie) fetchAuth(tvModel, cookie)
} else { } else {
// TODO val err = "错误"
Log.e(TAG, "$title $err")
tvModel.setErrInfo(err)
} }
} }
} else { } else {
@@ -144,7 +146,9 @@ object Request {
if (!tvModel.getTV().mustToken) { if (!tvModel.getTV().mustToken) {
fetchAuth(tvModel, cookie) fetchAuth(tvModel, cookie)
} else { } else {
// TODO val err = "错误"
Log.e(TAG, "$title $err")
tvModel.setErrInfo(err)
} }
} }
} else { } else {
@@ -171,7 +175,9 @@ object Request {
if (!tvModel.getTV().mustToken) { if (!tvModel.getTV().mustToken) {
fetchAuth(tvModel, cookie) fetchAuth(tvModel, cookie)
} else { } else {
// TODO val err = "错误"
Log.e(TAG, "$title $err")
tvModel.setErrInfo(err)
} }
} }
} else { } else {
@@ -241,19 +247,30 @@ object Request {
if (needToken && tvModel.tokenYSPRetryTimes < tvModel.tokenYSPRetryMaxTimes) { if (needToken && tvModel.tokenYSPRetryTimes < tvModel.tokenYSPRetryMaxTimes) {
tvModel.tokenYSPRetryTimes++ tvModel.tokenYSPRetryTimes++
tvModel.needGetToken = true tvModel.needGetToken = true
fetchVideo(tvModel) if (needAuth) {
// fetchAuth(tvModel) fetchAuth(tvModel)
} else {
fetchVideo(tvModel)
}
} else { } else {
if (!tvModel.getTV().mustToken) { if (!tvModel.getTV().mustToken) {
fetchVideo(tvModel, cookie) if (needAuth) {
// fetchAuth(tvModel, cookie) fetchAuth(tvModel, cookie)
} else {
fetchVideo(tvModel, cookie)
}
} else { } else {
// TODO val err = "错误"
Log.e(TAG, "$title $err")
tvModel.setErrInfo(err)
} }
} }
} else { } else {
fetchVideo(tvModel, cookie) if (needAuth) {
// fetchAuth(tvModel, cookie) fetchAuth(tvModel, cookie)
} else {
fetchVideo(tvModel, cookie)
}
} }
} else { } else {
val err = "结果错误" val err = "结果错误"
@@ -274,19 +291,30 @@ object Request {
if (needToken && tvModel.tokenYSPRetryTimes < tvModel.tokenYSPRetryMaxTimes) { if (needToken && tvModel.tokenYSPRetryTimes < tvModel.tokenYSPRetryMaxTimes) {
tvModel.tokenYSPRetryTimes++ tvModel.tokenYSPRetryTimes++
tvModel.needGetToken = true tvModel.needGetToken = true
fetchVideo(tvModel) if (needAuth) {
// fetchAuth(tvModel) fetchAuth(tvModel)
} else {
fetchVideo(tvModel)
}
} else { } else {
if (!tvModel.getTV().mustToken) { if (!tvModel.getTV().mustToken) {
fetchVideo(tvModel, cookie) if (needAuth) {
// fetchAuth(tvModel, cookie) fetchAuth(tvModel, cookie)
} else {
fetchVideo(tvModel, cookie)
}
} else { } else {
// TODO val err = "错误"
Log.e(TAG, "$title $err")
tvModel.setErrInfo(err)
} }
} }
} else { } else {
fetchVideo(tvModel, cookie) if (needAuth) {
// fetchAuth(tvModel, cookie) fetchAuth(tvModel, cookie)
} else {
fetchVideo(tvModel, cookie)
}
} }
} else { } else {
val err = "其他错误" val err = "其他错误"
@@ -303,19 +331,30 @@ object Request {
if (needToken && tvModel.tokenYSPRetryTimes < tvModel.tokenYSPRetryMaxTimes) { if (needToken && tvModel.tokenYSPRetryTimes < tvModel.tokenYSPRetryMaxTimes) {
tvModel.tokenYSPRetryTimes++ tvModel.tokenYSPRetryTimes++
tvModel.needGetToken = true tvModel.needGetToken = true
fetchVideo(tvModel) if (needAuth) {
// fetchAuth(tvModel) fetchAuth(tvModel, cookie)
} else {
fetchVideo(tvModel, cookie)
}
} else { } else {
if (!tvModel.getTV().mustToken) { if (!tvModel.getTV().mustToken) {
fetchVideo(tvModel, cookie) if (needAuth) {
// fetchAuth(tvModel, cookie) fetchAuth(tvModel, cookie)
} else {
fetchVideo(tvModel, cookie)
}
} else { } else {
// TODO val err = "错误"
Log.e(TAG, "$title $err")
tvModel.setErrInfo(err)
} }
} }
} else { } else {
fetchVideo(tvModel, cookie) if (needAuth) {
// fetchAuth(tvModel, cookie) fetchAuth(tvModel, cookie)
} else {
fetchVideo(tvModel, cookie)
}
} }
} else { } else {
val err = "状态错误" val err = "状态错误"
+1 -1
View File
@@ -1,4 +1,4 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:viewportWidth="50" android:viewportWidth="50"
android:viewportHeight="50" android:viewportHeight="50"
android:width="62.5dp" android:width="62.5dp"
+42 -16
View File
@@ -1,18 +1,44 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/channel" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="90dp" android:layout_width="match_parent"
android:layout_height="60dp" android:layout_height="match_parent"
android:layout_gravity="end|top" android:gravity="center"
android:layout_marginTop="20dp" >
android:layout_marginEnd="170dp"> <FrameLayout
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView <RelativeLayout
android:id="@+id/content" android:id="@+id/channel"
android:layout_width="wrap_content" android:layout_width="90dp"
android:layout_height="wrap_content" android:layout_height="60dp"
android:layout_gravity="end" android:layout_gravity="end|top"
android:textColor="#FFEEEEEE" android:layout_marginTop="15dp"
android:textStyle="bold" android:layout_marginEnd="170dp"
android:textSize="40sp" /> android:gravity="end|bottom" >
</FrameLayout>
<TextView
android:id="@+id/content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:textColor="@color/white"
android:textStyle="bold"
android:textSize="40sp"
tools:text="99"
android:layout_alignBaseline="@+id/time"/>
<TextView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:textColor="@color/white"
android:textStyle="bold"
android:textSize="32sp"
tools:text="12:34" />
</RelativeLayout>
</FrameLayout>
</LinearLayout>
+3 -3
View File
@@ -2,14 +2,14 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/error" android:id="@+id/error"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" > android:layout_height="match_parent"
android:background="@color/black" >
<LinearLayout <LinearLayout
android:id="@+id/main" android:id="@+id/main"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_gravity="center_horizontal" android:gravity="center"
android:gravity="center_vertical|center_horizontal"
android:orientation="vertical" > android:orientation="vertical" >
<ImageView <ImageView
+55 -41
View File
@@ -1,46 +1,60 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/info" android:layout_width="match_parent"
android:layout_width="400dp" android:layout_height="match_parent"
android:layout_height="80dp" android:gravity="center"
android:layout_gravity="center_horizontal|bottom" >
android:layout_marginBottom="20dp"> <FrameLayout
android:id="@+id/container"
<ImageView android:layout_width="match_parent"
android:id="@+id/logo"
android:layout_width="100dp"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@drawable/rounded_white_left" >
android:padding="10dp" />
<LinearLayout <LinearLayout
android:id="@+id/main" android:id="@+id/info"
android:layout_width="300dp" android:layout_width="400dp"
android:layout_height="match_parent" android:layout_height="80dp"
android:layout_marginStart="100dp" android:layout_gravity="center_horizontal|bottom"
android:background="@drawable/rounded_dark_right" android:layout_marginBottom="20dp"
android:gravity="start|center_vertical" android:orientation="horizontal">
android:orientation="vertical"
android:padding="7dp">
<TextView <ImageView
android:id="@+id/title" android:id="@+id/logo"
android:layout_width="wrap_content" android:layout_width="100dp"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:layout_gravity="start" android:background="@drawable/rounded_white_left"
android:gravity="start" android:padding="10dp" />
android:textColor="#FFEEEEEE"
android:textSize="20sp" />
<TextView <LinearLayout
android:id="@+id/desc" android:id="@+id/main"
android:layout_width="wrap_content" android:layout_width="300dp"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:layout_gravity="start" android:layout_marginStart="0dp"
android:layout_marginTop="8dp" android:background="@drawable/rounded_dark_right"
android:gravity="start" android:gravity="start|center_vertical"
android:singleLine="true" android:orientation="vertical"
android:textColor="#B3EEEEEE" android:padding="7dp">
android:textSize="14sp" />
</LinearLayout> <TextView
</FrameLayout> android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:gravity="start"
android:textColor="#FFEEEEEE"
android:textSize="20sp" />
<TextView
android:id="@+id/desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:layout_marginTop="8dp"
android:gravity="start"
android:singleLine="true"
android:textColor="#B3EEEEEE"
android:textSize="14sp" />
</LinearLayout>
</LinearLayout>
</FrameLayout>
</LinearLayout>
+21
View File
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/loading"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black"
>
<LinearLayout
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center" >
<ProgressBar
android:id="@+id/bar"
android:layout_width="50dp"
android:layout_height="50dp"
android:indeterminateTint="@color/white"/>
</LinearLayout>
</FrameLayout>
+25 -14
View File
@@ -1,21 +1,32 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/menu" android:id="@+id/container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@android:color/transparent" android:background="@android:color/transparent"
android:clickable="true" android:clickable="true"
android:focusable="false" android:focusable="false"
> android:gravity="center"
<ScrollView >
android:id="@+id/scroll"
<FrameLayout
android:id="@+id/menu"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
<LinearLayout >
android:id="@+id/content"
android:layout_width="match_parent" <ScrollView
android:layout_height="wrap_content" android:id="@+id/scroll"
android:orientation="vertical"> android:layout_width="wrap_content"
</LinearLayout> android:layout_height="wrap_content"
</ScrollView> >
</FrameLayout> <LinearLayout
android:id="@+id/content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
</LinearLayout>
</ScrollView>
</FrameLayout>
</LinearLayout>
+2 -3
View File
@@ -13,8 +13,8 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:orientation="vertical"
android:paddingTop="20dp" android:paddingTop="20dp"
android:paddingLeft="7dp" android:paddingLeft="10dp"
android:paddingRight="7dp" android:paddingRight="10dp"
android:background="@drawable/rounded_dark_left" android:background="@drawable/rounded_dark_left"
> >
<TextView <TextView
@@ -40,7 +40,6 @@
android:id="@+id/check_version" android:id="@+id/check_version"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:textSize="14sp" android:textSize="14sp"
android:text="@string/check_version" android:text="@string/check_version"
/> />
+43 -16
View File
@@ -1,18 +1,45 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/time" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="100dp" android:layout_width="match_parent"
android:layout_height="40dp" android:layout_height="match_parent"
android:layout_gravity="end|top" android:gravity="center"
android:layout_marginTop="25dp" >
android:layout_marginEnd="50dp"> <FrameLayout
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView <RelativeLayout
android:id="@+id/content" android:id="@+id/time"
android:layout_width="wrap_content" android:layout_width="120dp"
android:layout_height="wrap_content" android:layout_height="60dp"
android:layout_gravity="end" android:layout_gravity="end|top"
android:textColor="#FFEEEEEE" android:layout_marginTop="15dp"
android:textStyle="bold" android:layout_marginEnd="50dp"
android:textSize="32sp" /> android:gravity="end|bottom" >
</FrameLayout>
<TextView
android:id="@+id/channel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:textColor="@color/white"
android:textStyle="bold"
android:textSize="40sp"
tools:text="99"
android:layout_alignBaseline="@+id/content"/>
<TextView
android:id="@+id/content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:textColor="@color/white"
android:textStyle="bold"
android:textSize="32sp"
tools:text="12:34" />
</RelativeLayout>
</FrameLayout>
</LinearLayout>
+1 -1
View File
@@ -6,5 +6,5 @@
<string name="title_boot_startup">开机自启</string> <string name="title_boot_startup">开机自启</string>
<string name="title_grid">频道列表采用网格样式</string> <string name="title_grid">频道列表采用网格样式</string>
<string name="title_time">显示时间</string> <string name="title_time">显示时间</string>
<string name="exit">退出</string> <string name="exit">退出应用</string>
</resources> </resources>
+1
View File
@@ -1,5 +1,6 @@
<resources> <resources>
<style name="Theme.MyTV" parent="@style/Theme.Leanback"> <style name="Theme.MyTV" parent="@style/Theme.Leanback">
<item name="android:fitsSystemWindows">false</item>
</style> </style>
</resources> </resources>
+3
View File
@@ -0,0 +1,3 @@
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="." />
</paths>
+1
View File
@@ -0,0 +1 @@
{"version_code": 17368576, "version_name": "v1.9.6"}