112 lines
3.6 KiB
Dart
112 lines
3.6 KiB
Dart
import 'dart:convert';
|
|
import 'package:http/http.dart' as http;
|
|
|
|
/// Service for myQuran.com v3 Sholat API.
|
|
/// Provides Kemenag-accurate prayer times for Indonesian cities.
|
|
///
|
|
/// Ported directly from the jamshalat-diary project.
|
|
class MyQuranSholatService {
|
|
static const String _baseUrl = 'https://api.myquran.com/v3/sholat';
|
|
static final MyQuranSholatService instance = MyQuranSholatService._();
|
|
MyQuranSholatService._();
|
|
|
|
/// Search for a city/kabupaten by name.
|
|
/// Returns list of {id, lokasi}.
|
|
Future<List<Map<String, dynamic>>> searchCity(String query) async {
|
|
try {
|
|
final response = await http.get(
|
|
Uri.parse('$_baseUrl/kota/cari/$query'),
|
|
);
|
|
if (response.statusCode == 200) {
|
|
final data = json.decode(response.body);
|
|
if (data['status'] == true) {
|
|
return List<Map<String, dynamic>>.from(data['data']);
|
|
}
|
|
}
|
|
} catch (e) {
|
|
// silent fallback — device is offline
|
|
}
|
|
return [];
|
|
}
|
|
|
|
/// Get prayer times for today.
|
|
/// [cityId] = myQuran city ID (hash string)
|
|
/// Returns map: {tanggal, imsak, subuh, terbit, dhuha, dzuhur, ashar, maghrib, isya}
|
|
Future<Map<String, String>?> getDailySchedule(String cityId) async {
|
|
try {
|
|
final response = await http.get(Uri.parse('$_baseUrl/jadwal/$cityId/today'));
|
|
if (response.statusCode == 200) {
|
|
final data = json.decode(response.body);
|
|
if (data['status'] == true) {
|
|
final jadwalMap = data['data']['jadwal'] as Map<String, dynamic>;
|
|
if (jadwalMap.isNotEmpty) {
|
|
final firstKey = jadwalMap.keys.first;
|
|
final jadwal = jadwalMap[firstKey];
|
|
if (jadwal != null) {
|
|
final result = Map<String, String>.from(jadwal.map((k, v) => MapEntry(k.toString(), v.toString())));
|
|
result['date'] = firstKey;
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} catch (e) {
|
|
// silent fallback
|
|
}
|
|
return null;
|
|
}
|
|
|
|
|
|
/// Get monthly prayer schedule (bulk fetch for offline caching).
|
|
/// [month] = 'yyyy-MM' format (e.g., '2024-03')
|
|
/// Returns map of date → jadwal.
|
|
Future<Map<String, Map<String, String>>> getMonthlySchedule(
|
|
String cityId, String month) async {
|
|
try {
|
|
final response = await http.get(
|
|
Uri.parse('$_baseUrl/jadwal/$cityId/$month'),
|
|
);
|
|
if (response.statusCode == 200) {
|
|
final data = json.decode(response.body);
|
|
if (data['status'] == true) {
|
|
final jadwalMap = data['data']['jadwal'] as Map<String, dynamic>;
|
|
final result = <String, Map<String, String>>{};
|
|
for (final entry in jadwalMap.entries) {
|
|
result[entry.key] = Map<String, String>.from(
|
|
(entry.value as Map).map(
|
|
(k, v) => MapEntry(k.toString(), v.toString())),
|
|
);
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
} catch (e) {
|
|
// silent fallback
|
|
}
|
|
return {};
|
|
}
|
|
|
|
/// Get city info (kabko, prov) from a jadwal response.
|
|
Future<Map<String, String>?> getCityInfo(String cityId) async {
|
|
final today =
|
|
DateTime.now().toIso8601String().substring(0, 10);
|
|
try {
|
|
final response = await http.get(
|
|
Uri.parse('$_baseUrl/jadwal/$cityId/$today'),
|
|
);
|
|
if (response.statusCode == 200) {
|
|
final data = json.decode(response.body);
|
|
if (data['status'] == true) {
|
|
return {
|
|
'kabko': data['data']['kabko']?.toString() ?? '',
|
|
'prov': data['data']['prov']?.toString() ?? '',
|
|
};
|
|
}
|
|
}
|
|
} catch (e) {
|
|
// silent fallback
|
|
}
|
|
return null;
|
|
}
|
|
}
|