Initial commit: Sage Kitchen Management App v1.0.0
✨ Features implemented: - Smart inventory tracking with Hive database - Barcode scanning with auto-populated product info - Multiple API fallbacks (Open Food Facts, UPCItemDB) - Smart expiration date predictions by category - Discord webhook notifications (persisted) - Custom sage leaf vector icon - Material Design 3 UI with sage green theme - Privacy Policy & Terms of Service - Local-first, privacy-focused architecture 🎨 UI/UX: - Home dashboard with inventory stats - Add Item screen with barcode integration - Inventory list with expiration indicators - Settings with persistent preferences - About section with legal docs 🔧 Technical: - Flutter 3.35.5 with Riverpod state management - Hive 2.2.3 for local database - Mobile scanner for barcode detection - Feature-first architecture 🤖 Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
68
lib/features/notifications/services/discord_service.dart
Normal file
68
lib/features/notifications/services/discord_service.dart
Normal file
@@ -0,0 +1,68 @@
|
||||
import 'dart:convert';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
class DiscordService {
|
||||
String? webhookUrl;
|
||||
|
||||
/// Send a notification to Discord
|
||||
Future<bool> sendNotification({
|
||||
required String title,
|
||||
required String message,
|
||||
String? imageUrl,
|
||||
}) async {
|
||||
if (webhookUrl == null || webhookUrl!.isEmpty) {
|
||||
print('Discord webhook URL not configured');
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
final embed = {
|
||||
'title': title,
|
||||
'description': message,
|
||||
'color': 0x4CAF50, // Sage green (hex color)
|
||||
'timestamp': DateTime.now().toIso8601String(),
|
||||
};
|
||||
|
||||
if (imageUrl != null) {
|
||||
embed['thumbnail'] = {'url': imageUrl};
|
||||
}
|
||||
|
||||
final response = await http.post(
|
||||
Uri.parse(webhookUrl!),
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: jsonEncode({
|
||||
'embeds': [embed],
|
||||
}),
|
||||
);
|
||||
|
||||
return response.statusCode == 204;
|
||||
} catch (e) {
|
||||
print('Error sending Discord notification: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Send expiration alert
|
||||
Future<void> sendExpirationAlert({
|
||||
required String itemName,
|
||||
required int daysUntilExpiration,
|
||||
}) async {
|
||||
String emoji = '⚠️';
|
||||
String urgency = 'Warning';
|
||||
|
||||
if (daysUntilExpiration <= 0) {
|
||||
emoji = '🚨';
|
||||
urgency = 'Expired';
|
||||
} else if (daysUntilExpiration <= 3) {
|
||||
emoji = '⚠️';
|
||||
urgency = 'Critical';
|
||||
}
|
||||
|
||||
await sendNotification(
|
||||
title: '$emoji Food Expiration Alert - $urgency',
|
||||
message: daysUntilExpiration <= 0
|
||||
? '**$itemName** has expired!'
|
||||
: '**$itemName** expires in $daysUntilExpiration day${daysUntilExpiration == 1 ? '' : 's'}!',
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user