Update UI + Agora Call
This commit is contained in:
@@ -7,6 +7,7 @@ import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../../app/injection_container.dart';
|
||||
import '../../core/errors/friendly_error.dart';
|
||||
@@ -139,6 +140,8 @@ class _SosScreenState extends State<SosScreen>
|
||||
|
||||
Future<void> _confirmAndSend() async {
|
||||
if (_sosCubit.state.phase == SosPhase.sending) return;
|
||||
final paired = await _ensurePaired();
|
||||
if (!paired) return;
|
||||
|
||||
// Confirmation dialog — prevents accidental tap
|
||||
final confirm = await showDialog<bool>(
|
||||
@@ -181,6 +184,35 @@ class _SosScreenState extends State<SosScreen>
|
||||
await _sendSos();
|
||||
}
|
||||
|
||||
Future<bool> _ensurePaired() async {
|
||||
bool paired = false;
|
||||
await runFriendlyAction(
|
||||
() async {
|
||||
final res = await _api
|
||||
.get('/shared/pairing/status')
|
||||
.timeout(const Duration(seconds: 6));
|
||||
final data = res.data['data'];
|
||||
paired = data is Map && data['status'] == 'ACTIVE';
|
||||
},
|
||||
onError: (_) {},
|
||||
fallback: 'Status pairing belum bisa dicek.',
|
||||
);
|
||||
if (paired) return true;
|
||||
if (!mounted) return false;
|
||||
sl<TtsService>().speak('SOS belum bisa dikirim. Hubungkan Guardian dulu.');
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: const Text(
|
||||
'SOS hanya bisa dikirim setelah akun terhubung dengan Guardian.'),
|
||||
action: SnackBarAction(
|
||||
label: 'Pairing',
|
||||
onPressed: () => context.go('/user/pairing'),
|
||||
),
|
||||
),
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
Future<void> _sendSos() async {
|
||||
await runFriendlyAction(
|
||||
() async {
|
||||
@@ -217,96 +249,98 @@ class _SosScreenState extends State<SosScreen>
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// Header
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'SOS',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.headlineSmall
|
||||
?.copyWith(fontWeight: FontWeight.w800),
|
||||
),
|
||||
const Text(
|
||||
'Emergency alert ke Guardian',
|
||||
style: TextStyle(color: Color(0xFF64748B)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: _loadHistory,
|
||||
icon: const Icon(Icons.refresh),
|
||||
tooltip: 'Refresh riwayat',
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Active SOS banner
|
||||
if (_hasActiveSos)
|
||||
_ActiveSosBanner(event: _events.first, onRefresh: _loadHistory),
|
||||
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// SOS Button
|
||||
Center(
|
||||
child: sending
|
||||
? const _SendingIndicator()
|
||||
: AnimatedBuilder(
|
||||
animation: _pulseAnim,
|
||||
builder: (_, child) => Transform.scale(
|
||||
scale: _hasActiveSos ? _pulseAnim.value : 1.0,
|
||||
child: child,
|
||||
),
|
||||
child: _SosButton(
|
||||
active: _hasActiveSos,
|
||||
onPressed: _confirmAndSend,
|
||||
// Header
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'SOS',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.headlineSmall
|
||||
?.copyWith(fontWeight: FontWeight.w800),
|
||||
),
|
||||
const Text(
|
||||
'Emergency alert ke Guardian',
|
||||
style: TextStyle(color: Color(0xFF64748B)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: _loadHistory,
|
||||
icon: const Icon(Icons.refresh),
|
||||
tooltip: 'Refresh riwayat',
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Active SOS banner
|
||||
if (_hasActiveSos)
|
||||
_ActiveSosBanner(
|
||||
event: _events.first, onRefresh: _loadHistory),
|
||||
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// SOS Button
|
||||
Center(
|
||||
child: sending
|
||||
? const _SendingIndicator()
|
||||
: AnimatedBuilder(
|
||||
animation: _pulseAnim,
|
||||
builder: (_, child) => Transform.scale(
|
||||
scale: _hasActiveSos ? _pulseAnim.value : 1.0,
|
||||
child: child,
|
||||
),
|
||||
child: _SosButton(
|
||||
active: _hasActiveSos,
|
||||
onPressed: _confirmAndSend,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 8),
|
||||
|
||||
// Hint text
|
||||
Text(
|
||||
_hasActiveSos
|
||||
? 'SOS aktif — Guardian sudah mendapat notifikasi'
|
||||
: 'Tekan tombol untuk kirim SOS darurat ke Guardian',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: _hasActiveSos
|
||||
? const Color(0xFFDC2626)
|
||||
: const Color(0xFF64748B),
|
||||
fontWeight:
|
||||
_hasActiveSos ? FontWeight.w700 : FontWeight.normal,
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 28),
|
||||
|
||||
// History section
|
||||
const Text(
|
||||
'Riwayat SOS',
|
||||
style: TextStyle(fontWeight: FontWeight.w800, fontSize: 16),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
|
||||
Expanded(
|
||||
child: _SosHistory(
|
||||
loading: _historyLoading,
|
||||
error: _historyError,
|
||||
events: _events,
|
||||
onRefresh: _loadHistory,
|
||||
)),
|
||||
],
|
||||
),
|
||||
|
||||
const SizedBox(height: 8),
|
||||
|
||||
// Hint text
|
||||
Text(
|
||||
_hasActiveSos
|
||||
? 'SOS aktif — Guardian sudah mendapat notifikasi'
|
||||
: 'Tekan tombol untuk kirim SOS darurat ke Guardian',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: _hasActiveSos
|
||||
? const Color(0xFFDC2626)
|
||||
: const Color(0xFF64748B),
|
||||
fontWeight: _hasActiveSos ? FontWeight.w700 : FontWeight.normal,
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 28),
|
||||
|
||||
// History section
|
||||
const Text(
|
||||
'Riwayat SOS',
|
||||
style: TextStyle(fontWeight: FontWeight.w800, fontSize: 16),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
|
||||
Expanded(
|
||||
child: _SosHistory(
|
||||
loading: _historyLoading,
|
||||
error: _historyError,
|
||||
events: _events,
|
||||
onRefresh: _loadHistory,
|
||||
)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user