feat: complete Simple Mode contextual routing and navigation state synchronization
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lucide_icons/lucide_icons.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import '../../app/theme/app_colors.dart';
|
||||
import '../../data/local/hive_boxes.dart';
|
||||
import '../../data/local/models/app_settings.dart';
|
||||
|
||||
/// 5-tab bottom navigation bar per PRD §5.1.
|
||||
/// Uses Material Symbols outlined (inactive) and filled (active).
|
||||
@@ -15,52 +19,89 @@ class AppBottomNavBar extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).bottomNavigationBarTheme.backgroundColor,
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 0.5,
|
||||
return ValueListenableBuilder<Box<AppSettings>>(
|
||||
valueListenable: Hive.box<AppSettings>(HiveBoxes.settings).listenable(),
|
||||
builder: (context, box, _) {
|
||||
final isSimpleMode = box.get('default')?.simpleMode ?? false;
|
||||
|
||||
final simpleItems = const [
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(LucideIcons.home),
|
||||
activeIcon: Icon(LucideIcons.home),
|
||||
label: 'Beranda',
|
||||
),
|
||||
),
|
||||
),
|
||||
child: SafeArea(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8),
|
||||
child: BottomNavigationBar(
|
||||
currentIndex: currentIndex,
|
||||
onTap: onTap,
|
||||
items: const [
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(Icons.home_outlined),
|
||||
activeIcon: Icon(Icons.home),
|
||||
label: 'Beranda',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(Icons.calendar_today_outlined),
|
||||
activeIcon: Icon(Icons.calendar_today),
|
||||
label: 'Jadwal',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(Icons.rule_outlined),
|
||||
activeIcon: Icon(Icons.rule),
|
||||
label: 'Ibadah',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(Icons.bar_chart_outlined),
|
||||
activeIcon: Icon(Icons.bar_chart),
|
||||
label: 'Laporan',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(Icons.auto_fix_high_outlined),
|
||||
activeIcon: Icon(Icons.auto_fix_high),
|
||||
label: 'Alat',
|
||||
),
|
||||
],
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(LucideIcons.calendar),
|
||||
activeIcon: Icon(LucideIcons.calendar),
|
||||
label: 'Jadwal',
|
||||
),
|
||||
),
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(LucideIcons.bookOpen),
|
||||
activeIcon: Icon(LucideIcons.bookOpen),
|
||||
label: 'Tilawah',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(LucideIcons.headphones),
|
||||
activeIcon: Icon(LucideIcons.headphones),
|
||||
label: 'Murattal',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(LucideIcons.sparkles),
|
||||
activeIcon: Icon(LucideIcons.sparkles),
|
||||
label: 'Zikir',
|
||||
),
|
||||
];
|
||||
|
||||
final fullItems = const [
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(LucideIcons.home),
|
||||
activeIcon: Icon(LucideIcons.home),
|
||||
label: 'Beranda',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(LucideIcons.calendar),
|
||||
activeIcon: Icon(LucideIcons.calendar),
|
||||
label: 'Jadwal',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(LucideIcons.listChecks),
|
||||
activeIcon: Icon(LucideIcons.listChecks),
|
||||
label: 'Ibadah',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(LucideIcons.barChart3),
|
||||
activeIcon: Icon(LucideIcons.barChart3),
|
||||
label: 'Laporan',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(LucideIcons.wand2),
|
||||
activeIcon: Icon(LucideIcons.wand2),
|
||||
label: 'Alat',
|
||||
),
|
||||
];
|
||||
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).bottomNavigationBarTheme.backgroundColor,
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 0.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: SafeArea(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8),
|
||||
child: BottomNavigationBar(
|
||||
currentIndex: currentIndex,
|
||||
onTap: onTap,
|
||||
items: isSimpleMode ? simpleItems : fullItems,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
69
lib/core/widgets/tool_card.dart
Normal file
69
lib/core/widgets/tool_card.dart
Normal file
@@ -0,0 +1,69 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../app/theme/app_colors.dart';
|
||||
|
||||
class ToolCard extends StatelessWidget {
|
||||
final IconData icon;
|
||||
final String title;
|
||||
final Color color;
|
||||
final bool isDark;
|
||||
final VoidCallback onTap;
|
||||
|
||||
const ToolCard({
|
||||
super.key,
|
||||
required this.icon,
|
||||
required this.title,
|
||||
required this.color,
|
||||
required this.isDark,
|
||||
required this.onTap,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
height: 140,
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: isDark ? AppColors.surfaceDark : AppColors.surfaceLight,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
border: Border.all(
|
||||
color: isDark
|
||||
? color.withValues(alpha: 0.15)
|
||||
: AppColors.cream,
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: color.withValues(alpha: 0.08),
|
||||
blurRadius: 12,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Container(
|
||||
width: 44,
|
||||
height: 44,
|
||||
decoration: BoxDecoration(
|
||||
color: color.withValues(alpha: 0.15),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Icon(icon, color: color, size: 24),
|
||||
),
|
||||
Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w700,
|
||||
height: 1.3,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user