various ui improvements

This commit is contained in:
Fabian Freund
2025-05-03 23:43:30 +02:00
parent ca32c7d43d
commit 10b2e46984
8 changed files with 122 additions and 89 deletions
@@ -6,7 +6,7 @@ part of 'tab.dart';
// RiverpodGenerator
// **************************************************************************
String _$tabRepositoryHash() => r'743732f6911372ea901b5a9402791569bfe80137';
String _$tabRepositoryHash() => r'9b7ef03bec41f149b3cb456b73d7ee0e1b2804df';
/// See also [TabRepository].
@ProviderFor(TabRepository)
@@ -39,10 +39,6 @@ class BrowserScreen extends HookConsumerWidget {
final displayedSheet = ref.watch(bottomSheetControllerProvider);
final displayedOverlay = ref.watch(overlayControllerProvider);
final selectedTabId = ref.watch(
selectedTabStateProvider.select((value) => value?.id),
);
final lastBackButtonPress = useRef<DateTime?>(null);
final overlayController = useOverlayPortalController();
@@ -91,10 +87,7 @@ class BrowserScreen extends HookConsumerWidget {
return Visibility(
visible: !tabInFullScreen,
child: BrowserBottomAppBar(
selectedTabId: selectedTabId,
displayedSheet: displayedSheet,
),
child: BrowserBottomAppBar(displayedSheet: displayedSheet),
);
},
),
@@ -129,10 +122,7 @@ class BrowserScreen extends HookConsumerWidget {
: null,
child: BackButtonListener(
onBackButtonPressed: () async {
final tabState =
(selectedTabId != null)
? ref.read(tabStateProvider(selectedTabId))
: null;
final tabState = ref.read(selectedTabStateProvider);
final tabCount = ref.read(
tabListProvider.select((tabs) => tabs.value.length),
@@ -167,7 +157,7 @@ class BrowserScreen extends HookConsumerWidget {
lastBackButtonPress.value = null;
final controller = ref.read(
tabSessionProvider(tabId: selectedTabId).notifier,
selectedTabSessionNotifierProvider,
);
await controller.stopLoading();
@@ -176,7 +166,7 @@ class BrowserScreen extends HookConsumerWidget {
lastBackButtonPress.value = null;
final controller = ref.read(
tabSessionProvider(tabId: selectedTabId).notifier,
selectedTabSessionNotifierProvider,
);
await controller.goBack();
@@ -190,7 +180,7 @@ class BrowserScreen extends HookConsumerWidget {
if (ref
.read(tabRepositoryProvider.notifier)
.hasLaunchedFromIntent(selectedTabId)) {
.hasLaunchedFromIntent(tabState?.id)) {
//Mark back as unhandled and navigator will pop
await SystemNavigator.pop();
return false;
@@ -7,6 +7,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:lensai/core/routing/routes.dart';
import 'package:lensai/features/geckoview/domain/controllers/bottom_sheet.dart';
import 'package:lensai/features/geckoview/domain/providers.dart';
import 'package:lensai/features/geckoview/domain/providers/selected_tab.dart';
import 'package:lensai/features/geckoview/domain/providers/tab_session.dart';
import 'package:lensai/features/geckoview/domain/providers/tab_state.dart';
import 'package:lensai/features/geckoview/domain/providers/web_extensions_state.dart';
@@ -24,12 +25,8 @@ import 'package:lensai/utils/ui_helper.dart' as ui_helper;
import 'package:share_plus/share_plus.dart';
class BrowserBottomAppBar extends HookConsumerWidget {
const BrowserBottomAppBar({
required this.selectedTabId,
required this.displayedSheet,
});
const BrowserBottomAppBar({required this.displayedSheet});
final String? selectedTabId;
final Sheet? displayedSheet;
@override
@@ -39,17 +36,26 @@ class BrowserBottomAppBar extends HookConsumerWidget {
final tabMenuController = useMenuController();
final trippleDotMenuController = useMenuController();
final selectedTabId = ref.watch(selectedTabProvider);
final isPrivateTab = ref.watch(
selectedTabStateProvider.select((state) => state?.isPrivate ?? false),
);
return BottomAppBar(
height: AppBar().preferredSize.height,
padding: EdgeInsets.zero,
child: AppBar(
automaticallyImplyLeading: false,
titleSpacing: 8.0,
backgroundColor:
(isPrivateTab && displayedSheet is! ViewTabsSheet)
? const Color(0x648000D7)
: null,
title:
(selectedTabId != null && displayedSheet is! ViewTabsSheet)
? HookConsumer(
builder: (context, ref, child) {
final tabState = ref.watch(tabStateProvider(selectedTabId));
final tabState = ref.watch(selectedTabStateProvider);
final dragStartPosition = useRef(Offset.zero);
@@ -111,7 +117,7 @@ class BrowserBottomAppBar extends HookConsumerWidget {
onPressed: () async {
await ref
.read(tabRepositoryProvider.notifier)
.closeTab(selectedTabId!);
.closeTab(selectedTabId);
},
leadingIcon: const Icon(Icons.close),
child: const Text('Close Tab'),
@@ -374,7 +380,7 @@ class BrowserBottomAppBar extends HookConsumerWidget {
onPressed: () async {
await ref
.read(tabRepositoryProvider.notifier)
.closeTab(selectedTabId!);
.closeTab(selectedTabId);
trippleDotMenuController.close();
},
icon: const Icon(Icons.close),
@@ -11,6 +11,7 @@ import 'package:lensai/core/providers/global_drop.dart';
import 'package:lensai/core/routing/routes.dart';
import 'package:lensai/data/models/drag_data.dart';
import 'package:lensai/features/geckoview/domain/providers/selected_tab.dart';
import 'package:lensai/features/geckoview/domain/providers/tab_state.dart';
import 'package:lensai/features/geckoview/features/browser/domain/providers.dart';
import 'package:lensai/features/geckoview/features/browser/presentation/widgets/draggable_scrollable_header.dart';
import 'package:lensai/features/geckoview/features/browser/presentation/widgets/tab_preview.dart';
@@ -91,7 +92,7 @@ class _TabSheetHeader extends HookConsumerWidget {
// enableIMEPersonalizedLearning: !incognitoEnabled,
decoration: InputDecoration(
// border: InputBorder.none,
prefixIcon: const Icon(Icons.search),
prefixIcon: const Icon(MdiIcons.tabSearch),
hintText: 'Search inside tabs...',
floatingLabelBehavior: FloatingLabelBehavior.always,
suffixIcon: Row(
@@ -411,7 +412,11 @@ class ViewTabsSheetWidget extends HookConsumerWidget {
),
child: FloatingActionButton.small(
onPressed: () async {
await const SearchRoute(tabType: TabType.regular).push(context);
final isCurrentPrivate =
ref.read(selectedTabStateProvider)?.isPrivate ?? false;
await SearchRoute(
tabType: isCurrentPrivate ? TabType.private : TabType.regular,
).push(context);
onClose();
},
@@ -87,7 +87,22 @@ class TabPreview extends StatelessWidget {
),
if (tab.isPrivate) ...[
const SizedBox(width: 6.0),
const Icon(MdiIcons.dominoMask, color: Color(0xFF8000D7)),
const SizedBox(
height: 16,
width: 24,
child: Stack(
fit: StackFit.expand,
children: [
Positioned(
top: -4,
child: Icon(
MdiIcons.dominoMask,
color: Color(0xFF8000D7),
),
),
],
),
),
],
const SizedBox(width: 8.0),
],
@@ -1,5 +1,4 @@
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:lensai/features/geckoview/domain/entities/states/readerable.dart';
@@ -27,59 +26,66 @@ class ReaderButton extends HookConsumerWidget {
),
);
final icon = useMemoized(
() =>
readerabilityState.active
? Icon(
MdiIcons.bookOpen,
color: Theme.of(context).colorScheme.primary,
)
: const Icon(MdiIcons.bookOpenOutline, color: Colors.white),
[readerabilityState.active],
);
final icon =
readerabilityState.active
? Icon(
MdiIcons.bookOpen,
color: Theme.of(context).colorScheme.primary,
)
: Icon(
MdiIcons.bookOpenOutline,
color: Theme.of(context).colorScheme.onSurface,
);
return Visibility(
visible:
readerabilityState.readerable &&
(enableReadability || readerabilityState.active),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 15.0, horizontal: 8.0),
child: readerChanging.when(
skipLoadingOnReload: true,
data:
(_) => Visibility(
visible: readerabilityState.readerable,
child: InkWell(
onTap:
readerChanging.isLoading
? null
: () async {
await ref
.read(
readerableScreenControllerProvider.notifier,
)
.toggleReaderView(!readerabilityState.active);
},
child: readerChanging.when(
skipLoadingOnReload: true,
data:
(_) => Visibility(
visible: readerabilityState.readerable,
child: InkWell(
onTap:
readerChanging.isLoading
? null
: () async {
await ref
.read(readerableScreenControllerProvider.notifier)
.toggleReaderView(!readerabilityState.active);
},
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 15.0,
horizontal: 8.0,
),
child: icon,
),
),
error: (error, stackTrace) => SizedBox.shrink(),
loading:
() => AnimateGradientShader(
duration: const Duration(milliseconds: 500),
primaryEnd: Alignment.bottomLeft,
secondaryEnd: Alignment.topRight,
primaryColors: [
colorScheme.primary,
colorScheme.primaryContainer,
],
secondaryColors: [
colorScheme.secondary,
colorScheme.secondaryContainer,
],
),
error: (error, stackTrace) => SizedBox.shrink(),
loading:
() => AnimateGradientShader(
duration: const Duration(milliseconds: 500),
primaryEnd: Alignment.bottomLeft,
secondaryEnd: Alignment.topRight,
primaryColors: [
colorScheme.primary,
colorScheme.primaryContainer,
],
secondaryColors: [
colorScheme.secondary,
colorScheme.secondaryContainer,
],
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 15.0,
horizontal: 8.0,
),
child: icon,
),
),
),
),
);
}
@@ -88,24 +88,33 @@ class SearchScreen extends HookConsumerWidget {
pinned: true,
automaticallyImplyLeading: false,
title: Align(
child: SegmentedButton(
showSelectedIcon: false,
segments: const [
ButtonSegment(
value: TabType.regular,
label: Text('Regular'),
icon: Icon(MdiIcons.tab),
),
ButtonSegment(
value: TabType.private,
label: Text('Private'),
icon: Icon(MdiIcons.tabUnselected),
),
],
selected: {selectedTabType.value},
onSelectionChanged: (value) {
selectedTabType.value = value.first;
},
child: Focus(
canRequestFocus: false,
child: SegmentedButton(
showSelectedIcon: false,
segments: const [
ButtonSegment(
value: TabType.regular,
label: Text('Regular'),
icon: Icon(MdiIcons.tab),
),
ButtonSegment(
value: TabType.private,
label: Text('Private'),
icon: Icon(MdiIcons.tabUnselected),
),
],
selected: {selectedTabType.value},
onSelectionChanged: (value) {
selectedTabType.value = value.first;
},
style: switch (selectedTabType.value) {
TabType.regular => null,
TabType.private => SegmentedButton.styleFrom(
selectedBackgroundColor: const Color(0x648000D7),
),
},
),
),
),
bottom: PreferredSize(
@@ -63,6 +63,8 @@ class SelectableChips<T extends S, S, K> extends StatelessWidget {
builder: (context, controller) {
return ListView.builder(
controller: controller,
//Improve list performance by not rendering outside screen at all
cacheExtent: 0,
scrollDirection: Axis.horizontal,
itemCount: items.length,
itemBuilder: (context, index) {