feat: complete Simple Mode contextual routing and navigation state synchronization

This commit is contained in:
dwindown
2026-03-15 07:24:13 +07:00
parent faadc1865d
commit 25728583b3
21 changed files with 1095 additions and 320 deletions

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:lucide_icons/lucide_icons.dart';
import 'package:go_router/go_router.dart';
import 'package:intl/intl.dart';
import '../../../app/theme/app_colors.dart';
@@ -91,7 +92,7 @@ class _QuranBookmarksScreenState extends State<QuranBookmarksScreen> {
centerTitle: false,
actions: [
IconButton(
icon: const Icon(Icons.settings_display),
icon: const Icon(LucideIcons.settings2),
onPressed: _showDisplaySettings,
),
],
@@ -105,7 +106,7 @@ class _QuranBookmarksScreenState extends State<QuranBookmarksScreen> {
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.bookmark_border,
LucideIcons.bookmark,
size: 64,
color: AppColors.primary.withValues(alpha: 0.3),
),
@@ -220,7 +221,7 @@ class _QuranBookmarksScreenState extends State<QuranBookmarksScreen> {
mainAxisSize: MainAxisSize.min,
children: [
if (isLastRead) ...[
const Icon(Icons.push_pin, size: 12, color: AppColors.primary),
const Icon(LucideIcons.pin, size: 12, color: AppColors.primary),
const SizedBox(width: 4),
],
Text(
@@ -235,7 +236,7 @@ class _QuranBookmarksScreenState extends State<QuranBookmarksScreen> {
),
),
IconButton(
icon: const Icon(Icons.delete_outline, color: Colors.red, size: 20),
icon: const Icon(LucideIcons.trash2, color: Colors.red, size: 20),
onPressed: () => box.delete(bookmark.key),
padding: EdgeInsets.zero,
constraints: const BoxConstraints(),
@@ -287,7 +288,7 @@ class _QuranBookmarksScreenState extends State<QuranBookmarksScreen> {
width: double.infinity,
child: FilledButton.icon(
onPressed: () => context.push('/tools/quran/${bookmark.surahId}?startVerse=${bookmark.verseId}'),
icon: const Icon(Icons.menu_book, size: 18),
icon: const Icon(LucideIcons.bookOpen, size: 18),
label: const Text('Lanjutkan Membaca'),
style: FilledButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 12),
@@ -301,7 +302,7 @@ class _QuranBookmarksScreenState extends State<QuranBookmarksScreen> {
Row(
children: [
Icon(
Icons.access_time,
LucideIcons.clock,
size: 12,
color: isDark ? AppColors.textSecondaryDark : AppColors.textSecondaryLight,
),

View File

@@ -5,11 +5,15 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:just_audio/just_audio.dart';
import 'package:go_router/go_router.dart';
import 'package:lucide_icons/lucide_icons.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:url_launcher/url_launcher.dart';
import '../../../app/theme/app_colors.dart';
import '../../../data/services/equran_service.dart';
import '../../../data/services/unsplash_service.dart';
import 'package:hive_flutter/hive_flutter.dart';
import '../../../data/local/hive_boxes.dart';
import '../../../data/local/models/app_settings.dart';
/// Quran Murattal (audio player) screen.
/// Implements full Surah playback using just_audio and EQuran v2 API.
@@ -17,11 +21,13 @@ class QuranMurattalScreen extends ConsumerStatefulWidget {
final String surahId;
final String? initialQariId;
final bool autoPlay;
final bool isSimpleModeTab;
const QuranMurattalScreen({
super.key,
required this.surahId,
this.initialQariId,
this.autoPlay = false,
this.isSimpleModeTab = false,
});
@override
@@ -217,7 +223,7 @@ class _QuranMurattalScreenState extends ConsumerState<QuranMurattalScreen> {
final isSelected = entry.key == _selectedQariId;
return ListTile(
leading: Icon(
isSelected ? Icons.radio_button_checked : Icons.radio_button_unchecked,
isSelected ? LucideIcons.checkCircle2 : LucideIcons.circle,
color: isSelected ? AppColors.primary : Colors.grey,
),
title: Text(
@@ -327,7 +333,7 @@ class _QuranMurattalScreenState extends ConsumerState<QuranMurattalScreen> {
style: const TextStyle(fontSize: 12),
),
trailing: isCurrentSurah
? Icon(Icons.graphic_eq, color: AppColors.primary, size: 20)
? Icon(LucideIcons.music, color: AppColors.primary, size: 20)
: null,
onTap: () {
Navigator.pop(context);
@@ -354,6 +360,8 @@ class _QuranMurattalScreenState extends ConsumerState<QuranMurattalScreen> {
@override
Widget build(BuildContext context) {
final isDark = Theme.of(context).brightness == Brightness.dark;
final box = Hive.box<AppSettings>(HiveBoxes.settings);
final isSimpleMode = box.get('default')?.simpleMode ?? false;
final surahName = _surahData?['namaLatin'] ?? 'Surah ${widget.surahId}';
final hasPhoto = _unsplashPhoto != null;
@@ -361,6 +369,17 @@ class _QuranMurattalScreenState extends ConsumerState<QuranMurattalScreen> {
return Scaffold(
extendBodyBehindAppBar: hasPhoto,
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back,
color: hasPhoto ? Colors.white : null),
onPressed: () {
if (widget.isSimpleModeTab) {
context.go('/');
} else {
context.pop();
}
},
),
backgroundColor: hasPhoto ? Colors.transparent : null,
elevation: hasPhoto ? 0 : null,
iconTheme: hasPhoto ? const IconThemeData(color: Colors.white) : null,
@@ -393,7 +412,6 @@ class _QuranMurattalScreenState extends ConsumerState<QuranMurattalScreen> {
),
],
),
),
body: _isLoading
? const Center(child: CircularProgressIndicator())
@@ -607,7 +625,7 @@ class _QuranMurattalScreenState extends ConsumerState<QuranMurattalScreen> {
IconButton(
onPressed: () => setState(() => _isShuffleEnabled = !_isShuffleEnabled),
icon: Icon(
Icons.shuffle_rounded,
LucideIcons.shuffle,
size: 24,
color: _isShuffleEnabled
? (_unsplashPhoto != null ? Colors.white : AppColors.primary)
@@ -622,7 +640,7 @@ class _QuranMurattalScreenState extends ConsumerState<QuranMurattalScreen> {
? () => _navigateToSurah(-1)
: null,
icon: Icon(
Icons.skip_previous_rounded,
LucideIcons.skipBack,
size: 36,
color: (int.tryParse(widget.surahId) ?? 1) > 1
? (_unsplashPhoto != null ? Colors.white : (isDark ? AppColors.textSecondaryDark : AppColors.textSecondaryLight))
@@ -669,8 +687,8 @@ class _QuranMurattalScreenState extends ConsumerState<QuranMurattalScreen> {
)
: Icon(
_isPlaying
? Icons.pause_rounded
: Icons.play_arrow_rounded,
? LucideIcons.pause
: LucideIcons.play,
size: 36,
color: _unsplashPhoto != null
? Colors.black87
@@ -684,7 +702,7 @@ class _QuranMurattalScreenState extends ConsumerState<QuranMurattalScreen> {
? () => _navigateToSurah(1)
: null,
icon: Icon(
Icons.skip_next_rounded,
LucideIcons.skipForward,
size: 36,
color: (int.tryParse(widget.surahId) ?? 1) < 114
? (_unsplashPhoto != null ? Colors.white : (isDark ? AppColors.textSecondaryDark : AppColors.textSecondaryLight))
@@ -695,7 +713,7 @@ class _QuranMurattalScreenState extends ConsumerState<QuranMurattalScreen> {
IconButton(
onPressed: _showSurahPlaylist,
icon: Icon(
Icons.playlist_play_rounded,
LucideIcons.listMusic,
size: 28,
color: _unsplashPhoto != null
? Colors.white70
@@ -720,7 +738,7 @@ class _QuranMurattalScreenState extends ConsumerState<QuranMurattalScreen> {
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.person, size: 16,
Icon(LucideIcons.user, size: 16,
color: _unsplashPhoto != null ? Colors.white : AppColors.primary),
const SizedBox(width: 8),
Text(
@@ -732,7 +750,7 @@ class _QuranMurattalScreenState extends ConsumerState<QuranMurattalScreen> {
),
),
const SizedBox(width: 4),
Icon(Icons.expand_more,
Icon(LucideIcons.chevronDown,
size: 16,
color: _unsplashPhoto != null ? Colors.white : AppColors.primary),
],

View File

@@ -2,6 +2,7 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:lucide_icons/lucide_icons.dart';
import 'package:just_audio/just_audio.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:intl/intl.dart';
@@ -17,7 +18,14 @@ import '../../../core/providers/tilawah_tracking_provider.dart';
class QuranReadingScreen extends ConsumerStatefulWidget {
final String surahId;
final int? initialVerse;
const QuranReadingScreen({super.key, required this.surahId, this.initialVerse});
final bool isSimpleModeTab;
const QuranReadingScreen({
super.key,
required this.surahId,
this.initialVerse,
this.isSimpleModeTab = false,
});
@override
ConsumerState<QuranReadingScreen> createState() => _QuranReadingScreenState();
@@ -49,6 +57,14 @@ class _QuranReadingScreenState extends ConsumerState<QuranReadingScreen> {
bool _isHafalanPlaying = false;
StreamSubscription? _playerStateSubscription;
void _navigateToMurattal() {
if (widget.isSimpleModeTab) {
context.push('/quran/${widget.surahId}/murattal');
} else {
context.push('/tools/quran/${widget.surahId}/murattal');
}
}
@override
void initState() {
super.initState();
@@ -274,7 +290,7 @@ class _QuranReadingScreenState extends ConsumerState<QuranReadingScreen> {
),
),
ListTile(
leading: const Icon(Icons.push_pin, color: AppColors.primary),
leading: const Icon(LucideIcons.pin, color: AppColors.primary),
title: const Text('Tandai Terakhir Dibaca', style: TextStyle(fontWeight: FontWeight.w600)),
subtitle: const Text('Jadikan ayat ini sebagai titik lanjut membaca anda'),
onTap: () {
@@ -284,7 +300,7 @@ class _QuranReadingScreenState extends ConsumerState<QuranReadingScreen> {
),
const Divider(height: 1),
ListTile(
leading: const Icon(Icons.favorite, color: Colors.pink),
leading: const Icon(LucideIcons.heart, color: Colors.pink),
title: const Text('Tambah ke Favorit', style: TextStyle(fontWeight: FontWeight.w600)),
subtitle: const Text('Simpan ayat ini ke daftar favorit anda'),
onTap: () {
@@ -416,7 +432,7 @@ class _QuranReadingScreenState extends ConsumerState<QuranReadingScreen> {
const SizedBox(height: 16),
Row(
children: [
const Icon(Icons.auto_stories, size: 20, color: AppColors.primary),
const Icon(LucideIcons.bookOpen, size: 20, color: AppColors.primary),
const SizedBox(width: 8),
Text('Total Dibaca: $calculatedAyat Ayat', style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 15)),
],
@@ -558,7 +574,7 @@ class _QuranReadingScreenState extends ConsumerState<QuranReadingScreen> {
actions: [
IconButton(
icon: Icon(
Icons.psychology,
LucideIcons.brain,
color: _isHafalanMode ? AppColors.primary : (isDark ? AppColors.textSecondaryDark : AppColors.textSecondaryLight),
),
tooltip: 'Mode Hafalan',
@@ -572,7 +588,7 @@ class _QuranReadingScreenState extends ConsumerState<QuranReadingScreen> {
},
),
IconButton(
icon: const Icon(Icons.settings_display),
icon: const Icon(LucideIcons.settings2),
onPressed: _showDisplaySettings,
),
],
@@ -643,7 +659,7 @@ class _QuranReadingScreenState extends ConsumerState<QuranReadingScreen> {
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 8),
child: Icon(Icons.diamond,
child: Icon(LucideIcons.gem,
size: 10,
color: AppColors.primary
.withValues(alpha: 0.3)),
@@ -724,8 +740,8 @@ class _QuranReadingScreenState extends ConsumerState<QuranReadingScreen> {
color: AppColors.primary,
),
)
: Icon(Icons.stop_circle, color: AppColors.primary, size: 24))
: Icon(Icons.play_circle_outline,
: Icon(LucideIcons.stopCircle, color: AppColors.primary, size: 24))
: Icon(LucideIcons.playCircle,
color: isDark
? AppColors.textSecondaryDark
: AppColors.textSecondaryLight,
@@ -755,8 +771,8 @@ class _QuranReadingScreenState extends ConsumerState<QuranReadingScreen> {
},
icon: Icon(
trackingSession == null
? Icons.flag_outlined
: Icons.stop_circle,
? LucideIcons.flag
: LucideIcons.stopCircle,
color: trackingSession == null
? (isDark
? AppColors.textSecondaryDark
@@ -767,7 +783,7 @@ class _QuranReadingScreenState extends ConsumerState<QuranReadingScreen> {
IconButton(
onPressed: () => _showBookmarkOptions(i),
icon: Icon(
isLastRead ? Icons.push_pin : (isFav ? Icons.favorite : Icons.bookmark_outline),
isLastRead ? LucideIcons.pin : (isFav ? LucideIcons.heart : LucideIcons.bookmark),
color: isLastRead
? AppColors.primary
: (isFav ? Colors.pink : (isDark ? AppColors.textSecondaryDark : AppColors.textSecondaryLight)),
@@ -958,7 +974,7 @@ class _QuranReadingScreenState extends ConsumerState<QuranReadingScreen> {
],
),
child: Icon(
_isHafalanPlaying ? Icons.stop_rounded : Icons.play_arrow_rounded,
_isHafalanPlaying ? LucideIcons.square : LucideIcons.play,
color: Colors.white,
size: 28,
),
@@ -1015,7 +1031,7 @@ class _QuranReadingScreenState extends ConsumerState<QuranReadingScreen> {
);
}).toList(),
onChanged: onChanged,
icon: const Icon(Icons.expand_more, size: 16),
icon: const Icon(LucideIcons.chevronDown, size: 16),
isDense: true,
borderRadius: BorderRadius.circular(12),
),

View File

@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.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';
@@ -9,7 +10,8 @@ import '../../../data/local/models/quran_bookmark.dart';
import '../../../data/services/equran_service.dart';
class QuranScreen extends ConsumerStatefulWidget {
const QuranScreen({super.key});
final bool isSimpleModeTab;
const QuranScreen({super.key, this.isSimpleModeTab = false});
@override
ConsumerState<QuranScreen> createState() => _QuranScreenState();
@@ -98,6 +100,8 @@ class _QuranScreenState extends ConsumerState<QuranScreen> {
@override
Widget build(BuildContext context) {
final isDark = Theme.of(context).brightness == Brightness.dark;
final box = Hive.box<AppSettings>(HiveBoxes.settings);
final isSimpleMode = box.get('default')?.simpleMode ?? false;
final filtered = _searchQuery.isEmpty
? _surahs
: _surahs
@@ -110,14 +114,15 @@ class _QuranScreenState extends ConsumerState<QuranScreen> {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: !widget.isSimpleModeTab,
title: const Text('Al-Quran'),
actions: [
IconButton(
icon: const Icon(Icons.bookmark_outline),
icon: const Icon(LucideIcons.bookmark),
onPressed: () => context.push('/tools/quran/bookmarks'),
),
IconButton(
icon: const Icon(Icons.settings_display),
icon: const Icon(LucideIcons.settings2),
onPressed: _showDisplaySettings,
),
],
@@ -141,7 +146,7 @@ class _QuranScreenState extends ConsumerState<QuranScreen> {
onChanged: (v) => setState(() => _searchQuery = v),
decoration: InputDecoration(
hintText: 'Cari surah...',
prefixIcon: Icon(Icons.search,
prefixIcon: Icon(LucideIcons.search,
color: isDark
? AppColors.textSecondaryDark
: AppColors.textSecondaryLight),
@@ -227,7 +232,7 @@ class _QuranScreenState extends ConsumerState<QuranScreen> {
),
if (hasLastRead) ...[
const SizedBox(width: 8),
const Icon(Icons.push_pin, size: 14, color: AppColors.primary),
const Icon(LucideIcons.pin, size: 14, color: AppColors.primary),
],
],
),