Polish navigation, Quran flows, and sharing UX

This commit is contained in:
Dwindi Ramadhana
2026-03-18 00:07:10 +07:00
parent a049129a35
commit 2d09b5b356
59 changed files with 11835 additions and 3184 deletions

View File

@@ -5,6 +5,7 @@ import 'package:go_router/go_router.dart';
import 'package:lucide_icons/lucide_icons.dart';
import 'package:intl/intl.dart';
import '../../../app/theme/app_colors.dart';
import '../../../core/widgets/notification_bell_button.dart';
import '../../../core/widgets/progress_bar.dart';
import '../../../data/local/hive_boxes.dart';
import '../../../data/local/models/app_settings.dart';
@@ -27,7 +28,13 @@ class _ChecklistScreenState extends ConsumerState<ChecklistScreen> {
late Box<AppSettings> _settingsBox;
late AppSettings _settings;
final List<String> _fardhuPrayers = ['Subuh', 'Dzuhur', 'Ashar', 'Maghrib', 'Isya'];
final List<String> _fardhuPrayers = [
'Subuh',
'Dzuhur',
'Ashar',
'Maghrib',
'Isya'
];
@override
void initState() {
@@ -45,7 +52,7 @@ class _ChecklistScreenState extends ConsumerState<ChecklistScreen> {
for (final p in _fardhuPrayers) {
shalatLogs[p.toLowerCase()] = ShalatLog();
}
_logBox.put(
_todayKey,
DailyWorshipLog(
@@ -69,7 +76,8 @@ class _ChecklistScreenState extends ConsumerState<ChecklistScreen> {
final log = _todayLog;
// Lazily attach Dzikir and Puasa if user toggles them mid-day
if (_settings.trackDzikir && log.dzikirLog == null) log.dzikirLog = DzikirLog();
if (_settings.trackDzikir && log.dzikirLog == null)
log.dzikirLog = DzikirLog();
if (_settings.trackPuasa && log.puasaLog == null) log.puasaLog = PuasaLog();
int total = 0;
@@ -155,17 +163,16 @@ class _ChecklistScreenState extends ConsumerState<ChecklistScreen> {
Text(
DateFormat('EEEE, d MMM yyyy').format(DateTime.now()),
style: theme.textTheme.bodySmall?.copyWith(
color: isDark ? AppColors.textSecondaryDark : AppColors.textSecondaryLight,
color: isDark
? AppColors.textSecondaryDark
: AppColors.textSecondaryLight,
),
),
],
),
centerTitle: false,
actions: [
IconButton(
onPressed: () {},
icon: const Icon(LucideIcons.bell),
),
const NotificationBellButton(),
IconButton(
onPressed: () => context.push('/settings'),
icon: const Icon(LucideIcons.settings),
@@ -246,14 +253,16 @@ class _ChecklistScreenState extends ConsumerState<ChecklistScreen> {
),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
padding:
const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
decoration: BoxDecoration(
color: AppColors.primary.withValues(alpha: 0.15),
borderRadius: BorderRadius.circular(12),
),
child: Row(
children: [
const Icon(LucideIcons.star, color: AppColors.primary, size: 14),
const Icon(LucideIcons.star,
color: AppColors.primary, size: 14),
const SizedBox(width: 4),
Text(
'${log.totalPoints} pts',
@@ -334,7 +343,9 @@ class _ChecklistScreenState extends ConsumerState<ChecklistScreen> {
border: Border.all(
color: isCompleted
? AppColors.primary.withValues(alpha: 0.3)
: (isDark ? AppColors.primary.withValues(alpha: 0.08) : AppColors.cream),
: (isDark
? AppColors.primary.withValues(alpha: 0.08)
: AppColors.cream),
),
),
child: Theme(
@@ -347,10 +358,14 @@ class _ChecklistScreenState extends ConsumerState<ChecklistScreen> {
decoration: BoxDecoration(
color: isCompleted
? AppColors.primary.withValues(alpha: 0.15)
: (isDark ? AppColors.primary.withValues(alpha: 0.08) : AppColors.cream.withValues(alpha: 0.5)),
: (isDark
? AppColors.primary.withValues(alpha: 0.08)
: AppColors.cream.withValues(alpha: 0.5)),
borderRadius: BorderRadius.circular(12),
),
child: Icon(LucideIcons.building, size: 22, color: isCompleted ? AppColors.primary : AppColors.sage),
child: Icon(LucideIcons.building,
size: 22,
color: isCompleted ? AppColors.primary : AppColors.sage),
),
title: Text(
'Sholat $prayerName',
@@ -362,7 +377,9 @@ class _ChecklistScreenState extends ConsumerState<ChecklistScreen> {
),
),
subtitle: log.location != null
? Text('Di ${log.location}', style: const TextStyle(fontSize: 12, color: AppColors.primary))
? Text('Di ${log.location}',
style:
const TextStyle(fontSize: 12, color: AppColors.primary))
: null,
trailing: _CustomCheckbox(
value: isCompleted,
@@ -371,14 +388,17 @@ class _ChecklistScreenState extends ConsumerState<ChecklistScreen> {
_recalculateProgress();
},
),
childrenPadding: const EdgeInsets.only(left: 16, right: 16, bottom: 16),
childrenPadding:
const EdgeInsets.only(left: 16, right: 16, bottom: 16),
children: [
const Divider(),
const SizedBox(height: 8),
// Location Radio
Row(
children: [
const Text('Pelaksanaan:', style: TextStyle(fontSize: 13, fontWeight: FontWeight.w600)),
const Text('Pelaksanaan:',
style:
TextStyle(fontSize: 13, fontWeight: FontWeight.w600)),
const SizedBox(width: 16),
_radioOption('Masjid', log, () {
log.location = 'Masjid';
@@ -422,7 +442,9 @@ class _ChecklistScreenState extends ConsumerState<ChecklistScreen> {
color: selected ? AppColors.primary : Colors.grey,
),
const SizedBox(width: 4),
Text(title, style: TextStyle(fontSize: 13, color: selected ? AppColors.primary : null)),
Text(title,
style: TextStyle(
fontSize: 13, color: selected ? AppColors.primary : null)),
],
),
);
@@ -453,7 +475,9 @@ class _ChecklistScreenState extends ConsumerState<ChecklistScreen> {
border: Border.all(
color: log.isCompleted
? AppColors.primary.withValues(alpha: 0.3)
: (isDark ? AppColors.primary.withValues(alpha: 0.08) : AppColors.cream),
: (isDark
? AppColors.primary.withValues(alpha: 0.08)
: AppColors.cream),
),
),
child: Column(
@@ -467,10 +491,15 @@ class _ChecklistScreenState extends ConsumerState<ChecklistScreen> {
decoration: BoxDecoration(
color: log.isCompleted
? AppColors.primary.withValues(alpha: 0.15)
: (isDark ? AppColors.primary.withValues(alpha: 0.08) : AppColors.cream.withValues(alpha: 0.5)),
: (isDark
? AppColors.primary.withValues(alpha: 0.08)
: AppColors.cream.withValues(alpha: 0.5)),
borderRadius: BorderRadius.circular(12),
),
child: Icon(LucideIcons.bookOpen, size: 22, color: log.isCompleted ? AppColors.primary : AppColors.sage),
child: Icon(LucideIcons.bookOpen,
size: 22,
color:
log.isCompleted ? AppColors.primary : AppColors.sage),
),
const SizedBox(width: 14),
Expanded(
@@ -482,13 +511,17 @@ class _ChecklistScreenState extends ConsumerState<ChecklistScreen> {
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: log.isCompleted && isDark ? AppColors.textSecondaryDark : null,
decoration: log.isCompleted ? TextDecoration.lineThrough : null,
color: log.isCompleted && isDark
? AppColors.textSecondaryDark
: null,
decoration:
log.isCompleted ? TextDecoration.lineThrough : null,
),
),
Text(
'Target: ${log.targetValue} ${log.targetUnit}',
style: const TextStyle(fontSize: 12, color: AppColors.primary),
style: const TextStyle(
fontSize: 12, color: AppColors.primary),
),
],
),
@@ -516,14 +549,17 @@ class _ChecklistScreenState extends ConsumerState<ChecklistScreen> {
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w600,
color: isDark ? AppColors.textSecondaryDark : AppColors.textSecondaryLight,
color: isDark
? AppColors.textSecondaryDark
: AppColors.textSecondaryLight,
),
),
),
if (log.autoSync)
Tooltip(
message: 'Sinkron dari Al-Quran',
child: Icon(LucideIcons.refreshCw, size: 16, color: AppColors.primary),
child: Icon(LucideIcons.refreshCw,
size: 16, color: AppColors.primary),
),
IconButton(
icon: const Icon(LucideIcons.minusCircle, size: 20),
@@ -536,7 +572,8 @@ class _ChecklistScreenState extends ConsumerState<ChecklistScreen> {
: null,
),
IconButton(
icon: const Icon(LucideIcons.plusCircle, size: 20, color: AppColors.primary),
icon: const Icon(LucideIcons.plusCircle,
size: 20, color: AppColors.primary),
visualDensity: VisualDensity.compact,
onPressed: () {
log.rawAyatRead++;
@@ -568,7 +605,8 @@ class _ChecklistScreenState extends ConsumerState<ChecklistScreen> {
children: [
Icon(LucideIcons.sparkles, size: 20, color: AppColors.sage),
const SizedBox(width: 8),
const Text('Dzikir Harian', style: TextStyle(fontWeight: FontWeight.w600, fontSize: 15)),
const Text('Dzikir Harian',
style: TextStyle(fontWeight: FontWeight.w600, fontSize: 15)),
],
),
const SizedBox(height: 12),
@@ -599,13 +637,17 @@ class _ChecklistScreenState extends ConsumerState<ChecklistScreen> {
children: [
const Icon(LucideIcons.moonStar, size: 20, color: AppColors.sage),
const SizedBox(width: 8),
const Expanded(child: Text('Puasa Sunnah', style: TextStyle(fontWeight: FontWeight.w600, fontSize: 15))),
const Expanded(
child: Text('Puasa Sunnah',
style: TextStyle(fontWeight: FontWeight.w600, fontSize: 15))),
DropdownButton<String>(
value: log.jenisPuasa,
hint: const Text('Jenis', style: TextStyle(fontSize: 12)),
underline: const SizedBox(),
items: ['Senin', 'Kamis', 'Ayyamul Bidh', 'Daud', 'Lainnya']
.map((e) => DropdownMenuItem(value: e, child: Text(e, style: const TextStyle(fontSize: 13))))
.map((e) => DropdownMenuItem(
value: e,
child: Text(e, style: const TextStyle(fontSize: 13))))
.toList(),
onChanged: (v) {
log.jenisPuasa = v;
@@ -644,7 +686,9 @@ class _CustomCheckbox extends StatelessWidget {
borderRadius: BorderRadius.circular(6),
border: value ? null : Border.all(color: Colors.grey, width: 2),
),
child: value ? const Icon(LucideIcons.check, size: 16, color: Colors.white) : null,
child: value
? const Icon(LucideIcons.check, size: 16, color: Colors.white)
: null,
),
);
}