Apply a Material 3 seed-green palette and rounded components across the home, inventory, quick-add, quantity picker and variety-detail screens. The full-screen photo viewer can now set any photo as the cover (via attachment sort order) and delete after confirmation. Lot forms and packaging surface as choice chips. Extract About out of Settings into its own screen (app version via package_info_plus, website link). Add es/en strings for the new lot types, presentation, home tagline and About. Update Seedees v2 mockups.
171 lines
5 KiB
Dart
171 lines
5 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
import 'package:material_symbols_icons/symbols.dart';
|
|
|
|
import '../i18n/strings.g.dart';
|
|
import 'seed_glyph.dart';
|
|
import 'theme.dart';
|
|
|
|
/// The app's navigation drawer (redesign screen 05). A white sheet: Inventory is
|
|
/// the live destination (green seed glyph), the social items (market, profile,
|
|
/// chat…) belong to Block 2 and are greyed with a "soon" tag, and Settings sits
|
|
/// pinned at the bottom.
|
|
class AppDrawer extends StatelessWidget {
|
|
const AppDrawer({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final t = context.t;
|
|
return Drawer(
|
|
child: SafeArea(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
const _DrawerHeader(),
|
|
_DrawerItem(
|
|
icon: const SeedGlyph(SeedGlyphs.jars, size: 23),
|
|
label: t.menu.inventory,
|
|
onTap: () {
|
|
Navigator.of(context).pop();
|
|
context.go('/inventory');
|
|
},
|
|
),
|
|
_DrawerItem(
|
|
icon: const Icon(Symbols.storefront),
|
|
label: t.menu.market,
|
|
divider: true,
|
|
),
|
|
_DrawerItem(icon: const Icon(Icons.person), label: t.menu.profile),
|
|
_DrawerItem(
|
|
icon: const Icon(Icons.chat_bubble),
|
|
label: t.menu.chat,
|
|
),
|
|
_DrawerItem(
|
|
icon: const Icon(Icons.favorite),
|
|
label: t.menu.wishlist,
|
|
),
|
|
_DrawerItem(icon: const Icon(Icons.group), label: t.menu.following),
|
|
const Spacer(),
|
|
const Divider(height: 1),
|
|
_DrawerItem(
|
|
icon: const Icon(Icons.settings),
|
|
label: t.menu.settings,
|
|
onTap: () {
|
|
Navigator.of(context).pop();
|
|
context.push('/settings');
|
|
},
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// The drawer's brand header. Tapping it closes the drawer and returns to the
|
|
/// home screen.
|
|
class _DrawerHeader extends StatelessWidget {
|
|
const _DrawerHeader();
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return InkWell(
|
|
onTap: () {
|
|
Navigator.of(context).pop();
|
|
context.go('/');
|
|
},
|
|
child: Container(
|
|
padding: const EdgeInsets.fromLTRB(22, 18, 22, 16),
|
|
decoration: const BoxDecoration(
|
|
border: Border(bottom: BorderSide(color: seedDivider)),
|
|
),
|
|
child: Row(
|
|
children: [
|
|
Image.asset('assets/logo.png', height: 34),
|
|
const SizedBox(width: 12),
|
|
Text(
|
|
context.t.app.title,
|
|
style: const TextStyle(
|
|
color: seedGreen,
|
|
fontSize: 22,
|
|
fontWeight: FontWeight.w700,
|
|
letterSpacing: -0.2,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// A 52-tall drawer row. A live destination has an [onTap] (dark text, green
|
|
/// icon); a disabled Block-2 destination is greyed with a "soon" tag. [divider]
|
|
/// draws a hairline under the row (separating live from upcoming items).
|
|
class _DrawerItem extends StatelessWidget {
|
|
const _DrawerItem({
|
|
required this.icon,
|
|
required this.label,
|
|
this.onTap,
|
|
this.divider = false,
|
|
});
|
|
|
|
final Widget icon;
|
|
final String label;
|
|
final VoidCallback? onTap;
|
|
final bool divider;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final enabled = onTap != null;
|
|
final fg = enabled ? seedOnSurface : const Color(0xFF9AA88F);
|
|
final iconColor = enabled ? seedGreen : const Color(0xFF9AA88F);
|
|
final row = InkWell(
|
|
onTap: onTap,
|
|
child: Container(
|
|
height: 52,
|
|
padding: const EdgeInsets.symmetric(horizontal: 22),
|
|
decoration: divider
|
|
? const BoxDecoration(
|
|
border: Border(bottom: BorderSide(color: seedDivider)),
|
|
)
|
|
: null,
|
|
child: Row(
|
|
children: [
|
|
SizedBox(
|
|
width: 24,
|
|
child: Center(
|
|
child: IconTheme.merge(
|
|
data: IconThemeData(size: 23, color: iconColor),
|
|
child: icon,
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(width: 18),
|
|
Expanded(
|
|
child: Text(
|
|
label,
|
|
style: TextStyle(
|
|
color: fg,
|
|
fontSize: 15,
|
|
fontWeight: enabled ? FontWeight.w500 : FontWeight.w400,
|
|
),
|
|
),
|
|
),
|
|
if (!enabled)
|
|
Text(
|
|
context.t.common.comingSoon.toUpperCase(),
|
|
style: const TextStyle(
|
|
color: Color(0xFFB3BDA8),
|
|
fontSize: 11,
|
|
fontWeight: FontWeight.w500,
|
|
letterSpacing: 0.5,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
return row;
|
|
}
|
|
}
|