Use MyQuran Hijri calendar API for displayed date
This commit is contained in:
68
lib/data/services/hijri_service.dart
Normal file
68
lib/data/services/hijri_service.dart
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
|
import '../../core/hijri_date.dart';
|
||||||
|
|
||||||
|
class HijriCalendarService {
|
||||||
|
HijriCalendarService._({http.Client? client})
|
||||||
|
: _client = client ?? http.Client();
|
||||||
|
|
||||||
|
static final HijriCalendarService instance = HijriCalendarService._();
|
||||||
|
static const String _baseUrl = 'https://api.myquran.com/v3/cal/hijr';
|
||||||
|
|
||||||
|
final http.Client _client;
|
||||||
|
final Map<String, String> _cache = {};
|
||||||
|
|
||||||
|
Future<String> getHijriLabel(DateTime date) async {
|
||||||
|
final dateOnly = DateTime(date.year, date.month, date.day);
|
||||||
|
final dateKey = DateFormat('yyyy-MM-dd').format(dateOnly);
|
||||||
|
final cached = _cache[dateKey];
|
||||||
|
if (cached != null) return cached;
|
||||||
|
|
||||||
|
try {
|
||||||
|
final response = await _client.get(Uri.parse('$_baseUrl/$dateKey'));
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
final payload = json.decode(response.body) as Map<String, dynamic>;
|
||||||
|
final label = parseHijriLabel(payload);
|
||||||
|
if (label != null) {
|
||||||
|
_cache[dateKey] = label;
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (_) {
|
||||||
|
// Keep UI usable when the device is offline.
|
||||||
|
}
|
||||||
|
|
||||||
|
final fallback = HijriDateFormatter.format(dateOnly);
|
||||||
|
_cache[dateKey] = fallback;
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String? parseHijriLabel(Map<String, dynamic> payload) {
|
||||||
|
if (payload['status'] != true) return null;
|
||||||
|
|
||||||
|
final data = payload['data'];
|
||||||
|
if (data is! Map) return null;
|
||||||
|
|
||||||
|
final hijr = data['hijr'];
|
||||||
|
if (hijr is! Map) return null;
|
||||||
|
|
||||||
|
final today = hijr['today']?.toString().trim();
|
||||||
|
if (today != null && today.isNotEmpty) {
|
||||||
|
final parts = today.split(',');
|
||||||
|
return parts.length > 1 ? parts.last.trim() : today;
|
||||||
|
}
|
||||||
|
|
||||||
|
final day = hijr['day'];
|
||||||
|
final monthName = hijr['monthName']?.toString().trim();
|
||||||
|
final year = hijr['year'];
|
||||||
|
|
||||||
|
if (day != null && monthName != null && monthName.isNotEmpty && year != null) {
|
||||||
|
return '$day $monthName $year H';
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,7 +31,8 @@ class JumatScreen extends ConsumerWidget {
|
|||||||
final timeStr = DateFormat('HH:mm').format(clock);
|
final timeStr = DateFormat('HH:mm').format(clock);
|
||||||
final secStr = DateFormat(':ss').format(clock);
|
final secStr = DateFormat(':ss').format(clock);
|
||||||
final dateGregorian = DateFormat('EEEE, d MMMM yyyy', 'en').format(clock);
|
final dateGregorian = DateFormat('EEEE, d MMMM yyyy', 'en').format(clock);
|
||||||
final dateHijri = HijriDateFormatter.format(clock);
|
final dateHijri =
|
||||||
|
ref.watch(hijriDateProvider).valueOrNull ?? HijriDateFormatter.format(clock);
|
||||||
|
|
||||||
final durToKhutbah = screenData.timeUntilNext ?? const Duration(minutes: 0);
|
final durToKhutbah = screenData.timeUntilNext ?? const Duration(minutes: 0);
|
||||||
final minToKhutbah = durToKhutbah.inMinutes;
|
final minToKhutbah = durToKhutbah.inMinutes;
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ class MainScreen extends ConsumerWidget {
|
|||||||
final timeStr = DateFormat('HH:mm').format(clock);
|
final timeStr = DateFormat('HH:mm').format(clock);
|
||||||
final secStr = DateFormat(':ss').format(clock);
|
final secStr = DateFormat(':ss').format(clock);
|
||||||
final dateGregorian = DateFormat('EEEE, d MMMM yyyy', 'id').format(clock);
|
final dateGregorian = DateFormat('EEEE, d MMMM yyyy', 'id').format(clock);
|
||||||
|
final dateHijri =
|
||||||
|
ref.watch(hijriDateProvider).valueOrNull ?? HijriDateFormatter.format(clock);
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
color: SacredColors.background,
|
color: SacredColors.background,
|
||||||
@@ -98,7 +100,7 @@ class MainScreen extends ConsumerWidget {
|
|||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
// ── HEADER ──
|
// ── HEADER ──
|
||||||
_buildHeader(context, s, fs, settings, dateGregorian),
|
_buildHeader(context, s, fs, settings, dateGregorian, dateHijri),
|
||||||
|
|
||||||
// ── CENTER: Clock + Countdown ──
|
// ── CENTER: Clock + Countdown ──
|
||||||
Expanded(
|
Expanded(
|
||||||
@@ -211,9 +213,14 @@ class MainScreen extends ConsumerWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildHeader(BuildContext context, double s, double fs, AppSettings settings, String dateGregorian) {
|
Widget _buildHeader(
|
||||||
final dateHijri = HijriDateFormatter.format(DateTime.now());
|
BuildContext context,
|
||||||
|
double s,
|
||||||
|
double fs,
|
||||||
|
AppSettings settings,
|
||||||
|
String dateGregorian,
|
||||||
|
String dateHijri,
|
||||||
|
) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: EdgeInsets.only(top: 24 * s, bottom: 8 * s),
|
padding: EdgeInsets.only(top: 24 * s, bottom: 8 * s),
|
||||||
child: Row(
|
child: Row(
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||||||
import 'package:hive_flutter/hive_flutter.dart';
|
import 'package:hive_flutter/hive_flutter.dart';
|
||||||
|
|
||||||
import 'core/enums.dart';
|
import 'core/enums.dart';
|
||||||
|
import 'core/hijri_date.dart';
|
||||||
import 'data/local/models.dart';
|
import 'data/local/models.dart';
|
||||||
|
import 'data/services/hijri_service.dart';
|
||||||
import 'data/services/sync_service.dart';
|
import 'data/services/sync_service.dart';
|
||||||
|
|
||||||
// ──────────────────────────────────────────────
|
// ──────────────────────────────────────────────
|
||||||
@@ -75,6 +77,17 @@ final todayScheduleProvider = Provider<DailyPrayerSchedule?>((ref) {
|
|||||||
return SyncService.instance.getTodaySchedule(clock);
|
return SyncService.instance.getTodaySchedule(clock);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
final hijriDateProvider = FutureProvider<String>((ref) async {
|
||||||
|
final clock = ref.watch(clockProvider).valueOrNull ?? DateTime.now();
|
||||||
|
final dateOnly = DateTime(clock.year, clock.month, clock.day);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return await HijriCalendarService.instance.getHijriLabel(dateOnly);
|
||||||
|
} catch (_) {
|
||||||
|
return HijriDateFormatter.format(dateOnly);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// ──────────────────────────────────────────────
|
// ──────────────────────────────────────────────
|
||||||
// SCREEN STATE MACHINE PROVIDER
|
// SCREEN STATE MACHINE PROVIDER
|
||||||
// ──────────────────────────────────────────────
|
// ──────────────────────────────────────────────
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:jamshalat_masjid_screen/core/enums.dart';
|
import 'package:jamshalat_masjid_screen/core/enums.dart';
|
||||||
import 'package:jamshalat_masjid_screen/data/local/models.dart';
|
import 'package:jamshalat_masjid_screen/data/local/models.dart';
|
||||||
|
import 'package:jamshalat_masjid_screen/data/services/hijri_service.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
group('PrayerName display labels', () {
|
group('PrayerName display labels', () {
|
||||||
@@ -37,4 +38,22 @@ void main() {
|
|||||||
expect(updated.runningTexts, settings.runningTexts);
|
expect(updated.runningTexts, settings.runningTexts);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
group('HijriCalendarService parsing', () {
|
||||||
|
test('extracts hijri label from MyQuran calendar response', () {
|
||||||
|
final label = HijriCalendarService.parseHijriLabel({
|
||||||
|
'status': true,
|
||||||
|
'data': {
|
||||||
|
'hijr': {
|
||||||
|
'today': 'Senin, 11 Syawal 1447 H',
|
||||||
|
'day': 11,
|
||||||
|
'monthName': 'Syawal',
|
||||||
|
'year': 1447,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(label, '11 Syawal 1447 H');
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user