Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions android/app/capacitor.build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ android {
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
dependencies {
implementation project(':capacitor-app')
implementation project(':capacitor-screen-orientation')
implementation project(':capacitor-status-bar')

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@
import top.imsyy.splayer.android.playback.AndroidNativePlaybackPlugin;

public class MainActivity extends BridgeActivity {
private static final String PREF_SHOW_STATUS_BAR = "androidShowStatusBar";
// 供 plugin 跨类引用,避免双源硬编码
public static final String PREF_SHOW_STATUS_BAR = "androidShowStatusBar";
/** 横屏沉浸式:同时隐藏状态栏与全面屏导航手势条 */
public static final String PREF_IMMERSIVE_LANDSCAPE = "immersiveLandscape";
/** 进程级 sweep 启动标记:Activity 重建(旋屏 / 配置变更)时不再重复 post Runnable。 */
private static volatile boolean sweepBootstrapped = false;

Expand All @@ -29,6 +32,17 @@ protected void onCreate(Bundle savedInstanceState) {
registerPlugin(AndroidDownloadPlugin.class);
registerPlugin(AndroidCachePlugin.class);
super.onCreate(savedInstanceState);
// 冷启动重置沉浸式 pref,避免强杀残留隐藏导航栏;旋屏重建(savedInstanceState != null)保留
if (savedInstanceState == null) {
try {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
if (prefs.getBoolean(PREF_IMMERSIVE_LANDSCAPE, false)) {
prefs.edit().putBoolean(PREF_IMMERSIVE_LANDSCAPE, false).apply();
}
} catch (Exception ignored) {
// pref 读写失败不阻塞启动
}
}
applyImmersiveMode();
// 音频预载 TTL:推迟到首帧后再初始化(构造期会同步读 SharedPreferences,冷启动加密磁盘可能耗百毫秒)。
// 这里 post 2s,startPeriodicSweep 内部再 postDelayed 5s,首次 sweep 实际 ≈7s 后开始;
Expand Down Expand Up @@ -64,13 +78,23 @@ private boolean shouldShowStatusBar() {
}
}

private boolean isImmersiveLandscape() {
try {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
return prefs.getBoolean(PREF_IMMERSIVE_LANDSCAPE, false);
} catch (Exception e) {
return false;
}
}

public void applyImmersiveMode() {
WindowCompat.setDecorFitsSystemWindows(getWindow(), false);

View decorView = getWindow().getDecorView();
WindowInsetsControllerCompat controller = WindowCompat.getInsetsController(getWindow(), decorView);
boolean immersiveLandscape = isImmersiveLandscape();
boolean showStatusBar = shouldShowStatusBar() && !immersiveLandscape;
if (controller != null) {
boolean showStatusBar = shouldShowStatusBar();
if (showStatusBar) {
controller.setSystemBarsBehavior(
WindowInsetsControllerCompat.BEHAVIOR_DEFAULT);
Expand All @@ -80,15 +104,26 @@ public void applyImmersiveMode() {
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
controller.hide(WindowInsetsCompat.Type.statusBars());
}
// 沉浸式才隐藏导航栏,其他场景始终显示
if (immersiveLandscape) {
controller.hide(WindowInsetsCompat.Type.navigationBars());
} else {
controller.show(WindowInsetsCompat.Type.navigationBars());
}
}

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
if (!shouldShowStatusBar()) {
if (!showStatusBar) {
flags |= View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
}
if (immersiveLandscape) {
flags |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
}
decorView.setSystemUiVisibility(flags);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package top.imsyy.splayer.android.playback;

import android.content.SharedPreferences;
import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.net.Uri;
import android.os.Build;
import android.preference.PreferenceManager;
Expand All @@ -22,6 +24,7 @@
import java.util.function.Supplier;
import org.json.JSONException;
import org.json.JSONObject;
import top.imsyy.splayer.android.MainActivity;
import top.imsyy.splayer.android.cache.AudioCacheProvider;

@CapacitorPlugin(
Expand Down Expand Up @@ -234,9 +237,39 @@ public void setShowStatusBar(PluginCall call) {
call,
() -> {
SharedPreferences prefs = android.preference.PreferenceManager.getDefaultSharedPreferences(getContext());
prefs.edit().putBoolean("androidShowStatusBar", show).apply();
if (getActivity() instanceof top.imsyy.splayer.android.MainActivity) {
((top.imsyy.splayer.android.MainActivity) getActivity()).applyImmersiveMode();
prefs.edit().putBoolean(MainActivity.PREF_SHOW_STATUS_BAR, show).apply();
Activity activity = getActivity();
if (activity instanceof MainActivity) {
((MainActivity) activity).applyImmersiveMode();
}
call.resolve();
});
}

/**
* 横屏沉浸式:active=true 用 SENSOR_LANDSCAPE 跟随设备翻转,
* active=false 用 UNSPECIFIED 释放(前端会再调 lockPortrait)。
*/
@PluginMethod
public void setImmersiveLandscape(PluginCall call) {
boolean active = call.getBoolean("active", false);
runOnMainThread(
call,
() -> {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
prefs.edit().putBoolean(MainActivity.PREF_IMMERSIVE_LANDSCAPE, active).apply();
Activity activity = getActivity();
if (activity == null) {
// Activity 已销毁但 plugin 尚未 detach,避免 NPE
call.reject("Activity unavailable");
return;
}
activity.setRequestedOrientation(
active
? ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
: ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
if (activity instanceof MainActivity) {
((MainActivity) activity).applyImmersiveMode();
}
call.resolve();
});
Expand Down
3 changes: 3 additions & 0 deletions android/capacitor.settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,8 @@ project(':capacitor-android').projectDir = new File('../node_modules/.pnpm/@capa
include ':capacitor-app'
project(':capacitor-app').projectDir = new File('../node_modules/.pnpm/@capacitor+app@8.0.0_@capacitor+core@8.2.0/node_modules/@capacitor/app/android')

include ':capacitor-screen-orientation'
project(':capacitor-screen-orientation').projectDir = new File('../node_modules/.pnpm/@capacitor+screen-orientation@7.0.4_@capacitor+core@8.2.0/node_modules/@capacitor/screen-orientation/android')

include ':capacitor-status-bar'
project(':capacitor-status-bar').projectDir = new File('../node_modules/.pnpm/@capacitor+status-bar@8.0.1_@capacitor+core@8.2.0/node_modules/@capacitor/status-bar/android')
3 changes: 3 additions & 0 deletions components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ declare module 'vue' {
FontManager: typeof import('./src/components/Modal/Setting/FontManager.vue')['default']
FullPlayer: typeof import('./src/components/Player/FullPlayer.vue')['default']
FullPlayerMobile: typeof import('./src/components/Player/FullPlayerMobile.vue')['default']
FullPlayerMobileLandscape: typeof import('./src/components/Player/FullPlayerMobileLandscape.vue')['default']
FullscreenPlayerManager: typeof import('./src/components/Modal/Setting/FullscreenPlayerManager.vue')['default']
HomePageSectionManager: typeof import('./src/components/Modal/Setting/HomePageSectionManager.vue')['default']
JumpArtist: typeof import('./src/components/Modal/JumpArtist.vue')['default']
Expand Down Expand Up @@ -136,6 +137,7 @@ declare module 'vue' {
NText: typeof import('naive-ui')['NText']
NThing: typeof import('naive-ui')['NThing']
NTree: typeof import('naive-ui')['NTree']
OrientationOverlay: typeof import('./src/components/Player/OrientationOverlay.vue')['default']
PersonalFM: typeof import('./src/components/Player/PlayerComponents/PersonalFM.vue')['default']
PlayerBackground: typeof import('./src/components/Player/PlayerMeta/PlayerBackground.vue')['default']
PlayerComment: typeof import('./src/components/Player/PlayerComponents/PlayerComment.vue')['default']
Expand All @@ -145,6 +147,7 @@ declare module 'vue' {
PlayerLyric: typeof import('./src/components/Player/PlayerLyric/index.vue')['default']
PlayerMenu: typeof import('./src/components/Player/PlayerMenu.vue')['default']
PlayerProvider: typeof import('./src/components/Global/PlayerProvider.vue')['default']
PlayerQuickActionsMenu: typeof import('./src/components/Player/PlayerQuickActionsMenu.vue')['default']
PlayerRightMenu: typeof import('./src/components/Player/PlayerRightMenu.vue')['default']
PlayerSlider: typeof import('./src/components/Player/PlayerComponents/PlayerSlider.vue')['default']
PlayerSpectrum: typeof import('./src/components/Player/PlayerComponents/PlayerSpectrum.vue')['default']
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"@capacitor/android": "^8.0.0",
"@capacitor/app": "8.0.0",
"@capacitor/core": "^8.0.0",
"@capacitor/screen-orientation": "^7.0.4",
"@capacitor/status-bar": "^8.0.0",
"@imsyy/color-utils": "^1.0.2",
"@material/material-color-utilities": "^0.4.0",
Expand Down
12 changes: 12 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading