diff --git a/README.md b/README.md index 90473bf..f3f457a 100644 --- a/README.md +++ b/README.md @@ -32,9 +32,6 @@ ] ``` -注意: -配置地址更新后,如遇到之前节目还存在的情况,可能需要重启软件后生效,后面会进行优化 - 下载安装 [releases](https://github.com/lizongying/my-tv-0/releases/) 更多地址 [my-tv](https://lyrics.run/my-tv-0.html) @@ -44,6 +41,12 @@ ## 更新日志 +### v1.0.5 + +* 修复频道配置错误时可能崩溃的问题 +* 修复更新频道配置时可能不生效的问题 +* 修复图标为空时可能崩溃的问题 + ### v1.0.4 * 在触屏设备上双击打开节目列表 diff --git a/Screenshot_20240324_100541.png b/Screenshot_20240324_100541.png deleted file mode 100644 index 8244018..0000000 Binary files a/Screenshot_20240324_100541.png and /dev/null differ diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e3abff8..77c9ef8 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,24 +1,25 @@ - + + android:supportsRtl="true" + android:theme="@style/Theme.MyTV0" + android:usesCleartextTraffic="true"> + @@ -46,7 +47,7 @@ android:required="false" /> - + \ No newline at end of file diff --git a/app/src/main/java/com/lizongying/mytv0/GroupAdapter.kt b/app/src/main/java/com/lizongying/mytv0/GroupAdapter.kt index 738db6c..aa7bacf 100644 --- a/app/src/main/java/com/lizongying/mytv0/GroupAdapter.kt +++ b/app/src/main/java/com/lizongying/mytv0/GroupAdapter.kt @@ -16,7 +16,7 @@ import com.lizongying.mytv0.models.TVListModel class GroupAdapter( private val context: Context, private val recyclerView: RecyclerView, - private var tvgroupModel: TVGroupModel, + private var tvGroupModel: TVGroupModel, ) : RecyclerView.Adapter() { @@ -51,7 +51,7 @@ class GroupAdapter( } override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) { - val tvListModel = tvgroupModel.getTVListModel(position)!! + val tvListModel = tvGroupModel.getTVListModel(position)!! val view = viewHolder.itemView view.tag = position @@ -67,8 +67,8 @@ class GroupAdapter( viewHolder.focus(true) focused = view if (visiable) { - if (position != tvgroupModel.position.value) { - tvgroupModel.setPosition(position) + if (position != tvGroupModel.position.value) { + tvGroupModel.setPosition(position) } } else { visiable = true @@ -84,7 +84,7 @@ class GroupAdapter( listener?.onItemClicked(tvListModel) } - view.setOnKeyListener { v, keyCode, event: KeyEvent? -> + view.setOnKeyListener { _, keyCode, event: KeyEvent? -> if (event?.action == KeyEvent.ACTION_DOWN) { if (keyCode == KeyEvent.KEYCODE_DPAD_UP && position == 0) { recyclerView.smoothScrollToPosition(getItemCount() - 1) @@ -102,7 +102,7 @@ class GroupAdapter( viewHolder.bind(tvListModel.getName()) } - override fun getItemCount() = tvgroupModel.size() + override fun getItemCount() = tvGroupModel.size() class ViewHolder(private val context: Context, private val binding: GroupItemBinding) : RecyclerView.ViewHolder(binding.root) { @@ -143,6 +143,11 @@ class GroupAdapter( this.listener = listener } + fun update(tvGroupModel: TVGroupModel) { + this.tvGroupModel = tvGroupModel + notifyDataSetChanged() + } + companion object { private const val TAG = "CategoryAdapter" } diff --git a/app/src/main/java/com/lizongying/mytv0/ListAdapter.kt b/app/src/main/java/com/lizongying/mytv0/ListAdapter.kt index d18046d..e0422cc 100644 --- a/app/src/main/java/com/lizongying/mytv0/ListAdapter.kt +++ b/app/src/main/java/com/lizongying/mytv0/ListAdapter.kt @@ -1,15 +1,14 @@ package com.lizongying.mytv0 import android.content.Context +import android.util.Log import android.view.KeyEvent import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.view.ViewGroup.FOCUS_BEFORE_DESCENDANTS import android.view.ViewGroup.FOCUS_BLOCK_DESCENDANTS -import android.view.animation.ScaleAnimation import androidx.core.content.ContextCompat -import androidx.lifecycle.LifecycleOwner import androidx.recyclerview.widget.RecyclerView import com.bumptech.glide.Glide import com.lizongying.mytv0.databinding.ListItemBinding @@ -112,7 +111,10 @@ class ListAdapter( viewHolder.bindText(tvModel.tv.title) - viewHolder.bindImage(tvModel.tv.logo) + // maybe null + if (!tvModel.tv.logo.isNullOrBlank()) { + viewHolder.bindImage(tvModel.tv.logo) + } } override fun getItemCount() = tvListModel.size() diff --git a/app/src/main/java/com/lizongying/mytv0/MainActivity.kt b/app/src/main/java/com/lizongying/mytv0/MainActivity.kt index 378810a..f2e707e 100644 --- a/app/src/main/java/com/lizongying/mytv0/MainActivity.kt +++ b/app/src/main/java/com/lizongying/mytv0/MainActivity.kt @@ -79,7 +79,9 @@ class MainActivity : FragmentActivity() { } } - TVList.setPosition(SP.position) + if (!TVList.setPosition(SP.position)) { + TVList.setPosition(0) + } } override fun onTouchEvent(event: MotionEvent?): Boolean { diff --git a/app/src/main/java/com/lizongying/mytv0/MenuFragment.kt b/app/src/main/java/com/lizongying/mytv0/MenuFragment.kt index ba1124b..8bb2b25 100644 --- a/app/src/main/java/com/lizongying/mytv0/MenuFragment.kt +++ b/app/src/main/java/com/lizongying/mytv0/MenuFragment.kt @@ -45,16 +45,32 @@ class MenuFragment : Fragment(), GroupAdapter.ItemListener, ListAdapter.ItemList LinearLayoutManager(context) groupAdapter.setItemListener(this) + var tvListModel = TVList.groupModel.getTVListModel(TVList.groupModel.position.value!!) + if (tvListModel == null) { + TVList.groupModel.setPosition(0) + } + + tvListModel = TVList.groupModel.getTVListModel(TVList.groupModel.position.value!!) + listAdapter = ListAdapter( context!!, binding.list, - TVList.groupModel.getTVListModel(TVList.groupModel.position.value!!)!!, + tvListModel!!, ) binding.list.adapter = listAdapter binding.list.layoutManager = LinearLayoutManager(context) listAdapter.focusable(false) listAdapter.setItemListener(this) + + TVList.groupModel.tvGroupModel.observe(viewLifecycleOwner) { _ -> + + // not first time + if (TVList.groupModel.tvGroupModel.value != null) { + groupAdapter.update(TVList.groupModel) + } + } + return binding.root } diff --git a/app/src/main/java/com/lizongying/mytv0/MyApplication.kt b/app/src/main/java/com/lizongying/mytv0/MyApplication.kt new file mode 100644 index 0000000..d986876 --- /dev/null +++ b/app/src/main/java/com/lizongying/mytv0/MyApplication.kt @@ -0,0 +1,32 @@ +package com.lizongying.mytv0 + +import android.app.Application +import android.os.Handler +import android.os.Looper +import android.widget.Toast + +class MyApplication : Application() { + + companion object { + private lateinit var instance: MyApplication + + fun getInstance(): MyApplication { + return instance + } + } + + override fun onCreate() { + super.onCreate() + instance = this + } + + fun toast(message: CharSequence = "", duration: Int = Toast.LENGTH_SHORT) { + Handler(Looper.getMainLooper()).post { + Toast.makeText(applicationContext, message, duration).show() + } + } +} + +fun String.showToast(duration: Int = Toast.LENGTH_SHORT) { + MyApplication.getInstance().toast(this, duration) +} \ No newline at end of file diff --git a/app/src/main/java/com/lizongying/mytv0/SettingFragment.kt b/app/src/main/java/com/lizongying/mytv0/SettingFragment.kt index 85b36e8..77a1295 100644 --- a/app/src/main/java/com/lizongying/mytv0/SettingFragment.kt +++ b/app/src/main/java/com/lizongying/mytv0/SettingFragment.kt @@ -6,6 +6,7 @@ import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.Toast import androidx.fragment.app.Fragment import com.lizongying.mytv0.databinding.SettingBinding import com.lizongying.mytv0.models.TVList @@ -54,6 +55,7 @@ class SettingFragment: Fragment() { binding.checkVersion.setOnClickListener(OnClickListenerCheckVersion(updateManager)) binding.confirmButton.setOnClickListener { + val uriEditText = binding.myEditText var uri = uriEditText.text.toString() diff --git a/app/src/main/java/com/lizongying/mytv0/models/TVGroupModel.kt b/app/src/main/java/com/lizongying/mytv0/models/TVGroupModel.kt index 9f86d2e..3c52992 100644 --- a/app/src/main/java/com/lizongying/mytv0/models/TVGroupModel.kt +++ b/app/src/main/java/com/lizongying/mytv0/models/TVGroupModel.kt @@ -6,8 +6,8 @@ import androidx.lifecycle.ViewModel import com.lizongying.mytv0.SP class TVGroupModel : ViewModel() { - private val _tvGroupModel = MutableLiveData>() - val tvGroupModel: LiveData> + private val _tvGroupModel = MutableLiveData>() + val tvGroupModel: LiveData> get() = _tvGroupModel private val _position = MutableLiveData() @@ -18,8 +18,8 @@ class TVGroupModel : ViewModel() { _position.value = position } - fun setTVListModelList(tvTVListModelList: MutableList) { - _tvGroupModel.value = tvTVListModelList + fun setTVListModelList(tvListModelList: List) { + _tvGroupModel.value = tvListModelList } fun addTVListModel(tvListModel: TVListModel) { @@ -27,10 +27,22 @@ class TVGroupModel : ViewModel() { _tvGroupModel.value = mutableListOf(tvListModel) return } - _tvGroupModel.value?.add(tvListModel) + + val newList = _tvGroupModel.value!!.toMutableList() + newList.add(tvListModel) + _tvGroupModel.value = newList + } + + fun clear() { + _tvGroupModel.value = mutableListOf(getTVListModel(0)!!, getTVListModel(1)!!) + setPosition(0) + getTVListModel(1)?.clear() } fun getTVListModel(idx: Int): TVListModel? { + if (idx >= size()) { + return null + } return _tvGroupModel.value?.get(idx) } diff --git a/app/src/main/java/com/lizongying/mytv0/models/TVList.kt b/app/src/main/java/com/lizongying/mytv0/models/TVList.kt index 986017c..80d72bc 100644 --- a/app/src/main/java/com/lizongying/mytv0/models/TVList.kt +++ b/app/src/main/java/com/lizongying/mytv0/models/TVList.kt @@ -2,9 +2,12 @@ package com.lizongying.mytv0.models import android.content.Context import android.util.Log +import android.widget.Toast import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData +import com.google.gson.JsonSyntaxException import com.lizongying.mytv0.R +import com.lizongying.mytv0.showToast import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -17,7 +20,7 @@ object TVList { private lateinit var appDirectory: File private lateinit var serverUrl: String private lateinit var list: List - lateinit var listModel: List + var listModel: List = listOf() val groupModel = TVGroupModel() private val _position = MutableLiveData() @@ -38,7 +41,18 @@ object TVList { .use { it.readText() } } Log.i("", "channel $str") - str2List(str) + + groupModel.addTVListModel(TVListModel("我的收藏")) + + groupModel.addTVListModel(TVListModel("全部频道")) + + try { + str2List(str) + } catch (e: Exception) { + Log.e("", "error $e") + file.deleteOnExit() + Toast.makeText(context, "读取频道失败,请在菜单中进行设置", Toast.LENGTH_LONG).show() + } } private fun update() { @@ -61,11 +75,20 @@ object TVList { withContext(Dispatchers.Main) { str2List(str) } + "频道读取成功".showToast() } else { Log.e("", "request status ${response.code()}") + "频道状态错误".showToast() } + } catch (e: JsonSyntaxException) { + Log.e("JSON Parse Error", e.toString()) + "频道格式错误".showToast() + } catch (e: NullPointerException) { + Log.e("Null Pointer Error", e.toString()) + "无法读取频道".showToast() } catch (e: Exception) { Log.e("", "request error $e") + "频道请求错误".showToast() } } } @@ -85,14 +108,10 @@ object TVList { TVModel(tv) } - val group: MutableList = mutableListOf() + groupModel.clear() - var tvListModel = TVListModel("我的收藏") - group.add(tvListModel) - - tvListModel = TVListModel("全部频道") - tvListModel.setTVListModel(listModel) - group.add(tvListModel) + // 全部频道 + groupModel.getTVListModel(1)?.setTVListModel(listModel) val map: MutableMap> = mutableMapOf() for ((id, v) in list.withIndex()) { @@ -104,27 +123,30 @@ object TVList { } for ((k, v) in map) { - tvListModel = TVListModel(k) + val tvListModel = TVListModel(k) for (v1 in v) { tvListModel.addTVModel(v1) } - group.add(tvListModel) + groupModel.addTVListModel(tvListModel) } - - groupModel.setTVListModelList(group) } fun getTVModel(idx: Int): TVModel { return listModel[idx] } - fun setPosition(position: Int) { + fun setPosition(position: Int): Boolean { + if (position >= size()) { + return false + } + if (_position.value != position) { _position.value = position } // set a new position or retry when position same listModel[position].setReady() + return true } fun size(): Int { diff --git a/app/src/main/java/com/lizongying/mytv0/models/TVListModel.kt b/app/src/main/java/com/lizongying/mytv0/models/TVListModel.kt index 2cccac4..06b7b78 100644 --- a/app/src/main/java/com/lizongying/mytv0/models/TVListModel.kt +++ b/app/src/main/java/com/lizongying/mytv0/models/TVListModel.kt @@ -9,8 +9,8 @@ class TVListModel(private val name: String) : ViewModel() { return name } - private val _tvListModel = MutableLiveData>() - val tvListModel: LiveData> + private val _tvListModel = MutableLiveData>() + val tvListModel: LiveData> get() = _tvListModel private val _position = MutableLiveData() @@ -30,7 +30,7 @@ class TVListModel(private val name: String) : ViewModel() { } fun setTVListModel(tvListModel: List) { - _tvListModel.value = tvListModel.toMutableList() + _tvListModel.value = tvListModel } fun addTVModel(tvModel: TVModel) { @@ -38,7 +38,15 @@ class TVListModel(private val name: String) : ViewModel() { _tvListModel.value = mutableListOf(tvModel) return } - _tvListModel.value?.add(tvModel) + + val newList = _tvListModel.value!!.toMutableList() + newList.add(tvModel) + _tvListModel.value = newList + } + + fun clear() { + _tvListModel.value = mutableListOf() + setPosition(0) } fun getTVModel(idx: Int): TVModel? { diff --git a/build.gradle.kts b/build.gradle.kts index 0da18c4..cac8778 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,5 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - id("com.android.application") version "8.2.2" apply false + id("com.android.application") version "8.3.1" apply false id("org.jetbrains.kotlin.android") version "1.9.10" apply false } \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 5c0faf1..d1a6cee 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Thu Dec 14 14:50:34 HKT 2023 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-rc-1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists