app bar positioning
This commit is contained in:
@@ -300,13 +300,13 @@ AsyncValue<String?> selectedTabContainerId(Ref ref) {
|
||||
return const AsyncData(null);
|
||||
}
|
||||
|
||||
@Riverpod()
|
||||
Stream<int> tabScrollY(Ref ref, String? tabId, Duration sampleTime) {
|
||||
final eventService = ref.watch(eventServiceProvider);
|
||||
// @Riverpod()
|
||||
// Stream<int> tabScrollY(Ref ref, String? tabId, Duration sampleTime) {
|
||||
// final eventService = ref.watch(eventServiceProvider);
|
||||
|
||||
return eventService.scrollEvent
|
||||
.where((event) => event.tabId == tabId)
|
||||
.sampleTime(sampleTime)
|
||||
.map((event) => event.scrollY)
|
||||
.asBroadcastStream();
|
||||
}
|
||||
// return eventService.scrollEvent
|
||||
// .where((event) => event.tabId == tabId)
|
||||
// .sampleTime(sampleTime)
|
||||
// .map((event) => event.scrollY)
|
||||
// .asBroadcastStream();
|
||||
// }
|
||||
|
||||
@@ -337,72 +337,3 @@ final class SelectedTabContainerIdProvider
|
||||
|
||||
String _$selectedTabContainerIdHash() =>
|
||||
r'07899d29f69654d3b314d0da945ad402b1003b41';
|
||||
|
||||
@ProviderFor(tabScrollY)
|
||||
const tabScrollYProvider = TabScrollYFamily._();
|
||||
|
||||
final class TabScrollYProvider
|
||||
extends $FunctionalProvider<AsyncValue<int>, int, Stream<int>>
|
||||
with $FutureModifier<int>, $StreamProvider<int> {
|
||||
const TabScrollYProvider._({
|
||||
required TabScrollYFamily super.from,
|
||||
required (String?, Duration) super.argument,
|
||||
}) : super(
|
||||
retry: null,
|
||||
name: r'tabScrollYProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$tabScrollYHash();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return r'tabScrollYProvider'
|
||||
''
|
||||
'$argument';
|
||||
}
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$StreamProviderElement<int> $createElement($ProviderPointer pointer) =>
|
||||
$StreamProviderElement(pointer);
|
||||
|
||||
@override
|
||||
Stream<int> create(Ref ref) {
|
||||
final argument = this.argument as (String?, Duration);
|
||||
return tabScrollY(ref, argument.$1, argument.$2);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is TabScrollYProvider && other.argument == argument;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return argument.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
String _$tabScrollYHash() => r'dcb1e82b42bab98c4fc2ee4c7a22f37a28b8ce9e';
|
||||
|
||||
final class TabScrollYFamily extends $Family
|
||||
with $FunctionalFamilyOverride<Stream<int>, (String?, Duration)> {
|
||||
const TabScrollYFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'tabScrollYProvider',
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
isAutoDispose: true,
|
||||
);
|
||||
|
||||
TabScrollYProvider call(String? tabId, Duration sampleTime) =>
|
||||
TabScrollYProvider._(argument: (tabId, sampleTime), from: this);
|
||||
|
||||
@override
|
||||
String toString() => r'tabScrollYProvider';
|
||||
}
|
||||
|
||||
@@ -50,20 +50,27 @@ import 'package:weblibre/features/geckoview/features/browser/presentation/widget
|
||||
import 'package:weblibre/features/geckoview/features/contextmenu/extensions/hit_result.dart';
|
||||
import 'package:weblibre/features/geckoview/features/find_in_page/presentation/widgets/find_in_page.dart';
|
||||
import 'package:weblibre/features/geckoview/features/readerview/presentation/controllers/readerable.dart';
|
||||
import 'package:weblibre/features/user/data/models/general_settings.dart';
|
||||
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
|
||||
import 'package:weblibre/utils/ui_helper.dart' as ui_helper;
|
||||
|
||||
class _TabBar extends HookConsumerWidget {
|
||||
final bool showMainToolbar;
|
||||
final bool showContextualToolbar;
|
||||
final bool showQuickTabSwitcherBar;
|
||||
final ValueNotifier<bool> showAppBar;
|
||||
final ValueNotifier<bool> displayAppBar;
|
||||
final ValueNotifier<PersistentBottomSheetController?> sheetController;
|
||||
final Stream<Offset>? pointerMoveEvents;
|
||||
final TabBarPosition tabBarPosition;
|
||||
|
||||
const _TabBar({
|
||||
required this.showMainToolbar,
|
||||
required this.showContextualToolbar,
|
||||
required this.showQuickTabSwitcherBar,
|
||||
required this.showAppBar,
|
||||
required this.displayAppBar,
|
||||
required this.sheetController,
|
||||
required this.tabBarPosition,
|
||||
required this.pointerMoveEvents,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -75,29 +82,43 @@ class _TabBar extends HookConsumerWidget {
|
||||
selectedTabStateProvider.select((value) => value?.isFullScreen ?? false),
|
||||
);
|
||||
|
||||
final autoHideTabBar = ref.watch(
|
||||
generalSettingsWithDefaultsProvider.select(
|
||||
(value) => value.autoHideTabBar,
|
||||
final autoHideTabBar = switch (tabBarPosition) {
|
||||
TabBarPosition.top => false,
|
||||
TabBarPosition.bottom => ref.watch(
|
||||
generalSettingsWithDefaultsProvider.select(
|
||||
(value) => value.autoHideTabBar,
|
||||
),
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
final appBarVisible = tabBarPosition == TabBarPosition.top
|
||||
? !ref.watch(tabBarDismissableControllerProvider)
|
||||
: useValueListenable(displayAppBar);
|
||||
|
||||
if (!autoHideTabBar) {
|
||||
return Visibility(
|
||||
visible: !tabInFullScreen,
|
||||
child: BrowserBottomAppBar(
|
||||
displayedSheet: displayedSheet,
|
||||
showContextualToolbar: showContextualToolbar,
|
||||
showQuickTabSwitcherBar: showQuickTabSwitcherBar,
|
||||
),
|
||||
visible: !tabInFullScreen && appBarVisible,
|
||||
child: switch (tabBarPosition) {
|
||||
TabBarPosition.top => BrowserTopAppBar(
|
||||
showMainToolbar: showMainToolbar,
|
||||
showContextualToolbar: showContextualToolbar,
|
||||
showQuickTabSwitcherBar: showQuickTabSwitcherBar,
|
||||
),
|
||||
TabBarPosition.bottom => BrowserBottomAppBar(
|
||||
displayedSheet: displayedSheet,
|
||||
showMainToolbar: showMainToolbar,
|
||||
showContextualToolbar: showContextualToolbar,
|
||||
showQuickTabSwitcherBar: showQuickTabSwitcherBar,
|
||||
),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
final appBarVisible = useValueListenable(showAppBar);
|
||||
final diffAcc = useRef(0.0);
|
||||
|
||||
void resetHiddenState() {
|
||||
if (!ref.read(tabBarDismissableControllerProvider)) {
|
||||
showAppBar.value = true;
|
||||
displayAppBar.value = true;
|
||||
}
|
||||
|
||||
diffAcc.value = 0.0;
|
||||
@@ -137,12 +158,10 @@ class _TabBar extends HookConsumerWidget {
|
||||
}
|
||||
});
|
||||
|
||||
ref.listen(tabScrollYProvider(tabId, const Duration(milliseconds: 50)), (
|
||||
previous,
|
||||
next,
|
||||
) {
|
||||
if (previous?.value != null && next.value != null) {
|
||||
final diff = previous!.value! - next.value!;
|
||||
useOnStreamChange(
|
||||
pointerMoveEvents,
|
||||
onData: (event) {
|
||||
final diff = event.dy;
|
||||
if (diff < 0) {
|
||||
if (diffAcc.value > 0) {
|
||||
diffAcc.value = 0.0;
|
||||
@@ -150,7 +169,7 @@ class _TabBar extends HookConsumerWidget {
|
||||
|
||||
diffAcc.value += diff;
|
||||
if (diffAcc.value.abs() > kToolbarHeight * 1.5) {
|
||||
showAppBar.value = false;
|
||||
displayAppBar.value = false;
|
||||
}
|
||||
} else if (diff > 0) {
|
||||
if (diffAcc.value < 0) {
|
||||
@@ -162,18 +181,26 @@ class _TabBar extends HookConsumerWidget {
|
||||
resetHiddenState();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
return Visibility(
|
||||
visible:
|
||||
sheetController.value != null || (!tabInFullScreen && appBarVisible),
|
||||
maintainState: true,
|
||||
child: BrowserBottomAppBar(
|
||||
displayedSheet: displayedSheet,
|
||||
showContextualToolbar: showContextualToolbar,
|
||||
showQuickTabSwitcherBar: showQuickTabSwitcherBar,
|
||||
),
|
||||
child: switch (tabBarPosition) {
|
||||
TabBarPosition.top => BrowserTopAppBar(
|
||||
showMainToolbar: showMainToolbar,
|
||||
showContextualToolbar: showContextualToolbar,
|
||||
showQuickTabSwitcherBar: showQuickTabSwitcherBar,
|
||||
),
|
||||
TabBarPosition.bottom => BrowserBottomAppBar(
|
||||
showMainToolbar: showMainToolbar,
|
||||
displayedSheet: displayedSheet,
|
||||
showContextualToolbar: showContextualToolbar,
|
||||
showQuickTabSwitcherBar: showQuickTabSwitcherBar,
|
||||
),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -191,7 +218,13 @@ class BrowserScreen extends HookConsumerWidget {
|
||||
|
||||
final overlayController = useOverlayPortalController();
|
||||
|
||||
final showContextualAppBar = ref.watch(
|
||||
final tabBarPosition = ref.watch(
|
||||
generalSettingsWithDefaultsProvider.select(
|
||||
(value) => value.tabBarPosition,
|
||||
),
|
||||
);
|
||||
|
||||
final showContextualToolbar = ref.watch(
|
||||
generalSettingsWithDefaultsProvider.select(
|
||||
(value) => value.tabBarShowContextualBar,
|
||||
),
|
||||
@@ -203,10 +236,14 @@ class BrowserScreen extends HookConsumerWidget {
|
||||
),
|
||||
);
|
||||
|
||||
final showAppBar = useValueNotifier(true);
|
||||
final displayAppBar = useValueNotifier(true);
|
||||
final removeTopAppBar = useState(false);
|
||||
|
||||
ref.listen(tabBarDismissableControllerProvider, (previous, next) {
|
||||
showAppBar.value = !next;
|
||||
displayAppBar.value = !next;
|
||||
if (tabBarPosition == TabBarPosition.bottom) {
|
||||
removeTopAppBar.value = next;
|
||||
}
|
||||
});
|
||||
|
||||
ref.listen(overlayControllerProvider, (previous, next) {
|
||||
@@ -244,6 +281,8 @@ class BrowserScreen extends HookConsumerWidget {
|
||||
|
||||
final sheetController = useState<PersistentBottomSheetController?>(null);
|
||||
|
||||
final pointerMoveEventsController = useStreamController<Offset>();
|
||||
|
||||
return PopScope(
|
||||
//We need this for BackButtonListener to work downstream
|
||||
//No direct pop result will be handled here
|
||||
@@ -256,23 +295,50 @@ class BrowserScreen extends HookConsumerWidget {
|
||||
//This causes issues with a non dismissable barrier pushed, we ahve our own barrier and this does seem to have issues when dismissing, so disable it completely
|
||||
return null;
|
||||
},
|
||||
body: Column(
|
||||
children: [
|
||||
_TabBar(
|
||||
showAppBar: showAppBar,
|
||||
sheetController: sheetController,
|
||||
showContextualToolbar: showContextualAppBar,
|
||||
showQuickTabSwitcherBar: showQuickTabSwitcherBar,
|
||||
),
|
||||
Expanded(
|
||||
child: _Browser(
|
||||
overlayController: overlayController,
|
||||
sheetController: sheetController,
|
||||
showAppBar: showAppBar,
|
||||
tabInFullScreen: tabInFullScreen,
|
||||
),
|
||||
),
|
||||
],
|
||||
appBar: (tabBarPosition == TabBarPosition.top)
|
||||
? PreferredSize(
|
||||
preferredSize: BrowserTopAppBar(
|
||||
showMainToolbar: true,
|
||||
showContextualToolbar: showContextualToolbar,
|
||||
showQuickTabSwitcherBar: showQuickTabSwitcherBar,
|
||||
).preferredSize,
|
||||
child: _TabBar(
|
||||
tabBarPosition: TabBarPosition.top,
|
||||
showMainToolbar: true,
|
||||
displayAppBar: displayAppBar,
|
||||
sheetController: sheetController,
|
||||
showContextualToolbar: showContextualToolbar,
|
||||
showQuickTabSwitcherBar: showQuickTabSwitcherBar,
|
||||
pointerMoveEvents: null,
|
||||
),
|
||||
)
|
||||
: removeTopAppBar.value
|
||||
? const PreferredSize(
|
||||
preferredSize: Size.zero,
|
||||
child: SizedBox.shrink(),
|
||||
)
|
||||
: null,
|
||||
bottomNavigationBar: _TabBar(
|
||||
tabBarPosition: TabBarPosition.bottom,
|
||||
displayAppBar: displayAppBar,
|
||||
sheetController: sheetController,
|
||||
showMainToolbar: tabBarPosition == TabBarPosition.bottom,
|
||||
showContextualToolbar: showContextualToolbar,
|
||||
showQuickTabSwitcherBar: showQuickTabSwitcherBar,
|
||||
pointerMoveEvents: pointerMoveEventsController.stream,
|
||||
),
|
||||
body: _Browser(
|
||||
overlayController: overlayController,
|
||||
sheetController: sheetController,
|
||||
displayAppBar: displayAppBar,
|
||||
tabInFullScreen: tabInFullScreen,
|
||||
pointerMoveEventSink: pointerMoveEventsController.sink,
|
||||
bottomAppBarSize: BrowserBottomAppBar(
|
||||
showMainToolbar: false,
|
||||
showContextualToolbar: showContextualToolbar,
|
||||
showQuickTabSwitcherBar: showQuickTabSwitcherBar,
|
||||
displayedSheet: null,
|
||||
).preferredSize,
|
||||
),
|
||||
floatingActionButton: BrowserFab(),
|
||||
),
|
||||
@@ -286,15 +352,19 @@ class _Browser extends HookConsumerWidget {
|
||||
|
||||
final OverlayPortalController overlayController;
|
||||
final ValueNotifier<PersistentBottomSheetController?> sheetController;
|
||||
final ValueNotifier<bool> showAppBar;
|
||||
final ValueNotifier<bool> displayAppBar;
|
||||
final StreamSink<Offset> pointerMoveEventSink;
|
||||
final Size bottomAppBarSize;
|
||||
|
||||
final bool tabInFullScreen;
|
||||
|
||||
const _Browser({
|
||||
required this.overlayController,
|
||||
required this.sheetController,
|
||||
required this.showAppBar,
|
||||
required this.displayAppBar,
|
||||
required this.tabInFullScreen,
|
||||
required this.pointerMoveEventSink,
|
||||
required this.bottomAppBarSize,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -363,6 +433,7 @@ class _Browser extends HookConsumerWidget {
|
||||
child: _ViewUrlSheet(
|
||||
initialTabState: parameter.tabState,
|
||||
maxChildSize: relativeSafeArea,
|
||||
bottomAppBarSize: bottomAppBarSize,
|
||||
),
|
||||
),
|
||||
};
|
||||
@@ -453,7 +524,7 @@ class _Browser extends HookConsumerWidget {
|
||||
|
||||
//Make sure app bar is visible
|
||||
if (!ref.read(tabBarDismissableControllerProvider)) {
|
||||
showAppBar.value = true;
|
||||
displayAppBar.value = true;
|
||||
}
|
||||
|
||||
if (tabState?.isLoading == true) {
|
||||
@@ -530,6 +601,7 @@ class _Browser extends HookConsumerWidget {
|
||||
child: _BrowserView(
|
||||
sheetDisplayed: sheetController.value != null,
|
||||
isFullscreen: tabInFullScreen,
|
||||
pointerMoveEventSink: pointerMoveEventSink,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -542,10 +614,12 @@ class _Browser extends HookConsumerWidget {
|
||||
class _BrowserView extends StatelessWidget {
|
||||
final bool sheetDisplayed;
|
||||
final bool isFullscreen;
|
||||
final StreamSink<Offset>? pointerMoveEventSink;
|
||||
|
||||
const _BrowserView({
|
||||
required this.sheetDisplayed,
|
||||
required this.isFullscreen,
|
||||
this.pointerMoveEventSink,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -559,7 +633,7 @@ class _BrowserView extends StatelessWidget {
|
||||
left: !isFullscreen,
|
||||
child: Stack(
|
||||
children: [
|
||||
const BrowserView(),
|
||||
BrowserView(pointerMoveEventSink: pointerMoveEventSink),
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
@@ -627,8 +701,13 @@ class _BrowserView extends StatelessWidget {
|
||||
class _ViewUrlSheet extends HookConsumerWidget {
|
||||
final double maxChildSize;
|
||||
final TabState initialTabState;
|
||||
final Size bottomAppBarSize;
|
||||
|
||||
const _ViewUrlSheet({required this.initialTabState, this.maxChildSize = 1.0});
|
||||
const _ViewUrlSheet({
|
||||
required this.initialTabState,
|
||||
required this.bottomAppBarSize,
|
||||
this.maxChildSize = 1.0,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
@@ -666,6 +745,7 @@ class _ViewUrlSheet extends HookConsumerWidget {
|
||||
}
|
||||
},
|
||||
initialHeight: initialHeight,
|
||||
bottomAppBarHeight: bottomAppBarSize.height,
|
||||
),
|
||||
);
|
||||
},
|
||||
|
||||
+224
-87
@@ -44,35 +44,114 @@ import 'package:weblibre/features/geckoview/features/browser/presentation/widget
|
||||
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/tab_creation_menu.dart';
|
||||
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/tab_menu.dart';
|
||||
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/tabs_action_button.dart';
|
||||
import 'package:weblibre/features/geckoview/features/history/domain/repositories/history.dart';
|
||||
import 'package:weblibre/features/geckoview/features/readerview/presentation/controllers/readerable.dart';
|
||||
import 'package:weblibre/features/geckoview/features/readerview/presentation/widgets/reader_button.dart';
|
||||
import 'package:weblibre/features/tor/domain/services/tor_proxy.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/repositories/general_settings.dart';
|
||||
import 'package:weblibre/presentation/hooks/cached_future.dart';
|
||||
import 'package:weblibre/presentation/hooks/menu_controller.dart';
|
||||
import 'package:weblibre/presentation/icons/tor_icons.dart';
|
||||
import 'package:weblibre/presentation/widgets/selectable_chips.dart';
|
||||
import 'package:weblibre/presentation/widgets/url_icon.dart';
|
||||
import 'package:weblibre/utils/ui_helper.dart' as ui_helper;
|
||||
|
||||
class BrowserBottomAppBar extends HookConsumerWidget {
|
||||
class BrowserTopAppBar extends HookConsumerWidget {
|
||||
final bool showMainToolbar;
|
||||
final bool showContextualToolbar;
|
||||
final bool showQuickTabSwitcherBar;
|
||||
|
||||
const BrowserBottomAppBar({
|
||||
late final BrowserTabBar _tabBar;
|
||||
late final _size = Size.fromHeight(_tabBar.getToolbarHeight());
|
||||
|
||||
BrowserTopAppBar({
|
||||
required this.showMainToolbar,
|
||||
required this.showContextualToolbar,
|
||||
required this.showQuickTabSwitcherBar,
|
||||
}) {
|
||||
_tabBar = BrowserTabBar(
|
||||
showMainToolbar: showMainToolbar,
|
||||
displayedSheet: null,
|
||||
showContextualToolbar: false,
|
||||
showQuickTabSwitcherBar: false,
|
||||
showMainToolbarNavigationButton: !showContextualToolbar,
|
||||
showMainToolbarTabsCount: !showContextualToolbar,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return SafeArea(
|
||||
child: SizedBox(height: preferredSize.height, child: _tabBar),
|
||||
);
|
||||
}
|
||||
|
||||
Size get preferredSize => _size;
|
||||
}
|
||||
|
||||
class BrowserBottomAppBar extends HookConsumerWidget {
|
||||
final bool showMainToolbar;
|
||||
final bool showContextualToolbar;
|
||||
final bool showQuickTabSwitcherBar;
|
||||
final Sheet? displayedSheet;
|
||||
|
||||
late final BrowserTabBar _tabBar;
|
||||
late final _size = Size.fromHeight(_tabBar.getToolbarHeight());
|
||||
|
||||
BrowserBottomAppBar({
|
||||
required this.showMainToolbar,
|
||||
required this.displayedSheet,
|
||||
required this.showContextualToolbar,
|
||||
required this.showQuickTabSwitcherBar,
|
||||
});
|
||||
}) {
|
||||
_tabBar = BrowserTabBar(
|
||||
displayedSheet: displayedSheet,
|
||||
showMainToolbar: showMainToolbar,
|
||||
showContextualToolbar: showContextualToolbar,
|
||||
showQuickTabSwitcherBar: showQuickTabSwitcherBar,
|
||||
showMainToolbarNavigationButton: !showContextualToolbar,
|
||||
showMainToolbarTabsCount: !showContextualToolbar,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return BottomAppBar(
|
||||
height: _size.height,
|
||||
padding: EdgeInsets.zero,
|
||||
child: _tabBar,
|
||||
);
|
||||
}
|
||||
|
||||
Size get preferredSize => _size;
|
||||
}
|
||||
|
||||
class BrowserTabBar extends HookConsumerWidget {
|
||||
final bool showMainToolbar;
|
||||
final bool showContextualToolbar;
|
||||
final bool showQuickTabSwitcherBar;
|
||||
final Sheet? displayedSheet;
|
||||
|
||||
final bool showMainToolbarTabsCount;
|
||||
final bool showMainToolbarNavigationButton;
|
||||
|
||||
const BrowserTabBar({
|
||||
required this.showMainToolbar,
|
||||
required this.displayedSheet,
|
||||
required this.showContextualToolbar,
|
||||
required this.showQuickTabSwitcherBar,
|
||||
required this.showMainToolbarTabsCount,
|
||||
required this.showMainToolbarNavigationButton,
|
||||
});
|
||||
|
||||
static const contextualToolabarHeight = 54.0;
|
||||
static const quickTabSwitcherHeight = 48.0;
|
||||
|
||||
bool get displayAppBar =>
|
||||
!showContextualToolbar || displayedSheet is! ViewTabsSheet;
|
||||
showMainToolbar &&
|
||||
(!showContextualToolbar || displayedSheet is! ViewTabsSheet);
|
||||
|
||||
bool get displayQuickTabSwitcher =>
|
||||
showQuickTabSwitcherBar && displayedSheet is! ViewTabsSheet;
|
||||
@@ -113,67 +192,68 @@ class BrowserBottomAppBar extends HookConsumerWidget {
|
||||
|
||||
final dragStartPosition = useRef(Offset.zero);
|
||||
|
||||
return BottomAppBar(
|
||||
height: getToolbarHeight(),
|
||||
padding: EdgeInsets.zero,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
if (displayedSheet case EditUrlSheet()) {
|
||||
ref.read(bottomSheetControllerProvider.notifier).requestDismiss();
|
||||
return;
|
||||
}
|
||||
final toolbarHeight = useMemoized(() => getToolbarHeight());
|
||||
|
||||
final tabState = ref.read(selectedTabStateProvider);
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
if (displayedSheet case EditUrlSheet()) {
|
||||
ref.read(bottomSheetControllerProvider.notifier).requestDismiss();
|
||||
return;
|
||||
}
|
||||
|
||||
if (tabState != null) {
|
||||
ref
|
||||
.read(bottomSheetControllerProvider.notifier)
|
||||
.show(EditUrlSheet(tabState: tabState));
|
||||
}
|
||||
},
|
||||
onHorizontalDragStart: (details) {
|
||||
dragStartPosition.value = details.globalPosition;
|
||||
},
|
||||
onHorizontalDragEnd: (details) async {
|
||||
final distance = dragStartPosition.value - details.globalPosition;
|
||||
final tabState = ref.read(selectedTabStateProvider);
|
||||
|
||||
if (distance.dx.abs() > 50 && distance.dy.abs() < 20) {
|
||||
final selectedTab = ref.read(selectedTabProvider);
|
||||
final setting = await ref
|
||||
.read(generalSettingsRepositoryProvider.notifier)
|
||||
.fetchSettings();
|
||||
if (tabState != null) {
|
||||
ref
|
||||
.read(bottomSheetControllerProvider.notifier)
|
||||
.show(EditUrlSheet(tabState: tabState));
|
||||
}
|
||||
},
|
||||
onHorizontalDragStart: (details) {
|
||||
dragStartPosition.value = details.globalPosition;
|
||||
},
|
||||
onHorizontalDragEnd: (details) async {
|
||||
final distance = dragStartPosition.value - details.globalPosition;
|
||||
|
||||
if (selectedTab != null) {
|
||||
switch (setting.tabBarSwipeAction) {
|
||||
case TabBarSwipeAction.switchLastOpened:
|
||||
if (distance.dx.abs() > 50 && distance.dy.abs() < 20) {
|
||||
final selectedTab = ref.read(selectedTabProvider);
|
||||
final setting = await ref
|
||||
.read(generalSettingsRepositoryProvider.notifier)
|
||||
.fetchSettings();
|
||||
|
||||
if (selectedTab != null) {
|
||||
switch (setting.tabBarSwipeAction) {
|
||||
case TabBarSwipeAction.switchLastOpened:
|
||||
await ref
|
||||
.read(tabRepositoryProvider.notifier)
|
||||
.selectPreviouslyOpenedTab(selectedTab);
|
||||
case TabBarSwipeAction.navigateOrderedTabs:
|
||||
if (distance.dx < 0) {
|
||||
await ref
|
||||
.read(tabRepositoryProvider.notifier)
|
||||
.selectPreviouslyOpenedTab(selectedTab);
|
||||
case TabBarSwipeAction.navigateOrderedTabs:
|
||||
if (distance.dx < 0) {
|
||||
await ref
|
||||
.read(tabRepositoryProvider.notifier)
|
||||
.selectPreviousTab(selectedTab);
|
||||
} else {
|
||||
await ref
|
||||
.read(tabRepositoryProvider.notifier)
|
||||
.selectNextTab(selectedTab);
|
||||
}
|
||||
}
|
||||
.selectPreviousTab(selectedTab);
|
||||
} else {
|
||||
await ref
|
||||
.read(tabRepositoryProvider.notifier)
|
||||
.selectNextTab(selectedTab);
|
||||
}
|
||||
}
|
||||
} else if (distance.dy < 20 && distance.dx.abs() < 15) {
|
||||
ref.read(tabBarDismissableControllerProvider.notifier).dismiss();
|
||||
}
|
||||
},
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (showQuickTabSwitcherBar)
|
||||
Visibility(
|
||||
visible: displayQuickTabSwitcher,
|
||||
maintainState: true,
|
||||
child: QuickTabSwitcher(),
|
||||
),
|
||||
} else if (distance.dy < (toolbarHeight / 3) &&
|
||||
distance.dx.abs() < 15) {
|
||||
ref.read(tabBarDismissableControllerProvider.notifier).dismiss();
|
||||
}
|
||||
},
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (showQuickTabSwitcherBar)
|
||||
Visibility(
|
||||
visible: displayQuickTabSwitcher,
|
||||
maintainState: true,
|
||||
child: QuickTabSwitcher(),
|
||||
),
|
||||
if (showMainToolbar)
|
||||
Visibility(
|
||||
visible: displayAppBar,
|
||||
maintainState: true,
|
||||
@@ -269,29 +349,40 @@ class BrowserBottomAppBar extends HookConsumerWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
if (!showContextualToolbar)
|
||||
if (showMainToolbarTabsCount)
|
||||
TabsCountButton(
|
||||
selectedTabId: selectedTabId,
|
||||
displayedSheet: displayedSheet,
|
||||
showLongPressMenu: true,
|
||||
),
|
||||
if (!showContextualToolbar)
|
||||
NavigationMenuButton(selectedTabId: selectedTabId),
|
||||
if (showMainToolbarNavigationButton)
|
||||
NavigationMenuButton(
|
||||
selectedTabId: selectedTabId,
|
||||
showNavigationButtons: true,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (showContextualToolbar)
|
||||
ContextualToolbar(
|
||||
selectedTabId: selectedTabId,
|
||||
displayedSheet: displayedSheet,
|
||||
),
|
||||
],
|
||||
),
|
||||
if (showContextualToolbar)
|
||||
ContextualToolbar(
|
||||
selectedTabId: selectedTabId,
|
||||
displayedSheet: displayedSheet,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
typedef _QuickTabItem = ({
|
||||
Color? color,
|
||||
String id,
|
||||
bool isPrivate,
|
||||
bool isHistory,
|
||||
String title,
|
||||
Uri url,
|
||||
});
|
||||
|
||||
class ContextualToolbar extends HookConsumerWidget {
|
||||
const ContextualToolbar({
|
||||
super.key,
|
||||
@@ -333,7 +424,10 @@ class ContextualToolbar extends HookConsumerWidget {
|
||||
displayedSheet: displayedSheet,
|
||||
showLongPressMenu: false,
|
||||
),
|
||||
NavigationMenuButton(selectedTabId: selectedTabId),
|
||||
NavigationMenuButton(
|
||||
selectedTabId: selectedTabId,
|
||||
showNavigationButtons: false,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -342,7 +436,16 @@ class ContextualToolbar extends HookConsumerWidget {
|
||||
class QuickTabSwitcher extends HookConsumerWidget {
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final tabStates = ref.watch(fifoTabStatesProvider).value;
|
||||
final tabStates = ref.watch(fifoTabStatesProvider);
|
||||
final historyAsync = useCachedFuture(() {
|
||||
if (tabStates.value.length <= 1) {
|
||||
return ref
|
||||
.read(historyRepositoryProvider.notifier)
|
||||
.getVisitsPaginated(count: 25);
|
||||
}
|
||||
|
||||
return Future.value(<VisitInfo>[]);
|
||||
}, [tabStates.value.length <= 1]);
|
||||
|
||||
final chipScrollController = useScrollController();
|
||||
|
||||
@@ -351,19 +454,19 @@ class QuickTabSwitcher extends HookConsumerWidget {
|
||||
child: SizedBox(
|
||||
height: 48,
|
||||
width: double.maxFinite,
|
||||
child: SelectableChips<FifoTab, FifoTab, String>(
|
||||
child: SelectableChips<_QuickTabItem, _QuickTabItem, String>(
|
||||
enableDelete: false,
|
||||
scrollController: chipScrollController,
|
||||
itemId: (item) => item.$1.id,
|
||||
itemId: (item) => item.id,
|
||||
itemLabel: (item) {
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 64),
|
||||
child: Text(item.$1.titleOrAuthority),
|
||||
child: Text(item.title),
|
||||
),
|
||||
if (item.$1.isPrivate)
|
||||
if (item.isPrivate)
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(left: 8.0),
|
||||
child: Icon(
|
||||
@@ -372,23 +475,57 @@ class QuickTabSwitcher extends HookConsumerWidget {
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
if (item.isHistory)
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(left: 8.0),
|
||||
child: Icon(MdiIcons.history, size: 20),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
itemAvatar: (item) => UrlIcon([item.$1.url], iconSize: 16),
|
||||
itemBackgroundColor: (item) => item.$2?.color.withValues(alpha: 0.5),
|
||||
itemAvatar: (item) => UrlIcon([item.url], iconSize: 16),
|
||||
itemBackgroundColor: (item) => item.color?.withValues(alpha: 0.5),
|
||||
onSelected: (item) async {
|
||||
final animation = chipScrollController.animateTo(
|
||||
0,
|
||||
duration: const Duration(milliseconds: 200),
|
||||
curve: Curves.easeOutBack,
|
||||
);
|
||||
await ref
|
||||
.read(tabRepositoryProvider.notifier)
|
||||
.selectTab(item.$1.id);
|
||||
if (item.isHistory) {
|
||||
await ref
|
||||
.read(tabRepositoryProvider.notifier)
|
||||
.addTab(url: item.url, private: false);
|
||||
} else {
|
||||
await ref.read(tabRepositoryProvider.notifier).selectTab(item.id);
|
||||
}
|
||||
await animation;
|
||||
},
|
||||
availableItems: tabStates.skip(1),
|
||||
availableItems: tabStates.value
|
||||
.map(
|
||||
(state) => (
|
||||
id: state.$1.id,
|
||||
title: state.$1.titleOrAuthority,
|
||||
isPrivate: state.$1.isPrivate,
|
||||
isHistory: false,
|
||||
url: state.$1.url,
|
||||
color: state.$2?.color,
|
||||
),
|
||||
)
|
||||
.skip(1)
|
||||
.followedBy(
|
||||
(historyAsync.data ?? []).map((state) {
|
||||
final url = Uri.parse(state.url);
|
||||
|
||||
return (
|
||||
id: state.url,
|
||||
title: state.title ?? url.authority,
|
||||
isPrivate: false,
|
||||
isHistory: true,
|
||||
url: url,
|
||||
color: null,
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -430,18 +567,18 @@ class ShareMenuButton extends HookConsumerWidget {
|
||||
}
|
||||
|
||||
class NavigationMenuButton extends HookConsumerWidget {
|
||||
const NavigationMenuButton({super.key, required this.selectedTabId});
|
||||
|
||||
final String? selectedTabId;
|
||||
final bool showNavigationButtons;
|
||||
|
||||
const NavigationMenuButton({
|
||||
super.key,
|
||||
required this.selectedTabId,
|
||||
required this.showNavigationButtons,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final addonService = ref.watch(addonServiceProvider);
|
||||
final showContextualAppBar = ref.watch(
|
||||
generalSettingsWithDefaultsProvider.select(
|
||||
(value) => value.tabBarShowContextualBar,
|
||||
),
|
||||
);
|
||||
|
||||
final hamburgerMenuController = useMenuController();
|
||||
|
||||
@@ -674,7 +811,7 @@ class NavigationMenuButton extends HookConsumerWidget {
|
||||
child: const Text('Reload'),
|
||||
),
|
||||
if (selectedTabId != null) const Divider(),
|
||||
if (selectedTabId != null && !showContextualAppBar)
|
||||
if (selectedTabId != null && showNavigationButtons)
|
||||
Consumer(
|
||||
builder: (context, ref, child) {
|
||||
final history = ref.watch(
|
||||
|
||||
+85
-69
@@ -44,6 +44,7 @@ import 'package:weblibre/features/geckoview/features/browser/domain/providers/li
|
||||
import 'package:weblibre/features/geckoview/features/browser/domain/services/browser_data.dart';
|
||||
import 'package:weblibre/features/geckoview/features/browser/domain/services/engine_settings_replication.dart';
|
||||
import 'package:weblibre/features/geckoview/features/browser/domain/services/proxy_settings_replication.dart';
|
||||
import 'package:weblibre/features/geckoview/features/history/domain/repositories/history.dart';
|
||||
import 'package:weblibre/features/geckoview/features/preferences/data/repositories/preference_observer.dart';
|
||||
import 'package:weblibre/features/share_intent/domain/entities/shared_content.dart';
|
||||
import 'package:weblibre/features/user/data/models/general_settings.dart';
|
||||
@@ -59,11 +60,13 @@ class BrowserView extends StatefulHookConsumerWidget {
|
||||
final Duration screenshotPeriod;
|
||||
final Duration suggestionTimeout;
|
||||
final Future<void> Function()? postInitializationStep;
|
||||
final StreamSink<Offset>? pointerMoveEventSink;
|
||||
|
||||
const BrowserView({
|
||||
this.screenshotPeriod = const Duration(seconds: 10),
|
||||
this.suggestionTimeout = const Duration(seconds: 30),
|
||||
this.postInitializationStep,
|
||||
this.pointerMoveEventSink,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -106,9 +109,9 @@ class _BrowserViewState extends ConsumerState<BrowserView>
|
||||
|
||||
if (settings.historyAutoCleanInterval > Duration.zero) {
|
||||
await GeckoHistoryService().deleteVisitsBetween(
|
||||
DateTime(0),
|
||||
DateTime.now().subtract(settings.historyAutoCleanInterval),
|
||||
);
|
||||
DateTime(0),
|
||||
DateTime.now().subtract(settings.historyAutoCleanInterval),
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -216,74 +219,87 @@ class _BrowserViewState extends ConsumerState<BrowserView>
|
||||
},
|
||||
);
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
GeckoView(
|
||||
preInitializationStep: () async {
|
||||
await ref
|
||||
.read(eventServiceProvider)
|
||||
.viewReadyStateEvents
|
||||
.firstWhere((state) => state == true)
|
||||
.timeout(
|
||||
const Duration(seconds: 3),
|
||||
onTimeout: () {
|
||||
logger.e(
|
||||
'Browser fragement not reported ready, trying to intitialize anyways',
|
||||
);
|
||||
return true;
|
||||
},
|
||||
);
|
||||
},
|
||||
postInitializationStep: () async {
|
||||
await widget.postInitializationStep?.call();
|
||||
|
||||
if (!initializationCompleter.isCompleted) {
|
||||
const quickActions = QuickActions();
|
||||
|
||||
//Debounce: https://github.com/flutter/flutter/issues/131121
|
||||
DateTime? lastAction;
|
||||
await quickActions.initialize((type) async {
|
||||
if (lastAction == null ||
|
||||
DateTime.now().difference(lastAction!) >
|
||||
const Duration(seconds: 5)) {
|
||||
if (type == 'new_tab') {
|
||||
lastAction = DateTime.now();
|
||||
|
||||
final router = await ref.read(routerProvider.future);
|
||||
const route = SearchRoute(tabType: TabType.regular);
|
||||
|
||||
await router.push(route.location);
|
||||
} else if (type == 'new_private_tab') {
|
||||
lastAction = DateTime.now();
|
||||
|
||||
final router = await ref.read(routerProvider.future);
|
||||
const route = SearchRoute(tabType: TabType.private);
|
||||
|
||||
await router.push(route.location);
|
||||
} else {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await quickActions.setShortcutItems([
|
||||
//TODO: add icons
|
||||
const ShortcutItem(type: 'new_tab', localizedTitle: 'New Tab'),
|
||||
const ShortcutItem(
|
||||
type: 'new_private_tab',
|
||||
localizedTitle: 'New Private Tab',
|
||||
),
|
||||
]);
|
||||
|
||||
initializationCompleter.complete();
|
||||
return Listener(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onPointerMove: (widget.pointerMoveEventSink != null)
|
||||
? (event) {
|
||||
if (event.down) {
|
||||
widget.pointerMoveEventSink!.add(event.localDelta);
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
if (!hasTab)
|
||||
Positioned.fill(
|
||||
child: SizedBox.expand(child: Container(color: Colors.grey[800])),
|
||||
: null,
|
||||
child: Stack(
|
||||
children: [
|
||||
GeckoView(
|
||||
preInitializationStep: () async {
|
||||
await ref
|
||||
.read(eventServiceProvider)
|
||||
.viewReadyStateEvents
|
||||
.firstWhere((state) => state == true)
|
||||
.timeout(
|
||||
const Duration(seconds: 3),
|
||||
onTimeout: () {
|
||||
logger.e(
|
||||
'Browser fragement not reported ready, trying to intitialize anyways',
|
||||
);
|
||||
return true;
|
||||
},
|
||||
);
|
||||
},
|
||||
postInitializationStep: () async {
|
||||
await widget.postInitializationStep?.call();
|
||||
|
||||
if (!initializationCompleter.isCompleted) {
|
||||
const quickActions = QuickActions();
|
||||
|
||||
//Debounce: https://github.com/flutter/flutter/issues/131121
|
||||
DateTime? lastAction;
|
||||
await quickActions.initialize((type) async {
|
||||
if (lastAction == null ||
|
||||
DateTime.now().difference(lastAction!) >
|
||||
const Duration(seconds: 5)) {
|
||||
if (type == 'new_tab') {
|
||||
lastAction = DateTime.now();
|
||||
|
||||
final router = await ref.read(routerProvider.future);
|
||||
const route = SearchRoute(tabType: TabType.regular);
|
||||
|
||||
await router.push(route.location);
|
||||
} else if (type == 'new_private_tab') {
|
||||
lastAction = DateTime.now();
|
||||
|
||||
final router = await ref.read(routerProvider.future);
|
||||
const route = SearchRoute(tabType: TabType.private);
|
||||
|
||||
await router.push(route.location);
|
||||
} else {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await quickActions.setShortcutItems([
|
||||
//TODO: add icons
|
||||
const ShortcutItem(
|
||||
type: 'new_tab',
|
||||
localizedTitle: 'New Tab',
|
||||
),
|
||||
const ShortcutItem(
|
||||
type: 'new_private_tab',
|
||||
localizedTitle: 'New Private Tab',
|
||||
),
|
||||
]);
|
||||
|
||||
initializationCompleter.complete();
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
if (!hasTab)
|
||||
Positioned.fill(
|
||||
child: SizedBox.expand(child: Container(color: Colors.grey[800])),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -48,6 +48,7 @@ class ViewTabSheetWidget extends HookConsumerWidget {
|
||||
final DraggableScrollableController draggableScrollableController;
|
||||
final VoidCallback onClose;
|
||||
final double initialHeight;
|
||||
final double bottomAppBarHeight;
|
||||
|
||||
const ViewTabSheetWidget({
|
||||
required this.initialTabState,
|
||||
@@ -55,6 +56,7 @@ class ViewTabSheetWidget extends HookConsumerWidget {
|
||||
required this.draggableScrollableController,
|
||||
required this.onClose,
|
||||
required this.initialHeight,
|
||||
required this.bottomAppBarHeight,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -79,7 +81,7 @@ class ViewTabSheetWidget extends HookConsumerWidget {
|
||||
final totalHeight =
|
||||
headerBox.size.height +
|
||||
textBox.size.height +
|
||||
kToolbarHeight +
|
||||
bottomAppBarHeight +
|
||||
MediaQuery.of(context).viewInsets.bottom;
|
||||
|
||||
final relative = (totalHeight / MediaQuery.of(context).size.height)
|
||||
|
||||
@@ -362,6 +362,55 @@ class GeneralSettingsScreen extends HookConsumerWidget {
|
||||
);
|
||||
},
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0,
|
||||
vertical: 8,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const ListTile(
|
||||
title: Text('Tab Bar Position'),
|
||||
leading: Icon(MdiIcons.dockWindow),
|
||||
contentPadding: EdgeInsets.zero,
|
||||
),
|
||||
RadioGroup(
|
||||
groupValue: generalSettings.tabBarPosition,
|
||||
onChanged: (value) async {
|
||||
if (value != null) {
|
||||
await ref
|
||||
.read(
|
||||
saveGeneralSettingsControllerProvider.notifier,
|
||||
)
|
||||
.save(
|
||||
(currentSettings) => currentSettings.copyWith
|
||||
.tabBarPosition(value),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: const Column(
|
||||
children: [
|
||||
RadioListTile.adaptive(
|
||||
value: TabBarPosition.top,
|
||||
title: Text('Top'),
|
||||
subtitle: Text(
|
||||
'Persistent tab bar without auto-hide',
|
||||
),
|
||||
),
|
||||
RadioListTile.adaptive(
|
||||
value: TabBarPosition.bottom,
|
||||
title: Text('Bottom'),
|
||||
subtitle: Text('Tab bar with auto-hide support'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
SwitchListTile.adaptive(
|
||||
title: const Text('Show Contextual Tab Bar'),
|
||||
subtitle: const Text(
|
||||
|
||||
@@ -38,6 +38,8 @@ enum TabBarSwipeAction { switchLastOpened, navigateOrderedTabs }
|
||||
|
||||
enum TabIntentOpenSetting { regular, private, ask }
|
||||
|
||||
enum TabBarPosition { top, bottom }
|
||||
|
||||
enum DeleteBrowsingDataType {
|
||||
tabs('Open tabs'),
|
||||
history('Browsing history'),
|
||||
@@ -74,6 +76,7 @@ class GeneralSettings with FastEquatable {
|
||||
final bool tabBarReaderView;
|
||||
final bool tabBarShowContextualBar;
|
||||
final bool tabBarShowQuickTabSwitcherBar;
|
||||
final TabBarPosition tabBarPosition;
|
||||
|
||||
GeneralSettings({
|
||||
required this.themeMode,
|
||||
@@ -94,6 +97,7 @@ class GeneralSettings with FastEquatable {
|
||||
required this.tabBarReaderView,
|
||||
required this.tabBarShowContextualBar,
|
||||
required this.tabBarShowQuickTabSwitcherBar,
|
||||
required this.tabBarPosition,
|
||||
});
|
||||
|
||||
GeneralSettings.withDefaults({
|
||||
@@ -115,6 +119,7 @@ class GeneralSettings with FastEquatable {
|
||||
bool? tabBarReaderView,
|
||||
bool? tabBarShowContextualBar,
|
||||
bool? tabBarShowQuickTabSwitcherBar,
|
||||
TabBarPosition? tabBarPosition,
|
||||
}) : themeMode = themeMode ?? ThemeMode.dark,
|
||||
enableReadability = enableReadability ?? true,
|
||||
enforceReadability = enforceReadability ?? false,
|
||||
@@ -134,7 +139,8 @@ class GeneralSettings with FastEquatable {
|
||||
tabViewBottomSheet = tabViewBottomSheet ?? false,
|
||||
tabBarReaderView = tabBarReaderView ?? false,
|
||||
tabBarShowContextualBar = tabBarShowContextualBar ?? true,
|
||||
tabBarShowQuickTabSwitcherBar = tabBarShowQuickTabSwitcherBar ?? true;
|
||||
tabBarShowQuickTabSwitcherBar = tabBarShowQuickTabSwitcherBar ?? true,
|
||||
tabBarPosition = tabBarPosition ?? TabBarPosition.bottom;
|
||||
|
||||
factory GeneralSettings.fromJson(Map<String, dynamic> json) =>
|
||||
_$GeneralSettingsFromJson(json);
|
||||
@@ -161,5 +167,6 @@ class GeneralSettings with FastEquatable {
|
||||
tabBarReaderView,
|
||||
tabBarShowContextualBar,
|
||||
tabBarShowQuickTabSwitcherBar,
|
||||
tabBarPosition,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -51,6 +51,8 @@ abstract class _$GeneralSettingsCWProxy {
|
||||
bool tabBarShowQuickTabSwitcherBar,
|
||||
);
|
||||
|
||||
GeneralSettings tabBarPosition(TabBarPosition tabBarPosition);
|
||||
|
||||
/// 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)`.
|
||||
///
|
||||
@@ -77,6 +79,7 @@ abstract class _$GeneralSettingsCWProxy {
|
||||
bool tabBarReaderView,
|
||||
bool tabBarShowContextualBar,
|
||||
bool tabBarShowQuickTabSwitcherBar,
|
||||
TabBarPosition tabBarPosition,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -162,6 +165,10 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
|
||||
bool tabBarShowQuickTabSwitcherBar,
|
||||
) => call(tabBarShowQuickTabSwitcherBar: tabBarShowQuickTabSwitcherBar);
|
||||
|
||||
@override
|
||||
GeneralSettings tabBarPosition(TabBarPosition tabBarPosition) =>
|
||||
call(tabBarPosition: tabBarPosition);
|
||||
|
||||
@override
|
||||
/// 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)`.
|
||||
@@ -189,6 +196,7 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
|
||||
Object? tabBarReaderView = const $CopyWithPlaceholder(),
|
||||
Object? tabBarShowContextualBar = const $CopyWithPlaceholder(),
|
||||
Object? tabBarShowQuickTabSwitcherBar = const $CopyWithPlaceholder(),
|
||||
Object? tabBarPosition = const $CopyWithPlaceholder(),
|
||||
}) {
|
||||
return GeneralSettings(
|
||||
themeMode: themeMode == const $CopyWithPlaceholder() || themeMode == null
|
||||
@@ -295,6 +303,12 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
|
||||
? _value.tabBarShowQuickTabSwitcherBar
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
: tabBarShowQuickTabSwitcherBar as bool,
|
||||
tabBarPosition:
|
||||
tabBarPosition == const $CopyWithPlaceholder() ||
|
||||
tabBarPosition == null
|
||||
? _value.tabBarPosition
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
: tabBarPosition as TabBarPosition,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -351,6 +365,10 @@ GeneralSettings _$GeneralSettingsFromJson(
|
||||
tabBarReaderView: json['tabBarReaderView'] as bool?,
|
||||
tabBarShowContextualBar: json['tabBarShowContextualBar'] as bool?,
|
||||
tabBarShowQuickTabSwitcherBar: json['tabBarShowQuickTabSwitcherBar'] as bool?,
|
||||
tabBarPosition: $enumDecodeNullable(
|
||||
_$TabBarPositionEnumMap,
|
||||
json['tabBarPosition'],
|
||||
),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$GeneralSettingsToJson(
|
||||
@@ -381,6 +399,7 @@ Map<String, dynamic> _$GeneralSettingsToJson(
|
||||
'tabBarReaderView': instance.tabBarReaderView,
|
||||
'tabBarShowContextualBar': instance.tabBarShowContextualBar,
|
||||
'tabBarShowQuickTabSwitcherBar': instance.tabBarShowQuickTabSwitcherBar,
|
||||
'tabBarPosition': _$TabBarPositionEnumMap[instance.tabBarPosition]!,
|
||||
};
|
||||
|
||||
const _$ThemeModeEnumMap = {
|
||||
@@ -422,3 +441,8 @@ const _$TabBarSwipeActionEnumMap = {
|
||||
TabBarSwipeAction.switchLastOpened: 'switchLastOpened',
|
||||
TabBarSwipeAction.navigateOrderedTabs: 'navigateOrderedTabs',
|
||||
};
|
||||
|
||||
const _$TabBarPositionEnumMap = {
|
||||
TabBarPosition.top: 'top',
|
||||
TabBarPosition.bottom: 'bottom',
|
||||
};
|
||||
|
||||
@@ -114,6 +114,10 @@ class GeneralSettingsRepository extends _$GeneralSettingsRepository {
|
||||
),
|
||||
'tabBarShowQuickTabSwitcherBar': settings['tabBarShowQuickTabSwitcherBar']
|
||||
?.readAs(DriftSqlType.bool, db.typeMapping),
|
||||
'tabBarPosition': settings['tabBarPosition']?.readAs(
|
||||
DriftSqlType.string,
|
||||
db.typeMapping,
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ final class GeneralSettingsRepositoryProvider
|
||||
}
|
||||
|
||||
String _$generalSettingsRepositoryHash() =>
|
||||
r'4014986c9510d6d7210c5c16d814f6b018a1f93c';
|
||||
r'09542387844db25334384af115c538348b0ad33f';
|
||||
|
||||
abstract class _$GeneralSettingsRepository
|
||||
extends $StreamNotifier<GeneralSettings> {
|
||||
|
||||
Reference in New Issue
Block a user