#275 system bar transparency review
This commit is contained in:
parent
b29425e322
commit
73e9073407
22 changed files with 124 additions and 90 deletions
16
CHANGELOG.md
16
CHANGELOG.md
|
@ -40,7 +40,7 @@ All notable changes to this project will be documented in this file.
|
|||
|
||||
- slideshow
|
||||
- set wallpaper from any media
|
||||
- optional dynamic accent color on Android 12+
|
||||
- optional dynamic accent color on Android >=12
|
||||
- Search: date/dimension/size field equality (undocumented)
|
||||
- support Android 13 (API 33)
|
||||
- Turkish translation (thanks metezd)
|
||||
|
@ -135,7 +135,7 @@ All notable changes to this project will be documented in this file.
|
|||
|
||||
### Fixed
|
||||
|
||||
- app launch despite faulty storage volumes on Android 11+
|
||||
- app launch despite faulty storage volumes on Android >=11
|
||||
|
||||
## <a id="v1.6.2"></a>[v1.6.2] - 2022-03-07
|
||||
|
||||
|
@ -320,7 +320,7 @@ All notable changes to this project will be documented in this file.
|
|||
- Info: improved display for PNG text metadata, XMP and others
|
||||
- Export: output format selection
|
||||
- Search: added raw filter
|
||||
- Support modifying files in the Download folder on Android 11+
|
||||
- Support modifying files in the Download folder on Android >=11
|
||||
|
||||
### Changed
|
||||
|
||||
|
@ -330,7 +330,7 @@ All notable changes to this project will be documented in this file.
|
|||
### Fixed
|
||||
|
||||
- hide root album of hidden path
|
||||
- gesture & spacing handling for Android 10+ navigation gestures
|
||||
- gesture & spacing handling for Android >=10 navigation gestures
|
||||
- renaming was leaving behind obsolete items in some cases
|
||||
- speeding up videos on Xiaomi devices
|
||||
|
||||
|
@ -393,7 +393,7 @@ All notable changes to this project will be documented in this file.
|
|||
- Map & Stats from selection
|
||||
- Map: item browsing, rotation control
|
||||
- Navigation menu customization
|
||||
- shortcut support on older devices (API < 26)
|
||||
- shortcut support on older devices (API <26)
|
||||
- support Android 12/S (API 31)
|
||||
|
||||
## [v1.4.8] - 2021-08-08
|
||||
|
@ -407,7 +407,7 @@ All notable changes to this project will be documented in this file.
|
|||
### Fixed
|
||||
|
||||
- auto album identification and naming
|
||||
- opening HEIC images from downloads content URI on Android R+
|
||||
- opening HEIC images from downloads content URI on Android >=11
|
||||
|
||||
## [v1.4.7] - 2021-08-06 [YANKED]
|
||||
|
||||
|
@ -611,7 +611,7 @@ All notable changes to this project will be documented in this file.
|
|||
|
||||
- Viewer: support for multi-track HEIF
|
||||
- Viewer: export image (including multipage TIFF/HEIF and images embedded in XMP)
|
||||
- Info: show owner app (Android Q and up)
|
||||
- Info: show owner app (Android >=10)
|
||||
- listen to Media Store changes
|
||||
|
||||
### Changed
|
||||
|
@ -638,7 +638,7 @@ upgraded libtiff to 4.2.0 for TIFF decoding
|
|||
|
||||
### Fixed
|
||||
|
||||
- prevent scrolling when using Android Q style gesture navigation
|
||||
- prevent scrolling when using Android 10 style gesture navigation
|
||||
|
||||
## [v1.3.1] - 2021-01-04
|
||||
|
||||
|
|
|
@ -12,8 +12,8 @@ This change eventually prevents building the app with Flutter v3.0.2.
|
|||
android:installLocation="auto">
|
||||
|
||||
<!--
|
||||
Scoped storage on Android Q is inconvenient because users need to confirm edition on each individual file.
|
||||
So we request `WRITE_EXTERNAL_STORAGE` until Q (29), and enable `requestLegacyExternalStorage`
|
||||
Scoped storage on Android 10 is inconvenient because users need to confirm edition on each individual file.
|
||||
So we request `WRITE_EXTERNAL_STORAGE` until Android 10 (API 29), and enable `requestLegacyExternalStorage`
|
||||
-->
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
|
||||
|
@ -31,25 +31,25 @@ This change eventually prevents building the app with Flutter v3.0.2.
|
|||
<!-- to show foreground service progress via notification -->
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
|
||||
<!-- to access media with original metadata with scoped storage (Android Q+) -->
|
||||
<!-- to access media with original metadata with scoped storage (Android >=10) -->
|
||||
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
|
||||
|
||||
<!-- TODO TLAD remove this permission when this is fixed: https://github.com/flutter/flutter/issues/42451 -->
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
|
||||
<!-- for API < 26 -->
|
||||
<!-- for API <26 -->
|
||||
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
|
||||
|
||||
<!-- allow install on API 19, but Google Maps is from API 20 -->
|
||||
<uses-sdk tools:overrideLibrary="io.flutter.plugins.googlemaps" />
|
||||
|
||||
<!-- from Android R, we should define <queries> to make other apps visible to this app -->
|
||||
<!-- from Android 11, we should define <queries> to make other apps visible to this app -->
|
||||
<queries>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
</intent>
|
||||
<!--
|
||||
from Android R, `url_launcher` method `canLaunchUrl()` will return false,
|
||||
from Android 11, `url_launcher` method `canLaunchUrl()` will return false,
|
||||
if appropriate intents are not declared, cf https://pub.dev/packages/url_launcher#configuration=
|
||||
-->
|
||||
<!-- to open https URLs -->
|
||||
|
|
|
@ -285,7 +285,7 @@ open class MainActivity : FlutterActivity() {
|
|||
val filters = intent.getStringArrayExtra(EXTRA_KEY_FILTERS_ARRAY)?.toList()
|
||||
if (filters != null) return filters
|
||||
|
||||
// fallback for shortcuts created on API < 26
|
||||
// fallback for shortcuts created on API <26
|
||||
val filterString = intent.getStringExtra(EXTRA_KEY_FILTERS_STRING)
|
||||
if (filterString != null) {
|
||||
return filterString.split(EXTRA_STRING_ARRAY_SEPARATOR)
|
||||
|
|
|
@ -56,7 +56,7 @@ class ThumbnailFetcher internal constructor(
|
|||
try {
|
||||
if (!customFetch && (width == defaultSize || height == defaultSize) && !isFlipped) {
|
||||
// Fetch low quality thumbnails when size is not specified.
|
||||
// As of Android R, the Media Store content resolver may return a thumbnail
|
||||
// As of Android 11, the Media Store content resolver may return a thumbnail
|
||||
// that is automatically rotated according to EXIF orientation, but not flipped,
|
||||
// so we skip this step for flipped entries.
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
|
@ -108,7 +108,7 @@ class ThumbnailFetcher internal constructor(
|
|||
} else {
|
||||
@Suppress("deprecation")
|
||||
var bitmap = MediaStore.Images.Thumbnails.getThumbnail(resolver, contentId, MediaStore.Images.Thumbnails.MINI_KIND, null)
|
||||
// from Android Q, returned thumbnail is already rotated according to EXIF orientation
|
||||
// from Android 10, returned thumbnail is already rotated according to EXIF orientation
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q && bitmap != null) {
|
||||
bitmap = applyExifOrientation(context, bitmap, rotationDegrees, isFlipped)
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package deckers.thibault.aves.channel.calls.window
|
|||
import android.app.Activity
|
||||
import android.os.Build
|
||||
import android.view.WindowManager
|
||||
import deckers.thibault.aves.utils.LogUtils
|
||||
import io.flutter.plugin.common.MethodCall
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
|
||||
|
@ -60,8 +59,4 @@ class ActivityWindowHandler(private val activity: Activity) : WindowHandler(acti
|
|||
}
|
||||
result.success(true)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG_TAG = LogUtils.createTag<ActivityWindowHandler>()
|
||||
}
|
||||
}
|
|
@ -88,7 +88,7 @@ class ActivityResultStreamHandler(private val activity: Activity, arguments: Any
|
|||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
|
||||
error("requestMediaFileAccess-unsupported", "media file bulk access is not allowed before Android R", null)
|
||||
error("requestMediaFileAccess-unsupported", "media file bulk access is not allowed before Android 11", null)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -193,7 +193,7 @@ class MediaStoreImageProvider : ImageProvider() {
|
|||
val dateModifiedColumn = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATE_MODIFIED)
|
||||
val dateTakenColumn = cursor.getColumnIndex(MediaColumns.DATE_TAKEN)
|
||||
|
||||
// image & video for API >= Q, only for images for API < Q
|
||||
// image & video for API >=29, only for images for API <29
|
||||
val orientationColumn = cursor.getColumnIndex(MediaColumns.ORIENTATION)
|
||||
|
||||
// video only
|
||||
|
@ -347,7 +347,7 @@ class MediaStoreImageProvider : ImageProvider() {
|
|||
}
|
||||
} catch (securityException: SecurityException) {
|
||||
// even if the app has access permission granted on the containing directory,
|
||||
// the delete request may yield a `RecoverableSecurityException` on Android 10+
|
||||
// the delete request may yield a `RecoverableSecurityException` on Android >=10
|
||||
// when the underlying file no longer exists and this is an orphaned entry in the Media Store
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && contextWrapper is Activity) {
|
||||
Log.w(LOG_TAG, "caught a security exception when attempting to delete uri=$uri", securityException)
|
||||
|
@ -876,7 +876,7 @@ class MediaStoreImageProvider : ImageProvider() {
|
|||
private val VIDEO_PROJECTION = arrayOf(
|
||||
*BASE_PROJECTION,
|
||||
MediaColumns.DURATION,
|
||||
// `ORIENTATION` was only available for images before Android Q
|
||||
// `ORIENTATION` was only available for images before Android 10
|
||||
*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) arrayOf(
|
||||
MediaStore.MediaColumns.ORIENTATION,
|
||||
) else emptyArray()
|
||||
|
|
|
@ -2,7 +2,7 @@ package deckers.thibault.aves.utils
|
|||
|
||||
import android.os.Build
|
||||
|
||||
// compatibility extension for `removeIf` for API < N
|
||||
// compatibility extension for `removeIf` for API <24
|
||||
fun <E> MutableList<E>.compatRemoveIf(filter: (t: E) -> Boolean): Boolean {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
this.removeIf(filter)
|
||||
|
|
|
@ -98,7 +98,7 @@ object PermissionManager {
|
|||
segments.volumePath?.let { volumePath ->
|
||||
val dirSet = dirsPerVolume[volumePath] ?: HashSet()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
// request primary directory on volume from Android R
|
||||
// request primary directory on volume from Android 11
|
||||
val relativeDir = segments.relativeDir
|
||||
if (relativeDir != null) {
|
||||
val dirSegments = relativeDir.split(File.separator).takeWhile { it.isNotEmpty() }
|
||||
|
@ -111,11 +111,11 @@ object PermissionManager {
|
|||
}
|
||||
} else {
|
||||
// the requested path is the volume root itself
|
||||
// which cannot be granted, due to Android R restrictions
|
||||
// which cannot be granted, due to Android 11 restrictions
|
||||
dirSet.add("")
|
||||
}
|
||||
} else {
|
||||
// request volume root until Android Q
|
||||
// request volume root until Android 10
|
||||
dirSet.add("")
|
||||
}
|
||||
dirsPerVolume[volumePath] = dirSet
|
||||
|
@ -236,7 +236,7 @@ object PermissionManager {
|
|||
return dirs
|
||||
}
|
||||
|
||||
// As of Android R, `MediaStore.getDocumentUri` fails if any of the persisted
|
||||
// As of Android 11, `MediaStore.getDocumentUri` fails if any of the persisted
|
||||
// URI permissions we hold points to a folder that no longer exists,
|
||||
// so we should remove these obsolete URIs before proceeding.
|
||||
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
|
|
|
@ -468,7 +468,7 @@ object StorageUtils {
|
|||
fun requireAccessPermission(context: Context, anyPath: String): Boolean {
|
||||
if (isAppFile(context, anyPath)) return false
|
||||
|
||||
// on Android R, we should always require access permission, even on primary volume
|
||||
// on Android 11, we should always require access permission, even on primary volume
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) return true
|
||||
|
||||
val onPrimaryVolume = anyPath.startsWith(getPrimaryVolumePath(context))
|
||||
|
@ -487,7 +487,7 @@ object StorageUtils {
|
|||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && isMediaStoreContentUri(uri)) {
|
||||
val path = uri.path
|
||||
path ?: return uri
|
||||
// from Android R, accessing the original URI for a `file` or `downloads` media content yields a `SecurityException`
|
||||
// from Android 11, accessing the original URI for a `file` or `downloads` media content yields a `SecurityException`
|
||||
if (path.startsWith("/external/images/") || path.startsWith("/external/video/")) {
|
||||
// "Caller must hold ACCESS_MEDIA_LOCATION permission to access original"
|
||||
if (context.checkSelfPermission(Manifest.permission.ACCESS_MEDIA_LOCATION) == PackageManager.PERMISSION_GRANTED) {
|
||||
|
@ -499,7 +499,7 @@ object StorageUtils {
|
|||
}
|
||||
|
||||
// As of Glide v4.12.0, a special loader `QMediaStoreUriLoader` is automatically used
|
||||
// to work around a bug from Android Q where metadata redaction corrupts HEIC images.
|
||||
// to work around a bug from Android 10 where metadata redaction corrupts HEIC images.
|
||||
// This loader relies on `MediaStore.setRequireOriginal` but this yields a `SecurityException`
|
||||
// for some non image/video content URIs (e.g. `downloads`, `file`)
|
||||
fun getGlideSafeUri(context: Context, uri: Uri, mimeType: String): Uri {
|
||||
|
@ -594,7 +594,7 @@ object StorageUtils {
|
|||
val effectiveUri = getOriginalUri(context, uri)
|
||||
return try {
|
||||
MediaMetadataRetriever().apply {
|
||||
// on Android S preview, setting the data source works but yields an internal IOException
|
||||
// on Android 12 preview, setting the data source works but yields an internal IOException
|
||||
// (`Input file descriptor already original`), whether we provide the original URI or not
|
||||
setDataSource(context, effectiveUri)
|
||||
}
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<bool name="translucentNavBar">false</bool>
|
||||
</resources>
|
9
android/app/src/main/res/values-night/styles.xml
Normal file
9
android/app/src/main/res/values-night/styles.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
|
||||
<!-- API28+, draws next to the notch in fullscreen -->
|
||||
<item name="android:windowLayoutInDisplayCutoutMode" tools:targetApi="28">shortEdges</item>
|
||||
</style>
|
||||
</resources>
|
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<item name="android:windowTranslucentNavigation">@bool/translucentNavBar</item> <!-- API19+, tinted background & request the SYSTEM_UI_FLAG_LAYOUT_STABLE and SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN flags -->
|
||||
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item> <!-- API28+, draws next to the notch in fullscreen -->
|
||||
</style>
|
||||
</resources>
|
|
@ -1,4 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<bool name="translucentNavBar">true</bool>
|
||||
</resources>
|
|
@ -1,6 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<item name="android:windowTranslucentNavigation">@bool/translucentNavBar</item> <!-- API19+, tinted background & request the SYSTEM_UI_FLAG_LAYOUT_STABLE and SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN flags -->
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
|
||||
<!-- API28+, draws next to the notch in fullscreen -->
|
||||
<item name="android:windowLayoutInDisplayCutoutMode" tools:targetApi="28">shortEdges</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
|
|
@ -2,8 +2,8 @@ import 'dart:ui';
|
|||
|
||||
import 'package:aves/model/settings/enums/enums.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/widgets/aves_app.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class Themes {
|
||||
|
@ -35,7 +35,7 @@ class Themes {
|
|||
static const _lightSecondLayer = Color(0xFFF5F5F5); // aka `Colors.grey[100]`
|
||||
static const _lightThirdLayer = Color(0xFFEEEEEE); // aka `Colors.grey[200]`
|
||||
|
||||
static ThemeData lightTheme(Color accentColor) => ThemeData(
|
||||
static ThemeData lightTheme(Color accentColor, bool deviceInitialized) => ThemeData(
|
||||
colorScheme: ColorScheme.light(
|
||||
primary: accentColor,
|
||||
secondary: accentColor,
|
||||
|
@ -58,7 +58,7 @@ class Themes {
|
|||
foregroundColor: _lightActionIconColor,
|
||||
// `titleTextStyle.color` is used by text
|
||||
titleTextStyle: _appBarTitleTextStyle.copyWith(color: _lightTitleColor),
|
||||
systemOverlayStyle: SystemUiOverlayStyle.dark,
|
||||
systemOverlayStyle: deviceInitialized ? AvesApp.systemUIStyleForBrightness(Brightness.light, _lightFirstLayer) : null,
|
||||
),
|
||||
listTileTheme: const ListTileThemeData(
|
||||
iconColor: _lightActionIconColor,
|
||||
|
@ -87,7 +87,7 @@ class Themes {
|
|||
static const _darkSecondLayer = Color(0xFF363636);
|
||||
static const _darkThirdLayer = Color(0xFF424242); // aka `Colors.grey[800]`
|
||||
|
||||
static ThemeData darkTheme(Color accentColor) => ThemeData(
|
||||
static ThemeData darkTheme(Color accentColor, bool deviceInitialized) => ThemeData(
|
||||
colorScheme: ColorScheme.dark(
|
||||
primary: accentColor,
|
||||
secondary: accentColor,
|
||||
|
@ -112,7 +112,7 @@ class Themes {
|
|||
foregroundColor: _darkTitleColor,
|
||||
// `titleTextStyle.color` is used by text
|
||||
titleTextStyle: _appBarTitleTextStyle.copyWith(color: _darkTitleColor),
|
||||
systemOverlayStyle: SystemUiOverlayStyle.light,
|
||||
systemOverlayStyle: deviceInitialized ? AvesApp.systemUIStyleForBrightness(Brightness.dark, _darkFirstLayer) : null,
|
||||
),
|
||||
popupMenuTheme: const PopupMenuThemeData(
|
||||
color: _darkSecondLayer,
|
||||
|
@ -138,8 +138,8 @@ class Themes {
|
|||
static const _blackSecondLayer = Color(0xFF212121); // aka `Colors.grey[900]`
|
||||
static const _blackThirdLayer = Color(0xFF303030); // aka `Colors.grey[850]`
|
||||
|
||||
static ThemeData blackTheme(Color accentColor) {
|
||||
final baseTheme = darkTheme(accentColor);
|
||||
static ThemeData blackTheme(Color accentColor, bool deviceInitialized) {
|
||||
final baseTheme = darkTheme(accentColor, deviceInitialized);
|
||||
return baseTheme.copyWith(
|
||||
// `canvasColor` is used by `Drawer`, `DropdownButton` and `ExpansionTileCard`
|
||||
canvasColor: _blackSecondLayer,
|
||||
|
|
|
@ -60,15 +60,44 @@ class AvesApp extends StatefulWidget {
|
|||
@override
|
||||
State<AvesApp> createState() => _AvesAppState();
|
||||
|
||||
static void showSystemUI() {
|
||||
static void setSystemUIStyle(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final style = systemUIStyleForBrightness(theme.brightness, theme.scaffoldBackgroundColor);
|
||||
SystemChrome.setSystemUIOverlayStyle(style);
|
||||
}
|
||||
|
||||
static SystemUiOverlayStyle systemUIStyleForBrightness(Brightness themeBrightness, Color scaffoldBackgroundColor) {
|
||||
final barBrightness = themeBrightness == Brightness.light ? Brightness.dark : Brightness.light;
|
||||
const statusBarColor = Colors.transparent;
|
||||
// as of Flutter v3.3.0-0.2.pre, setting `SystemUiOverlayStyle` (whether manually or automatically because of `AppBar`)
|
||||
// prevents the canvas from drawing behind the nav bar on Android <10 (API <29),
|
||||
// so the nav bar is opaque, even when requesting `SystemUiMode.edgeToEdge` from Flutter
|
||||
// or setting `android:windowTranslucentNavigation` in Android themes.
|
||||
final navBarColor = device.supportEdgeToEdgeUIMode ? Colors.transparent : scaffoldBackgroundColor;
|
||||
return SystemUiOverlayStyle(
|
||||
systemNavigationBarColor: navBarColor,
|
||||
systemNavigationBarDividerColor: navBarColor,
|
||||
systemNavigationBarIconBrightness: barBrightness,
|
||||
// shows background scrim when using navigation buttons, but not when using gesture navigation
|
||||
systemNavigationBarContrastEnforced: true,
|
||||
statusBarColor: statusBarColor,
|
||||
statusBarBrightness: barBrightness,
|
||||
statusBarIconBrightness: barBrightness,
|
||||
systemStatusBarContrastEnforced: false,
|
||||
);
|
||||
}
|
||||
|
||||
static Future<void> showSystemUI() async {
|
||||
if (device.supportEdgeToEdgeUIMode) {
|
||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
|
||||
await SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
|
||||
} else {
|
||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values);
|
||||
await SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values);
|
||||
}
|
||||
}
|
||||
|
||||
static void hideSystemUI() => SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
|
||||
static Future<void> hideSystemUI() async {
|
||||
await SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
|
||||
}
|
||||
}
|
||||
|
||||
class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
||||
|
@ -121,6 +150,9 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
|||
future: _appSetup,
|
||||
builder: (context, snapshot) {
|
||||
final initialized = !snapshot.hasError && snapshot.connectionState == ConnectionState.done;
|
||||
if (initialized) {
|
||||
AvesApp.showSystemUI();
|
||||
}
|
||||
final home = initialized
|
||||
? getFirstPage()
|
||||
: Scaffold(
|
||||
|
@ -169,17 +201,22 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
|||
navigatorKey: AvesApp.navigatorKey,
|
||||
home: home,
|
||||
navigatorObservers: _navigatorObservers,
|
||||
builder: (context, child) => AvesColorsProvider(
|
||||
child: Theme(
|
||||
data: Theme.of(context).copyWith(
|
||||
pageTransitionsTheme: pageTransitionsTheme,
|
||||
builder: (context, child) {
|
||||
if (initialized) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => AvesApp.setSystemUIStyle(context));
|
||||
}
|
||||
return AvesColorsProvider(
|
||||
child: Theme(
|
||||
data: Theme.of(context).copyWith(
|
||||
pageTransitionsTheme: pageTransitionsTheme,
|
||||
),
|
||||
child: child!,
|
||||
),
|
||||
child: child!,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
onGenerateTitle: (context) => context.l10n.appName,
|
||||
theme: Themes.lightTheme(lightAccent),
|
||||
darkTheme: themeBrightness == AvesThemeBrightness.black ? Themes.blackTheme(darkAccent) : Themes.darkTheme(darkAccent),
|
||||
theme: Themes.lightTheme(lightAccent, initialized),
|
||||
darkTheme: themeBrightness == AvesThemeBrightness.black ? Themes.blackTheme(darkAccent, initialized) : Themes.darkTheme(darkAccent, initialized),
|
||||
themeMode: themeBrightness.appThemeMode,
|
||||
locale: settingsLocale,
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
|
|
|
@ -5,7 +5,7 @@ import 'package:provider/provider.dart';
|
|||
// This widget should be added on top of Scaffolds with:
|
||||
// - `resizeToAvoidBottomInset` set to false,
|
||||
// - a vertically scrollable body.
|
||||
// It will prevent the body from scrolling when a user swipe from bottom to use Android Q style navigation gestures.
|
||||
// It will prevent the body from scrolling when a user swipe from bottom to use Android 10 style navigation gestures.
|
||||
class BottomGestureAreaProtector extends StatelessWidget {
|
||||
const BottomGestureAreaProtector({super.key});
|
||||
|
||||
|
@ -45,7 +45,7 @@ class TopGestureAreaProtector extends StatelessWidget {
|
|||
}
|
||||
}
|
||||
|
||||
// It will prevent the body from scrolling when a user swipe from edges to use Android Q style navigation gestures.
|
||||
// It will prevent the body from scrolling when a user swipe from edges to use Android 10 style navigation gestures.
|
||||
class SideGestureAreaProtector extends StatelessWidget {
|
||||
const SideGestureAreaProtector({super.key});
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ class _HomePageState extends State<HomePage> {
|
|||
// hide in some countries apps that force quit on permission denial
|
||||
await [
|
||||
Permission.storage,
|
||||
// to access media with unredacted metadata with scoped storage (Android 10+)
|
||||
// to access media with unredacted metadata with scoped storage (Android >=10)
|
||||
Permission.accessMediaLocation,
|
||||
].request();
|
||||
}
|
||||
|
|
|
@ -652,19 +652,20 @@ class _EntryViewerStackState extends State<EntryViewerStack> with EntryViewContr
|
|||
}
|
||||
}
|
||||
|
||||
void _onLeave() {
|
||||
Future<void> _onLeave() async {
|
||||
if (!settings.viewerUseCutout) {
|
||||
windowService.setCutoutMode(true);
|
||||
await windowService.setCutoutMode(true);
|
||||
}
|
||||
if (settings.viewerMaxBrightness) {
|
||||
ScreenBrightness().resetScreenBrightness();
|
||||
await ScreenBrightness().resetScreenBrightness();
|
||||
}
|
||||
if (settings.keepScreenOn == KeepScreenOn.viewerOnly) {
|
||||
windowService.keepScreenOn(false);
|
||||
await windowService.keepScreenOn(false);
|
||||
}
|
||||
|
||||
AvesApp.showSystemUI();
|
||||
windowService.requestOrientation();
|
||||
await AvesApp.showSystemUI();
|
||||
AvesApp.setSystemUIStyle(context);
|
||||
await windowService.requestOrientation();
|
||||
}
|
||||
|
||||
// overlay
|
||||
|
@ -679,7 +680,8 @@ class _EntryViewerStackState extends State<EntryViewerStack> with EntryViewContr
|
|||
|
||||
Future<void> _onOverlayVisibleChange({bool animate = true}) async {
|
||||
if (_overlayVisible.value) {
|
||||
AvesApp.showSystemUI();
|
||||
await AvesApp.showSystemUI();
|
||||
AvesApp.setSystemUIStyle(context);
|
||||
if (animate) {
|
||||
await _overlayAnimationController.forward();
|
||||
} else {
|
||||
|
@ -692,7 +694,7 @@ class _EntryViewerStackState extends State<EntryViewerStack> with EntryViewContr
|
|||
_frozenViewInsets = mediaQuery.viewInsets;
|
||||
_frozenViewPadding = mediaQuery.viewPadding;
|
||||
});
|
||||
AvesApp.hideSystemUI();
|
||||
await AvesApp.hideSystemUI();
|
||||
if (animate) {
|
||||
await _overlayAnimationController.reverse();
|
||||
} else {
|
||||
|
|
|
@ -159,8 +159,9 @@ class _PanoramaPageState extends State<PanoramaPage> {
|
|||
}
|
||||
}
|
||||
|
||||
void _onLeave() {
|
||||
AvesApp.showSystemUI();
|
||||
Future<void> _onLeave() async {
|
||||
await AvesApp.showSystemUI();
|
||||
AvesApp.setSystemUIStyle(context);
|
||||
}
|
||||
|
||||
// system UI
|
||||
|
@ -176,9 +177,10 @@ class _PanoramaPageState extends State<PanoramaPage> {
|
|||
|
||||
Future<void> _onOverlayVisibleChange() async {
|
||||
if (_overlayVisible.value) {
|
||||
AvesApp.showSystemUI();
|
||||
await AvesApp.showSystemUI();
|
||||
AvesApp.setSystemUIStyle(context);
|
||||
} else {
|
||||
AvesApp.hideSystemUI();
|
||||
await AvesApp.hideSystemUI();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -234,7 +234,8 @@ class _EntryEditorState extends State<EntryEditor> with EntryViewControllerMixin
|
|||
|
||||
Future<void> _onOverlayVisibleChange({bool animate = true}) async {
|
||||
if (_overlayVisible.value) {
|
||||
AvesApp.showSystemUI();
|
||||
await AvesApp.showSystemUI();
|
||||
AvesApp.setSystemUIStyle(context);
|
||||
if (animate) {
|
||||
await _overlayAnimationController.forward();
|
||||
} else {
|
||||
|
@ -246,7 +247,7 @@ class _EntryEditorState extends State<EntryEditor> with EntryViewControllerMixin
|
|||
_frozenViewInsets = mediaQuery.viewInsets;
|
||||
_frozenViewPadding = mediaQuery.viewPadding;
|
||||
});
|
||||
AvesApp.hideSystemUI();
|
||||
await AvesApp.hideSystemUI();
|
||||
if (animate) {
|
||||
await _overlayAnimationController.reverse();
|
||||
} else {
|
||||
|
|
Loading…
Reference in a new issue