From 78570eed7c5747cf8b92f07ba49d9fd18a66c59a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=82=A8=E7=9A=84=E5=90=8D=E5=AD=97?= <您的邮箱> Date: Fri, 24 Oct 2025 14:00:14 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=8D=87=E7=BA=A7=E5=88=B0v3.0.9?= =?UTF-8?q?=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增直播开关控制功能,可隐藏/显示直播tab - 优化滑杆圆球大小至20dp直径,提升操作体验 - 改进滑杆刻度显示,非激活轨道显示刻度 - 增强播放进度条动态大小调整功能 - 新增实时倍速显示功能 - 优化源管理模块间距动态调整 - 修复播放进度条圆球跳回问题 - 完善直播开关逻辑和UI交互 - 更新版本号至3.0.9 --- app/build.gradle | 18 ++-- .../java/com/fongmi/android/tv/Updater.java | 21 +++- .../tv/ui/activity/SettingActivity.java | 19 ++++ .../leanback/res/layout/activity_setting.xml | 30 ++++++ app/src/leanback/res/layout/dialog_buffer.xml | 7 +- app/src/leanback/res/layout/dialog_speed.xml | 7 +- .../leanback/res/layout/view_control_seek.xml | 2 + .../java/com/fongmi/android/tv/Setting.java | 8 ++ .../fongmi/android/tv/db/dao/ConfigDao.java | 2 +- .../android/tv/ui/custom/CustomSeekView.java | 99 +++++++++++++++++-- app/src/main/res/values-zh-rCN/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + .../java/com/fongmi/android/tv/Updater.java | 21 +++- .../android/tv/ui/activity/HomeActivity.java | 2 +- .../tv/ui/activity/SettingPlayerActivity.java | 18 ++-- .../android/tv/ui/dialog/ControlDialog.java | 4 + .../android/tv/ui/dialog/TimerDialog.java | 2 + .../tv/ui/fragment/SettingFragment.java | 64 +++++++++--- .../com/fongmi/android/tv/utils/Timer.java | 2 +- .../res/drawable/shape_about_button.xml | 2 +- .../res/drawable/shape_accent_no_border.xml | 21 ++++ .../drawable/shape_dialog_button_selected.xml | 2 +- .../res/drawable/shape_episode_selected.xml | 2 +- .../res/drawable/shape_item_selected.xml | 2 +- .../res/drawable/shape_timer_delay_button.xml | 15 +++ .../res/drawable/shape_timer_reset_button.xml | 15 +++ app/src/mobile/res/layout/dialog_about.xml | 2 +- app/src/mobile/res/layout/dialog_buffer.xml | 11 ++- app/src/mobile/res/layout/dialog_control.xml | 39 ++++++-- app/src/mobile/res/layout/dialog_speed.xml | 8 +- app/src/mobile/res/layout/dialog_timer.xml | 82 +++++++++++---- .../mobile/res/layout/fragment_setting.xml | 94 +++++++----------- .../mobile/res/layout/view_control_seek.xml | 2 + app/src/mobile/res/values-zh-rCN/strings.xml | 4 +- app/src/mobile/res/values-zh-rTW/strings.xml | 4 +- app/src/mobile/res/values/colors.xml | 3 + app/src/mobile/res/values/strings.xml | 4 +- build.gradle | 6 +- 38 files changed, 487 insertions(+), 159 deletions(-) create mode 100644 app/src/mobile/res/drawable/shape_accent_no_border.xml create mode 100644 app/src/mobile/res/drawable/shape_timer_delay_button.xml create mode 100644 app/src/mobile/res/drawable/shape_timer_reset_button.xml diff --git a/app/build.gradle b/app/build.gradle index bb35f571..3e132dc8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -27,8 +27,8 @@ android { minSdk 24 //noinspection ExpiredTargetSdkVersion targetSdk 28 - versionCode 308 - versionName "3.0.8" + versionCode 309 + versionName "3.0.9" javaCompileOptions { annotationProcessorOptions { arguments = ["room.schemaLocation": "$projectDir/schemas".toString(), "eventBusIndex": "com.fongmi.android.tv.event.EventIndex"] @@ -113,7 +113,7 @@ dependencies { implementation project(':catvod') // implementation project(':chaquo') // 移除Python支持减少8-10MB体积 implementation project(':quickjs') - implementation 'androidx.appcompat:appcompat:1.7.1' + implementation 'androidx.appcompat:appcompat:1.7.0' implementation 'androidx.media:media:1.7.0' implementation 'androidx.media3:media3-common:' + media3Version implementation 'androidx.media3:media3-container:' + media3Version @@ -130,7 +130,7 @@ dependencies { implementation 'androidx.media3:media3-exoplayer-smoothstreaming:' + media3Version implementation 'androidx.media3:media3-extractor:' + media3Version implementation 'androidx.media3:media3-ui:' + media3Version - implementation 'androidx.room:room-runtime:2.7.2' + implementation 'androidx.room:room-runtime:2.6.1' implementation 'cat.ereza:customactivityoncrash:2.4.0' implementation 'io.github.anilbeesetti:nextlib-media3ext:1.8.0-0.9.0' implementation 'com.github.bassaer:materialdesigncolors:1.0.0' @@ -141,11 +141,11 @@ dependencies { implementation 'com.github.jahirfiquitiva:TextDrawable:1.0.3' implementation 'com.github.thegrizzlylabs:sardine-android:0.9' implementation 'com.github.teamnewpipe:NewPipeExtractor:v0.24.8' - implementation 'com.google.android.material:material:1.12.0' + implementation 'com.google.android.material:material:1.11.0' implementation 'com.google.zxing:core:3.5.3' - implementation 'com.guolindev.permissionx:permissionx:1.8.1' - implementation 'com.hierynomus:smbj:0.14.0' - implementation 'io.antmedia:rtmp-client:3.2.0' + implementation 'com.guolindev.permissionx:permissionx:1.7.1' + implementation 'com.hierynomus:smbj:0.13.0' + implementation 'io.antmedia:rtmp-client:3.1.0' implementation 'javax.servlet:javax.servlet-api:3.1.0' implementation 'org.aomedia.avif.android:avif:1.1.1.14d8e3c4' implementation 'org.eclipse.jetty:jetty-client:8.1.21.v20160908' @@ -162,7 +162,7 @@ dependencies { mobileImplementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' mobileImplementation 'com.google.android.flexbox:flexbox:3.0.0' mobileImplementation('com.journeyapps:zxing-android-embedded:4.3.0') { transitive = false } - annotationProcessor 'androidx.room:room-compiler:2.7.2' + annotationProcessor 'androidx.room:room-compiler:2.6.1' // annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0' annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.3.1' coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs_nio:2.1.5' diff --git a/app/src/leanback/java/com/fongmi/android/tv/Updater.java b/app/src/leanback/java/com/fongmi/android/tv/Updater.java index e1c18b75..b5d87490 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/Updater.java +++ b/app/src/leanback/java/com/fongmi/android/tv/Updater.java @@ -207,13 +207,26 @@ public class Updater implements Download.Callback { private void confirm(View view) { // 跳转到GitHub Releases页面而不是直接下载 try { + String url = "https://github.com/Tosencen/XMBOX/releases/tag/v3.0.8"; + Logger.d("Updater: Attempting to open URL: " + url); + Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setData(Uri.parse("https://github.com/Tosencen/XMBOX/releases/tag/v3.0.8")); + intent.setData(Uri.parse(url)); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - App.get().startActivity(intent); - dismiss(); + + // 检查是否有应用可以处理这个Intent + if (intent.resolveActivity(App.get().getPackageManager()) != null) { + App.get().startActivity(intent); + Logger.d("Updater: Successfully started browser intent"); + dismiss(); + } else { + Logger.e("Updater: No app can handle the URL"); + Notify.show("没有找到可以打开链接的应用,请手动访问GitHub下载"); + dismiss(); + } } catch (Exception e) { - Logger.e("Failed to open GitHub releases page: " + e.getMessage()); + Logger.e("Updater: Failed to open GitHub releases page: " + e.getMessage()); + e.printStackTrace(); Notify.show("无法打开更新页面,请手动访问GitHub下载"); dismiss(); } diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/SettingActivity.java b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/SettingActivity.java index 25425953..739cd118 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/SettingActivity.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/SettingActivity.java @@ -99,8 +99,17 @@ public class SettingActivity extends BaseActivity implements ConfigCallback, Sit mBinding.dohText.setText(getDohList()[getDohIndex()]); mBinding.proxyText.setText(getProxy(Setting.getProxy())); mBinding.incognitoText.setText(getSwitch(Setting.isIncognito())); + mBinding.liveTabVisibleText.setText(getSwitch(Setting.isLiveTabVisible())); mBinding.sizeText.setText((size = ResUtil.getStringArray(R.array.select_size))[Setting.getSize()]); mBinding.qualityText.setText((quality = ResUtil.getStringArray(R.array.select_quality))[Setting.getQuality()]); + setLiveSettingsVisibility(); + } + + private void setLiveSettingsVisibility() { + boolean isLiveTabVisible = !Setting.isLiveTabVisible(); // 注意:这里取反,因为开关是"隐藏直播" + mBinding.live.setVisibility(isLiveTabVisible ? View.VISIBLE : View.GONE); + mBinding.liveHome.setVisibility(isLiveTabVisible ? View.VISIBLE : View.GONE); + mBinding.liveHistory.setVisibility(isLiveTabVisible ? View.VISIBLE : View.GONE); } private void setCacheText() { @@ -134,6 +143,7 @@ public class SettingActivity extends BaseActivity implements ConfigCallback, Sit mBinding.wallDefault.setOnClickListener(this::setWallDefault); mBinding.wallRefresh.setOnClickListener(this::setWallRefresh); mBinding.incognito.setOnClickListener(this::setIncognito); + mBinding.liveTabVisible.setOnClickListener(this::setLiveTabVisible); mBinding.quality.setOnClickListener(this::setQuality); mBinding.size.setOnClickListener(this::setSize); mBinding.doh.setOnClickListener(this::setDoh); @@ -304,6 +314,15 @@ public class SettingActivity extends BaseActivity implements ConfigCallback, Sit mBinding.incognitoText.setText(getSwitch(Setting.isIncognito())); } + private void setLiveTabVisible(View view) { + Setting.putLiveTabVisible(!Setting.isLiveTabVisible()); + mBinding.liveTabVisibleText.setText(getSwitch(Setting.isLiveTabVisible())); + // 发送刷新事件,通知主界面更新导航栏 + RefreshEvent.config(); + // 更新直播设置项的可见性 + setLiveSettingsVisibility(); + } + private void setQuality(View view) { int index = Setting.getQuality(); Setting.putQuality(index = index == quality.length - 1 ? 0 : ++index); diff --git a/app/src/leanback/res/layout/activity_setting.xml b/app/src/leanback/res/layout/activity_setting.xml index ee00263c..960b96bb 100644 --- a/app/src/leanback/res/layout/activity_setting.xml +++ b/app/src/leanback/res/layout/activity_setting.xml @@ -265,6 +265,36 @@ + + + + + + + + + app:trackColorInactive="@color/white_20" + app:trackHeight="4dp" /> \ No newline at end of file diff --git a/app/src/leanback/res/layout/dialog_speed.xml b/app/src/leanback/res/layout/dialog_speed.xml index 51b9c2d3..d29b7bc9 100644 --- a/app/src/leanback/res/layout/dialog_speed.xml +++ b/app/src/leanback/res/layout/dialog_speed.xml @@ -14,8 +14,11 @@ android:valueFrom="2" android:valueTo="5" app:thumbColor="@color/primary" - app:tickVisible="false" + app:thumbRadius="10dp" + app:tickVisible="true" + app:tickColor="@color/black_50" app:trackColorActive="@color/primary" - app:trackColorInactive="@color/white_30" /> + app:trackColorInactive="@color/white_20" + app:trackHeight="4dp" /> \ No newline at end of file diff --git a/app/src/leanback/res/layout/view_control_seek.xml b/app/src/leanback/res/layout/view_control_seek.xml index f168da95..6e5f2f51 100644 --- a/app/src/leanback/res/layout/view_control_seek.xml +++ b/app/src/leanback/res/layout/view_control_seek.xml @@ -29,6 +29,8 @@ android:nextFocusUp="@id/next" android:nextFocusDown="@id/timeBar" app:bar_height="2dp" + app:scrubber_enabled_size="12dp" + app:scrubber_disabled_size="12dp" app:played_color="#FFEB3B" app:scrubber_color="#FFEB3B" app:buffered_color="#80FFEB3B" diff --git a/app/src/main/java/com/fongmi/android/tv/Setting.java b/app/src/main/java/com/fongmi/android/tv/Setting.java index 2a7991b2..04507e11 100644 --- a/app/src/main/java/com/fongmi/android/tv/Setting.java +++ b/app/src/main/java/com/fongmi/android/tv/Setting.java @@ -324,4 +324,12 @@ public class Setting { public static void setPrivacyAgreed(boolean agreed) { Prefers.put("privacy_agreed_v1", agreed); } + + public static boolean isLiveTabVisible() { + return Prefers.getBoolean("live_tab_visible", true); + } + + public static void putLiveTabVisible(boolean visible) { + Prefers.put("live_tab_visible", visible); + } } diff --git a/app/src/main/java/com/fongmi/android/tv/db/dao/ConfigDao.java b/app/src/main/java/com/fongmi/android/tv/db/dao/ConfigDao.java index a6ce92cc..5f5754f0 100644 --- a/app/src/main/java/com/fongmi/android/tv/db/dao/ConfigDao.java +++ b/app/src/main/java/com/fongmi/android/tv/db/dao/ConfigDao.java @@ -17,7 +17,7 @@ public abstract class ConfigDao extends BaseDao { @Query("SELECT * FROM Config WHERE type = :type ORDER BY time DESC") public abstract List findByType(int type); - @SuppressWarnings(RoomWarnings.QUERY_MISMATCH) + @SuppressWarnings(RoomWarnings.CURSOR_MISMATCH) @Query("SELECT id, name, url, type, time FROM Config WHERE type = :type ORDER BY time DESC") public abstract List findUrlByType(int type); diff --git a/app/src/main/java/com/fongmi/android/tv/ui/custom/CustomSeekView.java b/app/src/main/java/com/fongmi/android/tv/ui/custom/CustomSeekView.java index c9d21a8f..98d40215 100644 --- a/app/src/main/java/com/fongmi/android/tv/ui/custom/CustomSeekView.java +++ b/app/src/main/java/com/fongmi/android/tv/ui/custom/CustomSeekView.java @@ -2,7 +2,9 @@ package com.fongmi.android.tv.ui.custom; import android.content.Context; import android.util.AttributeSet; +import android.util.TypedValue; import android.view.LayoutInflater; +import android.view.MotionEvent; import android.widget.FrameLayout; import android.widget.TextView; @@ -33,6 +35,7 @@ public class CustomSeekView extends FrameLayout implements TimeBar.OnScrubListen private long currentPosition; private long currentBuffered; private boolean scrubbing; + private boolean isPressed; public CustomSeekView(Context context) { this(context, null); @@ -55,6 +58,28 @@ public class CustomSeekView extends FrameLayout implements TimeBar.OnScrubListen timeBar = findViewById(R.id.timeBar); timeBar.addListener(this); refresh = this::refresh; + + // 设置触摸事件监听器,实现动态尺寸调整 + timeBar.setOnTouchListener((v, event) -> { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + if (!isPressed) { + isPressed = true; + // 按下时:滑杆4dp,圆球16dp + setTimeBarSize(4, 16); + } + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + if (isPressed) { + isPressed = false; + // 松开时:滑杆2dp,圆球12dp + setTimeBarSize(2, 12); + } + break; + } + return false; // 不拦截事件,让DefaultTimeBar正常处理 + }); } public void setListener(Players player) { @@ -68,6 +93,58 @@ public class CustomSeekView extends FrameLayout implements TimeBar.OnScrubListen public void setDuration(long duration) { timeBar.setDuration(duration); } + + /** + * 动态设置进度条高度和拖拽手柄大小 + * @param barHeightDp 滑杆高度值(dp) + * @param scrubberSizeDp 拖拽手柄大小(dp) + */ + private void setTimeBarSize(int barHeightDp, int scrubberSizeDp) { + // 设置滑杆高度 + int barHeightPx = (int) TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + barHeightDp, + getContext().getResources().getDisplayMetrics() + ); + + // 设置拖拽手柄大小 + int scrubberSizePx = (int) TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + scrubberSizeDp, + getContext().getResources().getDisplayMetrics() + ); + + // 通过反射设置DefaultTimeBar的内部属性 + try { + // 设置滑杆高度 + java.lang.reflect.Field barHeightField = timeBar.getClass().getDeclaredField("barHeight"); + barHeightField.setAccessible(true); + barHeightField.setInt(timeBar, barHeightPx); + + // 设置拖拽手柄大小 - 尝试多个可能的字段名 + String[] scrubberFields = {"scrubberSize", "scrubberEnabledSize", "scrubberDisabledSize"}; + for (String fieldName : scrubberFields) { + try { + java.lang.reflect.Field scrubberField = timeBar.getClass().getDeclaredField(fieldName); + scrubberField.setAccessible(true); + scrubberField.setInt(timeBar, scrubberSizePx); + break; // 成功设置后退出循环 + } catch (NoSuchFieldException e) { + // 继续尝试下一个字段名 + } + } + + // 刷新视图 + timeBar.requestLayout(); + timeBar.invalidate(); + } catch (Exception e) { + // 如果反射失败,使用备用方案 + e.printStackTrace(); + // 备用方案:重新设置布局参数 + timeBar.getLayoutParams().height = barHeightPx; + timeBar.requestLayout(); + } + } private void start() { removeCallbacks(refresh); @@ -137,12 +214,15 @@ public class CustomSeekView extends FrameLayout implements TimeBar.OnScrubListen // 延迟刷新进度条,确保播放器已经处理了跳转操作 removeCallbacks(refresh); postDelayed(() -> { - refresh(); - // 确保进度条位置与实际播放位置一致 - long actualPosition = player.getPosition(); - if (Math.abs(actualPosition - positionMs) > 100) { // 如果差异超过100ms,再次调整 - timeBar.setPosition(actualPosition); - positionView.setText(player.stringToTime(actualPosition)); + // 只有在非拖动状态下才刷新进度条位置 + if (!scrubbing) { + refresh(); + // 确保进度条位置与实际播放位置一致 + long actualPosition = player.getPosition(); + if (Math.abs(actualPosition - positionMs) > 100) { // 如果差异超过100ms,再次调整 + timeBar.setPosition(actualPosition); + positionView.setText(player.stringToTime(actualPosition)); + } } }, 50); // 延迟50ms刷新 } @@ -168,9 +248,10 @@ public class CustomSeekView extends FrameLayout implements TimeBar.OnScrubListen public void onScrubStop(@NonNull TimeBar timeBar, long position, boolean canceled) { scrubbing = false; if (!canceled) { - // 先隐藏进度条提示,避免用户看到不一致的状态 - // 注意:这里不能直接访问mBinding.widget.seek,因为CustomSeekView不包含这个引用 - // 这个优化将在VideoActivity的onSeekEnd方法中实现 + // 立即设置进度条位置到目标位置,避免圆球跳回原始位置 + timeBar.setPosition(position); + positionView.setText(player.stringToTime(position)); + // 调整播放位置 seekToTimeBarPosition(position); // 确保播放状态正确 diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index dba4bde6..1a7ea447 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -73,6 +73,7 @@ 订阅管理 播放设置 无痕模式 + 隐藏直播 图片品质 图片尺寸 DoH diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index be025413..bd31d3d8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -78,6 +78,7 @@ Data Management Player setting Incognito mode + Hide Live Tab Image quality Image size DoH diff --git a/app/src/mobile/java/com/fongmi/android/tv/Updater.java b/app/src/mobile/java/com/fongmi/android/tv/Updater.java index 73d4dd0c..bede2065 100644 --- a/app/src/mobile/java/com/fongmi/android/tv/Updater.java +++ b/app/src/mobile/java/com/fongmi/android/tv/Updater.java @@ -213,13 +213,26 @@ public class Updater implements Download.Callback { private void confirm(View view) { // 跳转到GitHub Releases页面而不是直接下载 try { + String url = "https://github.com/Tosencen/XMBOX/releases/tag/v3.0.8"; + Logger.d("Updater: Attempting to open URL: " + url); + Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setData(Uri.parse("https://github.com/Tosencen/XMBOX/releases/tag/v3.0.8")); + intent.setData(Uri.parse(url)); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - App.get().startActivity(intent); - dismiss(); + + // 检查是否有应用可以处理这个Intent + if (intent.resolveActivity(App.get().getPackageManager()) != null) { + App.get().startActivity(intent); + Logger.d("Updater: Successfully started browser intent"); + dismiss(); + } else { + Logger.e("Updater: No app can handle the URL"); + Notify.show("没有找到可以打开链接的应用,请手动访问GitHub下载"); + dismiss(); + } } catch (Exception e) { - Logger.e("Failed to open GitHub releases page: " + e.getMessage()); + Logger.e("Updater: Failed to open GitHub releases page: " + e.getMessage()); + e.printStackTrace(); Notify.show("无法打开更新页面,请手动访问GitHub下载"); dismiss(); } diff --git a/app/src/mobile/java/com/fongmi/android/tv/ui/activity/HomeActivity.java b/app/src/mobile/java/com/fongmi/android/tv/ui/activity/HomeActivity.java index b35353f4..d4a1f6be 100644 --- a/app/src/mobile/java/com/fongmi/android/tv/ui/activity/HomeActivity.java +++ b/app/src/mobile/java/com/fongmi/android/tv/ui/activity/HomeActivity.java @@ -154,7 +154,7 @@ public class HomeActivity extends BaseActivity implements NavigationBarView.OnIt private void setNavigation() { mBinding.navigation.getMenu().findItem(R.id.vod).setVisible(true); mBinding.navigation.getMenu().findItem(R.id.setting).setVisible(true); - mBinding.navigation.getMenu().findItem(R.id.live).setVisible(LiveConfig.hasUrl()); + mBinding.navigation.getMenu().findItem(R.id.live).setVisible(LiveConfig.hasUrl() && !Setting.isLiveTabVisible()); } private boolean openLive() { diff --git a/app/src/mobile/java/com/fongmi/android/tv/ui/activity/SettingPlayerActivity.java b/app/src/mobile/java/com/fongmi/android/tv/ui/activity/SettingPlayerActivity.java index 9cd66f30..18369e7d 100644 --- a/app/src/mobile/java/com/fongmi/android/tv/ui/activity/SettingPlayerActivity.java +++ b/app/src/mobile/java/com/fongmi/android/tv/ui/activity/SettingPlayerActivity.java @@ -65,17 +65,19 @@ public class SettingPlayerActivity extends BaseActivity implements UaCallback, B protected void initEvent() { mBinding.back.setOnClickListener(v -> finish()); mBinding.ua.setOnClickListener(this::onUa); - mBinding.aac.setOnClickListener(this::setAAC); mBinding.scale.setOnClickListener(this::onScale); mBinding.speed.setOnClickListener(this::onSpeed); mBinding.buffer.setOnClickListener(this::onBuffer); mBinding.render.setOnClickListener(this::setRender); - mBinding.tunnel.setOnClickListener(this::setTunnel); mBinding.caption.setOnClickListener(this::setCaption); mBinding.caption.setOnLongClickListener(this::onCaption); mBinding.background.setOnClickListener(this::onBackground); - mBinding.audioDecode.setOnClickListener(this::setAudioDecode); - mBinding.danmakuLoad.setOnClickListener(this::setDanmakuLoad); + + // 直接给开关按钮设置点击监听器,避免双重点击冲突 + mBinding.tunnelSwitch.setOnClickListener(this::setTunnel); + mBinding.audioDecodeSwitch.setOnClickListener(this::setAudioDecode); + mBinding.aacSwitch.setOnClickListener(this::setAAC); + mBinding.danmakuLoadSwitch.setOnClickListener(this::setDanmakuLoad); } private void onUa(View view) { @@ -91,7 +93,7 @@ public class SettingPlayerActivity extends BaseActivity implements UaCallback, B private void setAAC(View view) { boolean isChecked = !Setting.isPreferAAC(); Setting.putPreferAAC(isChecked); - mBinding.aacSwitch.setChecked(isChecked); + // 不需要再次调用 setChecked,因为点击已经触发了状态变化 } private void onScale(View view) { @@ -132,7 +134,7 @@ public class SettingPlayerActivity extends BaseActivity implements UaCallback, B private void setTunnel(View view) { boolean isChecked = !Setting.isTunnel(); Setting.putTunnel(isChecked); - mBinding.tunnelSwitch.setChecked(isChecked); + // 不需要再次调用 setChecked,因为点击已经触发了状态变化 if (isChecked && Setting.getRender() == 1) setRender(view); } @@ -157,12 +159,12 @@ public class SettingPlayerActivity extends BaseActivity implements UaCallback, B private void setAudioDecode(View view) { boolean isChecked = !Setting.isAudioPrefer(); Setting.putAudioPrefer(isChecked); - mBinding.audioDecodeSwitch.setChecked(isChecked); + // 不需要再次调用 setChecked,因为点击已经触发了状态变化 } private void setDanmakuLoad(View view) { boolean isChecked = !Setting.isDanmakuLoad(); Setting.putDanmakuLoad(isChecked); - mBinding.danmakuLoadSwitch.setChecked(isChecked); + // 不需要再次调用 setChecked,因为点击已经触发了状态变化 } } \ No newline at end of file diff --git a/app/src/mobile/java/com/fongmi/android/tv/ui/dialog/ControlDialog.java b/app/src/mobile/java/com/fongmi/android/tv/ui/dialog/ControlDialog.java index 953ab5ea..31fc31ad 100644 --- a/app/src/mobile/java/com/fongmi/android/tv/ui/dialog/ControlDialog.java +++ b/app/src/mobile/java/com/fongmi/android/tv/ui/dialog/ControlDialog.java @@ -126,6 +126,8 @@ public class ControlDialog extends BaseDialog implements ParseAdapter.OnClickLis private void setSpeed(@NonNull Slider slider, float value, boolean fromUser) { parent.control.action.speed.setText(player.setSpeed(value)); if (history != null) history.setSpeed(player.getSpeed()); + // 实时更新倍速数值显示 + binding.speedValue.setText(String.format("%.1fx", value)); } private void setScaleText() { @@ -179,6 +181,8 @@ public class ControlDialog extends BaseDialog implements ParseAdapter.OnClickLis binding.player.setText(parent.control.action.player.getText()); binding.decode.setVisibility(parent.control.action.decode.getVisibility()); binding.danmaku.setVisibility(parent.control.action.danmaku.getVisibility()); + // 初始化倍速数值显示 + binding.speedValue.setText(String.format("%.1fx", Math.max(player.getSpeed(), 0.5f))); } public void setParseVisible(boolean visible) { diff --git a/app/src/mobile/java/com/fongmi/android/tv/ui/dialog/TimerDialog.java b/app/src/mobile/java/com/fongmi/android/tv/ui/dialog/TimerDialog.java index 3bf0b129..998089f3 100644 --- a/app/src/mobile/java/com/fongmi/android/tv/ui/dialog/TimerDialog.java +++ b/app/src/mobile/java/com/fongmi/android/tv/ui/dialog/TimerDialog.java @@ -60,6 +60,8 @@ public class TimerDialog extends BaseDialog implements Timer.Callback { binding.time2.setOnClickListener(this::setTimer); binding.time3.setOnClickListener(this::setTimer); binding.time4.setOnClickListener(this::setTimer); + binding.time5.setOnClickListener(this::setTimer); + binding.time6.setOnClickListener(this::setTimer); } private void setTimer(View view) { diff --git a/app/src/mobile/java/com/fongmi/android/tv/ui/fragment/SettingFragment.java b/app/src/mobile/java/com/fongmi/android/tv/ui/fragment/SettingFragment.java index ecec6356..b64cf5e5 100644 --- a/app/src/mobile/java/com/fongmi/android/tv/ui/fragment/SettingFragment.java +++ b/app/src/mobile/java/com/fongmi/android/tv/ui/fragment/SettingFragment.java @@ -8,9 +8,11 @@ import android.text.SpannableString; import android.text.TextUtils; import android.text.style.ForegroundColorSpan; import android.text.style.RelativeSizeSpan; +import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.LinearLayout; import android.widget.TextView; import androidx.annotation.NonNull; @@ -101,7 +103,7 @@ public class SettingFragment extends BaseFragment implements ConfigCallback, Sit protected void initView() { setSourceHintText(mBinding.vodUrl, VodConfig.getDesc(), R.string.source_hint_setting); setSourceHintText(mBinding.liveUrl, LiveConfig.getDesc(), R.string.source_hint_live); - setSourceHintText(mBinding.wallUrl, WallConfig.getDesc(), R.string.source_hint_wall); + // setSourceHintText(mBinding.wallUrl, WallConfig.getDesc(), R.string.source_hint_wall); // 壁纸功能已移除 mBinding.versionText.setText(getString(R.string.setting_version) + " " + BuildConfig.VERSION_NAME); setOtherText(); @@ -115,7 +117,30 @@ public class SettingFragment extends BaseFragment implements ConfigCallback, Sit mBinding.dohText.setText(getDohList()[getDohIndex()]); mBinding.proxyText.setText(getProxy(Setting.getProxy())); mBinding.incognitoSwitch.setChecked(Setting.isIncognito()); + mBinding.liveTabVisibleSwitch.setChecked(Setting.isLiveTabVisible()); mBinding.sizeText.setText((size = ResUtil.getStringArray(R.array.select_size))[Setting.getSize()]); + setLiveSettingsVisibility(); + } + + private void setLiveSettingsVisibility() { + boolean isLiveTabVisible = !Setting.isLiveTabVisible(); // 注意:这里取反,因为开关是"隐藏直播" + + // 获取直播容器的布局参数 + LinearLayout.LayoutParams liveContainerParams = (LinearLayout.LayoutParams) mBinding.liveContainer.getLayoutParams(); + + if (isLiveTabVisible) { + // 直播开关打开:显示直播模块,间距为12dp + mBinding.liveContainer.setVisibility(View.VISIBLE); + liveContainerParams.topMargin = (int) TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, 12, getResources().getDisplayMetrics()); + } else { + // 直播开关关闭:隐藏直播模块,间距为0dp(这样视频模块和下一个模块之间会有正常间距) + mBinding.liveContainer.setVisibility(View.GONE); + liveContainerParams.topMargin = 0; + } + + // 应用布局参数 + mBinding.liveContainer.setLayoutParams(liveContainerParams); } private void setCacheText() { @@ -131,7 +156,7 @@ public class SettingFragment extends BaseFragment implements ConfigCallback, Sit protected void initEvent() { mBinding.vod.setOnClickListener(this::onVod); mBinding.live.setOnClickListener(this::onLive); - mBinding.wall.setOnClickListener(this::onWall); + // mBinding.wall.setOnClickListener(this::onWall); // 壁纸功能已移除 mBinding.proxy.setOnClickListener(this::onProxy); mBinding.cache.setOnClickListener(this::onCache); mBinding.backup.setOnClickListener(this::onBackup); @@ -143,13 +168,14 @@ public class SettingFragment extends BaseFragment implements ConfigCallback, Sit mBinding.vodHome.setOnClickListener(this::onVodHome); mBinding.live.setOnLongClickListener(this::onLiveEdit); mBinding.liveHome.setOnClickListener(this::onLiveHome); - mBinding.wall.setOnLongClickListener(this::onWallEdit); + // mBinding.wall.setOnLongClickListener(this::onWallEdit); // 壁纸功能已移除 mBinding.vodHistory.setOnClickListener(this::onVodHistory); mBinding.version.setOnLongClickListener(this::onVersionDev); mBinding.liveHistory.setOnClickListener(this::onLiveHistory); - mBinding.wallDefault.setOnClickListener(this::setWallDefault); - mBinding.wallRefresh.setOnClickListener(this::setWallRefresh); - mBinding.incognito.setOnClickListener(this::setIncognito); + // mBinding.wallDefault.setOnClickListener(this::setWallDefault); // 壁纸功能已移除 + // mBinding.wallRefresh.setOnClickListener(this::setWallRefresh); // 壁纸功能已移除 + mBinding.incognitoSwitch.setOnClickListener(this::setIncognito); + mBinding.liveTabVisibleSwitch.setOnClickListener(this::setLiveTabVisible); mBinding.size.setOnClickListener(this::setSize); mBinding.doh.setOnClickListener(this::setDoh); } @@ -200,9 +226,9 @@ public class SettingFragment extends BaseFragment implements ConfigCallback, Sit case 2: Notify.progress(getActivity()); WallConfig.load(config, getCallback(2)); - if (mBinding != null && mBinding.wallUrl != null) { - mBinding.wallUrl.setText(config.getDesc()); - } + // if (mBinding != null && mBinding.wallUrl != null) { // 壁纸功能已移除 + // mBinding.wallUrl.setText(config.getDesc()); + // } break; } } catch (Exception e) { @@ -241,7 +267,7 @@ public class SettingFragment extends BaseFragment implements ConfigCallback, Sit setSourceHintText(mBinding.liveUrl, LiveConfig.getDesc(), R.string.source_hint_live); break; case 2: - setSourceHintText(mBinding.wallUrl, WallConfig.getDesc(), R.string.source_hint_wall); + // setSourceHintText(mBinding.wallUrl, WallConfig.getDesc(), R.string.source_hint_wall); // 壁纸功能已移除 break; } } @@ -257,7 +283,7 @@ public class SettingFragment extends BaseFragment implements ConfigCallback, Sit RefreshEvent.config(); setSourceHintText(mBinding.vodUrl, VodConfig.getDesc(), R.string.source_hint_setting); setSourceHintText(mBinding.liveUrl, LiveConfig.getDesc(), R.string.source_hint_live); - setSourceHintText(mBinding.wallUrl, WallConfig.getDesc(), R.string.source_hint_wall); + // setSourceHintText(mBinding.wallUrl, WallConfig.getDesc(), R.string.source_hint_wall); // 壁纸功能已移除 break; case 1: setCacheText(); @@ -268,7 +294,7 @@ public class SettingFragment extends BaseFragment implements ConfigCallback, Sit case 2: setCacheText(); Notify.dismiss(); - setSourceHintText(mBinding.wallUrl, WallConfig.getDesc(), R.string.source_hint_wall); + // setSourceHintText(mBinding.wallUrl, WallConfig.getDesc(), R.string.source_hint_wall); // 壁纸功能已移除 break; } } @@ -379,7 +405,17 @@ public class SettingFragment extends BaseFragment implements ConfigCallback, Sit private void setIncognito(View view) { boolean isChecked = !Setting.isIncognito(); Setting.putIncognito(isChecked); - mBinding.incognitoSwitch.setChecked(isChecked); + // 不需要再次调用 setChecked,因为点击已经触发了状态变化 + } + + private void setLiveTabVisible(View view) { + boolean isChecked = !Setting.isLiveTabVisible(); + Setting.putLiveTabVisible(isChecked); + // 发送刷新事件,通知主界面更新导航栏 + RefreshEvent.config(); + // 更新直播设置项的可见性 + setLiveSettingsVisibility(); + // 不需要再次调用 setChecked,因为点击已经触发了状态变化 } private void setSize(View view) { @@ -473,7 +509,7 @@ public class SettingFragment extends BaseFragment implements ConfigCallback, Sit if (hidden) return; setSourceHintText(mBinding.vodUrl, VodConfig.getDesc(), R.string.source_hint_setting); setSourceHintText(mBinding.liveUrl, LiveConfig.getDesc(), R.string.source_hint_live); - setSourceHintText(mBinding.wallUrl, WallConfig.getDesc(), R.string.source_hint_wall); + // setSourceHintText(mBinding.wallUrl, WallConfig.getDesc(), R.string.source_hint_wall); // 壁纸功能已移除 setCacheText(); } diff --git a/app/src/mobile/java/com/fongmi/android/tv/utils/Timer.java b/app/src/mobile/java/com/fongmi/android/tv/utils/Timer.java index 8bb8d8f8..4c3debcb 100644 --- a/app/src/mobile/java/com/fongmi/android/tv/utils/Timer.java +++ b/app/src/mobile/java/com/fongmi/android/tv/utils/Timer.java @@ -59,7 +59,7 @@ public class Timer { public void delay() { cancel(); - set(TimeUnit.MINUTES.toMillis(5) + tick); + set(TimeUnit.MINUTES.toMillis(15) + tick); } public void reset() { diff --git a/app/src/mobile/res/drawable/shape_about_button.xml b/app/src/mobile/res/drawable/shape_about_button.xml index 4054da6e..4313bace 100644 --- a/app/src/mobile/res/drawable/shape_about_button.xml +++ b/app/src/mobile/res/drawable/shape_about_button.xml @@ -3,7 +3,7 @@ android:color="?attr/colorControlHighlight"> - + + + + + + + + + + + + + + + + diff --git a/app/src/mobile/res/drawable/shape_dialog_button_selected.xml b/app/src/mobile/res/drawable/shape_dialog_button_selected.xml index 9d879f5a..f1c10e66 100644 --- a/app/src/mobile/res/drawable/shape_dialog_button_selected.xml +++ b/app/src/mobile/res/drawable/shape_dialog_button_selected.xml @@ -3,7 +3,7 @@ android:color="?attr/colorControlHighlight"> - + - + - + + + + + + + + + + diff --git a/app/src/mobile/res/drawable/shape_timer_reset_button.xml b/app/src/mobile/res/drawable/shape_timer_reset_button.xml new file mode 100644 index 00000000..31e8dc58 --- /dev/null +++ b/app/src/mobile/res/drawable/shape_timer_reset_button.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/app/src/mobile/res/layout/dialog_about.xml b/app/src/mobile/res/layout/dialog_about.xml index 96daf87b..99686f8c 100644 --- a/app/src/mobile/res/layout/dialog_about.xml +++ b/app/src/mobile/res/layout/dialog_about.xml @@ -54,7 +54,7 @@ android:layout_marginTop="24dp" android:background="@drawable/shape_about_button" android:text="我的GitHub" - android:textColor="@color/white" + android:textColor="@color/black" android:textSize="14sp" android:padding="12dp"/> diff --git a/app/src/mobile/res/layout/dialog_buffer.xml b/app/src/mobile/res/layout/dialog_buffer.xml index 937f7993..0cdb1d7a 100644 --- a/app/src/mobile/res/layout/dialog_buffer.xml +++ b/app/src/mobile/res/layout/dialog_buffer.xml @@ -15,9 +15,12 @@ android:stepSize="1" android:valueFrom="1" android:valueTo="10" - app:thumbColor="@color/yellow_500" - app:tickVisible="false" - app:trackColorActive="@color/yellow_500" - app:trackColorInactive="@color/yellow_50" /> + app:thumbColor="@color/accent" + app:thumbRadius="10dp" + app:tickVisible="true" + app:tickColor="@color/black_50" + app:trackColorActive="@color/accent" + app:trackColorInactive="@color/white_20" + app:trackHeight="6dp" /> \ No newline at end of file diff --git a/app/src/mobile/res/layout/dialog_control.xml b/app/src/mobile/res/layout/dialog_control.xml index 306967c8..f7f1e4e1 100644 --- a/app/src/mobile/res/layout/dialog_control.xml +++ b/app/src/mobile/res/layout/dialog_control.xml @@ -8,12 +8,30 @@ android:padding="16dp" tools:background="@color/white"> - + android:orientation="horizontal" + android:gravity="center_vertical"> + + + + + + + app:thumbColor="@color/accent" + app:thumbRadius="10dp" + app:tickVisible="true" + app:tickColor="@color/black_50" + app:trackColorActive="@color/accent" + app:trackColorInactive="@color/white_20" + app:trackHeight="6dp" /> + app:trackColorInactive="@color/white_20" + app:trackHeight="6dp" /> \ No newline at end of file diff --git a/app/src/mobile/res/layout/dialog_timer.xml b/app/src/mobile/res/layout/dialog_timer.xml index 22c830a3..64ea3814 100644 --- a/app/src/mobile/res/layout/dialog_timer.xml +++ b/app/src/mobile/res/layout/dialog_timer.xml @@ -29,50 +29,80 @@ + android:textSize="14sp" + android:gravity="center" /> + android:textSize="14sp" + android:gravity="center" /> + android:textSize="14sp" + android:gravity="center" /> + android:textSize="14sp" + android:gravity="center" /> + + + + @@ -96,25 +126,41 @@ android:textStyle="bold" tools:text="5:00" /> - + android:textColor="@color/black" + android:textSize="14sp" /> - + android:textColor="?android:attr/textColorPrimary" + android:textSize="14sp" /> \ No newline at end of file diff --git a/app/src/mobile/res/layout/fragment_setting.xml b/app/src/mobile/res/layout/fragment_setting.xml index 3116e3eb..01cbfb2e 100644 --- a/app/src/mobile/res/layout/fragment_setting.xml +++ b/app/src/mobile/res/layout/fragment_setting.xml @@ -44,6 +44,7 @@ @@ -145,6 +146,7 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + diff --git a/app/src/mobile/res/values-zh-rCN/strings.xml b/app/src/mobile/res/values-zh-rCN/strings.xml index 71c38b40..d92adc03 100644 --- a/app/src/mobile/res/values-zh-rCN/strings.xml +++ b/app/src/mobile/res/values-zh-rCN/strings.xml @@ -43,7 +43,9 @@ 15 分钟 30 分钟 1 小时 - 延长 5 分钟 + 2 小时 + 3 小时 + 延长 15 分钟 取消定时器 diff --git a/app/src/mobile/res/values-zh-rTW/strings.xml b/app/src/mobile/res/values-zh-rTW/strings.xml index 82c8f6f2..b88d6a3f 100644 --- a/app/src/mobile/res/values-zh-rTW/strings.xml +++ b/app/src/mobile/res/values-zh-rTW/strings.xml @@ -41,7 +41,9 @@ 15 分鐘 30 分鐘 1 小時 - 延長 5 分鐘 + 2 小時 + 3 小時 + 延長 15 分鐘 取消定時器 diff --git a/app/src/mobile/res/values/colors.xml b/app/src/mobile/res/values/colors.xml index 042fc82e..2e8d80c8 100644 --- a/app/src/mobile/res/values/colors.xml +++ b/app/src/mobile/res/values/colors.xml @@ -5,5 +5,8 @@ #FFEB3B @color/white_80 #4DFFEB3B + #80FFFFFF + #80000000 + #4DFFFFFF \ No newline at end of file diff --git a/app/src/mobile/res/values/strings.xml b/app/src/mobile/res/values/strings.xml index 4e2e2dfe..6f3e684f 100644 --- a/app/src/mobile/res/values/strings.xml +++ b/app/src/mobile/res/values/strings.xml @@ -43,7 +43,9 @@ 15 minutes 30 minutes 1 hour - Add 5 minutes + 2 hours + 3 hours + Add 15 minutes Cancel timer diff --git a/build.gradle b/build.gradle index 4ed03919..8542f1e8 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ tasks.register('clean', Delete) { } project.ext { - gsonVersion = '2.13.1' - media3Version = '1.8.0' - okhttpVersion = '5.1.0' + gsonVersion = '2.11.0' + media3Version = '1.4.1' + okhttpVersion = '4.12.0' }