diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index ea6f3e5b..c5c20aec 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -153,30 +153,30 @@
+ android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" />
+ android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" />
+ android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" />
+ android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" />
+ android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" />
+ android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" />
+ android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem">
@@ -189,54 +189,54 @@
+ android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" />
+ android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" />
+ android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" />
+ android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" />
+ android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" />
+ android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" />
+ android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" />
+ android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" />
+ android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" />
+ android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" />
+ android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" />
+ android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" />
+ android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" />
diff --git a/app/src/main/java/com/futo/platformplayer/RootInsetsController.kt b/app/src/main/java/com/futo/platformplayer/RootInsetsController.kt
new file mode 100644
index 00000000..bf1d45ff
--- /dev/null
+++ b/app/src/main/java/com/futo/platformplayer/RootInsetsController.kt
@@ -0,0 +1,118 @@
+package com.futo.platformplayer
+
+import android.app.Activity
+import android.graphics.Color
+import android.os.Build
+import android.view.ViewGroup
+import android.view.Window
+import android.view.WindowManager
+import androidx.core.graphics.Insets
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowCompat
+import androidx.core.view.WindowInsetsCompat
+import androidx.core.view.WindowInsetsCompat.Type
+import androidx.core.view.WindowInsetsControllerCompat
+import androidx.core.view.doOnAttach
+import androidx.core.view.updatePadding
+import kotlin.math.max
+
+class RootInsetsController private constructor(
+ private val activity: Activity,
+ private val window: Window,
+ private val root: ViewGroup
+) {
+ private val controller by lazy { WindowInsetsControllerCompat(window, root) }
+
+ private val basePaddingLeft = root.paddingLeft
+ private val basePaddingTop = root.paddingTop
+ private val basePaddingRight = root.paddingRight
+ private val basePaddingBottom = root.paddingBottom
+
+ private var currentInsets: WindowInsetsCompat = WindowInsetsCompat.CONSUMED
+ private var fullscreen = false
+
+ init {
+ WindowCompat.setDecorFitsSystemWindows(window, false)
+ window.statusBarColor = Color.TRANSPARENT
+ window.navigationBarColor = Color.TRANSPARENT
+ controller.systemBarsBehavior =
+ WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
+
+ ViewCompat.setOnApplyWindowInsetsListener(root) { _, insets ->
+ currentInsets = insets
+ applyPadding()
+ insets
+ }
+
+ root.doOnAttach { ViewCompat.requestApplyInsets(root) }
+ }
+
+ private fun effectiveInsets(): Insets {
+ if (fullscreen) return Insets.NONE
+
+ val sys = currentInsets.getInsets(Type.systemBars())
+ val cut = currentInsets.getInsetsIgnoringVisibility(Type.displayCutout())
+ val portrait = activity.resources.configuration.orientation == android.content.res.Configuration.ORIENTATION_PORTRAIT
+
+ val top = if (portrait) max(sys.top, cut.top) else sys.top
+ return Insets.of(sys.left, top, sys.right, sys.bottom)
+ }
+
+
+ private fun applyPadding() {
+ val e = effectiveInsets()
+ root.updatePadding(
+ left = basePaddingLeft + e.left,
+ top = basePaddingTop + e.top,
+ right = basePaddingRight + e.right,
+ bottom = basePaddingBottom + e.bottom
+ )
+ }
+
+ private fun forceRelayoutAndInsets() {
+ root.post {
+ ViewCompat.requestApplyInsets(root)
+ applyPadding()
+ root.post {
+ ViewCompat.requestApplyInsets(root)
+ applyPadding()
+ }
+ }
+ }
+
+ fun enterFullscreen(allowCutoutShortEdges: Boolean = true) {
+ fullscreen = true
+ if (allowCutoutShortEdges) {
+ window.attributes = window.attributes.apply {
+ layoutInDisplayCutoutMode =
+ WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
+ }
+ }
+ controller.hide(Type.systemBars())
+ forceRelayoutAndInsets()
+ }
+
+ fun exitFullscreen() {
+ fullscreen = false
+ window.attributes = window.attributes.apply {
+ layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
+ }
+ controller.show(Type.systemBars())
+ forceRelayoutAndInsets()
+ }
+
+ fun onConfigurationChanged() {
+ forceRelayoutAndInsets()
+ }
+
+ fun setLightSystemBarAppearance(lightStatus: Boolean, lightNav: Boolean) {
+ controller.isAppearanceLightStatusBars = lightStatus
+ controller.isAppearanceLightNavigationBars = lightNav
+ }
+
+ companion object {
+ fun attach(activity: Activity, root: ViewGroup): RootInsetsController {
+ return RootInsetsController(activity, activity.window, root)
+ }
+ }
+}
diff --git a/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt b/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt
index d824d18c..2d56cb35 100644
--- a/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt
+++ b/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt
@@ -16,7 +16,6 @@ import android.os.StrictMode.VmPolicy
import android.util.Log
import android.util.TypedValue
import android.view.View
-import android.view.WindowManager
import android.widget.FrameLayout
import android.widget.ImageView
import androidx.activity.result.ActivityResult
@@ -36,6 +35,7 @@ import androidx.lifecycle.withStateAtLeast
import androidx.media3.common.util.UnstableApi
import com.futo.platformplayer.BuildConfig
import com.futo.platformplayer.R
+import com.futo.platformplayer.RootInsetsController
import com.futo.platformplayer.Settings
import com.futo.platformplayer.UIDialogs
import com.futo.platformplayer.api.http.ManagedHttpClient
@@ -199,6 +199,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
private var _privateModeEnabled = false
private var _pictureInPictureEnabled = false
private var _isFullscreen = false
+ private lateinit var _rootInsetsController: RootInsetsController
private val _urlQrCodeResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
val scanResult = IntentIntegrator.parseActivityResult(result.resultCode, result.data)
@@ -284,9 +285,6 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
}
setContentView(R.layout.activity_main);
setNavigationBarColorAndIcons();
- if (Settings.instance.playback.allowVideoToGoUnderCutout)
- window.attributes.layoutInDisplayCutoutMode =
- WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
runBlocking {
try {
@@ -301,6 +299,9 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
FragmentedStorage.get();
rootView = findViewById(R.id.rootView);
+ _rootInsetsController = RootInsetsController.attach(this, rootView)
+ _rootInsetsController.setLightSystemBarAppearance(lightStatus = false, lightNav = false)
+
_fragContainerTopBar = findViewById(R.id.fragment_top_bar);
_fragContainerMain = findViewById(R.id.fragment_main);
_fragContainerBotBar = findViewById(R.id.fragment_bottom_bar);
@@ -411,6 +412,11 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
Logger.i(TAG, "onFullscreenChanged ${it}");
_isFullscreen = it
updatePrivateModeVisibility()
+ if (it) {
+ _rootInsetsController.enterFullscreen(allowCutoutShortEdges = Settings.instance.playback.allowVideoToGoUnderCutout)
+ } else {
+ _rootInsetsController.exitFullscreen()
+ }
}
_fragVideoDetail.onMinimize.subscribe {
@@ -639,6 +645,11 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
private var _qrCodeLoadingDialog: AlertDialog? = null
+ override fun onConfigurationChanged(newConfig: Configuration) {
+ super.onConfigurationChanged(newConfig)
+ _rootInsetsController.onConfigurationChanged()
+ }
+
fun showUrlQrCodeScanner() {
try {
_qrCodeLoadingDialog = UIDialogs.showDialog(this, R.drawable.ic_loader_animated, true,
diff --git a/app/src/main/res/layout/activity_add_source.xml b/app/src/main/res/layout/activity_add_source.xml
index 469a4508..3b12e6c6 100644
--- a/app/src/main/res/layout/activity_add_source.xml
+++ b/app/src/main/res/layout/activity_add_source.xml
@@ -15,7 +15,6 @@
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
- android:paddingTop="20dp"
android:paddingBottom="15dp">
diff --git a/app/src/main/res/layout/activity_manage_tabs.xml b/app/src/main/res/layout/activity_manage_tabs.xml
index 986dfa11..77c8e90c 100644
--- a/app/src/main/res/layout/activity_manage_tabs.xml
+++ b/app/src/main/res/layout/activity_manage_tabs.xml
@@ -14,7 +14,6 @@
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
- android:paddingTop="20dp"
android:paddingBottom="15dp">
diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml
index 0c815387..a29ac552 100644
--- a/app/src/main/res/layout/activity_settings.xml
+++ b/app/src/main/res/layout/activity_settings.xml
@@ -17,7 +17,6 @@
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
- android:paddingTop="20dp"
android:paddingBottom="15dp">
diff --git a/app/src/main/res/layout/fragview_post_detail.xml b/app/src/main/res/layout/fragview_post_detail.xml
index eb800c5a..0748c17e 100644
--- a/app/src/main/res/layout/fragview_post_detail.xml
+++ b/app/src/main/res/layout/fragview_post_detail.xml
@@ -5,7 +5,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
- android:fitsSystemWindows="false"
android:background="@drawable/bottom_menu_border"
android:id="@+id/root"
android:clickable="true">
diff --git a/app/src/main/res/layout/fragview_video_detail.xml b/app/src/main/res/layout/fragview_video_detail.xml
index 7b8c1dc2..bf287eb9 100644
--- a/app/src/main/res/layout/fragview_video_detail.xml
+++ b/app/src/main/res/layout/fragview_video_detail.xml
@@ -5,7 +5,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
- android:fitsSystemWindows="false"
android:background="@drawable/bottom_menu_border"
android:id="@+id/videodetail_root"
android:clickable="true">
diff --git a/app/src/main/res/layout/fragview_web_detail.xml b/app/src/main/res/layout/fragview_web_detail.xml
index 1bf5d38a..2194126a 100644
--- a/app/src/main/res/layout/fragview_web_detail.xml
+++ b/app/src/main/res/layout/fragview_web_detail.xml
@@ -5,7 +5,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
- android:fitsSystemWindows="false"
android:background="@drawable/bottom_menu_border"
android:id="@+id/root"
android:clickable="true">
diff --git a/app/src/main/res/values-v29/themes.xml b/app/src/main/res/values-v29/themes.xml
new file mode 100644
index 00000000..735f2a4a
--- /dev/null
+++ b/app/src/main/res/values-v29/themes.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index 3f2b80c5..fe77ab0b 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -42,7 +42,8 @@
- @color/gray_30
- @color/black
- - @color/black
+ - @android:color/transparent
+ - @android:color/transparent
- @style/Theme.FutoVideo.ImageButton
- @style/Theme.FutoVideo.EditText
@@ -91,6 +92,16 @@
- false
- true
- true
+ - @color/black
+ - @color/black
+ - @color/black
+ - @color/transparent
+ - false
+ - false
+
+
+