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:
107
lib/data/services/dzikir_service.dart
Normal file
107
lib/data/services/dzikir_service.dart
Normal file
@@ -0,0 +1,107 @@
|
||||
import 'dart:convert';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import '../local/hive_boxes.dart';
|
||||
import '../local/models/dzikir_counter.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
/// Represents a single dzikir item from the bundled JSON.
|
||||
class DzikirItem {
|
||||
final String id;
|
||||
final String arabic;
|
||||
final String transliteration;
|
||||
final String translation;
|
||||
final int targetCount;
|
||||
final String? source;
|
||||
|
||||
DzikirItem({
|
||||
required this.id,
|
||||
required this.arabic,
|
||||
required this.transliteration,
|
||||
required this.translation,
|
||||
required this.targetCount,
|
||||
this.source,
|
||||
});
|
||||
|
||||
factory DzikirItem.fromJson(Map<String, dynamic> json) {
|
||||
return DzikirItem(
|
||||
id: json['id'] as String,
|
||||
arabic: json['arabic'] as String? ?? '',
|
||||
transliteration: json['transliteration'] as String? ?? '',
|
||||
translation: json['translation'] as String? ?? '',
|
||||
targetCount: json['target_count'] as int? ?? 1,
|
||||
source: json['source'] as String?,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Types of dzikir sessions.
|
||||
enum DzikirType { pagi, petang }
|
||||
|
||||
/// Service to load dzikir data and manage counters.
|
||||
class DzikirService {
|
||||
DzikirService._();
|
||||
static final DzikirService instance = DzikirService._();
|
||||
|
||||
final Map<DzikirType, List<DzikirItem>> _cache = {};
|
||||
|
||||
/// Load dzikir items from bundled JSON.
|
||||
Future<List<DzikirItem>> getDzikir(DzikirType type) async {
|
||||
if (_cache.containsKey(type)) return _cache[type]!;
|
||||
|
||||
final path = type == DzikirType.pagi
|
||||
? 'assets/dzikir/dzikir_pagi.json'
|
||||
: 'assets/dzikir/dzikir_petang.json';
|
||||
|
||||
try {
|
||||
final jsonString = await rootBundle.loadString(path);
|
||||
final List<dynamic> data = json.decode(jsonString);
|
||||
_cache[type] =
|
||||
data.map((d) => DzikirItem.fromJson(d as Map<String, dynamic>)).toList();
|
||||
} catch (_) {
|
||||
_cache[type] = [];
|
||||
}
|
||||
|
||||
return _cache[type]!;
|
||||
}
|
||||
|
||||
/// Get counters for a specific date from Hive.
|
||||
Map<String, int> getCountersForDate(String date) {
|
||||
final box = Hive.box<DzikirCounter>(HiveBoxes.dzikirCounters);
|
||||
final result = <String, int>{};
|
||||
|
||||
for (final key in box.keys) {
|
||||
final counter = box.get(key);
|
||||
if (counter != null && counter.date == date) {
|
||||
result[counter.dzikirId] = counter.count;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Increment a dzikir counter for a specific ID on a specific date.
|
||||
Future<void> increment(String dzikirId, String date, int target) async {
|
||||
final box = Hive.box<DzikirCounter>(HiveBoxes.dzikirCounters);
|
||||
final key = '${dzikirId}_$date';
|
||||
|
||||
final existing = box.get(key);
|
||||
if (existing != null) {
|
||||
existing.count = (existing.count + 1).clamp(0, target);
|
||||
await existing.save();
|
||||
} else {
|
||||
await box.put(
|
||||
key,
|
||||
DzikirCounter(
|
||||
dzikirId: dzikirId,
|
||||
date: date,
|
||||
count: 1,
|
||||
target: target,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get today's date string.
|
||||
String get todayKey => DateFormat('yyyy-MM-dd').format(DateTime.now());
|
||||
}
|
||||
Reference in New Issue
Block a user