im so tired man
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user