mirror of
https://github.com/vleeuwenmenno/supplements.git
synced 2025-09-11 18:29:12 +02:00
feat: Integrate ShadSonner for improved toast notifications across multiple screens
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import '../models/ingredient.dart';
|
||||
@@ -571,10 +572,17 @@ class _AddSupplementScreenState extends State<AddSupplementScreen> {
|
||||
.toList();
|
||||
|
||||
if (validIngredients.isEmpty) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content:
|
||||
Text('Please add at least one ingredient with name and amount'),
|
||||
final sonner = ShadSonner.of(context);
|
||||
final id = DateTime.now().millisecondsSinceEpoch;
|
||||
sonner.show(
|
||||
ShadToast(
|
||||
id: id,
|
||||
title: const Text('Please add at least one ingredient with name and amount'),
|
||||
action: ShadButton(
|
||||
size: ShadButtonSize.sm,
|
||||
child: const Text('Dismiss'),
|
||||
onPressed: () => sonner.hide(id),
|
||||
),
|
||||
),
|
||||
);
|
||||
return;
|
||||
@@ -611,21 +619,36 @@ class _AddSupplementScreenState extends State<AddSupplementScreen> {
|
||||
if (mounted) {
|
||||
Navigator.of(context).pop();
|
||||
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(widget.supplement != null
|
||||
final sonner = ShadSonner.of(context);
|
||||
final id = DateTime.now().millisecondsSinceEpoch;
|
||||
sonner.show(
|
||||
ShadToast(
|
||||
id: id,
|
||||
title: Text(widget.supplement != null
|
||||
? 'Supplement updated successfully!'
|
||||
: 'Supplement added successfully!'),
|
||||
backgroundColor: Colors.green,
|
||||
action: ShadButton(
|
||||
size: ShadButtonSize.sm,
|
||||
child: const Text('Dismiss'),
|
||||
onPressed: () => sonner.hide(id),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Error: ${e.toString()}'),
|
||||
backgroundColor: Colors.red,
|
||||
final sonner = ShadSonner.of(context);
|
||||
final id = DateTime.now().millisecondsSinceEpoch;
|
||||
sonner.show(
|
||||
ShadToast(
|
||||
id: id,
|
||||
title: const Text('Error'),
|
||||
description: Text('${e.toString()}'),
|
||||
action: ShadButton(
|
||||
size: ShadButtonSize.sm,
|
||||
child: const Text('Dismiss'),
|
||||
onPressed: () => sonner.hide(id),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
import 'package:supplements/widgets/info_chip.dart';
|
||||
|
||||
import '../models/supplement.dart';
|
||||
@@ -97,10 +98,9 @@ class _ArchivedSupplementsScreenState extends State<ArchivedSupplementsScreen> {
|
||||
onPressed: () {
|
||||
context.read<SupplementProvider>().unarchiveSupplement(supplement.id!);
|
||||
Navigator.of(context).pop();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('${supplement.name} unarchived'),
|
||||
backgroundColor: Colors.green,
|
||||
ShadSonner.of(context).show(
|
||||
ShadToast(
|
||||
title: Text('${supplement.name} unarchived'),
|
||||
),
|
||||
);
|
||||
},
|
||||
@@ -128,10 +128,9 @@ class _ArchivedSupplementsScreenState extends State<ArchivedSupplementsScreen> {
|
||||
onPressed: () {
|
||||
context.read<SupplementProvider>().deleteArchivedSupplement(supplement.id!);
|
||||
Navigator.of(context).pop();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('${supplement.name} deleted permanently'),
|
||||
backgroundColor: Colors.red,
|
||||
ShadSonner.of(context).show(
|
||||
ShadToast(
|
||||
title: Text('${supplement.name} deleted permanently'),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
@@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
import 'package:supplements/providers/supplement_provider.dart';
|
||||
import 'package:supplements/services/notification_debug_store.dart';
|
||||
import 'package:supplements/services/simple_notification_service.dart';
|
||||
@@ -168,8 +169,10 @@ class _DebugNotificationsScreenState extends State<DebugNotificationsScreen> {
|
||||
await SimpleNotificationService.instance.cancelById(id);
|
||||
await _load();
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('Canceled notification $id')),
|
||||
ShadSonner.of(context).show(
|
||||
ShadToast(
|
||||
title: Text('Canceled notification $id'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -177,8 +180,10 @@ class _DebugNotificationsScreenState extends State<DebugNotificationsScreen> {
|
||||
await SimpleNotificationService.instance.cancelAll();
|
||||
await _load();
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Canceled all notifications')),
|
||||
ShadSonner.of(context).show(
|
||||
const ShadToast(
|
||||
title: Text('Canceled all notifications'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -186,15 +191,19 @@ class _DebugNotificationsScreenState extends State<DebugNotificationsScreen> {
|
||||
await NotificationDebugStore.instance.clear();
|
||||
await _load();
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Cleared debug log')),
|
||||
ShadSonner.of(context).show(
|
||||
const ShadToast(
|
||||
title: Text('Cleared debug log'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _copyToClipboard(String text) {
|
||||
Clipboard.setData(ClipboardData(text: text));
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Copied to clipboard')),
|
||||
ShadSonner.of(context).show(
|
||||
const ShadToast(
|
||||
title: Text('Copied to clipboard'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -280,8 +289,10 @@ class _DebugNotificationsScreenState extends State<DebugNotificationsScreen> {
|
||||
isSingle: true, // This is a single notification
|
||||
);
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Test snooze notification sent!')),
|
||||
ShadSonner.of(context).show(
|
||||
const ShadToast(
|
||||
title: Text('Test snooze notification sent!'),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: const Text('Send Test Snooze Notification'),
|
||||
|
@@ -1,8 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
|
||||
import '../providers/settings_provider.dart';
|
||||
import '../providers/supplement_provider.dart';
|
||||
|
||||
class HistoryScreen extends StatefulWidget {
|
||||
@@ -350,10 +349,17 @@ class _HistoryScreenState extends State<HistoryScreen> {
|
||||
context.read<SupplementProvider>().loadMonthlyIntakes(_selectedYear, _selectedMonth);
|
||||
});
|
||||
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('$supplementName intake deleted'),
|
||||
backgroundColor: Colors.red,
|
||||
final sonner = ShadSonner.of(context);
|
||||
final id = DateTime.now().millisecondsSinceEpoch;
|
||||
sonner.show(
|
||||
ShadToast(
|
||||
id: id,
|
||||
title: Text('$supplementName intake deleted'),
|
||||
action: ShadButton(
|
||||
size: ShadButtonSize.sm,
|
||||
child: const Text('Dismiss'),
|
||||
onPressed: () => sonner.hide(id),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
|
||||
import '../providers/settings_provider.dart';
|
||||
import 'debug_notifications_screen.dart';
|
||||
@@ -124,6 +125,7 @@ class SettingsScreen extends StatelessWidget {
|
||||
trailing: DropdownButton<int>(
|
||||
value: settingsProvider.snoozeMinutes,
|
||||
items: const [
|
||||
DropdownMenuItem(value: 2, child: Text('2 min')),
|
||||
DropdownMenuItem(value: 5, child: Text('5 min')),
|
||||
DropdownMenuItem(value: 10, child: Text('10 min')),
|
||||
DropdownMenuItem(value: 15, child: Text('15 min')),
|
||||
@@ -301,10 +303,18 @@ class SettingsScreen extends StatelessWidget {
|
||||
);
|
||||
} catch (e) {
|
||||
if (context.mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Invalid time ranges: ${e.toString()}'),
|
||||
backgroundColor: Colors.red,
|
||||
final sonner = ShadSonner.of(context);
|
||||
final id = DateTime.now().millisecondsSinceEpoch;
|
||||
sonner.show(
|
||||
ShadToast(
|
||||
id: id,
|
||||
title: const Text('Invalid time ranges'),
|
||||
description: Text('${e.toString()}'),
|
||||
action: ShadButton(
|
||||
size: ShadButtonSize.sm,
|
||||
child: const Text('Dismiss'),
|
||||
onPressed: () => sonner.hide(id),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
|
||||
import '../providers/settings_provider.dart';
|
||||
import '../providers/simple_sync_provider.dart';
|
||||
@@ -553,21 +554,36 @@ class _SimpleSyncSettingsScreenState extends State<SimpleSyncSettingsScreen> {
|
||||
final success = await syncProvider.testConnection();
|
||||
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(success
|
||||
final sonner = ShadSonner.of(context);
|
||||
final id = DateTime.now().millisecondsSinceEpoch;
|
||||
sonner.show(
|
||||
ShadToast(
|
||||
id: id,
|
||||
title: Text(success
|
||||
? 'Connection successful!'
|
||||
: 'Connection failed. Check your settings.'),
|
||||
backgroundColor: success ? Colors.green : Colors.red,
|
||||
action: ShadButton(
|
||||
size: ShadButtonSize.sm,
|
||||
child: const Text('Dismiss'),
|
||||
onPressed: () => sonner.hide(id),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Connection test failed: $e'),
|
||||
backgroundColor: Colors.red,
|
||||
final sonner = ShadSonner.of(context);
|
||||
final id = DateTime.now().millisecondsSinceEpoch;
|
||||
sonner.show(
|
||||
ShadToast(
|
||||
id: id,
|
||||
title: const Text('Connection test failed'),
|
||||
description: Text('$e'),
|
||||
action: ShadButton(
|
||||
size: ShadButtonSize.sm,
|
||||
child: const Text('Dismiss'),
|
||||
onPressed: () => sonner.hide(id),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -596,19 +612,34 @@ class _SimpleSyncSettingsScreenState extends State<SimpleSyncSettingsScreen> {
|
||||
);
|
||||
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Configuration saved successfully!'),
|
||||
backgroundColor: Colors.green,
|
||||
final sonner = ShadSonner.of(context);
|
||||
final id = DateTime.now().millisecondsSinceEpoch;
|
||||
sonner.show(
|
||||
ShadToast(
|
||||
id: id,
|
||||
title: const Text('Configuration saved successfully!'),
|
||||
action: ShadButton(
|
||||
size: ShadButtonSize.sm,
|
||||
child: const Text('Dismiss'),
|
||||
onPressed: () => sonner.hide(id),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Failed to save configuration: $e'),
|
||||
backgroundColor: Colors.red,
|
||||
final sonner = ShadSonner.of(context);
|
||||
final id = DateTime.now().millisecondsSinceEpoch;
|
||||
sonner.show(
|
||||
ShadToast(
|
||||
id: id,
|
||||
title: const Text('Failed to save configuration'),
|
||||
description: Text('$e'),
|
||||
action: ShadButton(
|
||||
size: ShadButtonSize.sm,
|
||||
child: const Text('Dismiss'),
|
||||
onPressed: () => sonner.hide(id),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -622,19 +653,34 @@ class _SimpleSyncSettingsScreenState extends State<SimpleSyncSettingsScreen> {
|
||||
await syncProvider.syncDatabase(isAutoSync: false);
|
||||
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Manual sync completed!'),
|
||||
backgroundColor: Colors.green,
|
||||
final sonner = ShadSonner.of(context);
|
||||
final id = DateTime.now().millisecondsSinceEpoch;
|
||||
sonner.show(
|
||||
ShadToast(
|
||||
id: id,
|
||||
title: const Text('Manual sync completed!'),
|
||||
action: ShadButton(
|
||||
size: ShadButtonSize.sm,
|
||||
child: const Text('Dismiss'),
|
||||
onPressed: () => sonner.hide(id),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Manual sync failed: $e'),
|
||||
backgroundColor: Colors.red,
|
||||
final sonner = ShadSonner.of(context);
|
||||
final id = DateTime.now().millisecondsSinceEpoch;
|
||||
sonner.show(
|
||||
ShadToast(
|
||||
id: id,
|
||||
title: const Text('Manual sync failed'),
|
||||
description: Text('$e'),
|
||||
action: ShadButton(
|
||||
size: ShadButtonSize.sm,
|
||||
child: const Text('Dismiss'),
|
||||
onPressed: () => sonner.hide(id),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
|
||||
import '../models/supplement.dart';
|
||||
import '../providers/settings_provider.dart';
|
||||
@@ -308,10 +309,9 @@ class SupplementsListScreen extends StatelessWidget {
|
||||
onPressed: () {
|
||||
context.read<SupplementProvider>().deleteSupplement(supplement.id!);
|
||||
Navigator.of(context).pop();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('${supplement.name} deleted'),
|
||||
backgroundColor: Colors.red,
|
||||
ShadSonner.of(context).show(
|
||||
ShadToast(
|
||||
title: Text('${supplement.name} deleted'),
|
||||
),
|
||||
);
|
||||
},
|
||||
@@ -338,10 +338,9 @@ class SupplementsListScreen extends StatelessWidget {
|
||||
onPressed: () {
|
||||
context.read<SupplementProvider>().archiveSupplement(supplement.id!);
|
||||
Navigator.of(context).pop();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('${supplement.name} archived'),
|
||||
backgroundColor: Colors.orange,
|
||||
ShadSonner.of(context).show(
|
||||
ShadToast(
|
||||
title: Text('${supplement.name} archived'),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
Reference in New Issue
Block a user