feat: Murattal player enhancements & prayer schedule auto-scroll
- 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
This commit is contained in:
108
lib/data/services/equran_service.dart
Normal file
108
lib/data/services/equran_service.dart
Normal file
@@ -0,0 +1,108 @@
|
||||
import 'dart:convert';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
/// Service for EQuran.id v2 API.
|
||||
/// Provides complete Quran data: Arabic, Indonesian translation,
|
||||
/// tafsir, and audio from 6 qari.
|
||||
class EQuranService {
|
||||
static const String _baseUrl = 'https://equran.id/api/v2';
|
||||
static final EQuranService instance = EQuranService._();
|
||||
EQuranService._();
|
||||
|
||||
// In-memory cache
|
||||
List<Map<String, dynamic>>? _surahListCache;
|
||||
|
||||
/// Get list of all 114 surahs.
|
||||
Future<List<Map<String, dynamic>>> getAllSurahs() async {
|
||||
if (_surahListCache != null) return _surahListCache!;
|
||||
try {
|
||||
final response = await http.get(Uri.parse('$_baseUrl/surat'));
|
||||
if (response.statusCode == 200) {
|
||||
final data = json.decode(response.body);
|
||||
if (data['code'] == 200) {
|
||||
_surahListCache =
|
||||
List<Map<String, dynamic>>.from(data['data']);
|
||||
return _surahListCache!;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// silent fallback
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/// Get full surah with all ayat, audio, etc.
|
||||
/// Returns the full surah data object.
|
||||
Future<Map<String, dynamic>?> getSurah(int number) async {
|
||||
try {
|
||||
final response =
|
||||
await http.get(Uri.parse('$_baseUrl/surat/$number'));
|
||||
if (response.statusCode == 200) {
|
||||
final data = json.decode(response.body);
|
||||
if (data['code'] == 200) {
|
||||
return Map<String, dynamic>.from(data['data']);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// silent fallback
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Get tafsir for a surah.
|
||||
Future<Map<String, dynamic>?> getTafsir(int number) async {
|
||||
try {
|
||||
final response =
|
||||
await http.get(Uri.parse('$_baseUrl/tafsir/$number'));
|
||||
if (response.statusCode == 200) {
|
||||
final data = json.decode(response.body);
|
||||
if (data['code'] == 200) {
|
||||
return Map<String, dynamic>.from(data['data']);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// silent fallback
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Get deterministic daily ayat from API
|
||||
Future<Map<String, dynamic>?> getDailyAyat() async {
|
||||
try {
|
||||
final now = DateTime.now();
|
||||
final dayOfYear = int.parse(now.difference(DateTime(now.year, 1, 1)).inDays.toString());
|
||||
|
||||
// Pick surah 1-114
|
||||
int surahId = (dayOfYear % 114) + 1;
|
||||
|
||||
final surahData = await getSurah(surahId);
|
||||
if (surahData != null && surahData['ayat'] != null) {
|
||||
int totalAyat = surahData['jumlahAyat'] ?? 1;
|
||||
int ayatIndex = dayOfYear % totalAyat;
|
||||
|
||||
final targetAyat = surahData['ayat'][ayatIndex];
|
||||
|
||||
return {
|
||||
'surahName': surahData['namaLatin'],
|
||||
'nomorSurah': surahId,
|
||||
'nomorAyat': targetAyat['nomorAyat'],
|
||||
'teksArab': targetAyat['teksArab'],
|
||||
'teksIndonesia': targetAyat['teksIndonesia'],
|
||||
};
|
||||
}
|
||||
} catch (e) {
|
||||
// silent fallback
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Available qari names mapped to audio key index.
|
||||
static const Map<String, String> qariNames = {
|
||||
'01': 'Abdullah Al-Juhany',
|
||||
'02': 'Abdul Muhsin Al-Qasim',
|
||||
'03': 'Abdurrahman As-Sudais',
|
||||
'04': 'Ibrahim Al-Dossari',
|
||||
'05': 'Misyari Rasyid Al-Afasi',
|
||||
'06': 'Yasser Al-Dosari',
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user