fixing a ton of sloppy mess...
This commit is contained in:
@@ -10,23 +10,68 @@ class CallService {
|
||||
|
||||
CallService(this._apiClient);
|
||||
|
||||
Future<Map<String, dynamic>?> requestToken(String channelName) async {
|
||||
final res = await _apiClient.dio.post('/shared/call/token', data: {'channelName': channelName});
|
||||
Future<Map<String, dynamic>?> requestToken({required int receiverId}) async {
|
||||
final res = await _apiClient.dio.post(
|
||||
'/shared/call/token',
|
||||
data: {'receiverId': receiverId},
|
||||
);
|
||||
final data = res.data['data'];
|
||||
return data is Map<String, dynamic> ? data : null;
|
||||
}
|
||||
|
||||
Future<void> notifyIncomingCall({required int receiverId, required String channelName}) async {
|
||||
Future<int?> getPairedReceiverId() async {
|
||||
final res = await _apiClient.dio.get('/pairing/status');
|
||||
final data = res.data['data'];
|
||||
if (data is! Map<String, dynamic>) return null;
|
||||
final id = data['pairedWithId'];
|
||||
return id is num ? id.toInt() : int.tryParse(id?.toString() ?? '');
|
||||
}
|
||||
|
||||
Future<void> notifyIncomingCall({
|
||||
required int receiverId,
|
||||
required String channelName,
|
||||
String? agoraToken,
|
||||
int receiverUid = 0,
|
||||
}) async {
|
||||
await _apiClient.dio.post('/shared/call/notify', data: {
|
||||
'receiverId': receiverId,
|
||||
'channelName': channelName,
|
||||
'agoraToken': agoraToken,
|
||||
'receiverUid': receiverUid,
|
||||
});
|
||||
}
|
||||
|
||||
Future<bool> joinChannel({required String channelName, int uid = 0}) async {
|
||||
Future<bool> callPairedUser({int uid = 0}) async {
|
||||
final receiverId = await getPairedReceiverId();
|
||||
if (receiverId == null) return false;
|
||||
|
||||
final tokenData = await requestToken(receiverId: receiverId);
|
||||
final channelName = tokenData?['channelName']?.toString();
|
||||
final token = tokenData?['token']?.toString();
|
||||
if (channelName == null || channelName.isEmpty) return false;
|
||||
|
||||
final joined = await joinChannel(
|
||||
channelName: channelName,
|
||||
token: token,
|
||||
uid: uid,
|
||||
);
|
||||
if (joined) {
|
||||
await notifyIncomingCall(
|
||||
receiverId: receiverId,
|
||||
channelName: channelName,
|
||||
agoraToken: token,
|
||||
receiverUid: uid,
|
||||
);
|
||||
}
|
||||
return joined;
|
||||
}
|
||||
|
||||
Future<bool> joinChannel({
|
||||
required String channelName,
|
||||
String? token,
|
||||
int uid = 0,
|
||||
}) async {
|
||||
try {
|
||||
final tokenData = await requestToken(channelName);
|
||||
final token = tokenData?['token']?.toString();
|
||||
_engine ??= createAgoraRtcEngine();
|
||||
await _engine!.initialize(const RtcEngineContext(appId: AppConstants.agoraAppId));
|
||||
await _engine!.enableAudio();
|
||||
|
||||
@@ -148,7 +148,7 @@ class _ActivityLogScreenState extends State<ActivityLogScreen> {
|
||||
onSelected: (_) {
|
||||
setState(() => _applyFilter(f));
|
||||
},
|
||||
selectedColor: AppColors.primary.withOpacity(0.15),
|
||||
selectedColor: AppColors.primary.withValues(alpha: 0.15),
|
||||
checkmarkColor: AppColors.primary,
|
||||
labelStyle: TextStyle(
|
||||
color: selected ? AppColors.primary : AppColors.muted,
|
||||
@@ -232,7 +232,7 @@ class _LogCard extends StatelessWidget {
|
||||
width: 36,
|
||||
height: 36,
|
||||
decoration: BoxDecoration(
|
||||
color: meta.color.withOpacity(0.12),
|
||||
color: meta.color.withValues(alpha: 0.12),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Icon(meta.icon, color: meta.color, size: 18),
|
||||
|
||||
@@ -91,7 +91,7 @@ class _SplashScreenState extends State<SplashScreen>
|
||||
width: 100,
|
||||
height: 100,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.12),
|
||||
color: Colors.white.withValues(alpha: 0.12),
|
||||
borderRadius: BorderRadius.circular(28),
|
||||
),
|
||||
child: const Icon(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// ignore_for_file: use_build_context_synchronously
|
||||
// ignore_for_file: use_build_context_synchronously, prefer_const_constructors
|
||||
// lib/features/call/call_screen.dart
|
||||
//
|
||||
// CallScreen — user memanggil Guardian via Agora
|
||||
@@ -34,8 +34,6 @@ class CallScreen extends StatefulWidget {
|
||||
|
||||
class _CallScreenState extends State<CallScreen>
|
||||
with SingleTickerProviderStateMixin {
|
||||
static const _channelName = 'walkguide-call';
|
||||
|
||||
_CallPhase _phase = _CallPhase.calling;
|
||||
bool _muted = false;
|
||||
bool _speakerOn = true;
|
||||
@@ -61,8 +59,7 @@ class _CallScreenState extends State<CallScreen>
|
||||
}
|
||||
|
||||
Future<void> _startCall() async {
|
||||
final joined =
|
||||
await sl<CallService>().joinChannel(channelName: _channelName);
|
||||
final joined = await sl<CallService>().callPairedUser();
|
||||
|
||||
if (!mounted) return;
|
||||
|
||||
|
||||
+15
-18
@@ -1,6 +1,5 @@
|
||||
// ignore_for_file: use_build_context_synchronously, deprecated_member_use
|
||||
// ignore_for_file: use_build_context_synchronously, deprecated_member_use, prefer_const_constructors
|
||||
import 'dart:async';
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -36,7 +35,6 @@ class _GuardianDashboardScreenState extends State<GuardianDashboardScreen>
|
||||
bool _loading = true;
|
||||
String? _error;
|
||||
String _guardianName = 'Guardian';
|
||||
int _refreshCount = 0;
|
||||
|
||||
// ── Live location (WebSocket) ────────────────────────────────────────────────
|
||||
LatLng? _liveLatLng;
|
||||
@@ -156,7 +154,6 @@ class _GuardianDashboardScreenState extends State<GuardianDashboardScreen>
|
||||
_liveLatLng = newLatLng;
|
||||
}
|
||||
_loading = false;
|
||||
_refreshCount++;
|
||||
});
|
||||
|
||||
// If SOS pending, start flash
|
||||
@@ -672,7 +669,7 @@ class _GuardianDashboardScreenState extends State<GuardianDashboardScreen>
|
||||
Border.all(color: const Color(0xFFE2E8F0), width: 1),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.04),
|
||||
color: Colors.black.withValues(alpha: 0.04),
|
||||
blurRadius: 12,
|
||||
offset: const Offset(0, 2)),
|
||||
],
|
||||
@@ -708,7 +705,7 @@ class _GuardianDashboardScreenState extends State<GuardianDashboardScreen>
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: const Color(0xFF1A56DB)
|
||||
.withOpacity(0.25 * _pulseAnim.value),
|
||||
.withValues(alpha: 0.25 * _pulseAnim.value),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
@@ -760,11 +757,11 @@ class _GuardianDashboardScreenState extends State<GuardianDashboardScreen>
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 10, vertical: 5),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.92),
|
||||
color: Colors.white.withValues(alpha: 0.92),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
color: Colors.black.withValues(alpha: 0.1),
|
||||
blurRadius: 8),
|
||||
],
|
||||
),
|
||||
@@ -801,7 +798,7 @@ class _GuardianDashboardScreenState extends State<GuardianDashboardScreen>
|
||||
horizontal: 10, vertical: 5),
|
||||
decoration: BoxDecoration(
|
||||
color:
|
||||
const Color(0xFF1A56DB).withOpacity(0.9),
|
||||
const Color(0xFF1A56DB).withValues(alpha: 0.9),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: Text('Buka Peta',
|
||||
@@ -823,11 +820,11 @@ class _GuardianDashboardScreenState extends State<GuardianDashboardScreen>
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 10, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.92),
|
||||
color: Colors.white.withValues(alpha: 0.92),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.08),
|
||||
color: Colors.black.withValues(alpha: 0.08),
|
||||
blurRadius: 6),
|
||||
],
|
||||
),
|
||||
@@ -859,7 +856,7 @@ class _GuardianDashboardScreenState extends State<GuardianDashboardScreen>
|
||||
border: Border.all(color: const Color(0xFFE2E8F0)),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.04),
|
||||
color: Colors.black.withValues(alpha: 0.04),
|
||||
blurRadius: 12,
|
||||
offset: const Offset(0, 2)),
|
||||
],
|
||||
@@ -872,7 +869,7 @@ class _GuardianDashboardScreenState extends State<GuardianDashboardScreen>
|
||||
CircleAvatar(
|
||||
radius: 20,
|
||||
backgroundColor:
|
||||
const Color(0xFF1A56DB).withOpacity(0.1),
|
||||
const Color(0xFF1A56DB).withValues(alpha: 0.1),
|
||||
child: Text(
|
||||
d.userName.isNotEmpty
|
||||
? d.userName[0].toUpperCase()
|
||||
@@ -1051,7 +1048,7 @@ class _GuardianDashboardScreenState extends State<GuardianDashboardScreen>
|
||||
border: Border.all(color: const Color(0xFFE2E8F0)),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.04),
|
||||
color: Colors.black.withValues(alpha: 0.04),
|
||||
blurRadius: 12,
|
||||
offset: const Offset(0, 2)),
|
||||
],
|
||||
@@ -1357,7 +1354,7 @@ class _KpiCard extends StatelessWidget {
|
||||
width: 1),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.03),
|
||||
color: Colors.black.withValues(alpha: 0.03),
|
||||
blurRadius: 8),
|
||||
],
|
||||
),
|
||||
@@ -1421,7 +1418,7 @@ class _ActivityTile extends StatelessWidget {
|
||||
width: 32,
|
||||
height: 32,
|
||||
decoration: BoxDecoration(
|
||||
color: cfg.color.withOpacity(0.1),
|
||||
color: cfg.color.withValues(alpha: 0.1),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Icon(cfg.icon, size: 16, color: cfg.color),
|
||||
@@ -1485,7 +1482,7 @@ class _QuickActionCard extends StatelessWidget {
|
||||
width: 28,
|
||||
height: 28,
|
||||
decoration: BoxDecoration(
|
||||
color: item.color.withOpacity(0.1),
|
||||
color: item.color.withValues(alpha: 0.1),
|
||||
borderRadius: BorderRadius.circular(7),
|
||||
),
|
||||
child: Icon(item.icon,
|
||||
@@ -1527,7 +1524,7 @@ class _SosBadge extends StatelessWidget {
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: const Color(0xFFDC2626).withOpacity(0.4),
|
||||
color: const Color(0xFFDC2626).withValues(alpha: 0.4),
|
||||
blurRadius: 8,
|
||||
spreadRadius: 1),
|
||||
],
|
||||
|
||||
+1
-1
@@ -100,7 +100,7 @@ class _NavState extends ChangeNotifier {
|
||||
'heading': pos.heading,
|
||||
})
|
||||
.timeout(const Duration(seconds: 5))
|
||||
.catchError((_) => null);
|
||||
.ignore();
|
||||
}
|
||||
|
||||
// ── search Nominatim ─────────────────────────────────────────────────────
|
||||
|
||||
@@ -4,10 +4,8 @@
|
||||
import 'dart:async';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import '../../app/injection_container.dart';
|
||||
import '../../core/constants/app_constants.dart';
|
||||
import '../../core/network/api_client.dart';
|
||||
import '../../core/services/tts_service.dart';
|
||||
import '../../core/theme/app_colors.dart';
|
||||
@@ -254,13 +252,13 @@ class _NotifCard extends StatelessWidget {
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
border: Border.all(
|
||||
color: unread
|
||||
? AppColors.primary.withOpacity(0.3)
|
||||
? AppColors.primary.withValues(alpha: 0.3)
|
||||
: const Color(0xFFE2E8F0),
|
||||
width: unread ? 1.5 : 1,
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.04),
|
||||
color: Colors.black.withValues(alpha: 0.04),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
@@ -279,8 +277,8 @@ class _NotifCard extends StatelessWidget {
|
||||
height: 36,
|
||||
decoration: BoxDecoration(
|
||||
color: isVoice
|
||||
? AppColors.success.withOpacity(0.12)
|
||||
: AppColors.primary.withOpacity(0.12),
|
||||
? AppColors.success.withValues(alpha: 0.12)
|
||||
: AppColors.primary.withValues(alpha: 0.12),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Icon(
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
// ignore_for_file: use_build_context_synchronously, deprecated_member_use
|
||||
// ignore_for_file: use_build_context_synchronously, deprecated_member_use, prefer_const_constructors
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../../app/injection_container.dart';
|
||||
import '../../core/network/api_client.dart';
|
||||
@@ -382,10 +381,8 @@ class _Page extends StatelessWidget {
|
||||
final String title;
|
||||
final String? subtitle;
|
||||
final Widget child;
|
||||
final List<Widget>? actions;
|
||||
|
||||
const _Page(
|
||||
{required this.title, required this.child, this.subtitle, this.actions});
|
||||
const _Page({required this.title, required this.child, this.subtitle});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -412,7 +409,6 @@ class _Page extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
),
|
||||
...?actions,
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
@@ -2168,10 +2168,10 @@ class _MapStatus extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.92),
|
||||
color: Colors.white.withValues(alpha: 0.92),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(color: Colors.black.withOpacity(0.12), blurRadius: 18)
|
||||
BoxShadow(color: Colors.black.withValues(alpha: 0.12), blurRadius: 18)
|
||||
],
|
||||
),
|
||||
child: Padding(
|
||||
@@ -2251,7 +2251,7 @@ class _Pill extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: color.withOpacity(0.16),
|
||||
color: color.withValues(alpha: 0.16),
|
||||
borderRadius: BorderRadius.circular(999),
|
||||
border: Border.all(color: color)),
|
||||
child: Padding(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// ignore_for_file: use_build_context_synchronously
|
||||
// ignore_for_file: use_build_context_synchronously, prefer_const_constructors, deprecated_member_use
|
||||
// lib/features/settings/user_settings_screen.dart
|
||||
|
||||
import 'dart:async';
|
||||
@@ -146,10 +146,10 @@ class _UserSettingsScreenState extends State<UserSettingsScreen> {
|
||||
Future<void> _logout() async {
|
||||
await sl<SecureStorage>().clearAll();
|
||||
context.read<AppCubit>().clearSession();
|
||||
unawaited(_api
|
||||
_api
|
||||
.post('/auth/logout')
|
||||
.timeout(const Duration(seconds: 3))
|
||||
.catchError((_) => null));
|
||||
.ignore();
|
||||
if (mounted) context.go('/login');
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
// lib/features/sos/sos_screen.dart
|
||||
// ignore_for_file: use_build_context_synchronously
|
||||
// ignore_for_file: use_build_context_synchronously, prefer_const_constructors, curly_braces_in_flow_control_structures
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../../app/injection_container.dart';
|
||||
import '../../core/network/api_client.dart';
|
||||
@@ -326,7 +325,7 @@ class _SosButton extends StatelessWidget {
|
||||
backgroundColor:
|
||||
active ? const Color(0xFFB91C1C) : const Color(0xFFDC2626),
|
||||
elevation: active ? 12 : 4,
|
||||
shadowColor: const Color(0xFFDC2626).withOpacity(0.5),
|
||||
shadowColor: const Color(0xFFDC2626).withValues(alpha: 0.5),
|
||||
),
|
||||
onPressed: onPressed,
|
||||
child: Column(
|
||||
@@ -363,7 +362,7 @@ class _SendingIndicator extends StatelessWidget {
|
||||
dimension: 200,
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFDC2626).withOpacity(0.15),
|
||||
color: const Color(0xFFDC2626).withValues(alpha: 0.15),
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(color: const Color(0xFFDC2626), width: 3),
|
||||
),
|
||||
@@ -505,7 +504,7 @@ class _SosEventTile extends StatelessWidget {
|
||||
Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: statusColor.withOpacity(0.1),
|
||||
color: statusColor.withValues(alpha: 0.1),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Icon(statusIcon, color: statusColor, size: 20),
|
||||
@@ -521,7 +520,7 @@ class _SosEventTile extends StatelessWidget {
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: statusColor.withOpacity(0.1),
|
||||
color: statusColor.withValues(alpha: 0.1),
|
||||
borderRadius: BorderRadius.circular(99),
|
||||
),
|
||||
child: Text(
|
||||
|
||||
@@ -466,7 +466,7 @@ class _Pill extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: color.withOpacity(0.16),
|
||||
color: color.withValues(alpha: 0.16),
|
||||
borderRadius: BorderRadius.circular(999),
|
||||
border: Border.all(color: color)),
|
||||
child: Padding(
|
||||
@@ -506,12 +506,10 @@ class _EmptyPanel extends StatelessWidget {
|
||||
final IconData icon;
|
||||
final String title;
|
||||
final String message;
|
||||
final Widget? action;
|
||||
const _EmptyPanel(
|
||||
{required this.icon,
|
||||
required this.title,
|
||||
required this.message,
|
||||
this.action});
|
||||
required this.message});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -533,10 +531,6 @@ class _EmptyPanel extends StatelessWidget {
|
||||
const TextStyle(fontWeight: FontWeight.w800, fontSize: 18)),
|
||||
const SizedBox(height: 6),
|
||||
Text(message, textAlign: TextAlign.center),
|
||||
if (action != null) ...[
|
||||
const SizedBox(height: 12),
|
||||
action!,
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user