refactor bottom app abr title

This commit is contained in:
Fabian Freund
2025-05-19 19:42:42 +02:00
parent 9b88e6d213
commit 4fe6f9663a
2 changed files with 419 additions and 432 deletions
@@ -1,58 +1,48 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart'; import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:skeletonizer/skeletonizer.dart'; import 'package:skeletonizer/skeletonizer.dart';
import 'package:text_scroll/text_scroll.dart'; import 'package:text_scroll/text_scroll.dart';
import 'package:weblibre/features/geckoview/domain/entities/states/tab.dart'; import 'package:weblibre/features/geckoview/domain/providers/tab_state.dart';
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/tab_icon.dart'; import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/tab_icon.dart';
class AppBarTitle extends StatelessWidget { class AppBarTitle extends HookConsumerWidget {
final TabState tab; const AppBarTitle({super.key});
final VoidCallback? onTap; @override
final VoidCallback? onLongPress; Widget build(BuildContext context, WidgetRef ref) {
final GestureDragStartCallback? onHorizontalDragStart; final theme = Theme.of(context);
final GestureDragEndCallback? onHorizontalDragEnd;
const AppBarTitle({ final tabState = ref.watch(selectedTabStateProvider);
required this.tab,
this.onTap,
this.onLongPress,
this.onHorizontalDragStart,
this.onHorizontalDragEnd,
super.key,
});
Icon _securityStatusIcon(BuildContext context) { if (tabState == null) {
if (tab.url.isScheme('http')) { return const SizedBox.shrink();
}
final icon = useMemoized(() {
if (tabState.url.isScheme('http')) {
return Icon( return Icon(
MdiIcons.lockOff, MdiIcons.lockOff,
color: Theme.of(context).colorScheme.error, color: Theme.of(context).colorScheme.error,
size: 14, size: 14,
); );
} else if (!tab.securityInfoState.secure) { } else if (!tabState.securityInfoState.secure) {
return Icon( return Icon(
MdiIcons.lockAlert, MdiIcons.lockAlert,
color: Theme.of(context).colorScheme.errorContainer, color: Theme.of(context).colorScheme.errorContainer,
size: 14, size: 14,
); );
} else if (!tab.isLoading) { } else if (!tabState.isLoading) {
return const Icon(MdiIcons.lock, size: 14); return const Icon(MdiIcons.lock, size: 14);
} else { } else {
return const Icon(MdiIcons.timerSand, size: 14); return const Icon(MdiIcons.timerSand, size: 14);
} }
} }, [tabState]);
@override return Row(
Widget build(BuildContext context) {
final theme = Theme.of(context);
return GestureDetector(
onTap: onTap,
onLongPress: onLongPress,
onHorizontalDragStart: onHorizontalDragStart,
onHorizontalDragEnd: onHorizontalDragEnd,
child: Row(
children: [ children: [
TabIcon(state: tab), TabIcon(state: tabState),
const SizedBox(width: 8), const SizedBox(width: 8),
Expanded( Expanded(
child: Column( child: Column(
@@ -60,15 +50,15 @@ class AppBarTitle extends StatelessWidget {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Skeletonizer( Skeletonizer(
enabled: tab.title.isEmpty, enabled: tabState.title.isEmpty,
child: Skeleton.replace( child: Skeleton.replace(
replacement: const Padding( replacement: const Padding(
padding: EdgeInsets.only(right: 4, top: 1, bottom: 1), padding: EdgeInsets.only(right: 4, top: 1, bottom: 1),
child: Bone.text(), child: Bone.text(),
), ),
child: TextScroll( child: TextScroll(
key: ValueKey(tab.title), key: ValueKey(tabState.title),
tab.title, tabState.title,
style: theme.textTheme.bodyLarge?.copyWith( style: theme.textTheme.bodyLarge?.copyWith(
color: theme.colorScheme.onSurface, color: theme.colorScheme.onSurface,
), ),
@@ -86,11 +76,11 @@ class AppBarTitle extends StatelessWidget {
), ),
Row( Row(
children: [ children: [
_securityStatusIcon(context), icon,
const SizedBox(width: 4), const SizedBox(width: 4),
Expanded( Expanded(
child: Text( child: Text(
tab.url.authority, tabState.url.authority,
style: theme.textTheme.bodyMedium?.copyWith( style: theme.textTheme.bodyMedium?.copyWith(
color: theme.colorScheme.onSurface, color: theme.colorScheme.onSurface,
), ),
@@ -102,7 +92,6 @@ class AppBarTitle extends StatelessWidget {
), ),
), ),
], ],
),
); );
} }
} }
@@ -41,9 +41,48 @@ class BrowserBottomAppBar extends HookConsumerWidget {
selectedTabStateProvider.select((state) => state?.isPrivate ?? false), selectedTabStateProvider.select((state) => state?.isPrivate ?? false),
); );
final dragStartPosition = useRef(Offset.zero);
return BottomAppBar( return BottomAppBar(
height: AppBar().preferredSize.height, height: AppBar().preferredSize.height,
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
child: GestureDetector(
onTap: () async {
final tabState = ref.read(selectedTabStateProvider);
if (tabState != null) {
await WebPageRoute(
url: tabState.url.toString(),
$extra: tabState,
).push(context);
}
},
onLongPress: () async {
final tabState = ref.read(selectedTabStateProvider);
if (tabState != null) {
final newUrl = await showDialog<Uri?>(
context: context,
builder: (context) => EditUrlDialog(initialUrl: tabState.url),
);
if (newUrl != null) {
await ref
.read(tabSessionProvider(tabId: null).notifier)
.loadUrl(url: newUrl);
}
}
},
onHorizontalDragStart: (details) {
dragStartPosition.value = details.globalPosition;
},
onHorizontalDragEnd: (details) async {
final distance = dragStartPosition.value - details.globalPosition;
if (distance.dx.abs() > 50) {
await ref.read(tabRepositoryProvider.notifier).selectPreviousTab();
}
},
child: AppBar( child: AppBar(
automaticallyImplyLeading: false, automaticallyImplyLeading: false,
titleSpacing: 8.0, titleSpacing: 8.0,
@@ -53,55 +92,7 @@ class BrowserBottomAppBar extends HookConsumerWidget {
: null, : null,
title: title:
(selectedTabId != null && displayedSheet is! ViewTabsSheet) (selectedTabId != null && displayedSheet is! ViewTabsSheet)
? HookConsumer( ? const AppBarTitle()
builder: (context, ref, child) {
final tabState = ref.watch(selectedTabStateProvider);
final dragStartPosition = useRef(Offset.zero);
return (tabState != null)
? AppBarTitle(
tab: tabState,
onTap: () async {
await WebPageRoute(
url: tabState.url.toString(),
$extra: tabState,
).push(context);
},
onLongPress: () async {
final newUrl = await showDialog<Uri?>(
context: context,
builder:
(context) =>
EditUrlDialog(initialUrl: tabState.url),
);
if (newUrl != null) {
await ref
.read(
tabSessionProvider(tabId: null).notifier,
)
.loadUrl(url: newUrl);
}
},
onHorizontalDragStart: (details) {
dragStartPosition.value = details.globalPosition;
},
onHorizontalDragEnd: (details) async {
final distance =
dragStartPosition.value -
details.globalPosition;
if (distance.dx.abs() > 50) {
await ref
.read(tabRepositoryProvider.notifier)
.selectPreviousTab();
}
},
)
: const SizedBox.shrink();
},
)
: null, : null,
actions: [ actions: [
if (selectedTabId != null && displayedSheet is! ViewTabsSheet) if (selectedTabId != null && displayedSheet is! ViewTabsSheet)
@@ -291,7 +282,9 @@ class BrowserBottomAppBar extends HookConsumerWidget {
if (selectedTabId != null) if (selectedTabId != null)
MenuItemButton( MenuItemButton(
onPressed: () async { onPressed: () async {
final tabState = ref.read(tabStateProvider(selectedTabId)); final tabState = ref.read(
tabStateProvider(selectedTabId),
);
if (tabState?.url case final Uri url) { if (tabState?.url case final Uri url) {
await ui_helper.launchUrlFeedback(context, url); await ui_helper.launchUrlFeedback(context, url);
@@ -303,7 +296,9 @@ class BrowserBottomAppBar extends HookConsumerWidget {
if (selectedTabId != null) if (selectedTabId != null)
MenuItemButton( MenuItemButton(
onPressed: () async { onPressed: () async {
final tabState = ref.read(tabStateProvider(selectedTabId)); final tabState = ref.read(
tabStateProvider(selectedTabId),
);
if (tabState?.url case final Uri url) { if (tabState?.url case final Uri url) {
await SharePlus.instance.share(ShareParams(uri: url)); await SharePlus.instance.share(ShareParams(uri: url));
@@ -377,7 +372,9 @@ class BrowserBottomAppBar extends HookConsumerWidget {
: IconButton( : IconButton(
onPressed: () async { onPressed: () async {
await ref await ref
.read(tabRepositoryProvider.notifier) .read(
tabRepositoryProvider.notifier,
)
.closeTab(selectedTabId); .closeTab(selectedTabId);
trippleDotMenuController.close(); trippleDotMenuController.close();
}, },
@@ -411,6 +408,7 @@ class BrowserBottomAppBar extends HookConsumerWidget {
), ),
], ],
), ),
),
); );
} }
} }