setting to control swipe to refresh

This commit is contained in:
Fabian Freund
2026-01-10 19:13:36 +01:00
parent e6e3201059
commit 81fb8f5221
14 changed files with 138 additions and 4 deletions
@@ -61,6 +61,23 @@ class EngineSettingsReplicationService
}, },
); );
ref.listen(
fireImmediately: true,
generalSettingsWithDefaultsProvider.select(
(settings) => settings.pullToRefreshEnabled,
),
(previous, next) async {
await _service.setPullToRefreshEnabled(next);
},
onError: (error, stackTrace) {
logger.e(
'Error listening to pullToRefreshEnabled',
error: error,
stackTrace: stackTrace,
);
},
);
ref.listen( ref.listen(
fireImmediately: true, fireImmediately: true,
engineSettingsRepositoryProvider, engineSettingsRepositoryProvider,
@@ -44,7 +44,7 @@ final class EngineSettingsReplicationServiceProvider
} }
String _$engineSettingsReplicationServiceHash() => String _$engineSettingsReplicationServiceHash() =>
r'7583ebc8ca9c11377486ff5a3e763493dcdc903a'; r'0a9539e19946028f525de64ed5f33e2483e7abc2';
abstract class _$EngineSettingsReplicationService extends $Notifier<void> { abstract class _$EngineSettingsReplicationService extends $Notifier<void> {
void build(); void build();
@@ -66,6 +66,7 @@ class GeneralSettingsScreen extends StatelessWidget {
_AutoHideTabBarTile(), _AutoHideTabBarTile(),
_BottomSheetTabViewTile(), _BottomSheetTabViewTile(),
_TabBarSwipeBehaviorSection(), _TabBarSwipeBehaviorSection(),
_PullToRefreshTile(),
_IconCacheTile(), _IconCacheTile(),
], ],
); );
@@ -840,6 +841,32 @@ class _TabBarSwipeBehaviorSection extends HookConsumerWidget {
} }
} }
class _PullToRefreshTile extends HookConsumerWidget {
const _PullToRefreshTile();
@override
Widget build(BuildContext context, WidgetRef ref) {
final pullToRefreshEnabled = ref.watch(
generalSettingsWithDefaultsProvider.select((s) => s.pullToRefreshEnabled),
);
return SwitchListTile.adaptive(
title: const Text('Pull to Refresh'),
subtitle: const Text('Swipe down on pages to reload them'),
secondary: const Icon(MdiIcons.gestureSwipeDown),
value: pullToRefreshEnabled,
onChanged: (value) async {
await ref
.read(saveGeneralSettingsControllerProvider.notifier)
.save(
(currentSettings) =>
currentSettings.copyWith.pullToRefreshEnabled(value),
);
},
);
}
}
class _IconCacheTile extends HookConsumerWidget { class _IconCacheTile extends HookConsumerWidget {
const _IconCacheTile(); const _IconCacheTile();
@@ -80,6 +80,7 @@ class GeneralSettings with FastEquatable {
final bool tabBarShowQuickTabSwitcherBar; final bool tabBarShowQuickTabSwitcherBar;
final TabBarPosition tabBarPosition; final TabBarPosition tabBarPosition;
final QuickTabSwitcherMode quickTabSwitcherMode; final QuickTabSwitcherMode quickTabSwitcherMode;
final bool pullToRefreshEnabled;
GeneralSettings({ GeneralSettings({
required this.themeMode, required this.themeMode,
@@ -102,6 +103,7 @@ class GeneralSettings with FastEquatable {
required this.tabBarShowQuickTabSwitcherBar, required this.tabBarShowQuickTabSwitcherBar,
required this.tabBarPosition, required this.tabBarPosition,
required this.quickTabSwitcherMode, required this.quickTabSwitcherMode,
required this.pullToRefreshEnabled,
}); });
GeneralSettings.withDefaults({ GeneralSettings.withDefaults({
@@ -125,6 +127,7 @@ class GeneralSettings with FastEquatable {
bool? tabBarShowQuickTabSwitcherBar, bool? tabBarShowQuickTabSwitcherBar,
TabBarPosition? tabBarPosition, TabBarPosition? tabBarPosition,
QuickTabSwitcherMode? quickTabSwitcherMode, QuickTabSwitcherMode? quickTabSwitcherMode,
bool? pullToRefreshEnabled,
}) : themeMode = themeMode ?? ThemeMode.dark, }) : themeMode = themeMode ?? ThemeMode.dark,
enableReadability = enableReadability ?? true, enableReadability = enableReadability ?? true,
enforceReadability = enforceReadability ?? false, enforceReadability = enforceReadability ?? false,
@@ -147,7 +150,8 @@ class GeneralSettings with FastEquatable {
tabBarShowQuickTabSwitcherBar = tabBarShowQuickTabSwitcherBar ?? true, tabBarShowQuickTabSwitcherBar = tabBarShowQuickTabSwitcherBar ?? true,
tabBarPosition = tabBarPosition ?? TabBarPosition.bottom, tabBarPosition = tabBarPosition ?? TabBarPosition.bottom,
quickTabSwitcherMode = quickTabSwitcherMode =
quickTabSwitcherMode ?? QuickTabSwitcherMode.lastUsedTabs; quickTabSwitcherMode ?? QuickTabSwitcherMode.lastUsedTabs,
pullToRefreshEnabled = pullToRefreshEnabled ?? true;
factory GeneralSettings.fromJson(Map<String, dynamic> json) => factory GeneralSettings.fromJson(Map<String, dynamic> json) =>
_$GeneralSettingsFromJson(json); _$GeneralSettingsFromJson(json);
@@ -176,5 +180,6 @@ class GeneralSettings with FastEquatable {
tabBarShowQuickTabSwitcherBar, tabBarShowQuickTabSwitcherBar,
tabBarPosition, tabBarPosition,
quickTabSwitcherMode, quickTabSwitcherMode,
pullToRefreshEnabled,
]; ];
} }
@@ -57,6 +57,8 @@ abstract class _$GeneralSettingsCWProxy {
QuickTabSwitcherMode quickTabSwitcherMode, QuickTabSwitcherMode quickTabSwitcherMode,
); );
GeneralSettings pullToRefreshEnabled(bool pullToRefreshEnabled);
/// 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)`.
/// ///
@@ -85,6 +87,7 @@ abstract class _$GeneralSettingsCWProxy {
bool tabBarShowQuickTabSwitcherBar, bool tabBarShowQuickTabSwitcherBar,
TabBarPosition tabBarPosition, TabBarPosition tabBarPosition,
QuickTabSwitcherMode quickTabSwitcherMode, QuickTabSwitcherMode quickTabSwitcherMode,
bool pullToRefreshEnabled,
}); });
} }
@@ -179,6 +182,10 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
QuickTabSwitcherMode quickTabSwitcherMode, QuickTabSwitcherMode quickTabSwitcherMode,
) => call(quickTabSwitcherMode: quickTabSwitcherMode); ) => call(quickTabSwitcherMode: quickTabSwitcherMode);
@override
GeneralSettings pullToRefreshEnabled(bool pullToRefreshEnabled) =>
call(pullToRefreshEnabled: pullToRefreshEnabled);
@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)`.
@@ -208,6 +215,7 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
Object? tabBarShowQuickTabSwitcherBar = const $CopyWithPlaceholder(), Object? tabBarShowQuickTabSwitcherBar = const $CopyWithPlaceholder(),
Object? tabBarPosition = const $CopyWithPlaceholder(), Object? tabBarPosition = const $CopyWithPlaceholder(),
Object? quickTabSwitcherMode = const $CopyWithPlaceholder(), Object? quickTabSwitcherMode = const $CopyWithPlaceholder(),
Object? pullToRefreshEnabled = const $CopyWithPlaceholder(),
}) { }) {
return GeneralSettings( return GeneralSettings(
themeMode: themeMode == const $CopyWithPlaceholder() || themeMode == null themeMode: themeMode == const $CopyWithPlaceholder() || themeMode == null
@@ -326,6 +334,12 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
? _value.quickTabSwitcherMode ? _value.quickTabSwitcherMode
// ignore: cast_nullable_to_non_nullable // ignore: cast_nullable_to_non_nullable
: quickTabSwitcherMode as QuickTabSwitcherMode, : quickTabSwitcherMode as QuickTabSwitcherMode,
pullToRefreshEnabled:
pullToRefreshEnabled == const $CopyWithPlaceholder() ||
pullToRefreshEnabled == null
? _value.pullToRefreshEnabled
// ignore: cast_nullable_to_non_nullable
: pullToRefreshEnabled as bool,
); );
} }
} }
@@ -390,6 +404,7 @@ GeneralSettings _$GeneralSettingsFromJson(
_$QuickTabSwitcherModeEnumMap, _$QuickTabSwitcherModeEnumMap,
json['quickTabSwitcherMode'], json['quickTabSwitcherMode'],
), ),
pullToRefreshEnabled: json['pullToRefreshEnabled'] as bool?,
); );
Map<String, dynamic> _$GeneralSettingsToJson( Map<String, dynamic> _$GeneralSettingsToJson(
@@ -423,6 +438,7 @@ Map<String, dynamic> _$GeneralSettingsToJson(
'tabBarPosition': _$TabBarPositionEnumMap[instance.tabBarPosition]!, 'tabBarPosition': _$TabBarPositionEnumMap[instance.tabBarPosition]!,
'quickTabSwitcherMode': 'quickTabSwitcherMode':
_$QuickTabSwitcherModeEnumMap[instance.quickTabSwitcherMode]!, _$QuickTabSwitcherModeEnumMap[instance.quickTabSwitcherMode]!,
'pullToRefreshEnabled': instance.pullToRefreshEnabled,
}; };
const _$ThemeModeEnumMap = { const _$ThemeModeEnumMap = {
@@ -122,6 +122,10 @@ class GeneralSettingsRepository extends _$GeneralSettingsRepository {
DriftSqlType.string, DriftSqlType.string,
db.typeMapping, db.typeMapping,
), ),
'pullToRefreshEnabled': settings['pullToRefreshEnabled']?.readAs(
DriftSqlType.bool,
db.typeMapping,
),
}); });
} }
@@ -35,7 +35,7 @@ final class GeneralSettingsRepositoryProvider
} }
String _$generalSettingsRepositoryHash() => String _$generalSettingsRepositoryHash() =>
r'74db28f2adc4e35a4c00bb2b7f137ed05a3bc662'; r'dceccac3a93e96907c7bd2b4c58f5021912553ac';
abstract class _$GeneralSettingsRepository abstract class _$GeneralSettingsRepository
extends $StreamNotifier<GeneralSettings> { extends $StreamNotifier<GeneralSettings> {
@@ -242,6 +242,12 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Activit
view = view, view = view,
) )
// Apply pull-to-refresh setting
binding.swipeToRefresh.isEnabled = GlobalComponents.pullToRefreshEnabled
GlobalComponents.onPullToRefreshEnabledChanged = { enabled ->
_binding?.swipeToRefresh?.isEnabled = enabled
}
shareResourceFeature.set( shareResourceFeature.set(
ShareResourceFeature( ShareResourceFeature(
context = components.profileApplicationContext, context = components.profileApplicationContext,
@@ -549,6 +555,7 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Activit
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
GlobalComponents.onPullToRefreshEnabledChanged = null
components.engineView?.setActivityContext(null) components.engineView?.setActivityContext(null)
_binding = null _binding = null
} }
@@ -36,6 +36,15 @@ object GlobalComponents {
val components: Components? val components: Components?
get() = _components get() = _components
// Pull-to-refresh setting
var pullToRefreshEnabled: Boolean = true
set(value) {
field = value
onPullToRefreshEnabledChanged?.invoke(value)
}
var onPullToRefreshEnabledChanged: ((Boolean) -> Unit)? = null
@DelicateCoroutinesApi @DelicateCoroutinesApi
private fun restoreBrowserState(newComponents: Components) = private fun restoreBrowserState(newComponents: Components) =
GlobalScope.launch(Dispatchers.Main) { GlobalScope.launch(Dispatchers.Main) {
@@ -6,7 +6,6 @@
package eu.weblibre.flutter_mozilla_components.api package eu.weblibre.flutter_mozilla_components.api
import eu.weblibre.flutter_mozilla_components.EngineProvider
import eu.weblibre.flutter_mozilla_components.GlobalComponents import eu.weblibre.flutter_mozilla_components.GlobalComponents
import eu.weblibre.flutter_mozilla_components.pigeons.ColorScheme import eu.weblibre.flutter_mozilla_components.pigeons.ColorScheme
import eu.weblibre.flutter_mozilla_components.pigeons.CookieBannerHandlingMode import eu.weblibre.flutter_mozilla_components.pigeons.CookieBannerHandlingMode
@@ -243,4 +242,8 @@ class GeckoEngineSettingsApiImpl : GeckoEngineSettingsApi {
components.useCases.sessionUseCases.reload() components.useCases.sessionUseCases.reload()
} }
} }
override fun setPullToRefreshEnabled(enabled: Boolean) {
GlobalComponents.pullToRefreshEnabled = enabled
}
} }
@@ -3504,6 +3504,7 @@ interface GeckoBrowserApi {
interface GeckoEngineSettingsApi { interface GeckoEngineSettingsApi {
fun setDefaultSettings(settings: GeckoEngineSettings) fun setDefaultSettings(settings: GeckoEngineSettings)
fun updateRuntimeSettings(settings: GeckoEngineSettings) fun updateRuntimeSettings(settings: GeckoEngineSettings)
fun setPullToRefreshEnabled(enabled: Boolean)
companion object { companion object {
/** The codec used by GeckoEngineSettingsApi. */ /** The codec used by GeckoEngineSettingsApi. */
@@ -3550,6 +3551,24 @@ interface GeckoEngineSettingsApi {
channel.setMessageHandler(null) channel.setMessageHandler(null)
} }
} }
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.flutter_mozilla_components.GeckoEngineSettingsApi.setPullToRefreshEnabled$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val enabledArg = args[0] as Boolean
val wrapped: List<Any?> = try {
api.setPullToRefreshEnabled(enabledArg)
listOf(null)
} catch (exception: Throwable) {
GeckoPigeonUtils.wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
} }
} }
} }
@@ -100,4 +100,8 @@ class GeckoEngineSettingsService {
GeckoEngineSettings(fingerprintingProtectionOverrides: state), GeckoEngineSettings(fingerprintingProtectionOverrides: state),
); );
} }
Future<void> setPullToRefreshEnabled(bool enabled) {
return _api.setPullToRefreshEnabled(enabled);
}
} }
@@ -4077,6 +4077,28 @@ class GeckoEngineSettingsApi {
return; return;
} }
} }
Future<void> setPullToRefreshEnabled(bool enabled) async {
final pigeonVar_channelName = 'dev.flutter.pigeon.flutter_mozilla_components.GeckoEngineSettingsApi.setPullToRefreshEnabled$pigeonVar_messageChannelSuffix';
final pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName,
pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger,
);
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(<Object?>[enabled]);
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) {
throw PlatformException(
code: pigeonVar_replyList[0]! as String,
message: pigeonVar_replyList[1] as String?,
details: pigeonVar_replyList[2],
);
} else {
return;
}
}
} }
class GeckoSessionApi { class GeckoSessionApi {
@@ -915,6 +915,7 @@ abstract class GeckoBrowserApi {
abstract class GeckoEngineSettingsApi { abstract class GeckoEngineSettingsApi {
void setDefaultSettings(GeckoEngineSettings settings); void setDefaultSettings(GeckoEngineSettings settings);
void updateRuntimeSettings(GeckoEngineSettings settings); void updateRuntimeSettings(GeckoEngineSettings settings);
void setPullToRefreshEnabled(bool enabled);
} }
@HostApi() @HostApi()