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_hooks/flutter_hooks.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: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';
class AppBarTitle extends StatelessWidget {
final TabState tab;
class AppBarTitle extends HookConsumerWidget {
const AppBarTitle({super.key});
final VoidCallback? onTap;
final VoidCallback? onLongPress;
final GestureDragStartCallback? onHorizontalDragStart;
final GestureDragEndCallback? onHorizontalDragEnd;
@override
Widget build(BuildContext context, WidgetRef ref) {
final theme = Theme.of(context);
const AppBarTitle({
required this.tab,
this.onTap,
this.onLongPress,
this.onHorizontalDragStart,
this.onHorizontalDragEnd,
super.key,
});
final tabState = ref.watch(selectedTabStateProvider);
Icon _securityStatusIcon(BuildContext context) {
if (tab.url.isScheme('http')) {
if (tabState == null) {
return const SizedBox.shrink();
}
final icon = useMemoized(() {
if (tabState.url.isScheme('http')) {
return Icon(
MdiIcons.lockOff,
color: Theme.of(context).colorScheme.error,
size: 14,
);
} else if (!tab.securityInfoState.secure) {
} else if (!tabState.securityInfoState.secure) {
return Icon(
MdiIcons.lockAlert,
color: Theme.of(context).colorScheme.errorContainer,
size: 14,
);
} else if (!tab.isLoading) {
} else if (!tabState.isLoading) {
return const Icon(MdiIcons.lock, size: 14);
} else {
return const Icon(MdiIcons.timerSand, size: 14);
}
}
}, [tabState]);
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return GestureDetector(
onTap: onTap,
onLongPress: onLongPress,
onHorizontalDragStart: onHorizontalDragStart,
onHorizontalDragEnd: onHorizontalDragEnd,
child: Row(
return Row(
children: [
TabIcon(state: tab),
TabIcon(state: tabState),
const SizedBox(width: 8),
Expanded(
child: Column(
@@ -60,15 +50,15 @@ class AppBarTitle extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
children: [
Skeletonizer(
enabled: tab.title.isEmpty,
enabled: tabState.title.isEmpty,
child: Skeleton.replace(
replacement: const Padding(
padding: EdgeInsets.only(right: 4, top: 1, bottom: 1),
child: Bone.text(),
),
child: TextScroll(
key: ValueKey(tab.title),
tab.title,
key: ValueKey(tabState.title),
tabState.title,
style: theme.textTheme.bodyLarge?.copyWith(
color: theme.colorScheme.onSurface,
),
@@ -86,11 +76,11 @@ class AppBarTitle extends StatelessWidget {
),
Row(
children: [
_securityStatusIcon(context),
icon,
const SizedBox(width: 4),
Expanded(
child: Text(
tab.url.authority,
tabState.url.authority,
style: theme.textTheme.bodyMedium?.copyWith(
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),
);
final dragStartPosition = useRef(Offset.zero);
return BottomAppBar(
height: AppBar().preferredSize.height,
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(
automaticallyImplyLeading: false,
titleSpacing: 8.0,
@@ -53,55 +92,7 @@ class BrowserBottomAppBar extends HookConsumerWidget {
: null,
title:
(selectedTabId != null && displayedSheet is! ViewTabsSheet)
? HookConsumer(
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();
},
)
? const AppBarTitle()
: null,
actions: [
if (selectedTabId != null && displayedSheet is! ViewTabsSheet)
@@ -291,7 +282,9 @@ class BrowserBottomAppBar extends HookConsumerWidget {
if (selectedTabId != null)
MenuItemButton(
onPressed: () async {
final tabState = ref.read(tabStateProvider(selectedTabId));
final tabState = ref.read(
tabStateProvider(selectedTabId),
);
if (tabState?.url case final Uri url) {
await ui_helper.launchUrlFeedback(context, url);
@@ -303,7 +296,9 @@ class BrowserBottomAppBar extends HookConsumerWidget {
if (selectedTabId != null)
MenuItemButton(
onPressed: () async {
final tabState = ref.read(tabStateProvider(selectedTabId));
final tabState = ref.read(
tabStateProvider(selectedTabId),
);
if (tabState?.url case final Uri url) {
await SharePlus.instance.share(ShareParams(uri: url));
@@ -377,7 +372,9 @@ class BrowserBottomAppBar extends HookConsumerWidget {
: IconButton(
onPressed: () async {
await ref
.read(tabRepositoryProvider.notifier)
.read(
tabRepositoryProvider.notifier,
)
.closeTab(selectedTabId);
trippleDotMenuController.close();
},
@@ -411,6 +408,7 @@ class BrowserBottomAppBar extends HookConsumerWidget {
),
],
),
),
);
}
}