Files
jamshalat-diary/lib/data/services/dzikir_service.dart
dwindown faadc1865d 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
2026-03-13 15:42:17 +07:00

108 lines
3.0 KiB
Dart

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());
}