From 5a5938792c2312b8f902d479633b73e6f45e41c2 Mon Sep 17 00:00:00 2001 From: xieyy Date: Fri, 21 Nov 2025 17:24:14 +0800 Subject: [PATCH 01/11] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E5=AE=8C=E5=96=84:=20?= =?UTF-8?q?=E8=B0=83=E6=95=B4WebView=E9=93=BE=E6=8E=A5=E6=8B=A6=E6=88=AA?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/activities/web_view/WebViewActivity.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/user_component/src/main/java/com/xyoye/user_component/ui/activities/web_view/WebViewActivity.kt b/user_component/src/main/java/com/xyoye/user_component/ui/activities/web_view/WebViewActivity.kt index 7dc092305..935b24dc8 100644 --- a/user_component/src/main/java/com/xyoye/user_component/ui/activities/web_view/WebViewActivity.kt +++ b/user_component/src/main/java/com/xyoye/user_component/ui/activities/web_view/WebViewActivity.kt @@ -83,7 +83,7 @@ class WebViewActivity : BaseActivity() webViewClient = object : WebViewClient() { override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean { - val uri = request?.url ?: return false + val uri = request?.url ?: return super.shouldOverrideUrlLoading(view, request) // 选取b站视频时,考虑将APP协议地址转换为普通番剧地址 val bangumiUrl = considerMapBangumiUrl(uri) @@ -92,12 +92,12 @@ class WebViewActivity : BaseActivity() return true } - // 非http(s)协议资源,不加载 - if (uri.scheme?.startsWith("http") != true) { + // 拦截BiliBili APP协议,避免在选取地址时打开外部APP + if (uri.scheme == "bilibili") { return true } - return false + return super.shouldOverrideUrlLoading(view, request) } } From d894a308dc5a35403d4f7ec930fb53b8aeefe9b2 Mon Sep 17 00:00:00 2001 From: xieyy Date: Fri, 21 Nov 2025 18:03:47 +0800 Subject: [PATCH 02/11] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E5=AE=8C=E5=96=84:=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0OpenCC=E8=BD=AC=E6=8D=A2=E5=89=8D=E5=AD=97?= =?UTF-8?q?=E7=AC=A6=E4=B8=B2=E6=A3=80=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/xyoye/open_cc/OpenCC.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/common_component/src/main/java/com/xyoye/open_cc/OpenCC.kt b/common_component/src/main/java/com/xyoye/open_cc/OpenCC.kt index 0d5cf2f22..8947cdaac 100644 --- a/common_component/src/main/java/com/xyoye/open_cc/OpenCC.kt +++ b/common_component/src/main/java/com/xyoye/open_cc/OpenCC.kt @@ -1,5 +1,7 @@ package com.xyoye.open_cc +import android.util.Log +import com.google.common.base.Utf8 import java.io.File /** @@ -34,6 +36,13 @@ object OpenCC { private fun convert(text: String, config: File): String { return try { + // 检查是否是符合 Unicode 6.0 的格式的UFT-8字符串 + // Bugly#2456345 + if (Utf8.isWellFormed(text.toByteArray()).not()) { + Log.d("OpenCC", "invalid utf-8 string: $text") + return text + } + convert(text, config.absolutePath) } catch (t: Throwable) { t.printStackTrace() From ed7db587e0a6cb6b829b9118ba101434cb1a2fdf Mon Sep 17 00:00:00 2001 From: xieyy Date: Fri, 21 Nov 2025 18:08:27 +0800 Subject: [PATCH 03/11] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E5=AE=8C=E5=96=84:=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0Json=E5=A4=84=E7=90=86=E7=9A=84=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=E6=8D=95=E8=8E=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bugly#2528413 --- .../bind_source/BindExtraSourceViewModel.kt | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/local_component/src/main/java/com/xyoye/local_component/ui/activities/bind_source/BindExtraSourceViewModel.kt b/local_component/src/main/java/com/xyoye/local_component/ui/activities/bind_source/BindExtraSourceViewModel.kt index 5802c1b5e..46a00b1cb 100644 --- a/local_component/src/main/java/com/xyoye/local_component/ui/activities/bind_source/BindExtraSourceViewModel.kt +++ b/local_component/src/main/java/com/xyoye/local_component/ui/activities/bind_source/BindExtraSourceViewModel.kt @@ -106,21 +106,31 @@ class BindExtraSourceViewModel : BaseViewModel() { * 解析分词结果 */ private fun parseSegmentResult(json: String): List? { - val responseJson = JSONObject(json) - val resultKey = responseJson.names()?.get(0)?.toString() - ?: return null - val jsonArray = responseJson.optJSONArray(resultKey) - ?: return null - val wordArray = jsonArray.optJSONArray(0) - ?: return null - - val words = mutableListOf() - val wordLength = wordArray.length() - for (i in 0 until wordLength) { - val word = wordArray.optString(i) - words.add(word) + if (json.isEmpty()) { + return null } - return words + + try { + val responseJson = JSONObject(json) + val resultKey = responseJson.names()?.get(0)?.toString() + ?: return null + val jsonArray = responseJson.optJSONArray(resultKey) + ?: return null + val wordArray = jsonArray.optJSONArray(0) + ?: return null + + val words = mutableListOf() + val wordLength = wordArray.length() + for (i in 0 until wordLength) { + val word = wordArray.optString(i) + words.add(word) + } + return words + } catch (e: Exception) { + e.printStackTrace() + } + + return null } private fun matchSearchTextCache(target: StorageFile): String? { From f8ccf5f564b1f81489103baec54ded0173a99b0f Mon Sep 17 00:00:00 2001 From: xieyy Date: Thu, 29 Jan 2026 11:49:51 +0800 Subject: [PATCH 04/11] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E5=AE=8C=E5=96=84:=20?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=8F=9C=E5=8D=95=E9=9A=90=E8=97=8F=E5=90=8E?= =?UTF-8?q?=E7=84=A6=E7=82=B9=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit close #279 --- .../com/xyoye/player/controller/video/PlayerControlView.kt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/player_component/src/main/java/com/xyoye/player/controller/video/PlayerControlView.kt b/player_component/src/main/java/com/xyoye/player/controller/video/PlayerControlView.kt index 1b7c8e816..72994610b 100644 --- a/player_component/src/main/java/com/xyoye/player/controller/video/PlayerControlView.kt +++ b/player_component/src/main/java/com/xyoye/player/controller/video/PlayerControlView.kt @@ -82,11 +82,6 @@ class PlayerControlView(context: Context): InterControllerView { private fun updateLockVisible(isVisible: Boolean) { if (isVisible) { - if (mControlWrapper.isLocked()) { - viewBinding.playerLockIv.postDelayed({ - viewBinding.playerLockIv.requestFocus() - }, 100) - } viewBinding.playerLockIv.isVisible = true ViewCompat.animate(viewBinding.playerLockIv) .translationX(0f) From a5a15dcdda0ef4632c8d664b5b6e29907a13b103 Mon Sep 17 00:00:00 2001 From: xieyy Date: Thu, 29 Jan 2026 15:50:09 +0800 Subject: [PATCH 05/11] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E5=AE=8C=E5=96=84:=20?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=B5=84=E6=BA=90=E5=88=87=E6=8D=A2=E7=84=A6?= =?UTF-8?q?=E7=82=B9=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit close #276 --- .../controller/setting/SettingTracksView.kt | 24 ++++++++++++++++--- .../controller/setting/SwitchSourceView.kt | 2 ++ .../main/res/layout/layout_setting_tracks.xml | 7 +++++- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/player_component/src/main/java/com/xyoye/player/controller/setting/SettingTracksView.kt b/player_component/src/main/java/com/xyoye/player/controller/setting/SettingTracksView.kt index b869d1f17..4933d4510 100644 --- a/player_component/src/main/java/com/xyoye/player/controller/setting/SettingTracksView.kt +++ b/player_component/src/main/java/com/xyoye/player/controller/setting/SettingTracksView.kt @@ -101,6 +101,8 @@ class SettingTracksView @JvmOverloads constructor( if (tracks.size > 0) { viewBinding.rvTrack.requestIndexChildFocus(0) + } else { + viewBinding.tvAddTrack.requestFocus() } return true } @@ -158,7 +160,9 @@ class SettingTracksView @JvmOverloads constructor( return false } val targetIndex = getTargetIndexByKeyCode(keyCode, focusedChildIndex) - viewBinding.rvTrack.requestIndexChildFocus(targetIndex) + if (targetIndex != -1) { + viewBinding.rvTrack.requestIndexChildFocus(targetIndex) + } return true } @@ -169,11 +173,22 @@ class SettingTracksView @JvmOverloads constructor( return when (keyCode) { //左、上规则 KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_UP -> { - tracks.previousItemIndex(focusedIndex) + if (focusedIndex == 0) { + viewBinding.tvAddTrack.requestFocus() + -1 + } else { + tracks.previousItemIndex(focusedIndex) + } } //右、下规则 KeyEvent.KEYCODE_DPAD_RIGHT, KeyEvent.KEYCODE_DPAD_DOWN -> { - tracks.nextItemIndex(focusedIndex) + val itemCount = viewBinding.rvTrack.adapter?.itemCount ?: 0 + if (focusedIndex == itemCount - 1) { + viewBinding.tvAddTrack.requestFocus() + -1 + } else { + tracks.nextItemIndex(focusedIndex) + } } else -> { @@ -199,6 +214,9 @@ class SettingTracksView @JvmOverloads constructor( viewBinding.rvTrack.setData(tracks) viewBinding.tvEmptyTrack.isVisible = tracks.isEmpty() + if (tracks.isEmpty()) { + viewBinding.tvAddTrack.requestFocus() + } } fun setTrackType(trackType: TrackType) { diff --git a/player_component/src/main/java/com/xyoye/player/controller/setting/SwitchSourceView.kt b/player_component/src/main/java/com/xyoye/player/controller/setting/SwitchSourceView.kt index 497347a6b..e02667c67 100644 --- a/player_component/src/main/java/com/xyoye/player/controller/setting/SwitchSourceView.kt +++ b/player_component/src/main/java/com/xyoye/player/controller/setting/SwitchSourceView.kt @@ -5,6 +5,7 @@ import android.os.Environment import android.util.AttributeSet import android.view.Gravity import android.view.KeyEvent +import android.view.View import androidx.annotation.Dimension import androidx.core.view.isVisible import androidx.recyclerview.widget.RecyclerView @@ -273,6 +274,7 @@ class SwitchSourceView( mPathData.addAll(pathData) viewBinding.rvPath.setData(mPathData) viewBinding.rvPath.scrollToPosition(mPathData.size - 1) + viewBinding.rvPath.post { viewBinding.rvPath.requestFocus(View.FOCUS_LEFT) } mFileData.clear() mFileData.addAll(getDirectoryChildData(directory)) diff --git a/player_component/src/main/res/layout/layout_setting_tracks.xml b/player_component/src/main/res/layout/layout_setting_tracks.xml index 40fbf01f5..8fbeee9af 100644 --- a/player_component/src/main/res/layout/layout_setting_tracks.xml +++ b/player_component/src/main/res/layout/layout_setting_tracks.xml @@ -54,8 +54,13 @@ android:layout_marginHorizontal="10dp" android:layout_marginBottom="20dp" android:background="@drawable/background_player_setting_text" - android:focusable="false" + android:focusable="true" + android:focusableInTouchMode="true" android:gravity="center" + android:nextFocusLeft="@id/rv_track" + android:nextFocusRight="@id/rv_track" + android:nextFocusUp="@id/rv_track" + android:nextFocusDown="@id/rv_track" android:paddingHorizontal="20dp" android:textColor="@color/text_white_immutable" android:textSize="14sp" From 1bafdcf241ce8a4474a6162c5aaeaa7d29406db5 Mon Sep 17 00:00:00 2001 From: xieyy Date: Thu, 29 Jan 2026 15:57:12 +0800 Subject: [PATCH 06/11] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E5=AE=8C=E5=96=84:=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=92=AD=E6=94=BE=E5=99=A8=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E7=84=A6=E7=82=B9=E5=8D=A0=E4=BD=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../xyoye/player/controller/video/PlayerTopView.kt | 6 +++++- .../src/main/res/layout/layout_player_top.xml | 12 ++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/player_component/src/main/java/com/xyoye/player/controller/video/PlayerTopView.kt b/player_component/src/main/java/com/xyoye/player/controller/video/PlayerTopView.kt index bb9fb4843..965ad7cdd 100644 --- a/player_component/src/main/java/com/xyoye/player/controller/video/PlayerTopView.kt +++ b/player_component/src/main/java/com/xyoye/player/controller/video/PlayerTopView.kt @@ -15,7 +15,7 @@ import com.xyoye.player_component.R import com.xyoye.player_component.databinding.LayoutPlayerTopBinding import com.xyoye.player_component.ui.activities.overlay_permission.OverlayPermissionActivity import com.xyoye.player_component.utils.BatteryHelper -import java.util.* +import java.util.Date /** * Created by xyoye on 2020/11/3. @@ -41,6 +41,10 @@ class PlayerTopView( private lateinit var mControlWrapper: ControlWrapper init { + // 新增焦点占位视图,避免焦点默认落在返回按钮上 + viewBinding.focusPlaceholder.setOnClickListener { + mControlWrapper.togglePlay() + } viewBinding.backIv.setOnClickListener { exitPlayerObserver?.invoke() diff --git a/player_component/src/main/res/layout/layout_player_top.xml b/player_component/src/main/res/layout/layout_player_top.xml index bef5ba5ba..21f7d5659 100644 --- a/player_component/src/main/res/layout/layout_player_top.xml +++ b/player_component/src/main/res/layout/layout_player_top.xml @@ -12,6 +12,18 @@ android:translationY="-50dp" tools:translationY="0dp"> + + Date: Thu, 29 Jan 2026 16:04:23 +0800 Subject: [PATCH 07/11] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E5=AE=8C=E5=96=84:=20?= =?UTF-8?q?=E5=AE=8C=E5=96=84=E7=84=A6=E7=82=B9=E6=B5=81=E8=BD=AC=E4=B8=8E?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E7=84=A6=E7=82=B9=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/xyoye/player/controller/video/PlayerTopView.kt | 4 ++-- player_component/src/main/res/layout/layout_player_bottom.xml | 2 ++ player_component/src/main/res/layout/layout_player_top.xml | 4 +++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/player_component/src/main/java/com/xyoye/player/controller/video/PlayerTopView.kt b/player_component/src/main/java/com/xyoye/player/controller/video/PlayerTopView.kt index 965ad7cdd..2e76d6a03 100644 --- a/player_component/src/main/java/com/xyoye/player/controller/video/PlayerTopView.kt +++ b/player_component/src/main/java/com/xyoye/player/controller/video/PlayerTopView.kt @@ -63,7 +63,7 @@ class PlayerTopView( } // 将初始焦点置于标题,而不是返回按钮 - post { viewBinding.videoTitleTv.requestFocus() } + post { viewBinding.focusPlaceholder.requestFocus() } } override fun attach(controlWrapper: ControlWrapper) { @@ -81,7 +81,7 @@ class PlayerTopView( ViewCompat.animate(viewBinding.playerTopLl).translationY(0f).setDuration(300).start() } else { - viewBinding.videoTitleTv.requestFocus() + viewBinding.focusPlaceholder.requestFocus() val height = viewBinding.playerTopLl.height.toFloat() ViewCompat.animate(viewBinding.playerTopLl).translationY(-height) .setDuration(300).start() diff --git a/player_component/src/main/res/layout/layout_player_bottom.xml b/player_component/src/main/res/layout/layout_player_bottom.xml index 8cb9e716f..96088ce19 100644 --- a/player_component/src/main/res/layout/layout_player_bottom.xml +++ b/player_component/src/main/res/layout/layout_player_bottom.xml @@ -64,6 +64,7 @@ android:nextFocusLeft="@+id/danmu_control_iv" android:nextFocusRight="@+id/iv_previous_source" android:nextFocusUp="@+id/player_lock_iv" + android:nextFocusDown="@+id/back_iv" android:padding="2dp" android:src="@drawable/ic_play_bt" app:layout_constraintEnd_toStartOf="@id/play_seek_bar" @@ -157,6 +158,7 @@ android:nextFocusLeft="@+id/send_danmu_tv" android:nextFocusRight="@+id/play_iv" android:nextFocusUp="@+id/player_shot_iv" + android:nextFocusDown="@+id/player_settings_iv" android:src="@drawable/ic_danmaku_control" app:layout_constraintBottom_toBottomOf="@id/play_iv" app:layout_constraintStart_toEndOf="@id/play_seek_bar" diff --git a/player_component/src/main/res/layout/layout_player_top.xml b/player_component/src/main/res/layout/layout_player_top.xml index 21f7d5659..8e4692de0 100644 --- a/player_component/src/main/res/layout/layout_player_top.xml +++ b/player_component/src/main/res/layout/layout_player_top.xml @@ -33,6 +33,7 @@ android:focusable="true" android:nextFocusLeft="@+id/player_settings_iv" android:nextFocusRight="@+id/iv_switch_popup" + android:nextFocusUp="@+id/play_iv" android:nextFocusDown="@+id/player_lock_iv" android:padding="10dp" android:src="@drawable/ic_arrow_back" @@ -123,7 +124,8 @@ android:focusable="true" android:nextFocusLeft="@+id/iv_switch_popup" android:nextFocusRight="@+id/back_iv" - android:nextFocusDown="@+id/player_lock_iv" + android:nextFocusUp="@+id/danmu_control_iv" + android:nextFocusDown="@+id/player_shot_iv" android:padding="12dp" android:src="@drawable/ic_player_setting" app:layout_constraintBottom_toBottomOf="@id/back_iv" From 1ef98b7983c8d83561848f7e8b8eeb33ef6c5f59 Mon Sep 17 00:00:00 2001 From: xieyy Date: Fri, 30 Jan 2026 11:55:35 +0800 Subject: [PATCH 08/11] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E5=AE=8C=E5=96=84:=20?= =?UTF-8?q?=E5=AE=8C=E5=96=84=E8=A7=86=E9=A2=91=E8=B5=84=E6=BA=90=E7=BB=91?= =?UTF-8?q?=E5=AE=9A=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit close #304 --- .../source/base/BaseVideoSource.kt | 3 ++ .../source/media/StorageVideoSource.kt | 8 +++++ .../storage/AbstractStorage.kt | 7 +++++ .../xyoye/common_component/storage/Storage.kt | 5 ++++ .../ui/activities/player/PlayerViewModel.kt | 23 +++++++++++++-- .../StorageFileFragmentViewModel.kt | 29 +++++++++---------- 6 files changed, 57 insertions(+), 18 deletions(-) diff --git a/common_component/src/main/java/com/xyoye/common_component/source/base/BaseVideoSource.kt b/common_component/src/main/java/com/xyoye/common_component/source/base/BaseVideoSource.kt index c44b8c138..2b8a5eca9 100644 --- a/common_component/src/main/java/com/xyoye/common_component/source/base/BaseVideoSource.kt +++ b/common_component/src/main/java/com/xyoye/common_component/source/base/BaseVideoSource.kt @@ -3,6 +3,7 @@ package com.xyoye.common_component.source.base import com.xyoye.common_component.source.inter.ExtraSource import com.xyoye.common_component.source.inter.VideoSource import com.xyoye.data_component.bean.LocalDanmuBean +import com.xyoye.data_component.entity.PlayHistoryEntity /** @@ -43,4 +44,6 @@ abstract class BaseVideoSource( override fun getStoragePath(): String? { return null } + + abstract fun updateFileHistory(playHistory: PlayHistoryEntity?) } \ No newline at end of file diff --git a/common_component/src/main/java/com/xyoye/common_component/source/media/StorageVideoSource.kt b/common_component/src/main/java/com/xyoye/common_component/source/media/StorageVideoSource.kt index a2566b9d2..3e87da8e0 100644 --- a/common_component/src/main/java/com/xyoye/common_component/source/media/StorageVideoSource.kt +++ b/common_component/src/main/java/com/xyoye/common_component/source/media/StorageVideoSource.kt @@ -7,6 +7,7 @@ import com.xyoye.common_component.storage.file.impl.TorrentStorageFile import com.xyoye.common_component.utils.getFileName import com.xyoye.common_component.utils.thunder.ThunderManager import com.xyoye.data_component.bean.LocalDanmuBean +import com.xyoye.data_component.entity.PlayHistoryEntity import com.xyoye.data_component.enums.MediaType /** @@ -92,6 +93,13 @@ class StorageVideoSource( return file.storagePath() } + override fun updateFileHistory(playHistory: PlayHistoryEntity?) { + file.playHistory = playHistory + file.storage.updateFileHistory(file, playHistory) + videoSources.firstOrNull { it.uniqueKey() == file.uniqueKey() } + ?.let { it.playHistory = playHistory } + } + fun getTorrentPath(): String? { if (file is TorrentStorageFile) { return file.filePath() diff --git a/common_component/src/main/java/com/xyoye/common_component/storage/AbstractStorage.kt b/common_component/src/main/java/com/xyoye/common_component/storage/AbstractStorage.kt index 5dc3496dc..1c600a0e0 100644 --- a/common_component/src/main/java/com/xyoye/common_component/storage/AbstractStorage.kt +++ b/common_component/src/main/java/com/xyoye/common_component/storage/AbstractStorage.kt @@ -11,6 +11,7 @@ import com.xyoye.common_component.utils.subtitle.SubtitleUtils import com.xyoye.data_component.bean.LocalDanmuBean import com.xyoye.data_component.data.DanmuEpisodeData import com.xyoye.data_component.entity.MediaLibraryEntity +import com.xyoye.data_component.entity.PlayHistoryEntity import java.io.File /** @@ -96,4 +97,10 @@ abstract class AbstractStorage( override suspend fun test(): Boolean { return true } + + override fun updateFileHistory(file: StorageFile, history: PlayHistoryEntity?) { + directoryFiles + .firstOrNull { it.uniqueKey() == file.uniqueKey() } + ?.let { it.playHistory = history } + } } \ No newline at end of file diff --git a/common_component/src/main/java/com/xyoye/common_component/storage/Storage.kt b/common_component/src/main/java/com/xyoye/common_component/storage/Storage.kt index 5d177eb79..71a739610 100644 --- a/common_component/src/main/java/com/xyoye/common_component/storage/Storage.kt +++ b/common_component/src/main/java/com/xyoye/common_component/storage/Storage.kt @@ -94,6 +94,11 @@ interface Storage { */ suspend fun test(): Boolean + /** + * 更新文件播放历史 + */ + fun updateFileHistory(file: StorageFile, history: PlayHistoryEntity?) + /** * 关闭媒体库 */ diff --git a/player_component/src/main/java/com/xyoye/player_component/ui/activities/player/PlayerViewModel.kt b/player_component/src/main/java/com/xyoye/player_component/ui/activities/player/PlayerViewModel.kt index fa9606eec..dc1326347 100644 --- a/player_component/src/main/java/com/xyoye/player_component/ui/activities/player/PlayerViewModel.kt +++ b/player_component/src/main/java/com/xyoye/player_component/ui/activities/player/PlayerViewModel.kt @@ -11,6 +11,7 @@ import com.xyoye.data_component.bean.LocalDanmuBean import com.xyoye.data_component.bean.SendDanmuBean import com.xyoye.data_component.bean.VideoTrackBean import com.xyoye.data_component.entity.DanmuBlockEntity +import com.xyoye.data_component.entity.PlayHistoryEntity import com.xyoye.data_component.enums.TrackType import kotlinx.coroutines.launch import master.flame.danmaku.danmaku.model.BaseDanmaku @@ -27,12 +28,23 @@ class PlayerViewModel : BaseViewModel() { val historyDao = DatabaseManager.instance.getPlayHistoryDao() viewModelScope.launch { + val playHistory = DatabaseManager.instance + .getPlayHistoryDao().getPlayHistory(uniqueKey, storageId) + ?: PlayHistoryEntity( + 0, + "", + "", + mediaType = videoSource.getMediaType(), + uniqueKey = uniqueKey, + storageId = storageId, + ) + when (track.type) { TrackType.AUDIO -> { val audioPath = track.type.getAudio(track.trackResource) if (audioPath != null && audioPath != videoSource.getAudioPath()) { videoSource.setAudioPath(audioPath) - historyDao.updateAudio(uniqueKey, storageId, audioPath) + playHistory.audioPath = audioPath } } @@ -40,7 +52,7 @@ class PlayerViewModel : BaseViewModel() { val subtitlePath = track.type.getSubtitle(track.trackResource) if (subtitlePath != null && subtitlePath != videoSource.getSubtitlePath()) { videoSource.setSubtitlePath(subtitlePath) - historyDao.updateSubtitle(uniqueKey, storageId, subtitlePath) + playHistory.subtitlePath = subtitlePath } } @@ -48,10 +60,15 @@ class PlayerViewModel : BaseViewModel() { val danmu = track.type.getDanmu(track.trackResource) if (danmu != null && danmu != videoSource.getDanmu()) { videoSource.setDanmu(danmu) - historyDao.updateDanmu(uniqueKey, storageId, danmu.danmuPath, danmu.episodeId) + playHistory.danmuPath = danmu.danmuPath + playHistory.episodeId = danmu.episodeId } } } + + historyDao.insert(playHistory) + val newHistory = historyDao.getPlayHistory(uniqueKey, storageId) + videoSource.updateFileHistory(newHistory) } } diff --git a/storage_component/src/main/java/com/xyoye/storage_component/ui/fragment/storage_file/StorageFileFragmentViewModel.kt b/storage_component/src/main/java/com/xyoye/storage_component/ui/fragment/storage_file/StorageFileFragmentViewModel.kt index 7add2b2fb..cb974e699 100644 --- a/storage_component/src/main/java/com/xyoye/storage_component/ui/fragment/storage_file/StorageFileFragmentViewModel.kt +++ b/storage_component/src/main/java/com/xyoye/storage_component/ui/fragment/storage_file/StorageFileFragmentViewModel.kt @@ -58,7 +58,7 @@ class StorageFileFragmentViewModel : BaseViewModel() { storage.openDirectory(target, refresh) .filter { isDisplayFile(it) } .sortedWith(StorageSortOption.comparator()) - .onEach { it.playHistory = getHistory(it) } + .map { updateStorageFileHistory(it, getHistory(it)) } .apply { _fileLiveData.postValue(this) } .also { filesSnapshot = it } } @@ -89,7 +89,7 @@ class StorageFileFragmentViewModel : BaseViewModel() { storage.search(text) .filter { isDisplayFile(it) } .sortedWith(StorageSortOption.comparator()) - .onEach { it.playHistory = getHistory(it) } + .map { updateStorageFileHistory(it, getHistory(it)) } .let { _fileLiveData.postValue(it) } } return @@ -160,19 +160,8 @@ class StorageFileFragmentViewModel : BaseViewModel() { refreshStorageLastPlay() fileList - .map { - val history = getHistory(it) - val isSameHistory = if (it.isFile()) { - it.playHistory == history && it.playHistory?.isLastPlay == history?.isLastPlay - } else { - it.playHistory?.id == history?.id - } - if (isSameHistory) { - return@map it - } - //历史记录不一致时,返回拷贝的新对象 - it.clone().apply { playHistory = history } - }.apply { _fileLiveData.postValue(this) } + .map { updateStorageFileHistory(it, getHistory(it)) } + .apply { _fileLiveData.postValue(this) } .also { filesSnapshot = it } } } @@ -264,4 +253,14 @@ class StorageFileFragmentViewModel : BaseViewModel() { storageId = storageFile.storage.library.id, ) } + + private fun updateStorageFileHistory( + file: StorageFile, + history: PlayHistoryEntity? + ): StorageFile { + file.storage.updateFileHistory(file, history) + return file.clone().apply { + playHistory = history + } + } } \ No newline at end of file From 06c853804acf4a1b422749eedae1371e86cad403 Mon Sep 17 00:00:00 2001 From: xieyy Date: Fri, 30 Jan 2026 14:03:56 +0800 Subject: [PATCH 09/11] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E5=AE=8C=E5=96=84:=20?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E6=B7=B1=E8=89=B2=E6=A8=A1=E5=BC=8F=E5=8F=91?= =?UTF-8?q?=E9=80=81=E5=BC=B9=E5=B9=95=E6=8E=A7=E4=BB=B6=E5=AD=97=E4=BD=93?= =?UTF-8?q?=E9=A2=9C=E8=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit close #302 --- .../src/main/res/drawable/background_danmu_input.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/player_component/src/main/res/drawable/background_danmu_input.xml b/player_component/src/main/res/drawable/background_danmu_input.xml index 226eb085e..d1bc023e5 100644 --- a/player_component/src/main/res/drawable/background_danmu_input.xml +++ b/player_component/src/main/res/drawable/background_danmu_input.xml @@ -3,6 +3,6 @@ - + \ No newline at end of file From 9f9e2b657a7f2c938a3aeded6e75a10256d31ea1 Mon Sep 17 00:00:00 2001 From: xieyy Date: Fri, 30 Jan 2026 18:01:02 +0800 Subject: [PATCH 10/11] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E5=AE=8C=E5=96=84:=20?= =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=AA=92=E4=BD=93=E5=BA=93=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E7=84=A6=E7=82=B9=E9=80=89=E4=B8=AD=E6=97=B6=E6=BB=9A=E5=8A=A8?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit close #277 --- .../storage_file/StorageFileActivity.kt | 57 ++++++++++++++++++- .../utils/storage/StorageFileStyleHelper.kt | 15 +++-- 2 files changed, 63 insertions(+), 9 deletions(-) diff --git a/storage_component/src/main/java/com/xyoye/storage_component/ui/activities/storage_file/StorageFileActivity.kt b/storage_component/src/main/java/com/xyoye/storage_component/ui/activities/storage_file/StorageFileActivity.kt index 7b0dad234..ad30ac628 100644 --- a/storage_component/src/main/java/com/xyoye/storage_component/ui/activities/storage_file/StorageFileActivity.kt +++ b/storage_component/src/main/java/com/xyoye/storage_component/ui/activities/storage_file/StorageFileActivity.kt @@ -5,13 +5,16 @@ import android.view.KeyEvent import android.view.Menu import android.view.MenuItem import android.view.View +import android.view.ViewTreeObserver import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentTransaction import androidx.lifecycle.Lifecycle import androidx.lifecycle.coroutineScope +import androidx.recyclerview.widget.RecyclerView import com.alibaba.android.arouter.facade.annotation.Autowired import com.alibaba.android.arouter.facade.annotation.Route import com.alibaba.android.arouter.launcher.ARouter +import com.google.android.material.appbar.AppBarLayout import com.google.android.material.shape.ShapeAppearanceModel import com.xyoye.common_component.base.BaseActivity import com.xyoye.common_component.config.RouteTable @@ -63,6 +66,11 @@ class StorageFileActivity : BaseActivity + handleGlobalFocusChange(newFocus) + } + var shareStorageFile: StorageFile? = null override fun initViewModel() = @@ -86,6 +94,8 @@ class StorageFileActivity : BaseActivity setToolbarExpanded(true) + + // 焦点在内容区列表 + hasAncestorOfType(newFocus, RecyclerView::class.java) -> setToolbarExpanded(false) + } + } + + /** + * 根据焦点归属切换标题栏展开/收缩 + */ + private fun setToolbarExpanded(expand: Boolean) { + val isExpanded = mToolbarStyleHelper.isToolbarCollapsed().not() + if (expand && isExpanded) { + return + } + dataBinding.appbarLayout.setExpanded(expand, true) + } + + /** + * 判断view是否存在指定类型的祖先 + */ + private fun hasAncestorOfType(view: View, clazz: Class): Boolean { + var current: View? = view + while (current != null) { + if (clazz.isInstance(current)) { + return true + } + current = current.parent as? View + } + return false + } + /** * 分发焦点到最后一个Fragment */ @@ -383,4 +438,4 @@ class StorageFileActivity : BaseActivity + changeToolbarStyle(verticalOffset != 0) } } + fun isToolbarCollapsed(): Boolean { + return mToolbarCollapsed + } + private fun changeToolbarStyle(collapsed: Boolean) { if (mToolbarCollapsed == collapsed) { return @@ -101,4 +100,4 @@ class StorageFileStyleHelper( mToolbarExpandedColor } } -} \ No newline at end of file +} From 35fa92dfa512baffb22762a051648f6ecc2bc456 Mon Sep 17 00:00:00 2001 From: xieyy Date: Fri, 30 Jan 2026 19:29:23 +0800 Subject: [PATCH 11/11] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=8A=9F=E8=83=BD:=20?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=89=93=E5=BC=80Torrent=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit close #287 --- player_component/src/main/AndroidManifest.xml | 2 + .../player_intent/PlayerIntentActivity.kt | 38 +++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/player_component/src/main/AndroidManifest.xml b/player_component/src/main/AndroidManifest.xml index d27ba723f..faea0224b 100644 --- a/player_component/src/main/AndroidManifest.xml +++ b/player_component/src/main/AndroidManifest.xml @@ -1123,6 +1123,8 @@ + + diff --git a/player_component/src/main/java/com/xyoye/player_component/ui/activities/player_intent/PlayerIntentActivity.kt b/player_component/src/main/java/com/xyoye/player_component/ui/activities/player_intent/PlayerIntentActivity.kt index eb0badf6e..aeab024dd 100644 --- a/player_component/src/main/java/com/xyoye/player_component/ui/activities/player_intent/PlayerIntentActivity.kt +++ b/player_component/src/main/java/com/xyoye/player_component/ui/activities/player_intent/PlayerIntentActivity.kt @@ -1,6 +1,8 @@ package com.xyoye.player_component.ui.activities.player_intent import android.net.Uri +import androidx.core.net.toFile +import androidx.core.net.toUri import com.alibaba.android.arouter.launcher.ARouter import com.gyf.immersionbar.BarHide import com.gyf.immersionbar.ImmersionBar @@ -8,6 +10,8 @@ import com.xyoye.common_component.base.BaseActivity import com.xyoye.common_component.config.RouteTable import com.xyoye.common_component.extension.decodeUrl import com.xyoye.common_component.utils.MediaUtils +import com.xyoye.common_component.utils.isTorrentFile +import com.xyoye.data_component.entity.MediaLibraryEntity import com.xyoye.player_component.BR import com.xyoye.player_component.R import com.xyoye.player_component.databinding.ActivityPlayerIntentBinding @@ -53,6 +57,11 @@ class PlayerIntentActivity : BaseActivity