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:
126
lib/data/services/prayer_service.dart
Normal file
126
lib/data/services/prayer_service.dart
Normal file
@@ -0,0 +1,126 @@
|
||||
import 'package:adhan/adhan.dart' as adhan;
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import '../local/hive_boxes.dart';
|
||||
import '../local/models/cached_prayer_times.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
/// Result object for prayer times.
|
||||
class PrayerTimesResult {
|
||||
final DateTime fajr;
|
||||
final DateTime sunrise;
|
||||
final DateTime dhuhr;
|
||||
final DateTime asr;
|
||||
final DateTime maghrib;
|
||||
final DateTime isha;
|
||||
|
||||
PrayerTimesResult({
|
||||
required this.fajr,
|
||||
required this.sunrise,
|
||||
required this.dhuhr,
|
||||
required this.asr,
|
||||
required this.maghrib,
|
||||
required this.isha,
|
||||
});
|
||||
}
|
||||
|
||||
/// Prayer time calculation service using the adhan package.
|
||||
class PrayerService {
|
||||
PrayerService._();
|
||||
static final PrayerService instance = PrayerService._();
|
||||
|
||||
/// Calculate prayer times for a given location and date.
|
||||
/// Uses cache if available; writes to cache after calculation.
|
||||
PrayerTimesResult getPrayerTimes(double lat, double lng, DateTime date) {
|
||||
final dateKey = DateFormat('yyyy-MM-dd').format(date);
|
||||
final cacheKey = '${lat.toStringAsFixed(4)}_${lng.toStringAsFixed(4)}_$dateKey';
|
||||
|
||||
// Check cache
|
||||
final cacheBox = Hive.box<CachedPrayerTimes>(HiveBoxes.cachedPrayerTimes);
|
||||
final cached = cacheBox.get(cacheKey);
|
||||
if (cached != null) {
|
||||
return PrayerTimesResult(
|
||||
fajr: cached.fajr,
|
||||
sunrise: cached.sunrise,
|
||||
dhuhr: cached.dhuhr,
|
||||
asr: cached.asr,
|
||||
maghrib: cached.maghrib,
|
||||
isha: cached.isha,
|
||||
);
|
||||
}
|
||||
|
||||
// Calculate using adhan package
|
||||
final coordinates = adhan.Coordinates(lat, lng);
|
||||
final dateComponents = adhan.DateComponents(date.year, date.month, date.day);
|
||||
final params = adhan.CalculationMethod.muslim_world_league.getParameters();
|
||||
params.madhab = adhan.Madhab.shafi;
|
||||
|
||||
final prayerTimes = adhan.PrayerTimes(coordinates, dateComponents, params);
|
||||
|
||||
final result = PrayerTimesResult(
|
||||
fajr: prayerTimes.fajr!,
|
||||
sunrise: prayerTimes.sunrise!,
|
||||
dhuhr: prayerTimes.dhuhr!,
|
||||
asr: prayerTimes.asr!,
|
||||
maghrib: prayerTimes.maghrib!,
|
||||
isha: prayerTimes.isha!,
|
||||
);
|
||||
|
||||
// Cache result
|
||||
cacheBox.put(
|
||||
cacheKey,
|
||||
CachedPrayerTimes(
|
||||
key: cacheKey,
|
||||
lat: lat,
|
||||
lng: lng,
|
||||
date: dateKey,
|
||||
fajr: result.fajr,
|
||||
sunrise: result.sunrise,
|
||||
dhuhr: result.dhuhr,
|
||||
asr: result.asr,
|
||||
maghrib: result.maghrib,
|
||||
isha: result.isha,
|
||||
),
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Get the next prayer name and time from now.
|
||||
MapEntry<String, DateTime>? getNextPrayer(PrayerTimesResult times) {
|
||||
final now = DateTime.now();
|
||||
final entries = {
|
||||
'Fajr': times.fajr,
|
||||
'Dhuhr': times.dhuhr,
|
||||
'Asr': times.asr,
|
||||
'Maghrib': times.maghrib,
|
||||
'Isha': times.isha,
|
||||
};
|
||||
|
||||
for (final entry in entries.entries) {
|
||||
if (entry.value.isAfter(now)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return null; // All prayers passed for today
|
||||
}
|
||||
|
||||
/// Get the current active prayer (the last prayer whose time has passed).
|
||||
String? getCurrentPrayer(PrayerTimesResult times) {
|
||||
final now = DateTime.now();
|
||||
String? current;
|
||||
|
||||
if (now.isAfter(times.isha)) {
|
||||
current = 'Isha';
|
||||
} else if (now.isAfter(times.maghrib)) {
|
||||
current = 'Maghrib';
|
||||
} else if (now.isAfter(times.asr)) {
|
||||
current = 'Asr';
|
||||
} else if (now.isAfter(times.dhuhr)) {
|
||||
current = 'Dhuhr';
|
||||
} else if (now.isAfter(times.fajr)) {
|
||||
current = 'Fajr';
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user