Initial project import and stabilization baseline
This commit is contained in:
111
lib/data/services/myquran_service.dart
Normal file
111
lib/data/services/myquran_service.dart
Normal file
@@ -0,0 +1,111 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user