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