Fix local dev config and ALOTTTT OFF FLUTTER, im tired boss..

This commit is contained in:
Wowieee4
2026-05-26 21:09:13 +07:00
parent b8ad8df993
commit a629357e8c
72 changed files with 2566 additions and 530 deletions
@@ -13,6 +13,7 @@ import '../../../app/injection_container.dart';
import '../../../core/network/api_client.dart';
import '../../../core/services/websocket_service.dart';
import '../../../core/storage/secure_storage.dart';
import '../../../core/utils/operation_guard.dart';
// ─────────────────────────────────────────────────────────────────────────────
// GUARDIAN DASHBOARD SCREEN
@@ -57,6 +58,7 @@ class _GuardianDashboardScreenState extends State<GuardianDashboardScreen>
duration: const Duration(milliseconds: 600),
);
bool _sosAlert = false;
List<Map<String, dynamic>> _pendingSos = const [];
// ── Refresh button animation ─────────────────────────────────────────────────
late final AnimationController _refreshCtrl = AnimationController(
@@ -89,7 +91,8 @@ class _GuardianDashboardScreenState extends State<GuardianDashboardScreen>
_error = null;
});
}
try {
await guarded<void>(
() async {
_guardianName =
await sl<SecureStorage>().getDisplayName() ?? 'Guardian';
@@ -103,7 +106,8 @@ class _GuardianDashboardScreenState extends State<GuardianDashboardScreen>
final dashboard = results[0] as Map<String, dynamic>?;
final activityList =
results[1] as List<Map<String, dynamic>>;
final sosPending = results[2] as int;
final sosPendingEvents = results[2] as List<Map<String, dynamic>>;
final sosPending = sosPendingEvents.length;
// Extract latest GPS from dashboard
final lastLoc = dashboard?['lastLocation'] as Map<String, dynamic>?;
@@ -150,6 +154,7 @@ class _GuardianDashboardScreenState extends State<GuardianDashboardScreen>
recentActivity: activityList,
isPaired: userStatus != null || dashboard != null,
);
_pendingSos = sosPendingEvents;
if (newLatLng != null) {
_liveLatLng = newLatLng;
}
@@ -163,32 +168,31 @@ class _GuardianDashboardScreenState extends State<GuardianDashboardScreen>
// Move map to latest location
if (newLatLng != null) {
try {
_mapController.move(newLatLng, 15);
} catch (_) {}
_moveMapSafely(newLatLng);
}
} catch (e) {
setState(() {
},
onError: (e) => setState(() {
_loading = false;
_error = _friendlyError(e);
});
}
}),
);
}
Future<Map<String, dynamic>?> _fetchDashboard() async {
try {
return await guarded<Map<String, dynamic>?>(
() async {
final res = await _api
.get('/guardian/dashboard')
.timeout(const Duration(seconds: 8));
final d = res.data['data'];
return d is Map ? Map<String, dynamic>.from(d) : null;
} catch (_) {
return null;
}
},
);
}
Future<List<Map<String, dynamic>>> _fetchActivity() async {
try {
return await guarded<List<Map<String, dynamic>>>(
() async {
final res = await _api
.get('/guardian/activity-logs',
queryParameters: {'size': 5, 'page': 0})
@@ -202,12 +206,15 @@ class _GuardianDashboardScreenState extends State<GuardianDashboardScreen>
.map((e) => Map<String, dynamic>.from(e))
.toList();
}
} catch (_) {}
return const [];
return const [];
},
) ??
const [];
}
Future<int> _fetchSosPending() async {
try {
Future<List<Map<String, dynamic>>> _fetchSosPending() async {
return await guarded<List<Map<String, dynamic>>>(
() async {
final res = await _api
.get('/guardian/sos-events',
queryParameters: {'size': 10, 'page': 0})
@@ -219,17 +226,21 @@ class _GuardianDashboardScreenState extends State<GuardianDashboardScreen>
return content
.whereType<Map>()
.where((e) => e['status'] == 'TRIGGERED')
.length;
.map((e) => Map<String, dynamic>.from(e))
.toList();
}
} catch (_) {}
return 0;
return const [];
},
) ??
const [];
}
// ── WebSocket subscription ──────────────────────────────────────────────────
void _subscribeWebSocket() {
final ws = sl<WebSocketService>();
Future.microtask(() async {
try {
await guarded<void>(
() async {
final userId = await _getLinkedUserId();
if (userId == null) return;
ws.subscribeLocation(userId, (lat, lng) {
@@ -239,26 +250,30 @@ class _GuardianDashboardScreenState extends State<GuardianDashboardScreen>
_liveLatLng = newPos;
_liveConnected = true;
});
try {
_mapController.move(newPos, 15);
} catch (_) {}
_moveMapSafely(newPos);
});
ws.subscribeSos((sosData) {
if (!mounted) return;
_triggerSosFlash();
setState(() {
_pendingSos = [
Map<String, dynamic>.from(sosData),
..._pendingSos,
];
_data = _data?.copyWith(
unreadSos: (_data?.unreadSos ?? 0) + 1);
});
_showSosSnackbar(sosData);
});
if (mounted) setState(() => _liveConnected = true);
} catch (_) {}
},
);
});
}
Future<String?> _getLinkedUserId() async {
try {
return await guarded<String?>(
() async {
final res = await _api
.get('/shared/pairing/status')
.timeout(const Duration(seconds: 5));
@@ -267,8 +282,9 @@ class _GuardianDashboardScreenState extends State<GuardianDashboardScreen>
return d['pairedWithId']?.toString() ??
d['userId']?.toString();
}
} catch (_) {}
return null;
return null;
},
);
}
void _triggerSosFlash() {
@@ -303,14 +319,56 @@ class _GuardianDashboardScreenState extends State<GuardianDashboardScreen>
),
]),
action: SnackBarAction(
label: 'Lihat',
label: 'Tangani',
textColor: Colors.white,
onPressed: () => context.go('/guardian/logs'),
onPressed: _handleLatestSos,
),
),
);
}
Future<void> _handleLatestSos() async {
final sosId = _pendingSos
.map((e) => e['id'])
.where((id) => id != null)
.map((id) => int.tryParse(id.toString()))
.firstWhere((id) => id != null, orElse: () => null);
if (sosId == null) {
await _loadAll(silent: true);
return;
}
await guarded<void>(
() async {
await _api
.put('/guardian/sos/$sosId/resolve')
.timeout(const Duration(seconds: 8));
if (!mounted) return;
setState(() {
_pendingSos =
_pendingSos.where((e) => e['id']?.toString() != '$sosId').toList();
_data = _data?.copyWith(unreadSos: _pendingSos.length);
if (_pendingSos.isEmpty) {
_sosAlert = false;
_sosCtrl.stop();
}
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('SOS ditandai sudah ditangani.')),
);
},
onError: (_) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Gagal menandai SOS. Coba refresh.')),
);
},
);
}
void _moveMapSafely(LatLng position) {
guarded<void>(() async => _mapController.move(position, 15));
}
Future<void> _refresh() async {
HapticFeedback.lightImpact();
_refreshCtrl.forward(from: 0);
@@ -517,10 +575,10 @@ class _GuardianDashboardScreenState extends State<GuardianDashboardScreen>
),
),
TextButton(
onPressed: () => context.go('/guardian/logs'),
onPressed: _handleLatestSos,
style: TextButton.styleFrom(
foregroundColor: Colors.white),
child: const Text('Tangani'),
child: const Text('Handle'),
),
IconButton(
onPressed: () {