💄 Better dashboard customization
This commit is contained in:
@@ -1598,5 +1598,33 @@
|
|||||||
"sidebar": "Sidebar",
|
"sidebar": "Sidebar",
|
||||||
"dropFilesHere": "Drop your files here",
|
"dropFilesHere": "Drop your files here",
|
||||||
"dragAndDropToAttach": "Drag your files here to attach it",
|
"dragAndDropToAttach": "Drag your files here to attach it",
|
||||||
"customize": "Customize"
|
"customize": "Customize",
|
||||||
|
"dashboardCustomizeTitle": "Customize Dashboard",
|
||||||
|
"dashboardTabVertical": "Vertical",
|
||||||
|
"dashboardTabHorizontal": "Horizontal",
|
||||||
|
"dashboardLayoutVertical": "Vertical Layout",
|
||||||
|
"dashboardLayoutHorizontal": "Horizontal Layout",
|
||||||
|
"dashboardAvailableCards": "Available Cards",
|
||||||
|
"dashboardDisplaySettings": "Display Settings",
|
||||||
|
"dashboardShowSearchBar": "Show Search Bar",
|
||||||
|
"dashboardShowClockAndCountdown": "Show Clock and Countdown",
|
||||||
|
"dashboardResetToDefaults": "Reset to Defaults",
|
||||||
|
"dashboardResetToDefaultsSubtitle": "Restore default dashboard layout and settings",
|
||||||
|
"dashboardResetConfirmMessage": "This will restore the dashboard to its default layout and settings. This action cannot be undone.",
|
||||||
|
"dashboardResetConfirmTitle": "Reset Dashboard",
|
||||||
|
"dashboardCardCheckIn": "Check In",
|
||||||
|
"dashboardCardFortuneGraph": "Fortune Graph",
|
||||||
|
"dashboardCardFortune": "Fortune",
|
||||||
|
"dashboardCardFeaturedPosts": "Featured Posts",
|
||||||
|
"dashboardCardFriends": "Friends",
|
||||||
|
"dashboardCardNotifications": "Notifications",
|
||||||
|
"dashboardCardChats": "Chats",
|
||||||
|
"dashboardCardActivityColumn": "Activity Column",
|
||||||
|
"dashboardCardPostsColumn": "Posts Column",
|
||||||
|
"dashboardCardSocialColumn": "Social Column",
|
||||||
|
"dashboardCardChatsColumn": "Chats Column",
|
||||||
|
"dashboardCardActivityColumnDescription": "Check In, Fortune Graph & Fortune",
|
||||||
|
"dashboardCardPostsColumnDescription": "Featured Posts",
|
||||||
|
"dashboardCardSocialColumnDescription": "Friends & Notifications",
|
||||||
|
"dashboardCardChatsColumnDescription": "Recent Chats"
|
||||||
}
|
}
|
||||||
@@ -363,6 +363,12 @@ class AppSettingsNotifier extends _$AppSettingsNotifier {
|
|||||||
}
|
}
|
||||||
state = state.copyWith(dashboardConfig: value);
|
state = state.copyWith(dashboardConfig: value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void resetDashboardConfig() {
|
||||||
|
final prefs = ref.read(sharedPreferencesProvider);
|
||||||
|
prefs.remove(kAppDashboardConfig);
|
||||||
|
state = state.copyWith(dashboardConfig: null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final updateInfoProvider =
|
final updateInfoProvider =
|
||||||
|
|||||||
@@ -144,8 +144,6 @@ class DashboardRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class DashboardGrid extends HookConsumerWidget {
|
class DashboardGrid extends HookConsumerWidget {
|
||||||
const DashboardGrid({super.key});
|
const DashboardGrid({super.key});
|
||||||
|
|
||||||
@@ -273,7 +271,7 @@ class DashboardGrid extends HookConsumerWidget {
|
|||||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||||
color: Theme.of(context).colorScheme.primary,
|
color: Theme.of(context).colorScheme.primary,
|
||||||
),
|
),
|
||||||
),
|
).tr(),
|
||||||
style: TextButton.styleFrom(
|
style: TextButton.styleFrom(
|
||||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
backgroundColor: Theme.of(context).colorScheme.surface,
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
@@ -337,17 +335,15 @@ class _DashboardGridWide extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add configured columns in the specified order
|
// Add configured columns in the specified order
|
||||||
final horizontalLayouts = appSettings.dashboardConfig?.horizontalLayouts ??
|
final horizontalLayouts =
|
||||||
|
appSettings.dashboardConfig?.horizontalLayouts ??
|
||||||
['activityColumn', 'postsColumn', 'socialColumn', 'chatsColumn'];
|
['activityColumn', 'postsColumn', 'socialColumn', 'chatsColumn'];
|
||||||
|
|
||||||
for (final columnId in horizontalLayouts) {
|
for (final columnId in horizontalLayouts) {
|
||||||
children.add(DashboardRenderer.buildColumn(columnId, ref));
|
children.add(DashboardRenderer.buildColumn(columnId, ref));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Row(
|
return Row(spacing: 16, children: children);
|
||||||
spacing: 16,
|
|
||||||
children: children,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,17 +363,23 @@ class _DashboardGridNarrow extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add configured cards in the specified order
|
// Add configured cards in the specified order
|
||||||
final verticalLayouts = appSettings.dashboardConfig?.verticalLayouts ??
|
final verticalLayouts =
|
||||||
['checkIn', 'fortuneCard', 'postFeatured', 'friendsOverview', 'notifications', 'chatList', 'fortuneGraph'];
|
appSettings.dashboardConfig?.verticalLayouts ??
|
||||||
|
[
|
||||||
|
'checkIn',
|
||||||
|
'fortuneCard',
|
||||||
|
'postFeatured',
|
||||||
|
'friendsOverview',
|
||||||
|
'notifications',
|
||||||
|
'chatList',
|
||||||
|
'fortuneGraph',
|
||||||
|
];
|
||||||
|
|
||||||
for (final cardId in verticalLayouts) {
|
for (final cardId in verticalLayouts) {
|
||||||
children.add(DashboardRenderer.buildCard(cardId, ref));
|
children.add(DashboardRenderer.buildCard(cardId, ref));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Column(
|
return Column(spacing: 16, children: children);
|
||||||
spacing: 16,
|
|
||||||
children: children,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,28 +1,69 @@
|
|||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||||
import 'package:island/widgets/content/sheet.dart';
|
import 'package:island/widgets/content/sheet.dart';
|
||||||
import 'package:island/pods/config.dart';
|
import 'package:island/pods/config.dart';
|
||||||
|
import 'package:island/widgets/alert.dart';
|
||||||
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
|
||||||
class DashboardCustomizationSheet extends HookConsumerWidget {
|
class DashboardCustomizationSheet extends HookConsumerWidget {
|
||||||
const DashboardCustomizationSheet({super.key});
|
const DashboardCustomizationSheet({super.key});
|
||||||
|
|
||||||
static const Map<String, Map<String, dynamic>> _cardMetadata = {
|
static Map<String, Map<String, dynamic>> _getCardMetadata(
|
||||||
|
BuildContext context,
|
||||||
|
) {
|
||||||
|
return {
|
||||||
// Vertical layout cards
|
// Vertical layout cards
|
||||||
'checkIn': {'name': 'Check In', 'icon': Symbols.check_circle},
|
'checkIn': {
|
||||||
'fortuneGraph': {'name': 'Fortune Graph', 'icon': Symbols.show_chart},
|
'name': 'dashboardCardCheckIn'.tr(),
|
||||||
'fortuneCard': {'name': 'Fortune', 'icon': Symbols.lightbulb},
|
'icon': Symbols.check_circle,
|
||||||
'postFeatured': {'name': 'Featured Posts', 'icon': Symbols.article},
|
},
|
||||||
'friendsOverview': {'name': 'Friends', 'icon': Symbols.group},
|
'fortuneGraph': {
|
||||||
'notifications': {'name': 'Notifications', 'icon': Symbols.notifications},
|
'name': 'dashboardCardFortuneGraph'.tr(),
|
||||||
'chatList': {'name': 'Chats', 'icon': Symbols.chat},
|
'icon': Symbols.show_chart,
|
||||||
|
},
|
||||||
|
'fortuneCard': {
|
||||||
|
'name': 'dashboardCardFortune'.tr(),
|
||||||
|
'icon': Symbols.lightbulb,
|
||||||
|
},
|
||||||
|
'postFeatured': {
|
||||||
|
'name': 'dashboardCardFeaturedPosts'.tr(),
|
||||||
|
'icon': Symbols.article,
|
||||||
|
},
|
||||||
|
'friendsOverview': {
|
||||||
|
'name': 'dashboardCardFriends'.tr(),
|
||||||
|
'icon': Symbols.group,
|
||||||
|
},
|
||||||
|
'notifications': {
|
||||||
|
'name': 'dashboardCardNotifications'.tr(),
|
||||||
|
'icon': Symbols.notifications,
|
||||||
|
},
|
||||||
|
'chatList': {'name': 'dashboardCardChats'.tr(), 'icon': Symbols.chat},
|
||||||
// Horizontal layout columns
|
// Horizontal layout columns
|
||||||
'activityColumn': {'name': 'Activity Column', 'icon': Symbols.dashboard, 'description': 'Check In, Fortune Graph & Fortune'},
|
'activityColumn': {
|
||||||
'postsColumn': {'name': 'Posts Column', 'icon': Symbols.article, 'description': 'Featured Posts'},
|
'name': 'dashboardCardActivityColumn'.tr(),
|
||||||
'socialColumn': {'name': 'Social Column', 'icon': Symbols.group, 'description': 'Friends & Notifications'},
|
'icon': Symbols.dashboard,
|
||||||
'chatsColumn': {'name': 'Chats Column', 'icon': Symbols.chat, 'description': 'Recent Chats'},
|
'description': 'dashboardCardActivityColumnDescription'.tr(),
|
||||||
|
},
|
||||||
|
'postsColumn': {
|
||||||
|
'name': 'dashboardCardPostsColumn'.tr(),
|
||||||
|
'icon': Symbols.article,
|
||||||
|
'description': 'dashboardCardPostsColumnDescription'.tr(),
|
||||||
|
},
|
||||||
|
'socialColumn': {
|
||||||
|
'name': 'dashboardCardSocialColumn'.tr(),
|
||||||
|
'icon': Symbols.group,
|
||||||
|
'description': 'dashboardCardSocialColumnDescription'.tr(),
|
||||||
|
},
|
||||||
|
'chatsColumn': {
|
||||||
|
'name': 'dashboardCardChatsColumn'.tr(),
|
||||||
|
'icon': Symbols.chat,
|
||||||
|
'description': 'dashboardCardChatsColumnDescription'.tr(),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
@@ -31,7 +72,8 @@ class DashboardCustomizationSheet extends HookConsumerWidget {
|
|||||||
|
|
||||||
// Local state for editing
|
// Local state for editing
|
||||||
final verticalLayouts = useState<List<String>>(
|
final verticalLayouts = useState<List<String>>(
|
||||||
(appSettings.dashboardConfig?.verticalLayouts ?? [
|
(appSettings.dashboardConfig?.verticalLayouts ??
|
||||||
|
[
|
||||||
'checkIn',
|
'checkIn',
|
||||||
'fortuneCard',
|
'fortuneCard',
|
||||||
'postFeatured',
|
'postFeatured',
|
||||||
@@ -39,7 +81,9 @@ class DashboardCustomizationSheet extends HookConsumerWidget {
|
|||||||
'notifications',
|
'notifications',
|
||||||
'chatList',
|
'chatList',
|
||||||
'fortuneGraph',
|
'fortuneGraph',
|
||||||
]).where((id) => id != 'accountUnactivated').toList(),
|
])
|
||||||
|
.where((id) => id != 'accountUnactivated')
|
||||||
|
.toList(),
|
||||||
);
|
);
|
||||||
|
|
||||||
final horizontalLayouts = useState<List<String>>(
|
final horizontalLayouts = useState<List<String>>(
|
||||||
@@ -67,70 +111,55 @@ class DashboardCustomizationSheet extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return SheetScaffold(
|
return SheetScaffold(
|
||||||
titleText: 'Customize Dashboard',
|
titleText: 'dashboardCustomizeTitle'.tr(),
|
||||||
actions: [TextButton(onPressed: saveConfig, child: const Text('Save'))],
|
actions: [IconButton(onPressed: saveConfig, icon: Icon(Symbols.save))],
|
||||||
|
child: DefaultTabController(
|
||||||
|
length: 2,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
TabBar(
|
TabBar(
|
||||||
controller: tabController,
|
controller: tabController,
|
||||||
tabs: const [
|
tabs: [
|
||||||
Tab(text: 'Vertical'),
|
Tab(text: 'dashboardTabVertical'.tr()),
|
||||||
Tab(text: 'Horizontal'),
|
Tab(text: 'dashboardTabHorizontal'.tr()),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
|
child: CustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
SliverFillRemaining(
|
||||||
child: TabBarView(
|
child: TabBarView(
|
||||||
controller: tabController,
|
controller: tabController,
|
||||||
children: [
|
children: [
|
||||||
// Vertical layout
|
// Vertical layout
|
||||||
_buildLayoutEditor(context, 'Vertical Layout', verticalLayouts, false),
|
_buildSliverLayoutEditor(
|
||||||
// Horizontal layout
|
|
||||||
_buildLayoutEditor(
|
|
||||||
context,
|
context,
|
||||||
'Horizontal Layout',
|
ref,
|
||||||
|
'dashboardLayoutVertical'.tr(),
|
||||||
|
verticalLayouts,
|
||||||
|
false,
|
||||||
|
showSearchBar,
|
||||||
|
showClockAndCountdown,
|
||||||
|
),
|
||||||
|
// Horizontal layout
|
||||||
|
_buildSliverLayoutEditor(
|
||||||
|
context,
|
||||||
|
ref,
|
||||||
|
'dashboardLayoutHorizontal'.tr(),
|
||||||
horizontalLayouts,
|
horizontalLayouts,
|
||||||
true,
|
true,
|
||||||
),
|
showSearchBar,
|
||||||
],
|
showClockAndCountdown,
|
||||||
),
|
|
||||||
),
|
|
||||||
const Divider(),
|
|
||||||
// Settings checkboxes
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(16),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'Display Settings',
|
|
||||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
CheckboxListTile(
|
|
||||||
title: const Text('Show Search Bar'),
|
|
||||||
value: showSearchBar.value,
|
|
||||||
onChanged: (value) {
|
|
||||||
if (value != null) {
|
|
||||||
showSearchBar.value = value;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
CheckboxListTile(
|
|
||||||
title: const Text('Show Clock and Countdown'),
|
|
||||||
value: showClockAndCountdown.value,
|
|
||||||
onChanged: (value) {
|
|
||||||
if (value != null) {
|
|
||||||
showClockAndCountdown.value = value;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,79 +179,81 @@ class DashboardCustomizationSheet extends HookConsumerWidget {
|
|||||||
return ['activityColumn', 'postsColumn', 'socialColumn', 'chatsColumn'];
|
return ['activityColumn', 'postsColumn', 'socialColumn', 'chatsColumn'];
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildLayoutEditor(
|
Widget _buildSliverLayoutEditor(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
|
WidgetRef ref,
|
||||||
String title,
|
String title,
|
||||||
ValueNotifier<List<String>> layouts,
|
ValueNotifier<List<String>> layouts,
|
||||||
bool isHorizontal,
|
bool isHorizontal,
|
||||||
|
ValueNotifier<bool> showSearchBar,
|
||||||
|
ValueNotifier<bool> showClockAndCountdown,
|
||||||
) {
|
) {
|
||||||
|
final cardMetadata = _getCardMetadata(context);
|
||||||
// Filter available cards based on layout mode
|
// Filter available cards based on layout mode
|
||||||
final relevantCards = isHorizontal
|
final relevantCards = isHorizontal
|
||||||
? _cardMetadata.entries.where((entry) => entry.key.contains('Column')).map((e) => e.key).toList()
|
? cardMetadata.entries
|
||||||
: _cardMetadata.entries.where((entry) => !entry.key.contains('Column')).map((e) => e.key).toList();
|
.where((entry) => entry.key.contains('Column'))
|
||||||
|
.map((e) => e.key)
|
||||||
|
.toList()
|
||||||
|
: cardMetadata.entries
|
||||||
|
.where((entry) => !entry.key.contains('Column'))
|
||||||
|
.map((e) => e.key)
|
||||||
|
.toList();
|
||||||
|
|
||||||
final availableCards =
|
final availableCards = relevantCards
|
||||||
relevantCards.where((cardId) => !layouts.value.contains(cardId)).toList();
|
.where((cardId) => !layouts.value.contains(cardId))
|
||||||
|
.toList();
|
||||||
|
|
||||||
return Column(
|
return CustomScrollView(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
slivers: [
|
||||||
children: [
|
// Title
|
||||||
Padding(
|
SliverToBoxAdapter(
|
||||||
padding: const EdgeInsets.all(16),
|
|
||||||
child: Text(
|
child: Text(
|
||||||
title,
|
title,
|
||||||
style: Theme.of(
|
style: Theme.of(
|
||||||
context,
|
context,
|
||||||
).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold),
|
).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold),
|
||||||
),
|
).padding(horizontal: 24, top: 16, bottom: 8),
|
||||||
),
|
),
|
||||||
// Reorderable list for cards
|
// Reorderable list for cards
|
||||||
Expanded(
|
SliverReorderableList(
|
||||||
child: ReorderableListView.builder(
|
|
||||||
buildDefaultDragHandles: false,
|
|
||||||
itemCount: layouts.value.length,
|
itemCount: layouts.value.length,
|
||||||
onReorder: (oldIndex, newIndex) {
|
|
||||||
if (oldIndex < newIndex) {
|
|
||||||
newIndex -= 1;
|
|
||||||
}
|
|
||||||
final item = layouts.value.removeAt(oldIndex);
|
|
||||||
layouts.value.insert(newIndex, item);
|
|
||||||
// Trigger rebuild
|
|
||||||
layouts.value = List.from(layouts.value);
|
|
||||||
},
|
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final cardId = layouts.value[index];
|
final cardId = layouts.value[index];
|
||||||
final metadata =
|
final metadata =
|
||||||
_cardMetadata[cardId] ??
|
cardMetadata[cardId] ?? {'name': cardId, 'icon': Symbols.help};
|
||||||
{'name': cardId, 'icon': Symbols.help};
|
|
||||||
|
|
||||||
return Card(
|
return ReorderableDragStartListener(
|
||||||
key: ValueKey(cardId),
|
key: ValueKey(cardId),
|
||||||
|
index: index,
|
||||||
|
child: Card(
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
|
dense: true,
|
||||||
leading: Icon(
|
leading: Icon(
|
||||||
metadata['icon'] as IconData,
|
metadata['icon'] as IconData,
|
||||||
color: Theme.of(context).colorScheme.primary,
|
color: Theme.of(context).colorScheme.primary,
|
||||||
),
|
),
|
||||||
|
contentPadding: const EdgeInsets.fromLTRB(16, 0, 8, 0),
|
||||||
title: Text(metadata['name'] as String),
|
title: Text(metadata['name'] as String),
|
||||||
subtitle: isHorizontal && metadata.containsKey('description')
|
subtitle: isHorizontal && metadata.containsKey('description')
|
||||||
? Text(
|
? Text(
|
||||||
metadata['description'] as String,
|
metadata['description'] as String,
|
||||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
style: Theme.of(context).textTheme.bodySmall
|
||||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
?.copyWith(
|
||||||
|
color: Theme.of(
|
||||||
|
context,
|
||||||
|
).colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
trailing: Row(
|
trailing: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
ReorderableDragStartListener(
|
Icon(
|
||||||
index: index,
|
|
||||||
child: Icon(
|
|
||||||
Symbols.drag_handle,
|
Symbols.drag_handle,
|
||||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
),
|
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Symbols.close,
|
Symbols.close,
|
||||||
@@ -230,25 +261,36 @@ class DashboardCustomizationSheet extends HookConsumerWidget {
|
|||||||
color: Theme.of(context).colorScheme.error,
|
color: Theme.of(context).colorScheme.error,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
layouts.value = layouts.value.where((id) => id != cardId).toList();
|
layouts.value = layouts.value
|
||||||
|
.where((id) => id != cardId)
|
||||||
|
.toList();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
onReorder: (oldIndex, newIndex) {
|
||||||
|
if (oldIndex < newIndex) {
|
||||||
|
newIndex -= 1;
|
||||||
|
}
|
||||||
|
final item = layouts.value.removeAt(oldIndex);
|
||||||
|
layouts.value.insert(newIndex, item);
|
||||||
|
layouts.value = List.from(layouts.value);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
// Available cards to add back
|
// Available cards to add back
|
||||||
if (availableCards.isNotEmpty)
|
if (availableCards.isNotEmpty)
|
||||||
Container(
|
SliverToBoxAdapter(
|
||||||
|
child: Container(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Available Cards',
|
'dashboardAvailableCards'.tr(),
|
||||||
style: Theme.of(context).textTheme.titleSmall?.copyWith(
|
style: Theme.of(context).textTheme.titleSmall?.copyWith(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
@@ -260,7 +302,7 @@ class DashboardCustomizationSheet extends HookConsumerWidget {
|
|||||||
runSpacing: 8,
|
runSpacing: 8,
|
||||||
children: availableCards.map((cardId) {
|
children: availableCards.map((cardId) {
|
||||||
final metadata =
|
final metadata =
|
||||||
_cardMetadata[cardId] ??
|
cardMetadata[cardId] ??
|
||||||
{'name': cardId, 'icon': Symbols.help};
|
{'name': cardId, 'icon': Symbols.help};
|
||||||
return ActionChip(
|
return ActionChip(
|
||||||
avatar: Icon(
|
avatar: Icon(
|
||||||
@@ -278,6 +320,78 @@ class DashboardCustomizationSheet extends HookConsumerWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
// Divider
|
||||||
|
const SliverToBoxAdapter(child: Divider()),
|
||||||
|
// Reset tile
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: ListTile(
|
||||||
|
dense: true,
|
||||||
|
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
leading: Icon(
|
||||||
|
Symbols.restore,
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
),
|
||||||
|
title: Text('dashboardResetToDefaults'.tr()),
|
||||||
|
subtitle: Text('dashboardResetToDefaultsSubtitle'.tr()),
|
||||||
|
trailing: Icon(
|
||||||
|
Symbols.chevron_right,
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
|
),
|
||||||
|
onTap: () async {
|
||||||
|
final confirmed = await showConfirmAlert(
|
||||||
|
'dashboardResetConfirmMessage'.tr(),
|
||||||
|
'dashboardResetConfirmTitle'.tr(),
|
||||||
|
isDanger: true,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (confirmed) {
|
||||||
|
ref.read(appSettingsProvider.notifier).resetDashboardConfig();
|
||||||
|
if (context.mounted) {
|
||||||
|
Navigator.of(context).pop(); // Close the sheet
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// Divider
|
||||||
|
const SliverToBoxAdapter(child: Divider()),
|
||||||
|
// Settings checkboxes
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'dashboardDisplaySettings'.tr(),
|
||||||
|
style: Theme.of(
|
||||||
|
context,
|
||||||
|
).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold),
|
||||||
|
).padding(horizontal: 24, top: 12, bottom: 8),
|
||||||
|
CheckboxListTile(
|
||||||
|
dense: true,
|
||||||
|
title: Text('dashboardShowSearchBar'.tr()),
|
||||||
|
value: showSearchBar.value,
|
||||||
|
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
onChanged: (value) {
|
||||||
|
if (value != null) {
|
||||||
|
showSearchBar.value = value;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
CheckboxListTile(
|
||||||
|
dense: true,
|
||||||
|
title: Text('dashboardShowClockAndCountdown'.tr()),
|
||||||
|
value: showClockAndCountdown.value,
|
||||||
|
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
onChanged: (value) {
|
||||||
|
if (value != null) {
|
||||||
|
showClockAndCountdown.value = value;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user