experimental gecko unmount setting
This commit is contained in:
@@ -34,7 +34,7 @@ final class AccountAuthRepositoryProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _$accountAuthRepositoryHash() =>
|
String _$accountAuthRepositoryHash() =>
|
||||||
r'e33a4577f8da11567f1412e615a3e020535c8f46';
|
r'5e36dc4e74f892c83cfc9c4193412566cb077cc8';
|
||||||
|
|
||||||
abstract class _$AccountAuthRepository
|
abstract class _$AccountAuthRepository
|
||||||
extends $AsyncNotifier<AccountAuthState> {
|
extends $AsyncNotifier<AccountAuthState> {
|
||||||
|
|||||||
+15
-4
@@ -180,16 +180,27 @@ class _BrowserViewState extends ConsumerState<BrowserView>
|
|||||||
|
|
||||||
final topRoute = ref.watch(currentTopRouteProvider);
|
final topRoute = ref.watch(currentTopRouteProvider);
|
||||||
final androidInfoAsync = ref.watch(androidDeviceInfoProvider);
|
final androidInfoAsync = ref.watch(androidDeviceInfoProvider);
|
||||||
|
final unmountGeckoViewOffRoute = ref.watch(
|
||||||
|
generalSettingsWithDefaultsProvider.select(
|
||||||
|
(settings) => settings.unmountGeckoViewOffRoute,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
final isGeckoViewVisible = androidInfoAsync.when(
|
final isGeckoViewVisible = androidInfoAsync.when(
|
||||||
data: (androidInfo) {
|
data: (androidInfo) {
|
||||||
|
final isOnBrowserRoute =
|
||||||
|
topRoute is GoRoute && topRoute.name == BrowserRoute.name;
|
||||||
|
|
||||||
if (androidInfo == null) {
|
if (androidInfo == null) {
|
||||||
// Not Android, always show GeckoView based on route
|
// Not Android, always show GeckoView based on route
|
||||||
return topRoute is GoRoute && topRoute.name == BrowserRoute.name;
|
return isOnBrowserRoute;
|
||||||
}
|
}
|
||||||
// Android: only apply visibility fix on Android 12 and lower (API <= 31)
|
// Android 12 and lower (API <= 31): always unmount off-route to work
|
||||||
if (androidInfo.sdkInt <= 31) {
|
// around the native visibility bug. On Android 13+ the engine normally
|
||||||
return topRoute is GoRoute && topRoute.name == BrowserRoute.name;
|
// stays mounted to avoid reload/flicker, unless the developer setting
|
||||||
|
// opts into the same off-route unmounting.
|
||||||
|
if (androidInfo.sdkInt <= 31 || unmountGeckoViewOffRoute) {
|
||||||
|
return isOnBrowserRoute;
|
||||||
}
|
}
|
||||||
// Android 13+: always show GeckoView
|
// Android 13+: always show GeckoView
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -34,9 +34,11 @@ import 'package:weblibre/features/settings/presentation/dialogs/user_agent_resta
|
|||||||
import 'package:weblibre/features/settings/presentation/widgets/custom_list_tile.dart';
|
import 'package:weblibre/features/settings/presentation/widgets/custom_list_tile.dart';
|
||||||
import 'package:weblibre/features/settings/presentation/widgets/settings_detail.dart';
|
import 'package:weblibre/features/settings/presentation/widgets/settings_detail.dart';
|
||||||
import 'package:weblibre/features/user/data/models/engine_settings.dart';
|
import 'package:weblibre/features/user/data/models/engine_settings.dart';
|
||||||
|
import 'package:weblibre/features/user/data/models/general_settings.dart';
|
||||||
import 'package:weblibre/features/user/domain/providers.dart';
|
import 'package:weblibre/features/user/domain/providers.dart';
|
||||||
import 'package:weblibre/features/user/domain/repositories/cache.dart';
|
import 'package:weblibre/features/user/domain/repositories/cache.dart';
|
||||||
import 'package:weblibre/features/user/domain/repositories/engine_settings.dart';
|
import 'package:weblibre/features/user/domain/repositories/engine_settings.dart';
|
||||||
|
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
|
||||||
import 'package:weblibre/utils/exit_app.dart';
|
import 'package:weblibre/utils/exit_app.dart';
|
||||||
import 'package:weblibre/utils/ui_helper.dart';
|
import 'package:weblibre/utils/ui_helper.dart';
|
||||||
|
|
||||||
@@ -80,6 +82,12 @@ const List<SettingsSectionDefinition> advancedSettingsSections = [
|
|||||||
title: 'Developer Tools',
|
title: 'Developer Tools',
|
||||||
keywords: ['debug'],
|
keywords: ['debug'],
|
||||||
entries: [
|
entries: [
|
||||||
|
SettingsEntryDefinition(
|
||||||
|
title: 'Unmount Engine Off-Screen',
|
||||||
|
subtitle: 'Free the web engine when an overlay is on top',
|
||||||
|
keywords: ['geckoview', 'memory', 'performance', 'suspend'],
|
||||||
|
child: _UnmountGeckoViewOffRouteTile(),
|
||||||
|
),
|
||||||
SettingsEntryDefinition(
|
SettingsEntryDefinition(
|
||||||
title: 'Icon Cache',
|
title: 'Icon Cache',
|
||||||
subtitle: 'Stored favicons',
|
subtitle: 'Stored favicons',
|
||||||
@@ -251,6 +259,39 @@ class _ExperimentalSettingsTile extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _UnmountGeckoViewOffRouteTile extends HookConsumerWidget {
|
||||||
|
const _UnmountGeckoViewOffRouteTile();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final unmountGeckoViewOffRoute = ref.watch(
|
||||||
|
generalSettingsWithDefaultsProvider.select(
|
||||||
|
(s) => s.unmountGeckoViewOffRoute,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return SwitchListTile.adaptive(
|
||||||
|
title: const Text('Unmount Engine Off-Screen'),
|
||||||
|
subtitle: const Text(
|
||||||
|
'Unmount the web engine while a full-screen overlay (settings, tabs, '
|
||||||
|
'search) is on top, freeing its resources. On Android 12 and lower '
|
||||||
|
'this is always done; enabling it applies the same behavior on '
|
||||||
|
'Android 13+, which may cause the page to reload when returning.',
|
||||||
|
),
|
||||||
|
secondary: const Icon(Icons.memory),
|
||||||
|
value: unmountGeckoViewOffRoute,
|
||||||
|
onChanged: (value) async {
|
||||||
|
await ref
|
||||||
|
.read(saveGeneralSettingsControllerProvider.notifier)
|
||||||
|
.save(
|
||||||
|
(currentSettings) =>
|
||||||
|
currentSettings.copyWith.unmountGeckoViewOffRoute(value),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class _IconCacheTile extends HookConsumerWidget {
|
class _IconCacheTile extends HookConsumerWidget {
|
||||||
const _IconCacheTile();
|
const _IconCacheTile();
|
||||||
|
|
||||||
|
|||||||
@@ -205,6 +205,15 @@ class GeneralSettings with FastEquatable {
|
|||||||
/// overriding [globalDesktopMode] for that visit. See `hostMatchesRule`.
|
/// overriding [globalDesktopMode] for that visit. See `hostMatchesRule`.
|
||||||
final List<String> desktopModeSites;
|
final List<String> desktopModeSites;
|
||||||
|
|
||||||
|
/// Developer setting: when true, the GeckoView is unmounted whenever a
|
||||||
|
/// full-cover route (settings, tab tray, search, …) is on top, freeing the
|
||||||
|
/// engine's resources while it is occluded. On Android 12 and lower (API
|
||||||
|
/// <= 31) this behavior is always applied to work around a native
|
||||||
|
/// visibility bug; on Android 13+ the engine normally stays mounted to
|
||||||
|
/// avoid reload/flicker, and this flag opts into the off-route unmounting
|
||||||
|
/// there too. Defaults to false.
|
||||||
|
final bool unmountGeckoViewOffRoute;
|
||||||
|
|
||||||
GeneralSettings({
|
GeneralSettings({
|
||||||
required this.themeMode,
|
required this.themeMode,
|
||||||
required this.uiScaleFactor,
|
required this.uiScaleFactor,
|
||||||
@@ -269,6 +278,7 @@ class GeneralSettings with FastEquatable {
|
|||||||
required this.pureBlack,
|
required this.pureBlack,
|
||||||
required this.globalDesktopMode,
|
required this.globalDesktopMode,
|
||||||
required this.desktopModeSites,
|
required this.desktopModeSites,
|
||||||
|
required this.unmountGeckoViewOffRoute,
|
||||||
});
|
});
|
||||||
|
|
||||||
GeneralSettings.withDefaults({
|
GeneralSettings.withDefaults({
|
||||||
@@ -335,6 +345,7 @@ class GeneralSettings with FastEquatable {
|
|||||||
bool? pureBlack,
|
bool? pureBlack,
|
||||||
bool? globalDesktopMode,
|
bool? globalDesktopMode,
|
||||||
List<String>? desktopModeSites,
|
List<String>? desktopModeSites,
|
||||||
|
bool? unmountGeckoViewOffRoute,
|
||||||
}) : themeMode = themeMode ?? ThemeMode.dark,
|
}) : themeMode = themeMode ?? ThemeMode.dark,
|
||||||
uiScaleFactor = uiScaleFactor ?? defaultUiScaleFactor,
|
uiScaleFactor = uiScaleFactor ?? defaultUiScaleFactor,
|
||||||
disableAnimations = disableAnimations ?? false,
|
disableAnimations = disableAnimations ?? false,
|
||||||
@@ -410,7 +421,8 @@ class GeneralSettings with FastEquatable {
|
|||||||
acceptSuggestionOnSubmit = acceptSuggestionOnSubmit ?? false,
|
acceptSuggestionOnSubmit = acceptSuggestionOnSubmit ?? false,
|
||||||
pureBlack = pureBlack ?? false,
|
pureBlack = pureBlack ?? false,
|
||||||
globalDesktopMode = globalDesktopMode ?? false,
|
globalDesktopMode = globalDesktopMode ?? false,
|
||||||
desktopModeSites = desktopModeSites ?? const [];
|
desktopModeSites = desktopModeSites ?? const [],
|
||||||
|
unmountGeckoViewOffRoute = unmountGeckoViewOffRoute ?? false;
|
||||||
|
|
||||||
factory GeneralSettings.fromJson(Map<String, dynamic> json) {
|
factory GeneralSettings.fromJson(Map<String, dynamic> json) {
|
||||||
// Migrate legacy `newTabPosition` setting to direction settings.
|
// Migrate legacy `newTabPosition` setting to direction settings.
|
||||||
@@ -551,5 +563,6 @@ class GeneralSettings with FastEquatable {
|
|||||||
pureBlack,
|
pureBlack,
|
||||||
globalDesktopMode,
|
globalDesktopMode,
|
||||||
desktopModeSites,
|
desktopModeSites,
|
||||||
|
unmountGeckoViewOffRoute,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,6 +153,8 @@ abstract class _$GeneralSettingsCWProxy {
|
|||||||
|
|
||||||
GeneralSettings desktopModeSites(List<String> desktopModeSites);
|
GeneralSettings desktopModeSites(List<String> desktopModeSites);
|
||||||
|
|
||||||
|
GeneralSettings unmountGeckoViewOffRoute(bool unmountGeckoViewOffRoute);
|
||||||
|
|
||||||
/// Creates a new instance with the provided field values.
|
/// Creates a new instance with the provided field values.
|
||||||
/// Passing `null` to a nullable field nullifies it, while `null` for a non-nullable field is ignored. To update a single field use `GeneralSettings(...).copyWith.fieldName(value)`.
|
/// Passing `null` to a nullable field nullifies it, while `null` for a non-nullable field is ignored. To update a single field use `GeneralSettings(...).copyWith.fieldName(value)`.
|
||||||
///
|
///
|
||||||
@@ -224,6 +226,7 @@ abstract class _$GeneralSettingsCWProxy {
|
|||||||
bool pureBlack,
|
bool pureBlack,
|
||||||
bool globalDesktopMode,
|
bool globalDesktopMode,
|
||||||
List<String> desktopModeSites,
|
List<String> desktopModeSites,
|
||||||
|
bool unmountGeckoViewOffRoute,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -503,6 +506,10 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
|
|||||||
GeneralSettings desktopModeSites(List<String> desktopModeSites) =>
|
GeneralSettings desktopModeSites(List<String> desktopModeSites) =>
|
||||||
call(desktopModeSites: desktopModeSites);
|
call(desktopModeSites: desktopModeSites);
|
||||||
|
|
||||||
|
@override
|
||||||
|
GeneralSettings unmountGeckoViewOffRoute(bool unmountGeckoViewOffRoute) =>
|
||||||
|
call(unmountGeckoViewOffRoute: unmountGeckoViewOffRoute);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
/// Creates a new instance with the provided field values.
|
/// Creates a new instance with the provided field values.
|
||||||
/// Passing `null` to a nullable field nullifies it, while `null` for a non-nullable field is ignored. To update a single field use `GeneralSettings(...).copyWith.fieldName(value)`.
|
/// Passing `null` to a nullable field nullifies it, while `null` for a non-nullable field is ignored. To update a single field use `GeneralSettings(...).copyWith.fieldName(value)`.
|
||||||
@@ -577,6 +584,7 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
|
|||||||
Object? pureBlack = const $CopyWithPlaceholder(),
|
Object? pureBlack = const $CopyWithPlaceholder(),
|
||||||
Object? globalDesktopMode = const $CopyWithPlaceholder(),
|
Object? globalDesktopMode = const $CopyWithPlaceholder(),
|
||||||
Object? desktopModeSites = const $CopyWithPlaceholder(),
|
Object? desktopModeSites = const $CopyWithPlaceholder(),
|
||||||
|
Object? unmountGeckoViewOffRoute = const $CopyWithPlaceholder(),
|
||||||
}) {
|
}) {
|
||||||
return GeneralSettings(
|
return GeneralSettings(
|
||||||
themeMode: themeMode == const $CopyWithPlaceholder() || themeMode == null
|
themeMode: themeMode == const $CopyWithPlaceholder() || themeMode == null
|
||||||
@@ -950,6 +958,12 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
|
|||||||
? _value.desktopModeSites
|
? _value.desktopModeSites
|
||||||
// ignore: cast_nullable_to_non_nullable
|
// ignore: cast_nullable_to_non_nullable
|
||||||
: desktopModeSites as List<String>,
|
: desktopModeSites as List<String>,
|
||||||
|
unmountGeckoViewOffRoute:
|
||||||
|
unmountGeckoViewOffRoute == const $CopyWithPlaceholder() ||
|
||||||
|
unmountGeckoViewOffRoute == null
|
||||||
|
? _value.unmountGeckoViewOffRoute
|
||||||
|
// ignore: cast_nullable_to_non_nullable
|
||||||
|
: unmountGeckoViewOffRoute as bool,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1089,6 +1103,7 @@ GeneralSettings _$GeneralSettingsFromJson(
|
|||||||
desktopModeSites: (json['desktopModeSites'] as List<dynamic>?)
|
desktopModeSites: (json['desktopModeSites'] as List<dynamic>?)
|
||||||
?.map((e) => e as String)
|
?.map((e) => e as String)
|
||||||
.toList(),
|
.toList(),
|
||||||
|
unmountGeckoViewOffRoute: json['unmountGeckoViewOffRoute'] as bool?,
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$GeneralSettingsToJson(
|
Map<String, dynamic> _$GeneralSettingsToJson(
|
||||||
@@ -1171,6 +1186,7 @@ Map<String, dynamic> _$GeneralSettingsToJson(
|
|||||||
'pureBlack': instance.pureBlack,
|
'pureBlack': instance.pureBlack,
|
||||||
'globalDesktopMode': instance.globalDesktopMode,
|
'globalDesktopMode': instance.globalDesktopMode,
|
||||||
'desktopModeSites': instance.desktopModeSites,
|
'desktopModeSites': instance.desktopModeSites,
|
||||||
|
'unmountGeckoViewOffRoute': instance.unmountGeckoViewOffRoute,
|
||||||
};
|
};
|
||||||
|
|
||||||
const _$ThemeModeEnumMap = {
|
const _$ThemeModeEnumMap = {
|
||||||
|
|||||||
@@ -295,6 +295,10 @@ class GeneralSettingsRepository extends _$GeneralSettingsRepository {
|
|||||||
'desktopModeSites': settings['desktopModeSites']
|
'desktopModeSites': settings['desktopModeSites']
|
||||||
?.readAs(DriftSqlType.string, db.typeMapping)
|
?.readAs(DriftSqlType.string, db.typeMapping)
|
||||||
.mapNotNull(jsonDecode),
|
.mapNotNull(jsonDecode),
|
||||||
|
'unmountGeckoViewOffRoute': settings['unmountGeckoViewOffRoute']?.readAs(
|
||||||
|
DriftSqlType.bool,
|
||||||
|
db.typeMapping,
|
||||||
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ final class GeneralSettingsRepositoryProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _$generalSettingsRepositoryHash() =>
|
String _$generalSettingsRepositoryHash() =>
|
||||||
r'ad70d95bd7f57b9ba06b0500a651b4e41ade572a';
|
r'9ee41d8283340300ec295d318ade92c15b19426d';
|
||||||
|
|
||||||
abstract class _$GeneralSettingsRepository
|
abstract class _$GeneralSettingsRepository
|
||||||
extends $StreamNotifier<GeneralSettings> {
|
extends $StreamNotifier<GeneralSettings> {
|
||||||
|
|||||||
Reference in New Issue
Block a user