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:
2025-10-04 13:54:21 -04:00
commit 7be7b270e6
155 changed files with 13133 additions and 0 deletions

View File

@@ -0,0 +1,77 @@
import 'package:flutter/material.dart';
/// Sage leaf icon widget for use in the app
class SageLeafIcon extends StatelessWidget {
final double size;
final Color? color;
const SageLeafIcon({
super.key,
this.size = 24,
this.color,
});
@override
Widget build(BuildContext context) {
return CustomPaint(
size: Size(size, size),
painter: SageLeafPainter(color: color ?? const Color(0xFF4CAF50)),
);
}
}
class SageLeafPainter extends CustomPainter {
final Color color;
SageLeafPainter({required this.color});
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = color
..style = PaintingStyle.fill;
final path = Path();
// Create a simple sage leaf shape
final centerX = size.width / 2;
final centerY = size.height / 2;
// Leaf outline
path.moveTo(centerX, size.height * 0.1);
path.quadraticBezierTo(
size.width * 0.8, size.height * 0.3,
size.width * 0.85, centerY,
);
path.quadraticBezierTo(
size.width * 0.8, size.height * 0.7,
centerX, size.height * 0.9,
);
path.quadraticBezierTo(
size.width * 0.2, size.height * 0.7,
size.width * 0.15, centerY,
);
path.quadraticBezierTo(
size.width * 0.2, size.height * 0.3,
centerX, size.height * 0.1,
);
path.close();
canvas.drawPath(path, paint);
// Draw leaf vein
final veinPaint = Paint()
..color = color.withOpacity(0.6)
..style = PaintingStyle.stroke
..strokeWidth = size.width * 0.02;
final veinPath = Path();
veinPath.moveTo(centerX, size.height * 0.1);
veinPath.lineTo(centerX, size.height * 0.9);
canvas.drawPath(veinPath, veinPaint);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}

View File

@@ -0,0 +1,80 @@
import 'package:flutter/material.dart';
import 'colors.dart';
/// App theme configuration
class AppTheme {
// Light Theme
static ThemeData get lightTheme {
return ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.light(
primary: AppColors.primary,
secondary: AppColors.primaryLight,
surface: AppColors.surface,
error: AppColors.error,
),
scaffoldBackgroundColor: AppColors.background,
appBarTheme: const AppBarTheme(
backgroundColor: AppColors.primary,
foregroundColor: Colors.white,
elevation: 0,
centerTitle: true,
),
cardTheme: CardThemeData(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
floatingActionButtonTheme: const FloatingActionButtonThemeData(
backgroundColor: AppColors.primary,
foregroundColor: Colors.white,
),
inputDecorationTheme: InputDecorationTheme(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
filled: true,
fillColor: Colors.white,
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primary,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
foregroundColor: AppColors.primary,
),
),
);
}
// Dark Theme (for future)
static ThemeData get darkTheme {
return ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.dark(
primary: AppColors.primaryLight,
secondary: AppColors.primary,
surface: const Color(0xFF1E1E1E),
error: AppColors.error,
),
scaffoldBackgroundColor: const Color(0xFF121212),
appBarTheme: const AppBarTheme(
backgroundColor: Color(0xFF1E1E1E),
foregroundColor: Colors.white,
elevation: 0,
centerTitle: true,
),
);
}
}

View File

@@ -0,0 +1,37 @@
import 'package:flutter/material.dart';
/// App color palette
class AppColors {
// Primary - Sage Green theme 🌿
static const primary = Color(0xFF4CAF50);
static const primaryDark = Color(0xFF388E3C);
static const primaryLight = Color(0xFF81C784);
// Expiration Status Colors
static const fresh = Color(0xFF4CAF50); // Green
static const caution = Color(0xFFFFEB3B); // Yellow
static const warning = Color(0xFFFF9800); // Orange
static const critical = Color(0xFFF44336); // Red
static const expired = Color(0xFF9E9E9E); // Gray
// UI Colors
static const background = Color(0xFFFAFAFA);
static const surface = Color(0xFFFFFFFF);
static const text = Color(0xFF212121);
static const textSecondary = Color(0xFF757575);
static const divider = Color(0xFFBDBDBD);
// Semantic Colors
static const success = Color(0xFF4CAF50);
static const error = Color(0xFFF44336);
static const info = Color(0xFF2196F3);
static const warning2 = Color(0xFFFF9800);
// Location Colors (subtle backgrounds)
static const fridgeColor = Color(0xFFE3F2FD); // Light blue
static const freezerColor = Color(0xFFE1F5FE); // Lighter blue
static const pantryColor = Color(0xFFFFF9C4); // Light yellow
static const spiceRackColor = Color(0xFFFFECB3); // Light amber
static const countertopColor = Color(0xFFE8F5E9); // Light green
static const otherColor = Color(0xFFF5F5F5); // Light gray
}