Update lot features
This commit is contained in:
@@ -1,13 +1,18 @@
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class AppConstants {
|
||||
static const String defaultServerUrl = 'http://202.46.28.170:8080';
|
||||
static const String _serverUrlKey = 'server_base_url';
|
||||
static const String _selectedYoloModelKey = 'selected_yolo_model';
|
||||
|
||||
// Ambil base URL dari SharedPreferences
|
||||
static Future<String?> getServerUrl() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
return prefs.getString(_serverUrlKey);
|
||||
final saved = prefs.getString(_serverUrlKey);
|
||||
if (saved == null || saved.trim().isEmpty) {
|
||||
return defaultServerUrl;
|
||||
}
|
||||
return saved;
|
||||
}
|
||||
|
||||
// Simpan URL setelah berhasil connect
|
||||
@@ -33,7 +38,7 @@ class AppConstants {
|
||||
|
||||
static Future<void> clearServerUrl() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.remove(_serverUrlKey);
|
||||
await prefs.setString(_serverUrlKey, defaultServerUrl);
|
||||
}
|
||||
|
||||
static String buildApiUrl(String baseUrl) => '$baseUrl/api/v1';
|
||||
|
||||
@@ -44,14 +44,19 @@ class CallService {
|
||||
required int receiverId,
|
||||
required String channelName,
|
||||
String? agoraToken,
|
||||
String? agoraAppId,
|
||||
int receiverUid = 0,
|
||||
}) async {
|
||||
await _apiClient.dio.post('/shared/call/notify', data: {
|
||||
'receiverId': receiverId,
|
||||
'channelName': channelName,
|
||||
'agoraToken': agoraToken,
|
||||
'receiverUid': receiverUid,
|
||||
});
|
||||
await _apiClient.dio.post(
|
||||
'/shared/call/notify',
|
||||
data: {
|
||||
'receiverId': receiverId,
|
||||
'channelName': channelName,
|
||||
'agoraToken': agoraToken,
|
||||
'agoraAppId': agoraAppId,
|
||||
'receiverUid': receiverUid,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>?> startPairedCall({int uid = 0}) async {
|
||||
@@ -61,12 +66,14 @@ class CallService {
|
||||
final tokenData = await requestToken(receiverId: receiverId);
|
||||
final channelName = tokenData?['channelName']?.toString();
|
||||
final token = tokenData?['token']?.toString();
|
||||
final appId = tokenData?['appId']?.toString();
|
||||
final localUid = (tokenData?['uid'] as num?)?.toInt() ?? uid;
|
||||
if (channelName == null || channelName.isEmpty) return null;
|
||||
|
||||
final joined = await joinChannel(
|
||||
channelName: channelName,
|
||||
token: token,
|
||||
appId: appId,
|
||||
uid: localUid,
|
||||
);
|
||||
if (!joined) return null;
|
||||
@@ -75,6 +82,7 @@ class CallService {
|
||||
receiverId: receiverId,
|
||||
channelName: channelName,
|
||||
agoraToken: token,
|
||||
agoraAppId: appId,
|
||||
receiverUid: 0,
|
||||
);
|
||||
|
||||
@@ -94,10 +102,10 @@ class CallService {
|
||||
required int callerId,
|
||||
required String channelName,
|
||||
}) async {
|
||||
await _apiClient.dio.post('/shared/call/accept', data: {
|
||||
'callerId': callerId.toString(),
|
||||
'channelName': channelName,
|
||||
});
|
||||
await _apiClient.dio.post(
|
||||
'/shared/call/accept',
|
||||
data: {'callerId': callerId.toString(), 'channelName': channelName},
|
||||
);
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>?> getAcceptedCall() async {
|
||||
@@ -126,21 +134,27 @@ class CallService {
|
||||
|
||||
Future<void> endCall(int? otherId, {String? channelName}) async {
|
||||
if (otherId == null) return;
|
||||
await _apiClient.dio.post('/shared/call/end', data: {
|
||||
'otherId': otherId.toString(),
|
||||
if (channelName != null && channelName.isNotEmpty)
|
||||
'channelName': channelName,
|
||||
});
|
||||
await _apiClient.dio.post(
|
||||
'/shared/call/end',
|
||||
data: {
|
||||
'otherId': otherId.toString(),
|
||||
if (channelName != null && channelName.isNotEmpty)
|
||||
'channelName': channelName,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<bool> joinChannel({
|
||||
required String channelName,
|
||||
String? token,
|
||||
String? appId,
|
||||
int uid = 0,
|
||||
}) async {
|
||||
final joinCompleter = Completer<bool>();
|
||||
try {
|
||||
if (AppConstants.agoraAppId.isEmpty) {
|
||||
final resolvedAppId =
|
||||
(appId != null && appId.isNotEmpty) ? appId : AppConstants.agoraAppId;
|
||||
if (resolvedAppId.isEmpty) {
|
||||
debugPrint('Agora join skipped: AGORA_APP_ID is not configured');
|
||||
return false;
|
||||
}
|
||||
@@ -150,9 +164,7 @@ class CallService {
|
||||
}
|
||||
|
||||
_engine ??= createAgoraRtcEngine();
|
||||
await _engine!.initialize(
|
||||
const RtcEngineContext(appId: AppConstants.agoraAppId),
|
||||
);
|
||||
await _engine!.initialize(RtcEngineContext(appId: resolvedAppId));
|
||||
_engine!.registerEventHandler(
|
||||
RtcEngineEventHandler(
|
||||
onJoinChannelSuccess: (_, __) {
|
||||
@@ -183,12 +195,17 @@ class CallService {
|
||||
await _engine!.setClientRole(role: ClientRoleType.clientRoleBroadcaster);
|
||||
await _engine!.setAudioProfile(
|
||||
profile: AudioProfileType.audioProfileDefault,
|
||||
scenario: AudioScenarioType.audioScenarioMeeting,
|
||||
scenario: AudioScenarioType.audioScenarioDefault,
|
||||
);
|
||||
await _engine!.enableAudio();
|
||||
await _engine!.enableLocalAudio(true);
|
||||
await _engine!.muteAllRemoteAudioStreams(false);
|
||||
await _engine!.muteLocalAudioStream(false);
|
||||
await _engine!.enableAudioVolumeIndication(
|
||||
interval: 500,
|
||||
smooth: 3,
|
||||
reportVad: true,
|
||||
);
|
||||
await _engine!.adjustRecordingSignalVolume(100);
|
||||
await _engine!.adjustPlaybackSignalVolume(100);
|
||||
await _engine!.setDefaultAudioRouteToSpeakerphone(true);
|
||||
|
||||
@@ -14,7 +14,7 @@ class IncomingCallPollingService {
|
||||
|
||||
void start() {
|
||||
if (_timer != null) return;
|
||||
_timer = Timer.periodic(const Duration(seconds: 2), (_) => _check());
|
||||
_timer = Timer.periodic(const Duration(seconds: 1), (_) => _check());
|
||||
unawaited(_check());
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ class IncomingCallPollingService {
|
||||
try {
|
||||
final res = await _apiClient.dio
|
||||
.get('/shared/call/pending')
|
||||
.timeout(const Duration(seconds: 3));
|
||||
.timeout(const Duration(seconds: 2));
|
||||
final data = res.data['data'];
|
||||
if (data is! Map) return;
|
||||
if (data['type']?.toString() != 'INCOMING_CALL') return;
|
||||
@@ -42,4 +42,4 @@ class IncomingCallPollingService {
|
||||
debugPrint('Incoming call polling skipped: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user