mirror of
https://github.com/vleeuwenmenno/supplements.git
synced 2025-09-11 10:27:08 +02:00
feat: Integrate ShadSonner for improved toast notifications across multiple screens
This commit is contained in:
@@ -8,7 +8,11 @@
|
|||||||
],
|
],
|
||||||
"env": {
|
"env": {
|
||||||
"DEFAULT_MINIMUM_TOKENS": ""
|
"DEFAULT_MINIMUM_TOKENS": ""
|
||||||
}
|
},
|
||||||
|
"alwaysAllow": [
|
||||||
|
"resolve-library-id",
|
||||||
|
"get-library-docs"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,5 +1,6 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<!-- Permissions for notifications -->
|
<!-- Permissions for notifications -->
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />
|
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />
|
||||||
|
@@ -105,7 +105,9 @@ class MyApp extends StatelessWidget {
|
|||||||
colorScheme: const ShadZincColorScheme.dark(),
|
colorScheme: const ShadZincColorScheme.dark(),
|
||||||
),
|
),
|
||||||
themeMode: settingsProvider.themeMode,
|
themeMode: settingsProvider.themeMode,
|
||||||
home: const HomeScreen(),
|
home: ShadSonner(
|
||||||
|
child: const HomeScreen(),
|
||||||
|
),
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
import '../models/ingredient.dart';
|
import '../models/ingredient.dart';
|
||||||
@@ -571,10 +572,17 @@ class _AddSupplementScreenState extends State<AddSupplementScreen> {
|
|||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
if (validIngredients.isEmpty) {
|
if (validIngredients.isEmpty) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
final sonner = ShadSonner.of(context);
|
||||||
const SnackBar(
|
final id = DateTime.now().millisecondsSinceEpoch;
|
||||||
content:
|
sonner.show(
|
||||||
Text('Please add at least one ingredient with name and amount'),
|
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;
|
return;
|
||||||
@@ -611,21 +619,36 @@ class _AddSupplementScreenState extends State<AddSupplementScreen> {
|
|||||||
if (mounted) {
|
if (mounted) {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
final sonner = ShadSonner.of(context);
|
||||||
SnackBar(
|
final id = DateTime.now().millisecondsSinceEpoch;
|
||||||
content: Text(widget.supplement != null
|
sonner.show(
|
||||||
|
ShadToast(
|
||||||
|
id: id,
|
||||||
|
title: Text(widget.supplement != null
|
||||||
? 'Supplement updated successfully!'
|
? 'Supplement updated successfully!'
|
||||||
: 'Supplement added successfully!'),
|
: 'Supplement added successfully!'),
|
||||||
backgroundColor: Colors.green,
|
action: ShadButton(
|
||||||
|
size: ShadButtonSize.sm,
|
||||||
|
child: const Text('Dismiss'),
|
||||||
|
onPressed: () => sonner.hide(id),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
final sonner = ShadSonner.of(context);
|
||||||
SnackBar(
|
final id = DateTime.now().millisecondsSinceEpoch;
|
||||||
content: Text('Error: ${e.toString()}'),
|
sonner.show(
|
||||||
backgroundColor: Colors.red,
|
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:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||||
import 'package:supplements/widgets/info_chip.dart';
|
import 'package:supplements/widgets/info_chip.dart';
|
||||||
|
|
||||||
import '../models/supplement.dart';
|
import '../models/supplement.dart';
|
||||||
@@ -97,10 +98,9 @@ class _ArchivedSupplementsScreenState extends State<ArchivedSupplementsScreen> {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.read<SupplementProvider>().unarchiveSupplement(supplement.id!);
|
context.read<SupplementProvider>().unarchiveSupplement(supplement.id!);
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ShadSonner.of(context).show(
|
||||||
SnackBar(
|
ShadToast(
|
||||||
content: Text('${supplement.name} unarchived'),
|
title: Text('${supplement.name} unarchived'),
|
||||||
backgroundColor: Colors.green,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -128,10 +128,9 @@ class _ArchivedSupplementsScreenState extends State<ArchivedSupplementsScreen> {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.read<SupplementProvider>().deleteArchivedSupplement(supplement.id!);
|
context.read<SupplementProvider>().deleteArchivedSupplement(supplement.id!);
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ShadSonner.of(context).show(
|
||||||
SnackBar(
|
ShadToast(
|
||||||
content: Text('${supplement.name} deleted permanently'),
|
title: Text('${supplement.name} deleted permanently'),
|
||||||
backgroundColor: Colors.red,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||||
import 'package:supplements/providers/supplement_provider.dart';
|
import 'package:supplements/providers/supplement_provider.dart';
|
||||||
import 'package:supplements/services/notification_debug_store.dart';
|
import 'package:supplements/services/notification_debug_store.dart';
|
||||||
import 'package:supplements/services/simple_notification_service.dart';
|
import 'package:supplements/services/simple_notification_service.dart';
|
||||||
@@ -168,8 +169,10 @@ class _DebugNotificationsScreenState extends State<DebugNotificationsScreen> {
|
|||||||
await SimpleNotificationService.instance.cancelById(id);
|
await SimpleNotificationService.instance.cancelById(id);
|
||||||
await _load();
|
await _load();
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ShadSonner.of(context).show(
|
||||||
SnackBar(content: Text('Canceled notification $id')),
|
ShadToast(
|
||||||
|
title: Text('Canceled notification $id'),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,8 +180,10 @@ class _DebugNotificationsScreenState extends State<DebugNotificationsScreen> {
|
|||||||
await SimpleNotificationService.instance.cancelAll();
|
await SimpleNotificationService.instance.cancelAll();
|
||||||
await _load();
|
await _load();
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ShadSonner.of(context).show(
|
||||||
const SnackBar(content: Text('Canceled all notifications')),
|
const ShadToast(
|
||||||
|
title: Text('Canceled all notifications'),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,15 +191,19 @@ class _DebugNotificationsScreenState extends State<DebugNotificationsScreen> {
|
|||||||
await NotificationDebugStore.instance.clear();
|
await NotificationDebugStore.instance.clear();
|
||||||
await _load();
|
await _load();
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ShadSonner.of(context).show(
|
||||||
const SnackBar(content: Text('Cleared debug log')),
|
const ShadToast(
|
||||||
|
title: Text('Cleared debug log'),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _copyToClipboard(String text) {
|
void _copyToClipboard(String text) {
|
||||||
Clipboard.setData(ClipboardData(text: text));
|
Clipboard.setData(ClipboardData(text: text));
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ShadSonner.of(context).show(
|
||||||
const SnackBar(content: Text('Copied to clipboard')),
|
const ShadToast(
|
||||||
|
title: Text('Copied to clipboard'),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,8 +289,10 @@ class _DebugNotificationsScreenState extends State<DebugNotificationsScreen> {
|
|||||||
isSingle: true, // This is a single notification
|
isSingle: true, // This is a single notification
|
||||||
);
|
);
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ShadSonner.of(context).show(
|
||||||
const SnackBar(content: Text('Test snooze notification sent!')),
|
const ShadToast(
|
||||||
|
title: Text('Test snooze notification sent!'),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: const Text('Send Test Snooze Notification'),
|
child: const Text('Send Test Snooze Notification'),
|
||||||
|
@@ -1,8 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:intl/intl.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||||
|
|
||||||
import '../providers/settings_provider.dart';
|
|
||||||
import '../providers/supplement_provider.dart';
|
import '../providers/supplement_provider.dart';
|
||||||
|
|
||||||
class HistoryScreen extends StatefulWidget {
|
class HistoryScreen extends StatefulWidget {
|
||||||
@@ -350,10 +349,17 @@ class _HistoryScreenState extends State<HistoryScreen> {
|
|||||||
context.read<SupplementProvider>().loadMonthlyIntakes(_selectedYear, _selectedMonth);
|
context.read<SupplementProvider>().loadMonthlyIntakes(_selectedYear, _selectedMonth);
|
||||||
});
|
});
|
||||||
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
final sonner = ShadSonner.of(context);
|
||||||
SnackBar(
|
final id = DateTime.now().millisecondsSinceEpoch;
|
||||||
content: Text('$supplementName intake deleted'),
|
sonner.show(
|
||||||
backgroundColor: Colors.red,
|
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/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||||
|
|
||||||
import '../providers/settings_provider.dart';
|
import '../providers/settings_provider.dart';
|
||||||
import 'debug_notifications_screen.dart';
|
import 'debug_notifications_screen.dart';
|
||||||
@@ -124,6 +125,7 @@ class SettingsScreen extends StatelessWidget {
|
|||||||
trailing: DropdownButton<int>(
|
trailing: DropdownButton<int>(
|
||||||
value: settingsProvider.snoozeMinutes,
|
value: settingsProvider.snoozeMinutes,
|
||||||
items: const [
|
items: const [
|
||||||
|
DropdownMenuItem(value: 2, child: Text('2 min')),
|
||||||
DropdownMenuItem(value: 5, child: Text('5 min')),
|
DropdownMenuItem(value: 5, child: Text('5 min')),
|
||||||
DropdownMenuItem(value: 10, child: Text('10 min')),
|
DropdownMenuItem(value: 10, child: Text('10 min')),
|
||||||
DropdownMenuItem(value: 15, child: Text('15 min')),
|
DropdownMenuItem(value: 15, child: Text('15 min')),
|
||||||
@@ -301,10 +303,18 @@ class SettingsScreen extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
final sonner = ShadSonner.of(context);
|
||||||
SnackBar(
|
final id = DateTime.now().millisecondsSinceEpoch;
|
||||||
content: Text('Invalid time ranges: ${e.toString()}'),
|
sonner.show(
|
||||||
backgroundColor: Colors.red,
|
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:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||||
|
|
||||||
import '../providers/settings_provider.dart';
|
import '../providers/settings_provider.dart';
|
||||||
import '../providers/simple_sync_provider.dart';
|
import '../providers/simple_sync_provider.dart';
|
||||||
@@ -553,21 +554,36 @@ class _SimpleSyncSettingsScreenState extends State<SimpleSyncSettingsScreen> {
|
|||||||
final success = await syncProvider.testConnection();
|
final success = await syncProvider.testConnection();
|
||||||
|
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
final sonner = ShadSonner.of(context);
|
||||||
SnackBar(
|
final id = DateTime.now().millisecondsSinceEpoch;
|
||||||
content: Text(success
|
sonner.show(
|
||||||
|
ShadToast(
|
||||||
|
id: id,
|
||||||
|
title: Text(success
|
||||||
? 'Connection successful!'
|
? 'Connection successful!'
|
||||||
: 'Connection failed. Check your settings.'),
|
: '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) {
|
} catch (e) {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
final sonner = ShadSonner.of(context);
|
||||||
SnackBar(
|
final id = DateTime.now().millisecondsSinceEpoch;
|
||||||
content: Text('Connection test failed: $e'),
|
sonner.show(
|
||||||
backgroundColor: Colors.red,
|
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) {
|
if (mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
final sonner = ShadSonner.of(context);
|
||||||
const SnackBar(
|
final id = DateTime.now().millisecondsSinceEpoch;
|
||||||
content: Text('Configuration saved successfully!'),
|
sonner.show(
|
||||||
backgroundColor: Colors.green,
|
ShadToast(
|
||||||
|
id: id,
|
||||||
|
title: const Text('Configuration saved successfully!'),
|
||||||
|
action: ShadButton(
|
||||||
|
size: ShadButtonSize.sm,
|
||||||
|
child: const Text('Dismiss'),
|
||||||
|
onPressed: () => sonner.hide(id),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
final sonner = ShadSonner.of(context);
|
||||||
SnackBar(
|
final id = DateTime.now().millisecondsSinceEpoch;
|
||||||
content: Text('Failed to save configuration: $e'),
|
sonner.show(
|
||||||
backgroundColor: Colors.red,
|
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);
|
await syncProvider.syncDatabase(isAutoSync: false);
|
||||||
|
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
final sonner = ShadSonner.of(context);
|
||||||
const SnackBar(
|
final id = DateTime.now().millisecondsSinceEpoch;
|
||||||
content: Text('Manual sync completed!'),
|
sonner.show(
|
||||||
backgroundColor: Colors.green,
|
ShadToast(
|
||||||
|
id: id,
|
||||||
|
title: const Text('Manual sync completed!'),
|
||||||
|
action: ShadButton(
|
||||||
|
size: ShadButtonSize.sm,
|
||||||
|
child: const Text('Dismiss'),
|
||||||
|
onPressed: () => sonner.hide(id),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
final sonner = ShadSonner.of(context);
|
||||||
SnackBar(
|
final id = DateTime.now().millisecondsSinceEpoch;
|
||||||
content: Text('Manual sync failed: $e'),
|
sonner.show(
|
||||||
backgroundColor: Colors.red,
|
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:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||||
|
|
||||||
import '../models/supplement.dart';
|
import '../models/supplement.dart';
|
||||||
import '../providers/settings_provider.dart';
|
import '../providers/settings_provider.dart';
|
||||||
@@ -308,10 +309,9 @@ class SupplementsListScreen extends StatelessWidget {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.read<SupplementProvider>().deleteSupplement(supplement.id!);
|
context.read<SupplementProvider>().deleteSupplement(supplement.id!);
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ShadSonner.of(context).show(
|
||||||
SnackBar(
|
ShadToast(
|
||||||
content: Text('${supplement.name} deleted'),
|
title: Text('${supplement.name} deleted'),
|
||||||
backgroundColor: Colors.red,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -338,10 +338,9 @@ class SupplementsListScreen extends StatelessWidget {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.read<SupplementProvider>().archiveSupplement(supplement.id!);
|
context.read<SupplementProvider>().archiveSupplement(supplement.id!);
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ShadSonner.of(context).show(
|
||||||
SnackBar(
|
ShadToast(
|
||||||
content: Text('${supplement.name} archived'),
|
title: Text('${supplement.name} archived'),
|
||||||
backgroundColor: Colors.orange,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@@ -4,6 +4,7 @@ import 'dart:convert';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:supplements/logging.dart';
|
import 'package:supplements/logging.dart';
|
||||||
import 'package:supplements/services/simple_notification_service.dart';
|
import 'package:supplements/services/simple_notification_service.dart';
|
||||||
@@ -32,9 +33,6 @@ class NotificationRouter {
|
|||||||
printLog('🔔 handleNotificationResponse: Received actionId: $actionId');
|
printLog('🔔 handleNotificationResponse: Received actionId: $actionId');
|
||||||
printLog('🔔 handleNotificationResponse: Decoded payloadMap: $payloadMap');
|
printLog('🔔 handleNotificationResponse: Decoded payloadMap: $payloadMap');
|
||||||
|
|
||||||
// Cancel retry notifications for any interaction (take, snooze, or tap)
|
|
||||||
await _cancelRetryNotificationsForResponse(payloadMap);
|
|
||||||
|
|
||||||
// Handle Snooze actions without surfacing UI
|
// Handle Snooze actions without surfacing UI
|
||||||
if (actionId == 'snooze_single' || actionId == 'snooze_group') {
|
if (actionId == 'snooze_single' || actionId == 'snooze_group') {
|
||||||
try {
|
try {
|
||||||
@@ -49,6 +47,11 @@ class NotificationRouter {
|
|||||||
|
|
||||||
// Default: route to in-app UI for Take actions and normal taps
|
// Default: route to in-app UI for Take actions and normal taps
|
||||||
await _routeFromPayload(payloadMap);
|
await _routeFromPayload(payloadMap);
|
||||||
|
|
||||||
|
// Cancel retry notifications only for Take actions (not for taps or snoozes)
|
||||||
|
if (actionId == 'take_single' || actionId == 'take_group') {
|
||||||
|
await _cancelRetryNotificationsForResponse(payloadMap);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> handleAppLaunchDetails(NotificationAppLaunchDetails? details) async {
|
Future<void> handleAppLaunchDetails(NotificationAppLaunchDetails? details) async {
|
||||||
@@ -294,8 +297,10 @@ class NotificationRouter {
|
|||||||
|
|
||||||
void _showSnack(BuildContext context, String message) {
|
void _showSnack(BuildContext context, String message) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ShadSonner.of(context).show(
|
||||||
SnackBar(content: Text(message)),
|
ShadToast(
|
||||||
|
title: Text(message),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||||
|
|
||||||
import '../../models/supplement.dart';
|
import '../../models/supplement.dart';
|
||||||
import '../../providers/supplement_provider.dart';
|
import '../../providers/supplement_provider.dart';
|
||||||
@@ -183,10 +184,17 @@ Future<void> showBulkTakeDialog(
|
|||||||
|
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
if (recorded > 0) {
|
if (recorded > 0) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
final sonner = ShadSonner.of(context);
|
||||||
SnackBar(
|
final id = DateTime.now().millisecondsSinceEpoch;
|
||||||
content: Text('Recorded $recorded supplement${recorded == 1 ? '' : 's'}'),
|
sonner.show(
|
||||||
backgroundColor: Colors.green,
|
ShadToast(
|
||||||
|
id: id,
|
||||||
|
title: Text('Recorded $recorded supplement${recorded == 1 ? '' : 's'}'),
|
||||||
|
action: ShadButton(
|
||||||
|
size: ShadButtonSize.sm,
|
||||||
|
child: const Text('Dismiss'),
|
||||||
|
onPressed: () => sonner.hide(id),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user