im so tired man

This commit is contained in:
Wowieee4
2026-05-28 11:27:06 +07:00
parent 66da2473e1
commit 6272ece15d
86 changed files with 1759 additions and 4090 deletions
@@ -166,6 +166,11 @@ class CallService {
debugPrint('Agora remote user offline: $remoteUid $reason');
_onRemoteUserOffline?.call();
},
onRemoteAudioStateChanged: (_, remoteUid, state, reason, __) {
debugPrint(
'Agora remote audio state: uid=$remoteUid state=$state reason=$reason',
);
},
onError: (type, msg) {
debugPrint('Agora error: $type $msg');
if (!joinCompleter.isCompleted) joinCompleter.complete(false);
@@ -175,9 +180,18 @@ class CallService {
await _engine!.setChannelProfile(
ChannelProfileType.channelProfileCommunication,
);
await _engine!.setClientRole(role: ClientRoleType.clientRoleBroadcaster);
await _engine!.setAudioProfile(
profile: AudioProfileType.audioProfileDefault,
scenario: AudioScenarioType.audioScenarioMeeting,
);
await _engine!.enableAudio();
await _engine!.enableLocalAudio(true);
await _engine!.muteAllRemoteAudioStreams(false);
await _engine!.muteLocalAudioStream(false);
await _engine!.adjustRecordingSignalVolume(100);
await _engine!.adjustPlaybackSignalVolume(100);
await _engine!.setDefaultAudioRouteToSpeakerphone(true);
await _engine!.setEnableSpeakerphone(true);
await _engine!.joinChannel(
token: token ?? '',
@@ -9,7 +9,6 @@ import '../network/api_client.dart';
class FcmService {
final ApiClient _apiClient;
final FirebaseMessaging _messaging = FirebaseMessaging.instance;
final FlutterLocalNotificationsPlugin _localNotifications =
FlutterLocalNotificationsPlugin();
@@ -18,6 +17,7 @@ class FcmService {
Future<void> init() async {
if (kIsWeb) return;
try {
final messaging = FirebaseMessaging.instance;
await _localNotifications.initialize(
const InitializationSettings(
android: AndroidInitializationSettings('@mipmap/ic_launcher'),
@@ -31,10 +31,10 @@ class FcmService {
} catch (_) {}
},
);
await _messaging.requestPermission(alert: true, badge: true, sound: true);
final token = await _messaging.getToken();
await messaging.requestPermission(alert: true, badge: true, sound: true);
final token = await messaging.getToken();
if (token != null) await syncToken(token);
FirebaseMessaging.instance.onTokenRefresh.listen(syncToken);
messaging.onTokenRefresh.listen(syncToken);
FirebaseMessaging.onMessage.listen((message) {
debugPrint('FCM foreground: ${message.data}');
_showLocalNotification(message);
@@ -55,6 +55,10 @@ class FcmService {
Future<void> syncToken(String token) async {
try {
if (_apiClient.baseUrl == null) {
debugPrint('FCM token sync skipped: server URL is not ready.');
return;
}
await _apiClient.dio.put('/auth/fcm-token', data: {'fcmToken': token});
} catch (e) {
debugPrint('FCM token sync skipped: $e');
@@ -1,5 +1,6 @@
import 'dart:async';
import 'package:battery_plus/battery_plus.dart';
import 'package:dio/dio.dart';
import 'package:geolocator/geolocator.dart';
@@ -10,6 +11,7 @@ import 'offline_queue_service.dart';
class LocationReporterService {
final ApiClient _apiClient;
final OfflineQueueService _offlineQueue;
final Battery _battery = Battery();
Timer? _timer;
LocationReporterService(this._apiClient, this._offlineQueue);
@@ -32,12 +34,14 @@ class LocationReporterService {
try {
await Geolocator.requestPermission();
final position = await Geolocator.getCurrentPosition();
final batteryLevel = await _readBatteryLevel();
await _apiClient.dio.post('/user/location', data: {
'lat': position.latitude,
'lng': position.longitude,
'accuracy': position.accuracy,
'speed': position.speed,
'heading': position.heading,
if (batteryLevel != null) 'batteryLevel': batteryLevel,
});
} on DioException catch (_) {
await _offlineQueue.enqueue(OfflineRequest(
@@ -50,4 +54,12 @@ class LocationReporterService {
// GPS permission can be unavailable during desktop/web testing.
}
}
Future<int?> _readBatteryLevel() async {
try {
return await _battery.batteryLevel;
} catch (_) {
return null;
}
}
}
@@ -19,6 +19,8 @@ class VoiceCommand {
/// Callback yang dipanggil saat command terdeteksi
/// Registered oleh router/screen yang relevan
typedef CommandCallback = void Function(VoiceCommandKey key);
typedef CommandRouter = void Function(String route);
typedef CommandAction = void Function();
class VoiceCommandHandler {
final SttService _stt;
@@ -26,9 +28,19 @@ class VoiceCommandHandler {
List<VoiceCommand> _commands = [];
CommandCallback? onCommand;
CommandRouter? _router;
final Map<VoiceCommandKey, CommandAction> _actions = {};
VoiceCommandHandler(this._stt, this._tts);
void registerRouter(CommandRouter router) {
_router = router;
}
void registerAction(VoiceCommandKey key, CommandAction action) {
_actions[key] = action;
}
void loadCommands(List<VoiceCommand> commands) {
_commands = commands;
_stt.onResult = _processText;
@@ -66,9 +78,28 @@ class VoiceCommandHandler {
}
void _handleCommand(VoiceCommandKey key) {
_routeFor(key);
_actions[key]?.call();
onCommand?.call(key);
// Built-in actions for TTS-only commands
if (key == VoiceCommandKey.repeatLast) _tts.repeatLast();
if (key == VoiceCommandKey.stopTts) _tts.stop();
}
void _routeFor(VoiceCommandKey key) {
final route = switch (key) {
VoiceCommandKey.openWalkguide || VoiceCommandKey.startWalkguide =>
'/user/walkguide',
VoiceCommandKey.openNotification => '/user/notifications',
VoiceCommandKey.openSos || VoiceCommandKey.sendSos => '/user/sos',
VoiceCommandKey.openActivity => '/user/activity',
VoiceCommandKey.openNavigation => '/user/navigation',
VoiceCommandKey.openSettings => '/user/settings',
VoiceCommandKey.callGuardian => '/call',
_ => null,
};
if (route != null) {
_router?.call(route);
}
}
}