- Murattal: Spotify-style 5-button controls [Shuffle, Prev, Play, Next, Playlist] - Murattal: Animated 7-bar equalizer visualization in player circle - Murattal: Unsplash API background with frosted glass player overlay - Murattal: Transparent AppBar with backdrop blur - Murattal: Surah playlist bottom sheet with full 114 Surah list - Murattal: Auto-play disabled on screen open, enabled on navigation - Murattal: Shuffle mode for random Surah playback - Murattal: Photographer attribution per Unsplash guidelines - Dashboard: Auto-scroll prayer schedule to next active prayer - Fix: setState lifecycle errors on Reading & Murattal screens - Setup: flutter_dotenv, cached_network_image, url_launcher deps
99 lines
2.5 KiB
Dart
99 lines
2.5 KiB
Dart
import 'dart:convert';
|
|
import 'package:flutter/services.dart';
|
|
|
|
/// Represents a single Surah with its verses.
|
|
class Surah {
|
|
final int id;
|
|
final String nameArabic;
|
|
final String nameLatin;
|
|
final int verseCount;
|
|
final int juzStart;
|
|
final String revelationType;
|
|
final List<Verse> verses;
|
|
|
|
Surah({
|
|
required this.id,
|
|
required this.nameArabic,
|
|
required this.nameLatin,
|
|
required this.verseCount,
|
|
this.juzStart = 1,
|
|
this.revelationType = 'Meccan',
|
|
this.verses = const [],
|
|
});
|
|
|
|
factory Surah.fromJson(Map<String, dynamic> json) {
|
|
return Surah(
|
|
id: json['id'] as int,
|
|
nameArabic: json['name_arabic'] as String? ?? '',
|
|
nameLatin: json['name_latin'] as String? ?? '',
|
|
verseCount: json['verse_count'] as int? ?? 0,
|
|
juzStart: json['juz_start'] as int? ?? 1,
|
|
revelationType: json['revelation_type'] as String? ?? 'Meccan',
|
|
verses: (json['verses'] as List<dynamic>?)
|
|
?.map((v) => Verse.fromJson(v as Map<String, dynamic>))
|
|
.toList() ??
|
|
[],
|
|
);
|
|
}
|
|
}
|
|
|
|
/// A single Quran verse.
|
|
class Verse {
|
|
final int id;
|
|
final String arabic;
|
|
final String? transliteration;
|
|
final String translationId;
|
|
|
|
Verse({
|
|
required this.id,
|
|
required this.arabic,
|
|
this.transliteration,
|
|
required this.translationId,
|
|
});
|
|
|
|
factory Verse.fromJson(Map<String, dynamic> json) {
|
|
return Verse(
|
|
id: json['id'] as int,
|
|
arabic: json['arabic'] as String? ?? '',
|
|
transliteration: json['transliteration'] as String?,
|
|
translationId: json['translation_id'] as String? ?? '',
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Service to load Quran data from bundled JSON asset.
|
|
class QuranService {
|
|
QuranService._();
|
|
static final QuranService instance = QuranService._();
|
|
|
|
List<Surah>? _cachedSurahs;
|
|
|
|
/// Load all 114 Surahs from local JSON. Cached in memory after first load.
|
|
Future<List<Surah>> getAllSurahs() async {
|
|
if (_cachedSurahs != null) return _cachedSurahs!;
|
|
|
|
try {
|
|
final jsonString =
|
|
await rootBundle.loadString('assets/quran/quran_id.json');
|
|
final List<dynamic> data = json.decode(jsonString);
|
|
_cachedSurahs = data
|
|
.map((s) => Surah.fromJson(s as Map<String, dynamic>))
|
|
.toList();
|
|
} catch (_) {
|
|
_cachedSurahs = [];
|
|
}
|
|
|
|
return _cachedSurahs!;
|
|
}
|
|
|
|
/// Get a single Surah by ID.
|
|
Future<Surah?> getSurah(int id) async {
|
|
final surahs = await getAllSurahs();
|
|
try {
|
|
return surahs.firstWhere((s) => s.id == id);
|
|
} catch (_) {
|
|
return null;
|
|
}
|
|
}
|
|
}
|