Revert "add fab insets avoid overlapping"
This reverts commit 5230d3cb6b.
This commit is contained in:
@@ -29,7 +29,6 @@ import 'package:weblibre/features/bangs/domain/providers/bangs.dart';
|
|||||||
import 'package:weblibre/features/bangs/domain/repositories/data.dart';
|
import 'package:weblibre/features/bangs/domain/repositories/data.dart';
|
||||||
import 'package:weblibre/features/bangs/presentation/widgets/bang_details.dart';
|
import 'package:weblibre/features/bangs/presentation/widgets/bang_details.dart';
|
||||||
import 'package:weblibre/presentation/widgets/failure_widget.dart';
|
import 'package:weblibre/presentation/widgets/failure_widget.dart';
|
||||||
import 'package:weblibre/presentation/widgets/floating_action_button_inset.dart';
|
|
||||||
|
|
||||||
class UserBangs extends HookConsumerWidget {
|
class UserBangs extends HookConsumerWidget {
|
||||||
static const _userGroupFilter = [BangGroup.user];
|
static const _userGroupFilter = [BangGroup.user];
|
||||||
@@ -46,9 +45,6 @@ class UserBangs extends HookConsumerWidget {
|
|||||||
skipLoadingOnReload: true,
|
skipLoadingOnReload: true,
|
||||||
data: (bangs) {
|
data: (bangs) {
|
||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
padding: EdgeInsets.only(
|
|
||||||
bottom: floatingActionButtonBottomInset(context),
|
|
||||||
),
|
|
||||||
itemCount: bangs.length,
|
itemCount: bangs.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final bang = bangs[index];
|
final bang = bangs[index];
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ import 'package:weblibre/features/geckoview/domain/providers/selected_tab.dart';
|
|||||||
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/tab_view/tab_preview.dart';
|
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/tab_view/tab_preview.dart';
|
||||||
import 'package:weblibre/features/geckoview/features/tabs/domain/providers.dart';
|
import 'package:weblibre/features/geckoview/features/tabs/domain/providers.dart';
|
||||||
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
|
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
|
||||||
import 'package:weblibre/presentation/widgets/floating_action_button_inset.dart';
|
|
||||||
import 'package:weblibre/utils/ui_helper.dart';
|
import 'package:weblibre/utils/ui_helper.dart';
|
||||||
|
|
||||||
class TabTreeDialog extends HookConsumerWidget {
|
class TabTreeDialog extends HookConsumerWidget {
|
||||||
@@ -109,54 +108,47 @@ class TabTreeDialog extends HookConsumerWidget {
|
|||||||
extendBodyBehindAppBar: true,
|
extendBodyBehindAppBar: true,
|
||||||
body: Skeletonizer(
|
body: Skeletonizer(
|
||||||
enabled: !tabs.hasValue || tabs.value?.isEmpty == true,
|
enabled: !tabs.hasValue || tabs.value?.isEmpty == true,
|
||||||
child: Padding(
|
child: Skeleton.replace(
|
||||||
padding: EdgeInsets.only(
|
replacement: const Bone.square(),
|
||||||
bottom: floatingActionButtonBottomInset(context),
|
child: GraphView.builder(
|
||||||
),
|
graph: graph,
|
||||||
child: Skeleton.replace(
|
algorithm: graphAlgo,
|
||||||
replacement: const Bone.square(),
|
controller: graphViewController,
|
||||||
child: GraphView.builder(
|
initialNode: selectedTabId.mapNotNull((tabId) => ValueKey(tabId)),
|
||||||
graph: graph,
|
paint: Paint()
|
||||||
algorithm: graphAlgo,
|
..color = Theme.of(context).colorScheme.outline
|
||||||
controller: graphViewController,
|
..strokeWidth = 1
|
||||||
initialNode: selectedTabId.mapNotNull(
|
..style = PaintingStyle.stroke,
|
||||||
(tabId) => ValueKey(tabId),
|
builder: (Node node) {
|
||||||
),
|
final id = node.key!.value as String;
|
||||||
paint: Paint()
|
return SizedBox.fromSize(
|
||||||
..color = Theme.of(context).colorScheme.outline
|
size: childSize,
|
||||||
..strokeWidth = 1
|
child: SingleGridTabPreview(
|
||||||
..style = PaintingStyle.stroke,
|
key: ValueKey(id),
|
||||||
builder: (Node node) {
|
tabId: id,
|
||||||
final id = node.key!.value as String;
|
activeTabId: selectedTabId,
|
||||||
return SizedBox.fromSize(
|
onClose: () {
|
||||||
size: childSize,
|
final tabViewBottomSheet = ref
|
||||||
child: SingleGridTabPreview(
|
.read(generalSettingsWithDefaultsProvider)
|
||||||
key: ValueKey(id),
|
.tabViewBottomSheet;
|
||||||
tabId: id,
|
|
||||||
activeTabId: selectedTabId,
|
|
||||||
onClose: () {
|
|
||||||
final tabViewBottomSheet = ref
|
|
||||||
.read(generalSettingsWithDefaultsProvider)
|
|
||||||
.tabViewBottomSheet;
|
|
||||||
|
|
||||||
if (tabViewBottomSheet) {
|
if (tabViewBottomSheet) {
|
||||||
ref
|
ref
|
||||||
.read(bottomSheetControllerProvider.notifier)
|
.read(bottomSheetControllerProvider.notifier)
|
||||||
.requestDismiss();
|
.requestDismiss();
|
||||||
}
|
}
|
||||||
|
|
||||||
const BrowserRoute().go(context);
|
const BrowserRoute().go(context);
|
||||||
},
|
},
|
||||||
onBeforeDelete: () {
|
onBeforeDelete: () {
|
||||||
if (graph.nodes.length <= 2) {
|
if (graph.nodes.length <= 2) {
|
||||||
context.pop();
|
context.pop();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
sourceSearchQuery: null,
|
sourceSearchQuery: null,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import 'package:weblibre/features/geckoview/features/browser/presentation/widget
|
|||||||
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/tab_view/tab_tree_view.dart';
|
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/tab_view/tab_tree_view.dart';
|
||||||
import 'package:weblibre/features/sync/domain/repositories/sync.dart';
|
import 'package:weblibre/features/sync/domain/repositories/sync.dart';
|
||||||
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
|
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
|
||||||
import 'package:weblibre/presentation/widgets/floating_action_button_inset.dart';
|
import 'package:weblibre/presentation/hooks/scroll_visibility.dart';
|
||||||
|
|
||||||
class TabViewScreen extends HookConsumerWidget {
|
class TabViewScreen extends HookConsumerWidget {
|
||||||
const TabViewScreen({super.key});
|
const TabViewScreen({super.key});
|
||||||
@@ -50,67 +50,68 @@ class TabViewScreen extends HookConsumerWidget {
|
|||||||
|
|
||||||
final scrollController = useScrollController(keys: [tabsReorderable]);
|
final scrollController = useScrollController(keys: [tabsReorderable]);
|
||||||
|
|
||||||
|
// Track FAB visibility based on scroll direction
|
||||||
|
final isFabVisible = useScrollVisibility(scrollController);
|
||||||
|
|
||||||
return Dialog.fullscreen(
|
return Dialog.fullscreen(
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: Builder(
|
child: switch (effectiveTabsViewMode) {
|
||||||
builder: (safeAreaContext) {
|
TabsViewMode.list => ViewTabListWidget(
|
||||||
return Padding(
|
key: ValueKey(tabsReorderable),
|
||||||
padding: EdgeInsets.only(
|
scrollController: scrollController,
|
||||||
bottom: isSyncedScope
|
tabsReorderable: tabsReorderable,
|
||||||
? 0
|
showNewTabFab: false,
|
||||||
: floatingActionButtonBottomInset(safeAreaContext),
|
onClose: () {
|
||||||
),
|
const BrowserRoute().go(context);
|
||||||
child: switch (effectiveTabsViewMode) {
|
},
|
||||||
TabsViewMode.list => ViewTabListWidget(
|
),
|
||||||
key: ValueKey(tabsReorderable),
|
TabsViewMode.grid => ViewTabGridWidget(
|
||||||
scrollController: scrollController,
|
key: ValueKey(tabsReorderable),
|
||||||
tabsReorderable: tabsReorderable,
|
scrollController: scrollController,
|
||||||
showNewTabFab: false,
|
tabsReorderable: tabsReorderable,
|
||||||
onClose: () {
|
showNewTabFab: false,
|
||||||
const BrowserRoute().go(context);
|
onClose: () {
|
||||||
},
|
const BrowserRoute().go(context);
|
||||||
),
|
},
|
||||||
TabsViewMode.grid => ViewTabGridWidget(
|
),
|
||||||
key: ValueKey(tabsReorderable),
|
TabsViewMode.tree => ViewTabTreesWidget(
|
||||||
scrollController: scrollController,
|
scrollController: scrollController,
|
||||||
tabsReorderable: tabsReorderable,
|
showNewTabFab: false,
|
||||||
showNewTabFab: false,
|
onClose: () {
|
||||||
onClose: () {
|
const BrowserRoute().go(context);
|
||||||
const BrowserRoute().go(context);
|
},
|
||||||
},
|
),
|
||||||
),
|
},
|
||||||
TabsViewMode.tree => ViewTabTreesWidget(
|
|
||||||
scrollController: scrollController,
|
|
||||||
showNewTabFab: false,
|
|
||||||
onClose: () {
|
|
||||||
const BrowserRoute().go(context);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
floatingActionButton: isSyncedScope
|
floatingActionButton: isSyncedScope
|
||||||
? null
|
? null
|
||||||
: FloatingActionButton(
|
: AnimatedSlide(
|
||||||
onPressed: () async {
|
duration: const Duration(milliseconds: 200),
|
||||||
final settings = ref.read(
|
offset: isFabVisible.value ? Offset.zero : const Offset(0, 2),
|
||||||
generalSettingsWithDefaultsProvider,
|
curve: Curves.easeInOut,
|
||||||
);
|
child: AnimatedOpacity(
|
||||||
|
duration: const Duration(milliseconds: 200),
|
||||||
|
opacity: isFabVisible.value ? 1.0 : 0.0,
|
||||||
|
child: FloatingActionButton(
|
||||||
|
onPressed: () async {
|
||||||
|
final settings = ref.read(
|
||||||
|
generalSettingsWithDefaultsProvider,
|
||||||
|
);
|
||||||
|
|
||||||
await SearchRoute(
|
await SearchRoute(
|
||||||
tabType:
|
tabType:
|
||||||
ref.read(selectedTabTypeProvider) ??
|
ref.read(selectedTabTypeProvider) ??
|
||||||
settings.effectiveDefaultCreateTabType,
|
settings.effectiveDefaultCreateTabType,
|
||||||
).push(context);
|
).push(context);
|
||||||
|
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
const BrowserRoute().go(context);
|
const BrowserRoute().go(context);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: const Icon(Icons.add),
|
child: const Icon(Icons.add),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
+4
-15
@@ -47,7 +47,6 @@ import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/co
|
|||||||
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/tab.dart';
|
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/tab.dart';
|
||||||
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/tab_search.dart';
|
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/tab_search.dart';
|
||||||
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
|
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
|
||||||
import 'package:weblibre/presentation/widgets/floating_action_button_inset.dart';
|
|
||||||
|
|
||||||
class _TabDraggable extends HookConsumerWidget {
|
class _TabDraggable extends HookConsumerWidget {
|
||||||
final TabEntity entity;
|
final TabEntity entity;
|
||||||
@@ -539,20 +538,10 @@ class ViewTabGridWidget extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
body: Padding(
|
body: _TabGridView(
|
||||||
padding: EdgeInsets.only(
|
scrollController: scrollController,
|
||||||
bottom: showNewTabFab
|
tabsReorderable: tabsReorderable,
|
||||||
? floatingActionButtonBottomInset(
|
onClose: onClose,
|
||||||
context,
|
|
||||||
fabHeight: smallFloatingActionButtonHeight,
|
|
||||||
)
|
|
||||||
: 0,
|
|
||||||
),
|
|
||||||
child: _TabGridView(
|
|
||||||
scrollController: scrollController,
|
|
||||||
tabsReorderable: tabsReorderable,
|
|
||||||
onClose: onClose,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (showNewTabFab)
|
if (showNewTabFab)
|
||||||
|
|||||||
+4
-15
@@ -46,7 +46,6 @@ import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/ta
|
|||||||
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/tab_search.dart';
|
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/tab_search.dart';
|
||||||
import 'package:weblibre/features/sync/domain/repositories/sync.dart';
|
import 'package:weblibre/features/sync/domain/repositories/sync.dart';
|
||||||
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
|
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
|
||||||
import 'package:weblibre/presentation/widgets/floating_action_button_inset.dart';
|
|
||||||
|
|
||||||
class _TabDraggable extends HookConsumerWidget {
|
class _TabDraggable extends HookConsumerWidget {
|
||||||
final TabEntity entity;
|
final TabEntity entity;
|
||||||
@@ -568,20 +567,10 @@ class ViewTabListWidget extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
body: Padding(
|
body: _TabListView(
|
||||||
padding: EdgeInsets.only(
|
scrollController: scrollController,
|
||||||
bottom: (showNewTabFab && !isSyncedScope)
|
tabsReorderable: tabsReorderable,
|
||||||
? floatingActionButtonBottomInset(
|
onClose: onClose,
|
||||||
context,
|
|
||||||
fabHeight: smallFloatingActionButtonHeight,
|
|
||||||
)
|
|
||||||
: 0,
|
|
||||||
),
|
|
||||||
child: _TabListView(
|
|
||||||
scrollController: scrollController,
|
|
||||||
tabsReorderable: tabsReorderable,
|
|
||||||
onClose: onClose,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (showNewTabFab && !isSyncedScope)
|
if (showNewTabFab && !isSyncedScope)
|
||||||
|
|||||||
+1
-9
@@ -38,7 +38,6 @@ import 'package:weblibre/features/geckoview/features/tabs/domain/providers/selec
|
|||||||
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/tab.dart';
|
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/tab.dart';
|
||||||
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/tab_search.dart';
|
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/tab_search.dart';
|
||||||
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
|
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
|
||||||
import 'package:weblibre/presentation/widgets/floating_action_button_inset.dart';
|
|
||||||
import 'package:weblibre/utils/ui_helper.dart' as ui_helper;
|
import 'package:weblibre/utils/ui_helper.dart' as ui_helper;
|
||||||
|
|
||||||
class _TabTreePreview extends HookConsumerWidget {
|
class _TabTreePreview extends HookConsumerWidget {
|
||||||
@@ -308,14 +307,7 @@ class ViewTabTreesWidget extends HookConsumerWidget {
|
|||||||
padding: const EdgeInsets.symmetric(horizontal: 4.0),
|
padding: const EdgeInsets.symmetric(horizontal: 4.0),
|
||||||
child: GridView.builder(
|
child: GridView.builder(
|
||||||
controller: scrollController,
|
controller: scrollController,
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.zero,
|
||||||
bottom: showNewTabFab
|
|
||||||
? floatingActionButtonBottomInset(
|
|
||||||
context,
|
|
||||||
fabHeight: smallFloatingActionButtonHeight,
|
|
||||||
)
|
|
||||||
: 0,
|
|
||||||
),
|
|
||||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
//Sync values for itemHeight calculation _calculateItemHeight
|
//Sync values for itemHeight calculation _calculateItemHeight
|
||||||
childAspectRatio: 0.75,
|
childAspectRatio: 0.75,
|
||||||
|
|||||||
+125
-139
@@ -36,7 +36,6 @@ import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/co
|
|||||||
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/gecko_inference.dart';
|
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/gecko_inference.dart';
|
||||||
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/tab.dart';
|
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/tab.dart';
|
||||||
import 'package:weblibre/presentation/widgets/failure_widget.dart';
|
import 'package:weblibre/presentation/widgets/failure_widget.dart';
|
||||||
import 'package:weblibre/presentation/widgets/floating_action_button_inset.dart';
|
|
||||||
import 'package:weblibre/presentation/widgets/selectable_chips.dart';
|
import 'package:weblibre/presentation/widgets/selectable_chips.dart';
|
||||||
|
|
||||||
class ContainerDraftSuggestionsScreen extends HookConsumerWidget {
|
class ContainerDraftSuggestionsScreen extends HookConsumerWidget {
|
||||||
@@ -56,153 +55,140 @@ class ContainerDraftSuggestionsScreen extends HookConsumerWidget {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: const Text('Draft Containers')),
|
appBar: AppBar(title: const Text('Draft Containers')),
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: Builder(
|
child: Padding(
|
||||||
builder: (safeAreaContext) {
|
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||||
return Padding(
|
child: suggestionsAsync.when(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
skipLoadingOnReload: true,
|
||||||
child: suggestionsAsync.when(
|
data: (suggestions) {
|
||||||
skipLoadingOnReload: true,
|
final screenWidth = MediaQuery.of(context).size.width;
|
||||||
data: (suggestions) {
|
|
||||||
final screenWidth = MediaQuery.of(context).size.width;
|
|
||||||
|
|
||||||
final crossAxisCount = useMemoized(() {
|
final crossAxisCount = useMemoized(() {
|
||||||
final calculatedCount = calculateCrossAxisItemCount(
|
final calculatedCount = calculateCrossAxisItemCount(
|
||||||
screenWidth: screenWidth,
|
screenWidth: screenWidth,
|
||||||
horizontalPadding: 4.0,
|
horizontalPadding: 4.0,
|
||||||
crossAxisSpacing: 8.0,
|
crossAxisSpacing: 8.0,
|
||||||
);
|
);
|
||||||
|
|
||||||
return math.max(
|
return math.max(
|
||||||
math.min(
|
math.min(
|
||||||
calculatedCount,
|
calculatedCount,
|
||||||
selectedContainer.value?.tabIds.length ?? 0,
|
selectedContainer.value?.tabIds.length ?? 0,
|
||||||
),
|
),
|
||||||
2,
|
2,
|
||||||
);
|
);
|
||||||
}, [screenWidth, selectedContainer.value?.tabIds.length]);
|
}, [screenWidth, selectedContainer.value?.tabIds.length]);
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 48,
|
height: 48,
|
||||||
child: SelectableChips(
|
child: SelectableChips(
|
||||||
enableDelete: false,
|
enableDelete: false,
|
||||||
sortSelectedFirst: false,
|
sortSelectedFirst: false,
|
||||||
itemId: (container) => container,
|
itemId: (container) => container,
|
||||||
itemAvatar: (container) =>
|
itemAvatar: (container) =>
|
||||||
const Icon(MdiIcons.creation, size: 20),
|
const Icon(MdiIcons.creation, size: 20),
|
||||||
itemLabel: (container) => HookConsumer(
|
itemLabel: (container) => HookConsumer(
|
||||||
builder: (context, ref, child) {
|
builder: (context, ref, child) {
|
||||||
final items = useListenableSelector(
|
final items = useListenableSelector(
|
||||||
selectedContainerTabs,
|
selectedContainerTabs,
|
||||||
() => selectedContainerTabs.value[container],
|
() => selectedContainerTabs.value[container],
|
||||||
|
);
|
||||||
|
|
||||||
|
final topic = items.isNotEmpty
|
||||||
|
? ref.watch(
|
||||||
|
tabsTopicProvider(EquatableValue(items!)),
|
||||||
|
)
|
||||||
|
: AsyncValue.data(container.topic);
|
||||||
|
|
||||||
|
return topic.when(
|
||||||
|
skipLoadingOnReload: true,
|
||||||
|
data: (topic) => Text(topic ?? 'Untitled'),
|
||||||
|
error: (error, stackTrace) {
|
||||||
|
logger.e(
|
||||||
|
'Failed predicting selected tabs topic',
|
||||||
|
error: error,
|
||||||
|
stackTrace: stackTrace,
|
||||||
);
|
);
|
||||||
|
|
||||||
final topic = items.isNotEmpty
|
return Text(container.topic ?? 'Untitled');
|
||||||
? ref.watch(
|
|
||||||
tabsTopicProvider(EquatableValue(items!)),
|
|
||||||
)
|
|
||||||
: AsyncValue.data(container.topic);
|
|
||||||
|
|
||||||
return topic.when(
|
|
||||||
skipLoadingOnReload: true,
|
|
||||||
data: (topic) => Text(topic ?? 'Untitled'),
|
|
||||||
error: (error, stackTrace) {
|
|
||||||
logger.e(
|
|
||||||
'Failed predicting selected tabs topic',
|
|
||||||
error: error,
|
|
||||||
stackTrace: stackTrace,
|
|
||||||
);
|
|
||||||
|
|
||||||
return Text(container.topic ?? 'Untitled');
|
|
||||||
},
|
|
||||||
loading: () =>
|
|
||||||
const Skeletonizer(child: Text('Untitled')),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
),
|
loading: () =>
|
||||||
itemBadgeCount: (container) =>
|
const Skeletonizer(child: Text('Untitled')),
|
||||||
container.tabIds.length,
|
);
|
||||||
availableItems: suggestions!,
|
},
|
||||||
selectedItem: selectedContainer.value,
|
|
||||||
onSelected: (item) {
|
|
||||||
selectedContainer.value = item;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const Divider(),
|
itemBadgeCount: (container) => container.tabIds.length,
|
||||||
const SizedBox(height: 4),
|
availableItems: suggestions!,
|
||||||
if (selectedContainer.value != null)
|
selectedItem: selectedContainer.value,
|
||||||
Expanded(
|
onSelected: (item) {
|
||||||
child: GridView.builder(
|
selectedContainer.value = item;
|
||||||
padding: EdgeInsets.only(
|
},
|
||||||
bottom: (selectedTabs?.isNotEmpty ?? false)
|
),
|
||||||
? floatingActionButtonBottomInset(
|
),
|
||||||
safeAreaContext,
|
const Divider(),
|
||||||
)
|
const SizedBox(height: 4),
|
||||||
: 0,
|
if (selectedContainer.value != null)
|
||||||
),
|
Expanded(
|
||||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
child: GridView.builder(
|
||||||
//Sync values for itemHeight calculation _calculateItemHeight
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
childAspectRatio: 0.75,
|
//Sync values for itemHeight calculation _calculateItemHeight
|
||||||
mainAxisSpacing: 8.0,
|
childAspectRatio: 0.75,
|
||||||
crossAxisSpacing: 8.0,
|
mainAxisSpacing: 8.0,
|
||||||
crossAxisCount: crossAxisCount,
|
crossAxisSpacing: 8.0,
|
||||||
),
|
crossAxisCount: crossAxisCount,
|
||||||
itemCount: selectedContainer.value!.tabIds.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
final tabId =
|
|
||||||
selectedContainer.value!.tabIds[index];
|
|
||||||
final equatable = selectedContainer.value!;
|
|
||||||
|
|
||||||
return (selectedContainerTabs.value[equatable]
|
|
||||||
?.contains(tabId) ==
|
|
||||||
true)
|
|
||||||
? GridTabPreview(
|
|
||||||
tabId: tabId,
|
|
||||||
isActive: false,
|
|
||||||
onDelete: () {
|
|
||||||
selectedContainerTabs.value = {
|
|
||||||
...selectedContainerTabs.value,
|
|
||||||
equatable: {
|
|
||||||
...?selectedContainerTabs
|
|
||||||
.value[equatable],
|
|
||||||
}..remove(tabId),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
)
|
|
||||||
: SuggestedSingleGridTabPreview(
|
|
||||||
tabId: tabId,
|
|
||||||
activeTabId: null,
|
|
||||||
onTap: () {
|
|
||||||
selectedContainerTabs.value = {
|
|
||||||
...selectedContainerTabs.value,
|
|
||||||
equatable: {
|
|
||||||
...?selectedContainerTabs
|
|
||||||
.value[equatable],
|
|
||||||
tabId,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
itemCount: selectedContainer.value!.tabIds.length,
|
||||||
);
|
itemBuilder: (context, index) {
|
||||||
|
final tabId = selectedContainer.value!.tabIds[index];
|
||||||
|
final equatable = selectedContainer.value!;
|
||||||
|
|
||||||
|
return (selectedContainerTabs.value[equatable]
|
||||||
|
?.contains(tabId) ==
|
||||||
|
true)
|
||||||
|
? GridTabPreview(
|
||||||
|
tabId: tabId,
|
||||||
|
isActive: false,
|
||||||
|
onDelete: () {
|
||||||
|
selectedContainerTabs.value = {
|
||||||
|
...selectedContainerTabs.value,
|
||||||
|
equatable: {
|
||||||
|
...?selectedContainerTabs
|
||||||
|
.value[equatable],
|
||||||
|
}..remove(tabId),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
)
|
||||||
|
: SuggestedSingleGridTabPreview(
|
||||||
|
tabId: tabId,
|
||||||
|
activeTabId: null,
|
||||||
|
onTap: () {
|
||||||
|
selectedContainerTabs.value = {
|
||||||
|
...selectedContainerTabs.value,
|
||||||
|
equatable: {
|
||||||
|
...?selectedContainerTabs
|
||||||
|
.value[equatable],
|
||||||
|
tabId,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
error: (error, stackTrace) {
|
||||||
|
return FailureWidget(
|
||||||
|
title: 'Failed to create suggestions',
|
||||||
|
onRetry: () {
|
||||||
|
ref.invalidate(suggestClustersProvider);
|
||||||
},
|
},
|
||||||
error: (error, stackTrace) {
|
);
|
||||||
return FailureWidget(
|
},
|
||||||
title: 'Failed to create suggestions',
|
loading: () => const Center(child: CircularProgressIndicator()),
|
||||||
onRetry: () {
|
),
|
||||||
ref.invalidate(suggestClustersProvider);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
loading: () => const Center(child: CircularProgressIndicator()),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
floatingActionButton: (selectedTabs?.isNotEmpty ?? false)
|
floatingActionButton: (selectedTabs?.isNotEmpty ?? false)
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ import 'package:weblibre/features/geckoview/features/tabs/presentation/widgets/c
|
|||||||
import 'package:weblibre/features/tor/presentation/controllers/start_tor_proxy.dart';
|
import 'package:weblibre/features/tor/presentation/controllers/start_tor_proxy.dart';
|
||||||
import 'package:weblibre/features/tor/presentation/widgets/tor_dialog.dart';
|
import 'package:weblibre/features/tor/presentation/widgets/tor_dialog.dart';
|
||||||
import 'package:weblibre/presentation/widgets/failure_widget.dart';
|
import 'package:weblibre/presentation/widgets/failure_widget.dart';
|
||||||
import 'package:weblibre/presentation/widgets/floating_action_button_inset.dart';
|
|
||||||
|
|
||||||
class ContainerListScreen extends HookConsumerWidget {
|
class ContainerListScreen extends HookConsumerWidget {
|
||||||
const ContainerListScreen({super.key});
|
const ContainerListScreen({super.key});
|
||||||
@@ -54,9 +53,6 @@ class ContainerListScreen extends HookConsumerWidget {
|
|||||||
builder: (context, controller) {
|
builder: (context, controller) {
|
||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
padding: EdgeInsets.only(
|
|
||||||
bottom: floatingActionButtonBottomInset(context),
|
|
||||||
),
|
|
||||||
itemCount: containers.length,
|
itemCount: containers.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final container = containers[index];
|
final container = containers[index];
|
||||||
@@ -168,9 +164,6 @@ class ContainerListScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
loading: () => ListView.builder(
|
loading: () => ListView.builder(
|
||||||
padding: EdgeInsets.only(
|
|
||||||
bottom: floatingActionButtonBottomInset(context),
|
|
||||||
),
|
|
||||||
itemCount: 3,
|
itemCount: 3,
|
||||||
itemBuilder: (context, index) => ContainerListTile(
|
itemBuilder: (context, index) => ContainerListTile(
|
||||||
ContainerData(id: 'null', color: Colors.transparent),
|
ContainerData(id: 'null', color: Colors.transparent),
|
||||||
|
|||||||
+1
-8
@@ -34,7 +34,6 @@ import 'package:weblibre/features/geckoview/features/tabs/domain/providers/selec
|
|||||||
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/container.dart';
|
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/container.dart';
|
||||||
import 'package:weblibre/features/geckoview/features/tabs/presentation/widgets/container_list_tile.dart';
|
import 'package:weblibre/features/geckoview/features/tabs/presentation/widgets/container_list_tile.dart';
|
||||||
import 'package:weblibre/presentation/widgets/failure_widget.dart';
|
import 'package:weblibre/presentation/widgets/failure_widget.dart';
|
||||||
import 'package:weblibre/presentation/widgets/floating_action_button_inset.dart';
|
|
||||||
|
|
||||||
class ContainerSelectionScreen extends HookConsumerWidget {
|
class ContainerSelectionScreen extends HookConsumerWidget {
|
||||||
const ContainerSelectionScreen({super.key});
|
const ContainerSelectionScreen({super.key});
|
||||||
@@ -55,10 +54,7 @@ class ContainerSelectionScreen extends HookConsumerWidget {
|
|||||||
builder: (context, controller) {
|
builder: (context, controller) {
|
||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
padding: EdgeInsets.only(
|
itemCount: containers.length,
|
||||||
bottom: floatingActionButtonBottomInset(context),
|
|
||||||
),
|
|
||||||
itemCount: containers.length + 1,
|
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
return ListTileTheme(
|
return ListTileTheme(
|
||||||
@@ -108,9 +104,6 @@ class ContainerSelectionScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
loading: () => ListView.builder(
|
loading: () => ListView.builder(
|
||||||
padding: EdgeInsets.only(
|
|
||||||
bottom: floatingActionButtonBottomInset(context),
|
|
||||||
),
|
|
||||||
itemCount: 3,
|
itemCount: 3,
|
||||||
itemBuilder: (context, index) => ContainerListTile(
|
itemBuilder: (context, index) => ContainerListTile(
|
||||||
ContainerData(id: Namespace.nil.value, color: Colors.transparent),
|
ContainerData(id: Namespace.nil.value, color: Colors.transparent),
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import 'package:weblibre/core/filesystem.dart';
|
|||||||
import 'package:weblibre/core/routing/routes.dart';
|
import 'package:weblibre/core/routing/routes.dart';
|
||||||
import 'package:weblibre/features/user/domain/repositories/profile.dart';
|
import 'package:weblibre/features/user/domain/repositories/profile.dart';
|
||||||
import 'package:weblibre/presentation/widgets/failure_widget.dart';
|
import 'package:weblibre/presentation/widgets/failure_widget.dart';
|
||||||
import 'package:weblibre/presentation/widgets/floating_action_button_inset.dart';
|
|
||||||
|
|
||||||
class ProfileListScreen extends HookConsumerWidget {
|
class ProfileListScreen extends HookConsumerWidget {
|
||||||
const ProfileListScreen({super.key});
|
const ProfileListScreen({super.key});
|
||||||
@@ -50,9 +49,6 @@ class ProfileListScreen extends HookConsumerWidget {
|
|||||||
body: usersAsync.when(
|
body: usersAsync.when(
|
||||||
skipLoadingOnReload: true,
|
skipLoadingOnReload: true,
|
||||||
data: (profiles) => ListView.builder(
|
data: (profiles) => ListView.builder(
|
||||||
padding: EdgeInsets.only(
|
|
||||||
bottom: floatingActionButtonBottomInset(context),
|
|
||||||
),
|
|
||||||
itemCount: profiles.length,
|
itemCount: profiles.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final profile = profiles[index];
|
final profile = profiles[index];
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import 'package:weblibre/features/web_feed/domain/providers.dart';
|
|||||||
import 'package:weblibre/features/web_feed/presentation/controllers/fetch_articles.dart';
|
import 'package:weblibre/features/web_feed/presentation/controllers/fetch_articles.dart';
|
||||||
import 'package:weblibre/features/web_feed/presentation/widgets/feed_card.dart';
|
import 'package:weblibre/features/web_feed/presentation/widgets/feed_card.dart';
|
||||||
import 'package:weblibre/presentation/widgets/failure_widget.dart';
|
import 'package:weblibre/presentation/widgets/failure_widget.dart';
|
||||||
import 'package:weblibre/presentation/widgets/floating_action_button_inset.dart';
|
|
||||||
|
|
||||||
class FeedListScreen extends HookConsumerWidget {
|
class FeedListScreen extends HookConsumerWidget {
|
||||||
const FeedListScreen({super.key});
|
const FeedListScreen({super.key});
|
||||||
@@ -77,9 +76,6 @@ class FeedListScreen extends HookConsumerWidget {
|
|||||||
.fetchAllArticles();
|
.fetchAllArticles();
|
||||||
},
|
},
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
padding: EdgeInsets.only(
|
|
||||||
bottom: floatingActionButtonBottomInset(context),
|
|
||||||
),
|
|
||||||
itemCount: feeds.length,
|
itemCount: feeds.length,
|
||||||
itemBuilder: (context, i) {
|
itemBuilder: (context, i) {
|
||||||
return FeedCard(feed: feeds[i]);
|
return FeedCard(feed: feeds[i]);
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2024-2026 Fabian Freund.
|
|
||||||
*
|
|
||||||
* This file is part of WebLibre
|
|
||||||
* (see https://weblibre.eu).
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as
|
|
||||||
* published by the Free Software Foundation, either version 3 of the
|
|
||||||
* License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
const standardFloatingActionButtonHeight = kMinInteractiveDimension;
|
|
||||||
const smallFloatingActionButtonHeight = 40.0;
|
|
||||||
|
|
||||||
double floatingActionButtonBottomInset(
|
|
||||||
BuildContext context, {
|
|
||||||
double fabHeight = standardFloatingActionButtonHeight,
|
|
||||||
double extraPadding = 8.0,
|
|
||||||
}) {
|
|
||||||
return fabHeight +
|
|
||||||
kFloatingActionButtonMargin +
|
|
||||||
MediaQuery.paddingOf(context).bottom +
|
|
||||||
extraPadding;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user