refactor bottom app abr title
This commit is contained in:
+25
-36
@@ -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 {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+50
-52
@@ -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 {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user