diff --git a/README.md b/README.md index f3f457a..ca1289c 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,11 @@ ## 更新日志 +### v1.0.6 + +* 修复视频可能无声音的问题 +* 修复视频可能无法播放的问题 + ### v1.0.5 * 修复频道配置错误时可能崩溃的问题 diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f6852b6..68115f7 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -64,8 +64,8 @@ fun getVersionName(): String { } dependencies { - implementation("androidx.constraintlayout:constraintlayout:2.1.4") - val media3Version = "1.3.0-rc01" + // 19 + val media3Version = "1.3.0" implementation("androidx.media3:media3-ui:$media3Version") // For media playback using ExoPlayer @@ -78,8 +78,8 @@ dependencies { implementation("androidx.leanback:leanback:1.0.0") implementation("com.github.bumptech.glide:glide:4.11.0") - // 21:2.9.0 17:2.6.4 - val retrofit2Version = "2.6.4" + // 21:2.11.0 17:2.6.4 + val retrofit2Version = "2.11.0" implementation("com.squareup.retrofit2:converter-gson:$retrofit2Version") implementation ("com.squareup.retrofit2:converter-protobuf:$retrofit2Version") implementation ("com.squareup.retrofit2:retrofit:$retrofit2Version") @@ -90,6 +90,8 @@ dependencies { implementation("com.google.android.exoplayer:exoplayer-core:$exoplayerVersion") implementation("com.google.android.exoplayer:exoplayer-hls:$exoplayerVersion") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0-RC") implementation("androidx.constraintlayout:constraintlayout:2.1.4") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0-RC") + + implementation(files("libs/lib-decoder-ffmpeg-release.aar")) } \ No newline at end of file diff --git a/app/libs/lib-decoder-ffmpeg-release.aar b/app/libs/lib-decoder-ffmpeg-release.aar new file mode 100644 index 0000000..fa7bb1d Binary files /dev/null and b/app/libs/lib-decoder-ffmpeg-release.aar differ diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 77c9ef8..880e77c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -46,6 +46,7 @@ android:name="android.hardware.touchscreen" android:required="false" /> + diff --git a/app/src/main/java/com/lizongying/mytv0/GroupAdapter.kt b/app/src/main/java/com/lizongying/mytv0/GroupAdapter.kt index aa7bacf..e429f16 100644 --- a/app/src/main/java/com/lizongying/mytv0/GroupAdapter.kt +++ b/app/src/main/java/com/lizongying/mytv0/GroupAdapter.kt @@ -145,7 +145,9 @@ class GroupAdapter( fun update(tvGroupModel: TVGroupModel) { this.tvGroupModel = tvGroupModel - notifyDataSetChanged() + recyclerView.post { + notifyDataSetChanged() + } } companion object { diff --git a/app/src/main/java/com/lizongying/mytv0/ListAdapter.kt b/app/src/main/java/com/lizongying/mytv0/ListAdapter.kt index e0422cc..d70844e 100644 --- a/app/src/main/java/com/lizongying/mytv0/ListAdapter.kt +++ b/app/src/main/java/com/lizongying/mytv0/ListAdapter.kt @@ -1,7 +1,6 @@ package com.lizongying.mytv0 import android.content.Context -import android.util.Log import android.view.KeyEvent import android.view.LayoutInflater import android.view.View @@ -111,10 +110,7 @@ class ListAdapter( viewHolder.bindText(tvModel.tv.title) - // maybe null - if (!tvModel.tv.logo.isNullOrBlank()) { - viewHolder.bindImage(tvModel.tv.logo) - } + viewHolder.bindImage(tvModel.tv.logo) } override fun getItemCount() = tvListModel.size() @@ -125,11 +121,15 @@ class ListAdapter( binding.textView.text = text } - fun bindImage(url: String) { - Glide.with(context) - .load(url) - .centerInside() - .into(binding.imageView) + fun bindImage(url: String?) { + if (url.isNullOrBlank()) { + binding.imageView.setImageDrawable(null) + } else { + Glide.with(context) + .load(url) + .centerInside() + .into(binding.imageView) + } } fun focus(hasFocus: Boolean) { diff --git a/app/src/main/java/com/lizongying/mytv0/MainActivity.kt b/app/src/main/java/com/lizongying/mytv0/MainActivity.kt index f2e707e..8884559 100644 --- a/app/src/main/java/com/lizongying/mytv0/MainActivity.kt +++ b/app/src/main/java/com/lizongying/mytv0/MainActivity.kt @@ -1,7 +1,9 @@ package com.lizongying.mytv0 +import android.content.Context import android.content.pm.PackageInfo import android.content.pm.PackageManager +import android.media.AudioManager import android.os.Build import android.os.Bundle import android.os.Handler @@ -15,10 +17,12 @@ import android.view.WindowManager import android.widget.Toast import androidx.fragment.app.FragmentActivity import com.lizongying.mytv0.models.TVList +import kotlin.math.abs class MainActivity : FragmentActivity() { + private var ok = 0 private var playerFragment = PlayerFragment() private var infoFragment = InfoFragment() private var channelFragment = ChannelFragment() @@ -53,8 +57,23 @@ class MainActivity : FragmentActivity() { .commitNow() } - gestureDetector = GestureDetector(this, GestureListener()) + gestureDetector = GestureDetector(this, GestureListener(this)) + watch() + + if (!TVList.setPosition(SP.position)) { + TVList.setPosition(0) + } + } + + fun ready() { + ok++ + if (ok == 1) { + watch() + } + } + + fun watch() { TVList.listModel.forEach { tvModel -> tvModel.errInfo.observe(this) { _ -> if (tvModel.errInfo.value != null @@ -70,6 +89,7 @@ class MainActivity : FragmentActivity() { if (tvModel.ready.value != null && tvModel.tv.id == TVList.position.value ) { + playerFragment.play(tvModel) Log.i(TAG, "info ${tvModel.tv.title}") infoFragment.show(tvModel) if (SP.channelNum) { @@ -78,10 +98,6 @@ class MainActivity : FragmentActivity() { } } } - - if (!TVList.setPosition(SP.position)) { - TVList.setPosition(0) - } } override fun onTouchEvent(event: MotionEvent?): Boolean { @@ -91,9 +107,13 @@ class MainActivity : FragmentActivity() { return super.onTouchEvent(event) } - private inner class GestureListener : GestureDetector.SimpleOnGestureListener() { + private inner class GestureListener(private val context: Context) : + GestureDetector.SimpleOnGestureListener() { + + private val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager override fun onSingleTapConfirmed(e: MotionEvent): Boolean { + Log.i(TAG, "onSingleTapConfirmed showMenu") showMenu() return true } @@ -109,18 +129,78 @@ class MainActivity : FragmentActivity() { velocityX: Float, velocityY: Float ): Boolean { - if (velocityY > 0) { - if (menuFragment.isHidden && settingFragment.isHidden) { - prev() + if ((e1?.x ?: 0f) > windowManager.defaultDisplay.width / 3 + && (e1?.x ?: 0f) < windowManager.defaultDisplay.width * 2 / 3 + ) { + if (velocityY > 0) { + if (menuFragment.isHidden && settingFragment.isHidden) { + prev() + } } - } - if (velocityY < 0) { - if (menuFragment.isHidden && settingFragment.isHidden) { - next() + if (velocityY < 0) { + if (menuFragment.isHidden && settingFragment.isHidden) { + next() + } } } + return super.onFling(e1, e2, velocityX, velocityY) } + + override fun onScroll( + e1: MotionEvent?, + e2: MotionEvent, + distanceX: Float, + distanceY: Float + ): Boolean { + // 计算手势滑动的方向和距离 + val deltaY = e1?.y?.let { e2.y.minus(it) } ?: 0f + val deltaX = e1?.x?.let { e2.x.minus(it) } ?: 0f + + // 如果是垂直滑动 + if (abs(deltaY) > abs(deltaX)) { + if ((e1?.x ?: 0f) > windowManager.defaultDisplay.width * 2 / 3) { + adjustVolume(deltaY) // 调整音量 + } + } + + return super.onScroll(e1, e2, distanceX, distanceY) + } + + private fun adjustVolume(deltaY: Float) { + val maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) + val currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC) + val deltaVolume = deltaY / 1000 * maxVolume / windowManager.defaultDisplay.height + + var newVolume = currentVolume + deltaVolume + if (newVolume < 0) { + newVolume = 0F + } else if (newVolume > maxVolume) { + newVolume = maxVolume.toFloat() + } + + audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, newVolume.toInt(), 0) + + // 可以添加一个toast来显示当前音量 + Toast.makeText(context, "Volume: $newVolume / $maxVolume", Toast.LENGTH_SHORT).show() + } + +// private fun changeBrightness(deltaBrightness: Float) { +// brightness += deltaBrightness +// if (brightness < 0) { +// brightness = 0f +// } else if (brightness > 1) { +// brightness = 1f +// } +// +// val layoutParams = windowManager.attributes +// layoutParams.screenBrightness = brightness +// windowManager.attributes = layoutParams +// +// // 可以添加一个toast来显示当前亮度 +// Toast.makeText(context, "Brightness: $brightness", Toast.LENGTH_SHORT).show() +// } + } fun play(position: Int) { diff --git a/app/src/main/java/com/lizongying/mytv0/MenuFragment.kt b/app/src/main/java/com/lizongying/mytv0/MenuFragment.kt index 8bb2b25..d458da0 100644 --- a/app/src/main/java/com/lizongying/mytv0/MenuFragment.kt +++ b/app/src/main/java/com/lizongying/mytv0/MenuFragment.kt @@ -64,10 +64,15 @@ class MenuFragment : Fragment(), GroupAdapter.ItemListener, ListAdapter.ItemList listAdapter.setItemListener(this) TVList.groupModel.tvGroupModel.observe(viewLifecycleOwner) { _ -> + (activity as MainActivity).watch() // not first time if (TVList.groupModel.tvGroupModel.value != null) { groupAdapter.update(TVList.groupModel) + tvListModel = TVList.groupModel.getTVListModel(TVList.groupModel.position.value!!) + if (tvListModel != null) { + (binding.list.adapter as ListAdapter).update(tvListModel!!) + } } } @@ -90,8 +95,7 @@ class MenuFragment : Fragment(), GroupAdapter.ItemListener, ListAdapter.ItemList } } - override fun onItemClicked(tvModel: TVModel) { - TVList.setPosition(tvModel.tv.id) + override fun onItemClicked(tvModel: TVModel) { TVList.setPosition(tvModel.tv.id) (activity as MainActivity).hideMenuFragment() } diff --git a/app/src/main/java/com/lizongying/mytv0/PlayerFragment.kt b/app/src/main/java/com/lizongying/mytv0/PlayerFragment.kt index e98d9c8..50eeebe 100644 --- a/app/src/main/java/com/lizongying/mytv0/PlayerFragment.kt +++ b/app/src/main/java/com/lizongying/mytv0/PlayerFragment.kt @@ -22,12 +22,10 @@ import androidx.media3.datasource.DefaultHttpDataSource import androidx.media3.datasource.TransferListener import androidx.media3.exoplayer.DefaultRenderersFactory import androidx.media3.exoplayer.ExoPlayer -import androidx.media3.exoplayer.hls.HlsMediaSource import androidx.media3.exoplayer.mediacodec.MediaCodecSelector import androidx.media3.exoplayer.mediacodec.MediaCodecUtil import com.google.android.exoplayer2.SimpleExoPlayer import com.lizongying.mytv0.databinding.PlayerBinding -import com.lizongying.mytv0.models.TVList import com.lizongying.mytv0.models.TVModel @@ -65,6 +63,7 @@ class PlayerFragment : Fragment(), SurfaceHolder.Callback { val renderersFactory = context?.let { DefaultRenderersFactory(it) } val playerMediaCodecSelector = PlayerMediaCodecSelector() renderersFactory?.setMediaCodecSelector(playerMediaCodecSelector) + renderersFactory?.setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON) player = context?.let { ExoPlayer.Builder(it) @@ -93,8 +92,9 @@ class PlayerFragment : Fragment(), SurfaceHolder.Callback { tvModel?.setReady() } }) + + (activity as MainActivity).ready() Log.i(TAG, "player ready") - ready() } }) } @@ -102,22 +102,6 @@ class PlayerFragment : Fragment(), SurfaceHolder.Callback { return _binding!!.root } - fun ready() { - TVList.listModel.forEach { tvModel -> - tvModel.ready.observe(this) { _ -> - - // not first time - if (tvModel.ready.value != null - && tvModel.tv.id == TVList.position.value - && tvModel.videoUrl.value != null -// && tvModel.videoUrl.value != videoUrl - ) { - play(tvModel) - } - } - } - } - @OptIn(UnstableApi::class) fun play(tvModel: TVModel) { videoUrl = tvModel.videoUrl.value ?: return @@ -162,13 +146,12 @@ class PlayerFragment : Fragment(), SurfaceHolder.Callback { } }) - val hlsMediaSource = HlsMediaSource.Factory(httpDataSource).createMediaSource( - MediaItem.fromUri(videoUrl) - ) - - setMediaSource(hlsMediaSource) +// val hlsMediaSource = HlsMediaSource.Factory(httpDataSource).createMediaSource( +// MediaItem.fromUri(videoUrl) +// ) +// setMediaSource(hlsMediaSource) -// setMediaItem(MediaItem.fromUri(videoUrl)) + setMediaItem(MediaItem.fromUri(videoUrl)) prepare() } exoPlayer?.run { @@ -259,8 +242,8 @@ class PlayerFragment : Fragment(), SurfaceHolder.Callback { } } }) + (activity as MainActivity).ready() Log.i(TAG, "exoPlayer ready") - ready() } override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) { diff --git a/app/src/main/java/com/lizongying/mytv0/SettingFragment.kt b/app/src/main/java/com/lizongying/mytv0/SettingFragment.kt index 77a1295..6222950 100644 --- a/app/src/main/java/com/lizongying/mytv0/SettingFragment.kt +++ b/app/src/main/java/com/lizongying/mytv0/SettingFragment.kt @@ -2,17 +2,15 @@ package com.lizongying.mytv0 import android.net.Uri import android.os.Bundle -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 -class SettingFragment: Fragment() { +class SettingFragment : Fragment() { private var _binding: SettingBinding? = null private val binding get() = _binding!! @@ -52,10 +50,12 @@ class SettingFragment: Fragment() { } val updateManager = UpdateManager(context, this, context.appVersionCode) - binding.checkVersion.setOnClickListener(OnClickListenerCheckVersion(updateManager)) + binding.checkVersion.setOnClickListener { + OnClickListenerCheckVersion(updateManager) + (activity as MainActivity).settingActive() + } binding.confirmButton.setOnClickListener { - val uriEditText = binding.myEditText var uri = uriEditText.text.toString() @@ -65,18 +65,18 @@ class SettingFragment: Fragment() { } else { uriEditText.error = "无效的地址" } + (activity as MainActivity).settingActive() } binding.appreciate.setOnClickListener { val imageModalFragment = AppreciateModalFragment() - // Pass the drawable ID as an argument val args = Bundle() args.putInt(AppreciateModalFragment.KEY, R.drawable.appreciate) imageModalFragment.arguments = args imageModalFragment.show(requireFragmentManager(), AppreciateModalFragment.TAG) - Log.i(TAG, "appreciate setOnClickListener") + (activity as MainActivity).settingActive() } return binding.root 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 80d72bc..1887337 100644 --- a/app/src/main/java/com/lizongying/mytv0/models/TVList.kt +++ b/app/src/main/java/com/lizongying/mytv0/models/TVList.kt @@ -40,8 +40,6 @@ object TVList { context.resources.openRawResource(R.raw.channels).bufferedReader() .use { it.readText() } } - Log.i("", "channel $str") - groupModel.addTVListModel(TVListModel("我的收藏")) groupModel.addTVListModel(TVListModel("全部频道")) @@ -107,6 +105,7 @@ object TVList { listModel = list.map { tv -> TVModel(tv) } + setPosition(0) groupModel.clear() diff --git a/app/src/main/res/layout/setting.xml b/app/src/main/res/layout/setting.xml index 2e29807..5eddd40 100644 --- a/app/src/main/res/layout/setting.xml +++ b/app/src/main/res/layout/setting.xml @@ -65,11 +65,12 @@ + android:scrollbars="vertical" + android:inputType="textMultiLine" />