diff --git a/app/build.gradle b/app/build.gradle index cb898a7c..d7eafffb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -23,7 +23,7 @@ android { //noinspection ExpiredTargetSdkVersion targetSdk 28 versionCode 305 - versionName "3.0.5" + versionName "3.0.6" javaCompileOptions { annotationProcessorOptions { arguments = ["room.schemaLocation": "$projectDir/schemas".toString(), "eventBusIndex": "com.fongmi.android.tv.event.EventIndex"] 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 15c9c8a5..f911e04f 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/Updater.java +++ b/app/src/leanback/java/com/fongmi/android/tv/Updater.java @@ -72,6 +72,11 @@ public class Updater implements Download.Callback { } public void start(Activity activity) { + // 检查是否启用启动时自动检查更新 + if (!Setting.getAutoUpdateCheck()) { + Logger.d("Auto update check is disabled"); + return; + } App.execute(() -> doInBackground(activity)); } diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/dialog/SiteDialog.java b/app/src/leanback/java/com/fongmi/android/tv/ui/dialog/SiteDialog.java index 58ae20b3..0a548e4e 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/dialog/SiteDialog.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/dialog/SiteDialog.java @@ -98,8 +98,8 @@ public class SiteDialog implements SiteAdapter.OnClickListener { if (!binding.mode.hasFocus()) { binding.recycler.post(() -> { binding.recycler.scrollToPosition(VodConfig.getHomeIndex()); - // 清除焦点,避免滚动后自动获得焦点显示黄色背景 - binding.recycler.post(() -> binding.recycler.clearFocus()); + // 请求焦点,确保选中项保持高亮状态 + binding.recycler.post(() -> binding.recycler.requestFocus()); }); } } diff --git a/app/src/leanback/res/color/button_text.xml b/app/src/leanback/res/color/button_text.xml index b072c564..1c94af07 100644 --- a/app/src/leanback/res/color/button_text.xml +++ b/app/src/leanback/res/color/button_text.xml @@ -1,5 +1,8 @@ + + + \ No newline at end of file diff --git a/app/src/leanback/res/layout/adapter_site.xml b/app/src/leanback/res/layout/adapter_site.xml index a189d31b..9c2c0b88 100644 --- a/app/src/leanback/res/layout/adapter_site.xml +++ b/app/src/leanback/res/layout/adapter_site.xml @@ -19,6 +19,7 @@ android:singleLine="true" android:textColor="@color/button_text" android:textSize="18sp" + android:duplicateParentState="true" tools:text="泥巴" /> TimeUnit.HOURS.toMillis(3)) { timeBar.setKeyTimeIncrement(TimeUnit.MINUTES.toMillis(5)); } else if (duration > TimeUnit.MINUTES.toMillis(30)) { @@ -124,8 +132,19 @@ public class CustomSeekView extends FrameLayout implements TimeBar.OnScrubListen } private void seekToTimeBarPosition(long positionMs) { + // 先设置播放位置 player.seekTo(positionMs); - refresh(); + // 延迟刷新进度条,确保播放器已经处理了跳转操作 + removeCallbacks(refresh); + postDelayed(() -> { + refresh(); + // 确保进度条位置与实际播放位置一致 + long actualPosition = player.getPosition(); + if (Math.abs(actualPosition - positionMs) > 100) { // 如果差异超过100ms,再次调整 + timeBar.setPosition(actualPosition); + positionView.setText(player.stringToTime(actualPosition)); + } + }, 50); // 延迟50ms刷新 } @Override @@ -148,6 +167,16 @@ public class CustomSeekView extends FrameLayout implements TimeBar.OnScrubListen @Override public void onScrubStop(@NonNull TimeBar timeBar, long position, boolean canceled) { scrubbing = false; - if (!canceled) seekToTimeBarPosition(position); + if (!canceled) { + // 先隐藏进度条提示,避免用户看到不一致的状态 + // 注意:这里不能直接访问mBinding.widget.seek,因为CustomSeekView不包含这个引用 + // 这个优化将在VideoActivity的onSeekEnd方法中实现 + // 调整播放位置 + seekToTimeBarPosition(position); + // 确保播放状态正确 + if (!player.isPlaying()) { + player.play(); + } + } } } diff --git a/app/src/main/res/drawable/ic_m3_account_circle.xml b/app/src/main/res/drawable/ic_m3_account_circle.xml new file mode 100644 index 00000000..2b120a72 --- /dev/null +++ b/app/src/main/res/drawable/ic_m3_account_circle.xml @@ -0,0 +1,11 @@ + + + + diff --git a/app/src/main/res/drawable/ic_m3_incognito.xml b/app/src/main/res/drawable/ic_m3_incognito.xml new file mode 100644 index 00000000..70ac577f --- /dev/null +++ b/app/src/main/res/drawable/ic_m3_incognito.xml @@ -0,0 +1,11 @@ + + + + diff --git a/app/src/main/res/drawable/ic_m3_incognito_outline.xml b/app/src/main/res/drawable/ic_m3_incognito_outline.xml new file mode 100644 index 00000000..d8ab3839 --- /dev/null +++ b/app/src/main/res/drawable/ic_m3_incognito_outline.xml @@ -0,0 +1,11 @@ + + + + diff --git a/app/src/main/res/drawable/ic_m3_list_alt.xml b/app/src/main/res/drawable/ic_m3_list_alt.xml new file mode 100644 index 00000000..e7284765 --- /dev/null +++ b/app/src/main/res/drawable/ic_m3_list_alt.xml @@ -0,0 +1,11 @@ + + + + diff --git a/app/src/main/res/drawable/ic_m3_person_add.xml b/app/src/main/res/drawable/ic_m3_person_add.xml new file mode 100644 index 00000000..bd9ba29f --- /dev/null +++ b/app/src/main/res/drawable/ic_m3_person_add.xml @@ -0,0 +1,11 @@ + + + + diff --git a/app/src/main/res/drawable/ic_m3_photo_size.xml b/app/src/main/res/drawable/ic_m3_photo_size.xml new file mode 100644 index 00000000..fc67b6cd --- /dev/null +++ b/app/src/main/res/drawable/ic_m3_photo_size.xml @@ -0,0 +1,11 @@ + + + + diff --git a/app/src/main/res/drawable/ic_m3_photo_size_outline.xml b/app/src/main/res/drawable/ic_m3_photo_size_outline.xml new file mode 100644 index 00000000..024a586d --- /dev/null +++ b/app/src/main/res/drawable/ic_m3_photo_size_outline.xml @@ -0,0 +1,11 @@ + + + + diff --git a/app/src/main/res/drawable/ic_m3_private_connectivity.xml b/app/src/main/res/drawable/ic_m3_private_connectivity.xml new file mode 100644 index 00000000..743bd318 --- /dev/null +++ b/app/src/main/res/drawable/ic_m3_private_connectivity.xml @@ -0,0 +1,11 @@ + + + + diff --git a/app/src/main/res/drawable/ic_m3_videocam_outline.xml b/app/src/main/res/drawable/ic_m3_videocam_outline.xml new file mode 100644 index 00000000..2feb392c --- /dev/null +++ b/app/src/main/res/drawable/ic_m3_videocam_outline.xml @@ -0,0 +1,11 @@ + + + + diff --git a/app/src/main/res/drawable/ic_m3_visibility_off.xml b/app/src/main/res/drawable/ic_m3_visibility_off.xml new file mode 100644 index 00000000..6376501e --- /dev/null +++ b/app/src/main/res/drawable/ic_m3_visibility_off.xml @@ -0,0 +1,11 @@ + + + + diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 4e9c85c0..dba4bde6 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -125,7 +125,7 @@ 修改 确定 取消 - 从剪贴板粘贴 + 点我粘贴 请输入接口… 请输入名称… 请输入地址… diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index dbf97e81..446523b1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -91,7 +91,7 @@ Choose Off On - v3.0.3 + v3.0.6 View on GitHub @@ -126,7 +126,7 @@ Edit OK Cancel - Paste from clipboard + Click to paste Please enter the config… Please enter the name… Please enter the url… 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 d6c1718d..09180293 100644 --- a/app/src/mobile/java/com/fongmi/android/tv/Updater.java +++ b/app/src/mobile/java/com/fongmi/android/tv/Updater.java @@ -32,6 +32,7 @@ public class Updater implements Download.Callback { private AlertDialog dialog; private boolean dev; private String downloadUrl; + private boolean forceCheck; // 标记是否是用户主动检查更新 private File getFile() { return Path.cache("update.apk"); @@ -60,6 +61,7 @@ public class Updater implements Download.Callback { public Updater force() { Notify.show(R.string.update_check); Setting.putUpdate(true); + this.forceCheck = true; // 标记为用户主动检查更新 return this; } @@ -160,7 +162,10 @@ public class Updater implements Download.Callback { Logger.d("Already latest version: " + tagName); } else { // 未找到对应的APK文件 - App.post(() -> Notify.show("检查更新完成,未找到适合此设备的安装包")); + // 只在用户主动检查更新时显示提示 + if (forceCheck) { + App.post(() -> Notify.show("检查更新完成,未找到适合此设备的安装包")); + } Logger.d("APK not found for this device"); } } catch (Exception e) { diff --git a/app/src/mobile/java/com/fongmi/android/tv/ui/activity/VideoActivity.java b/app/src/mobile/java/com/fongmi/android/tv/ui/activity/VideoActivity.java index 823cf07b..aa5f0e63 100644 --- a/app/src/mobile/java/com/fongmi/android/tv/ui/activity/VideoActivity.java +++ b/app/src/mobile/java/com/fongmi/android/tv/ui/activity/VideoActivity.java @@ -30,6 +30,7 @@ import android.view.WindowManager; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; +import java.util.concurrent.TimeUnit; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -1465,6 +1466,55 @@ public class VideoActivity extends BaseActivity implements Clock.Callback, Custo this.rotate = rotate; if (fullscreen && rotate) noPadding(mBinding.control.getRoot()); if (fullscreen && !rotate) setPadding(mBinding.control.getRoot()); + // 检测屏幕方向变化并处理 + onOrientationChanged(); + } + + // 添加屏幕方向变化处理方法 + private void onOrientationChanged() { + if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { + // 切换到横屏模式 + onLandscapeMode(); + } else { + // 切换到竖屏模式 + onPortraitMode(); + } + } + + private void onLandscapeMode() { + // 横屏模式下的特殊处理 + // 调整进度条的敏感度 + if (mPlayers != null) { + long duration = mPlayers.getDuration(); + if (duration > TimeUnit.MINUTES.toMillis(30)) { + mBinding.control.seek.setKeyTimeIncrement(TimeUnit.MINUTES.toMillis(1)); + } else if (duration > TimeUnit.MINUTES.toMillis(10)) { + mBinding.control.seek.setKeyTimeIncrement(TimeUnit.SECONDS.toMillis(30)); + } else if (duration > 0) { + mBinding.control.seek.setKeyTimeIncrement(TimeUnit.SECONDS.toMillis(15)); + } + } + + // 确保进度条状态正确 + if (mPlayers != null) { + long position = mPlayers.getPosition(); + long duration = mPlayers.getDuration(); + if (position > 0 && duration > 0) { + mBinding.control.seek.setPosition(position); + mBinding.control.seek.setDuration(duration); + } + } + } + + private void onPortraitMode() { + // 竖屏模式下的处理 + // 恢复进度条的默认敏感度 + if (mPlayers != null) { + long duration = mPlayers.getDuration(); + if (duration > 0) { + mBinding.control.seek.setKeyTimeIncrement(duration); + } + } } public boolean isStop() { @@ -1566,10 +1616,40 @@ public class VideoActivity extends BaseActivity implements Clock.Callback, Custo @Override public void onSeekEnd(long time) { - mBinding.widget.seek.setVisibility(View.GONE); - mPlayers.seek(time); - showProgress(); - onPlay(); + handleLandscapeSeek(time); + } + + // 添加新的方法,处理横屏模式下的特殊逻辑 + private void handleLandscapeSeek(long time) { + if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { + // 横屏模式下的特殊处理 + mBinding.widget.seek.setVisibility(View.GONE); + mPlayers.pause(); + mPlayers.seek(time); + showProgress(); + App.post(() -> { + long actualPosition = mPlayers.getPosition(); + if (Math.abs(actualPosition - time) > 500) { + mPlayers.seek(time); + } + onPlay(); + hideProgress(); + }, 150); // 横屏模式下延迟更长,确保跳转完成 + } else { + // 竖屏模式使用原有逻辑 + mBinding.widget.seek.setVisibility(View.GONE); + mPlayers.pause(); + mPlayers.seek(time); + showProgress(); + App.post(() -> { + long actualPosition = mPlayers.getPosition(); + if (Math.abs(actualPosition - time) > 500) { + mPlayers.seek(time); + } + onPlay(); + hideProgress(); + }, 100); // 竖屏模式下延迟较短 + } } @Override diff --git a/app/src/mobile/java/com/fongmi/android/tv/ui/custom/CustomKeyDownVod.java b/app/src/mobile/java/com/fongmi/android/tv/ui/custom/CustomKeyDownVod.java index ce371d73..935d029b 100644 --- a/app/src/mobile/java/com/fongmi/android/tv/ui/custom/CustomKeyDownVod.java +++ b/app/src/mobile/java/com/fongmi/android/tv/ui/custom/CustomKeyDownVod.java @@ -8,6 +8,7 @@ import android.view.MotionEvent; import android.view.ScaleGestureDetector; import android.view.View; import android.view.WindowManager; +import android.content.res.Configuration; import androidx.annotation.NonNull; @@ -109,6 +110,17 @@ public class CustomKeyDownVod extends GestureDetector.SimpleOnGestureListener im if (isEdge(e1) || changeScale || lock || e1.getPointerCount() > 1) return true; float deltaX = e2.getX() - e1.getX(); float deltaY = e1.getY() - e2.getY(); + + // 在横屏模式下,调整触摸事件的处理逻辑 + if (activity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { + // 横屏模式下,增加对水平滑动的敏感度 + if (Math.abs(deltaX) > Math.abs(deltaY) * 0.5f) { + if (touch) checkFunc(distanceX, distanceY, e2); + if (changeTime) listener.onSeek(time = (long) (deltaX * 50)); + return true; + } + } + if (touch) checkFunc(distanceX, distanceY, e2); if (changeTime) listener.onSeek(time = (long) (deltaX * 50)); if (changeBright) setBright(deltaY); @@ -145,9 +157,32 @@ public class CustomKeyDownVod extends GestureDetector.SimpleOnGestureListener im private void checkFunc(float distanceX, float distanceY, MotionEvent e2) { int four = ResUtil.getScreenWidth(activity) / 4; - if (e2.getX() > four && e2.getX() < four * 3) center = true; - else if (Math.abs(distanceX) < Math.abs(distanceY)) checkSide(e2); - if (Math.abs(distanceX) >= Math.abs(distanceY)) changeTime = true; + + // 在横屏模式下,调整中心区域的判断 + if (activity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { + // 横屏模式下,扩大中心区域,更容易触发进度条调整 + int centerStart = ResUtil.getScreenWidth(activity) / 3; + int centerEnd = ResUtil.getScreenWidth(activity) * 2 / 3; + if (e2.getX() > centerStart && e2.getX() < centerEnd) { + center = true; + } else if (Math.abs(distanceX) < Math.abs(distanceY)) { + checkSide(e2); + } + // 横屏模式下,降低触发进度条调整的阈值 + if (Math.abs(distanceX) >= Math.abs(distanceY) * 0.7f) { + changeTime = true; + } + } else { + // 竖屏模式保持原有逻辑 + if (e2.getX() > four && e2.getX() < four * 3) { + center = true; + } else if (Math.abs(distanceX) < Math.abs(distanceY)) { + checkSide(e2); + } + if (Math.abs(distanceX) >= Math.abs(distanceY)) { + changeTime = true; + } + } touch = false; } diff --git a/app/src/mobile/java/com/fongmi/android/tv/ui/dialog/ConfigDialog.java b/app/src/mobile/java/com/fongmi/android/tv/ui/dialog/ConfigDialog.java index 16776a2f..d32f3e33 100644 --- a/app/src/mobile/java/com/fongmi/android/tv/ui/dialog/ConfigDialog.java +++ b/app/src/mobile/java/com/fongmi/android/tv/ui/dialog/ConfigDialog.java @@ -21,6 +21,7 @@ import com.fongmi.android.tv.api.config.WallConfig; import com.fongmi.android.tv.bean.Config; import com.fongmi.android.tv.databinding.DialogConfigBinding; import com.fongmi.android.tv.impl.ConfigCallback; +import com.fongmi.android.tv.impl.Callback; import com.fongmi.android.tv.ui.custom.CustomTextListener; import com.fongmi.android.tv.utils.FileChooser; import com.google.android.material.dialog.MaterialAlertDialogBuilder; @@ -156,7 +157,63 @@ public class ConfigDialog { } // 只有URL不为空时,才设置配置 + // 保存原始URL,以便在添加失败时恢复 + String originalUrl = ori; callback.setConfig(Config.find(url, type)); + + // 添加一个延迟检查,如果配置没有成功加载,则恢复原始URL + new android.os.Handler().postDelayed(() -> { + // 检查配置是否成功加载 + Config currentConfig = getConfig(); + if (currentConfig == null || !currentConfig.getUrl().equals(url)) { + // 配置加载失败,恢复原始URL + if (!TextUtils.isEmpty(originalUrl)) { + // 如果有原始URL,恢复原始URL + callback.setConfig(Config.find(originalUrl, type)); + } else { + // 如果没有原始URL,设置为空 + switch (type) { + case 0: + VodConfig.get().clear().config(Config.vod()).load(new Callback() { + @Override + public void success() {} + + @Override + public void success(String result) {} + + @Override + public void error(String msg) {} + }); + break; + case 1: + LiveConfig.get().clear().config(Config.live()).load(new Callback() { + @Override + public void success() {} + + @Override + public void success(String result) {} + + @Override + public void error(String msg) {} + }); + break; + case 2: + WallConfig.get().clear().config(Config.wall()).load(new Callback() { + @Override + public void success() {} + + @Override + public void success(String result) {} + + @Override + public void error(String msg) {} + }); + break; + } + } + } + }, 2000); // 2秒后检查 + dialog.dismiss(); } diff --git a/catvod/src/main/java/com/github/catvod/utils/Logger.java b/catvod/src/main/java/com/github/catvod/utils/Logger.java new file mode 100644 index 00000000..fea62587 --- /dev/null +++ b/catvod/src/main/java/com/github/catvod/utils/Logger.java @@ -0,0 +1,35 @@ +package com.github.catvod.utils; + +import android.util.Log; + +public class Logger { + private static final String TAG = "XMBOX"; + + public static void d(String msg) { + Log.d(TAG, msg); + } + + public static void e(String msg) { + Log.e(TAG, msg); + } + + public static void e(String msg, Throwable tr) { + Log.e(TAG, msg, tr); + } + + public static void i(String msg) { + Log.i(TAG, msg); + } + + public static void v(String msg) { + Log.v(TAG, msg); + } + + public static void w(String msg) { + Log.w(TAG, msg); + } + + public static void w(String msg, Throwable tr) { + Log.w(TAG, msg, tr); + } +}