diff --git a/android/app/src/main/kotlin/com/example/piliplus/MainActivity.kt b/android/app/src/main/kotlin/com/example/piliplus/MainActivity.kt index 21d46b470..28dcbd39f 100644 --- a/android/app/src/main/kotlin/com/example/piliplus/MainActivity.kt +++ b/android/app/src/main/kotlin/com/example/piliplus/MainActivity.kt @@ -10,6 +10,7 @@ import android.content.pm.ShortcutInfo import android.content.pm.ShortcutManager import android.content.res.Configuration import android.graphics.BitmapFactory +import android.graphics.Point import android.graphics.drawable.Icon import android.os.Build import android.os.Bundle @@ -20,6 +21,7 @@ import androidx.core.net.toUri import com.ryanheise.audioservice.AudioServiceActivity import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodChannel +import kotlin.math.roundToInt import kotlin.system.exitProcess import java.io.File @@ -171,6 +173,31 @@ class MainActivity : AudioServiceActivity() { } } + "maxScreenSize" -> { + try { + val density = resources.displayMetrics.density + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + val maxBounds = windowManager.maximumWindowMetrics.bounds + result.success( + mapOf( + "maxWidth" to (maxBounds.width() / density).roundToInt(), + "maxHeight" to (maxBounds.height() / density).roundToInt(), + ) + ) + } else { + val realSizePoint = Point() + windowManager.defaultDisplay.getRealSize(realSizePoint) + result.success( + mapOf( + "maxWidth" to (realSizePoint.x / density).roundToInt(), + "maxHeight" to (realSizePoint.y / density).roundToInt(), + ) + ) + } + } catch (e: Exception) { + } + } + else -> result.notImplemented() } } diff --git a/lib/main.dart b/lib/main.dart index 92f018767..5af902a2c 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -20,6 +20,7 @@ import 'package:PiliPlus/utils/date_utils.dart'; import 'package:PiliPlus/utils/extension/iterable_ext.dart'; import 'package:PiliPlus/utils/extension/theme_ext.dart'; import 'package:PiliPlus/utils/json_file_handler.dart'; +import 'package:PiliPlus/utils/max_screen_size.dart'; import 'package:PiliPlus/utils/path_utils.dart'; import 'package:PiliPlus/utils/platform_utils.dart'; import 'package:PiliPlus/utils/request_utils.dart'; @@ -111,7 +112,7 @@ void main() async { if (PlatformUtils.isMobile) { await Future.wait([ - if (Platform.isAndroid) _initSdkInt(), + if (Platform.isAndroid) ...[_initSdkInt(), MaxScreenSize.init()], if (Pref.horizontalScreen) ?fullMode() else ?portraitUpMode(), setupServiceLocator(), ]); diff --git a/lib/pages/live_room/view.dart b/lib/pages/live_room/view.dart index 5fafa3646..37d78c54d 100644 --- a/lib/pages/live_room/view.dart +++ b/lib/pages/live_room/view.dart @@ -39,6 +39,7 @@ import 'package:PiliPlus/utils/extension/num_ext.dart'; import 'package:PiliPlus/utils/extension/size_ext.dart'; import 'package:PiliPlus/utils/extension/theme_ext.dart'; import 'package:PiliPlus/utils/image_utils.dart'; +import 'package:PiliPlus/utils/max_screen_size.dart'; import 'package:PiliPlus/utils/mobile_observer.dart'; import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/platform_utils.dart'; @@ -100,6 +101,10 @@ class _LiveRoomPageState extends State final size = MediaQuery.sizeOf(context); maxWidth = size.width; maxHeight = size.height; + isWindowMode = MaxScreenSize.isWindowMode( + width: maxWidth, + height: maxHeight, + ); isPortrait = size.isPortrait; plPlayerController.screenRatio = maxHeight / maxWidth; } @@ -194,6 +199,7 @@ class _LiveRoomPageState extends State late double maxWidth; late double maxHeight; + bool isWindowMode = false; late EdgeInsets padding; late bool isPortrait; @@ -402,7 +408,7 @@ class _LiveRoomPageState extends State primary: !plPlayerController.removeSafeArea, resizeToAvoidBottomInset: false, backgroundColor: Colors.transparent, - appBar: isFullScreen && !isPortrait + appBar: isWindowMode && isFullScreen && !isPortrait ? null : _buildAppBar(isFullScreen), body: isPortrait @@ -424,7 +430,7 @@ class _LiveRoomPageState extends State Widget _buildPH(bool isFullScreen) { final height = maxWidth / Style.aspectRatio16x9; final videoHeight = isFullScreen - ? maxHeight - (isPortrait ? padding.top : 0) + ? maxHeight - (isWindowMode && !isPortrait ? 0 : padding.top) : height; final bottomHeight = maxHeight - padding.top - height - kToolbarHeight; return Column( @@ -453,7 +459,7 @@ class _LiveRoomPageState extends State Widget _buildPP(bool isFullScreen) { final bottomHeight = 70 + padding.bottom; final videoHeight = isFullScreen - ? maxHeight - (isPortrait ? padding.top : 0) + ? maxHeight - (isWindowMode && !isPortrait ? 0 : padding.top) : maxHeight - bottomHeight; return Stack( clipBehavior: Clip.none, @@ -707,7 +713,7 @@ class _LiveRoomPageState extends State final videoHeight = maxHeight - padding.top - kToolbarHeight; final width = isFullScreen ? maxWidth : videoWidth; final height = isFullScreen - ? maxHeight - (isPortrait ? padding.top : 0) + ? maxHeight - (isWindowMode && !isPortrait ? 0 : padding.top) : videoHeight; return Padding( padding: isFullScreen diff --git a/lib/pages/video/view.dart b/lib/pages/video/view.dart index 660816ed5..c37eeb016 100644 --- a/lib/pages/video/view.dart +++ b/lib/pages/video/view.dart @@ -55,6 +55,7 @@ import 'package:PiliPlus/utils/extension/num_ext.dart'; import 'package:PiliPlus/utils/extension/scroll_controller_ext.dart'; import 'package:PiliPlus/utils/extension/theme_ext.dart'; import 'package:PiliPlus/utils/image_utils.dart'; +import 'package:PiliPlus/utils/max_screen_size.dart'; import 'package:PiliPlus/utils/mobile_observer.dart'; import 'package:PiliPlus/utils/num_utils.dart'; import 'package:PiliPlus/utils/page_utils.dart'; @@ -453,6 +454,10 @@ class _VideoDetailPageVState extends State final size = MediaQuery.sizeOf(context); maxWidth = size.width; maxHeight = size.height; + isWindowMode = MaxScreenSize.isWindowMode( + width: maxWidth, + height: maxHeight, + ); videoDetailController.plPlayerController.screenRatio = maxHeight / maxWidth; final shortestSide = size.shortestSide; @@ -471,8 +476,9 @@ class _VideoDetailPageVState extends State : Theme.of(context); } - bool get removeAppBar => - videoDetailController.removeSafeArea || (isFullScreen && !isPortrait); + bool removeAppBar(bool isFullScreen) => + videoDetailController.removeSafeArea || + (isWindowMode && isFullScreen && !isPortrait); Widget get childWhenDisabled { return Obx( @@ -480,7 +486,7 @@ class _VideoDetailPageVState extends State final isFullScreen = this.isFullScreen; return Scaffold( resizeToAvoidBottomInset: false, - appBar: removeAppBar + appBar: removeAppBar(isFullScreen) ? null : PreferredSize( preferredSize: const Size.fromHeight(0), @@ -520,7 +526,7 @@ class _VideoDetailPageVState extends State onlyOneScrollInBody: true, pinnedHeaderSliverHeightBuilder: () { double pinnedHeight = this.isFullScreen || !isPortrait - ? maxHeight - (isPortrait ? padding.top : 0) + ? maxHeight - (isWindowMode && !isPortrait ? 0 : padding.top) : videoDetailController.isExpanding || videoDetailController.isCollapsing ? videoDetailController.animHeight @@ -546,7 +552,7 @@ class _VideoDetailPageVState extends State }, headerSliverBuilder: (context, innerBoxIsScrolled) { final height = isFullScreen || !isPortrait - ? maxHeight - (isPortrait ? padding.top : 0) + ? maxHeight - (isWindowMode && !isPortrait ? 0 : padding.top) : videoDetailController.isExpanding || videoDetailController.isCollapsing ? videoDetailController.animHeight @@ -782,7 +788,7 @@ class _VideoDetailPageVState extends State final isFullScreen = this.isFullScreen; return Scaffold( resizeToAvoidBottomInset: false, - appBar: removeAppBar + appBar: removeAppBar(isFullScreen) ? null : AppBar(backgroundColor: Colors.black, toolbarHeight: 0), body: Padding( @@ -923,7 +929,7 @@ class _VideoDetailPageVState extends State final videoWidth = isFullScreen ? maxWidth : width; final double height = width / Style.aspectRatio16x9; final videoHeight = isFullScreen - ? maxHeight - (isPortrait ? padding.top : 0) + ? maxHeight - (isWindowMode && !isPortrait ? 0 : padding.top) : height; if (height > maxHeight) { return childSplit(Style.aspectRatio16x9); @@ -1017,7 +1023,7 @@ class _VideoDetailPageVState extends State final isFullScreen = this.isFullScreen; return Scaffold( resizeToAvoidBottomInset: false, - appBar: removeAppBar + appBar: removeAppBar(isFullScreen) ? null : AppBar(backgroundColor: Colors.black, toolbarHeight: 0), body: Padding( @@ -1049,7 +1055,7 @@ class _VideoDetailPageVState extends State final shouldShowSeasonPanel = _shouldShowSeasonPanel; final double height = maxHeight / 2.5; final videoHeight = isFullScreen - ? maxHeight - (isPortrait ? padding.top : 0) + ? maxHeight - (isWindowMode && !isPortrait ? 0 : padding.top) : height; final bottomHeight = maxHeight - height - padding.top; return Column( @@ -1298,6 +1304,7 @@ class _VideoDetailPageVState extends State late bool isPortrait; late double maxWidth; late double maxHeight; + bool isWindowMode = false; late EdgeInsets padding; @override diff --git a/lib/utils/max_screen_size.dart b/lib/utils/max_screen_size.dart new file mode 100644 index 000000000..bd9b04d3e --- /dev/null +++ b/lib/utils/max_screen_size.dart @@ -0,0 +1,25 @@ +import 'dart:io' show Platform; + +import 'package:PiliPlus/utils/utils.dart'; + +abstract final class MaxScreenSize { + static int? _maxWidth; + static int? _maxHeight; + + static Future init() async { + final res = await Utils.channel.invokeMethod('maxScreenSize'); + if (res is Map) { + _maxWidth = res['maxWidth']; + _maxHeight = res['maxHeight']; + } + } + + static bool isWindowMode({required num width, required num height}) { + if (!Platform.isAndroid) return false; + width = width.round(); + height = height.round(); + final hasWidthMatch = width == _maxWidth || width == _maxHeight; + final hasHeightMatch = height == _maxWidth || height == _maxHeight; + return !(hasWidthMatch && hasHeightMatch); + } +}