diff --git a/modules/legacy/modules/device_management/lib/src/features/call_history/presentation/providers/call_history_provider.g.dart b/modules/legacy/modules/device_management/lib/src/features/call_history/presentation/providers/call_history_provider.g.dart index c4dcdbf6..6c7cf829 100644 --- a/modules/legacy/modules/device_management/lib/src/features/call_history/presentation/providers/call_history_provider.g.dart +++ b/modules/legacy/modules/device_management/lib/src/features/call_history/presentation/providers/call_history_provider.g.dart @@ -66,7 +66,7 @@ final class CallHistoryProvider } } -String _$callHistoryHash() => r'f5b99a06bc69f62660d1cf7b66648a279724f216'; +String _$callHistoryHash() => r'86542b22355569620e6c9d58091b6580103b852e'; final class CallHistoryFamily extends $Family with $FunctionalFamilyOverride>, String> { diff --git a/modules/legacy/modules/device_management/lib/src/features/videocall/domain/entities/videocall_error.dart b/modules/legacy/modules/device_management/lib/src/features/videocall/domain/entities/videocall_error.dart index 2e520376..5f3a9a6b 100644 --- a/modules/legacy/modules/device_management/lib/src/features/videocall/domain/entities/videocall_error.dart +++ b/modules/legacy/modules/device_management/lib/src/features/videocall/domain/entities/videocall_error.dart @@ -8,6 +8,7 @@ enum VideocallErrorEvent { cameraPermission, microphonePermission, generic, + deviceBusy, } enum VideocallSuccessEvent { diff --git a/modules/legacy/modules/device_management/lib/src/features/videocall/presentation/providers/videocall_controller.dart b/modules/legacy/modules/device_management/lib/src/features/videocall/presentation/providers/videocall_controller.dart index 5f20fd81..746685d4 100644 --- a/modules/legacy/modules/device_management/lib/src/features/videocall/presentation/providers/videocall_controller.dart +++ b/modules/legacy/modules/device_management/lib/src/features/videocall/presentation/providers/videocall_controller.dart @@ -1,8 +1,10 @@ import 'dart:async'; import 'package:flutter/material.dart'; +import 'package:legacy_device_state/legacy_device_state.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; +import 'package:sf_infrastructure/sf_infrastructure.dart'; import 'package:sf_shared/sf_shared.dart'; import 'package:videocall_sdk/videocall_sdk.dart' hide VideocallState; @@ -34,6 +36,7 @@ class VideocallController extends _$VideocallController { StreamSubscription<({int reason, String description})>? _callRemoveSub; StreamSubscription? _missedCallSub; StreamSubscription? _clientStateSub; + StreamSubscription? _webSocketSub; bool _wasInCall = false; @override @@ -54,6 +57,7 @@ class VideocallController extends _$VideocallController { _callRemoveSub?.cancel(); _missedCallSub?.cancel(); _clientStateSub?.cancel(); + _webSocketSub?.cancel(); if (_wasInCall) { _callService.hangUp(); _deviceService.stopAudio(); @@ -136,6 +140,10 @@ class VideocallController extends _$VideocallController { ); _missedCallSub = _callService.missedCallStream.listen(_onMissedCall); _clientStateSub = _client.stateStream.listen(_onClientStateChange); + _webSocketSub = ref + .read(webSocketServiceProvider) + .events + .listen(_onWebSocketEvent); } String _sanitize(String value) => @@ -514,6 +522,28 @@ class VideocallController extends _$VideocallController { } } + void _onWebSocketEvent(WebSocketEvent event) { + if (!ref.mounted) return; + if (event is VideoCallRequestResponseEvent) { + debugPrint('[Videocall] WS video_call_request_response: ${event.status}'); + if (event.isOk) { + state = state.copyWith(isDeviceRinging: true); + } else { + _callService.hangUp(); + _deviceService.stopAudio(); + _deviceService.stopCamera(); + state = state.copyWith( + screenMode: VideocallScreenMode.idle, + errorEvent: VideocallErrorEvent.deviceBusy, + currentCall: null, + localCanvas: null, + remoteCanvas: null, + isDeviceRinging: false, + ); + } + } + } + void clearError() { state = state.copyWith(errorEvent: null); } diff --git a/modules/legacy/modules/device_management/lib/src/features/videocall/presentation/providers/videocall_controller.g.dart b/modules/legacy/modules/device_management/lib/src/features/videocall/presentation/providers/videocall_controller.g.dart index 6dd99ecf..079ec9da 100644 --- a/modules/legacy/modules/device_management/lib/src/features/videocall/presentation/providers/videocall_controller.g.dart +++ b/modules/legacy/modules/device_management/lib/src/features/videocall/presentation/providers/videocall_controller.g.dart @@ -42,7 +42,7 @@ final class VideocallControllerProvider } String _$videocallControllerHash() => - r'e94071625d05927701912826102a5b526b72140b'; + r'7338ee15f5325ce3e77837ce6bd70d97fbd52b5c'; abstract class _$VideocallController extends $Notifier { VideocallState build(); diff --git a/modules/legacy/modules/device_management/lib/src/features/videocall/presentation/providers/videocall_state.dart b/modules/legacy/modules/device_management/lib/src/features/videocall/presentation/providers/videocall_state.dart index 0b6c206b..4c20c0c3 100644 --- a/modules/legacy/modules/device_management/lib/src/features/videocall/presentation/providers/videocall_state.dart +++ b/modules/legacy/modules/device_management/lib/src/features/videocall/presentation/providers/videocall_state.dart @@ -18,6 +18,7 @@ abstract class VideocallState with _$VideocallState { @Default(true) bool isMicEnabled, @Default(true) bool isSpeakerEnabled, @Default(true) bool isFrontCamera, + @Default(false) bool isDeviceRinging, @Default(false) bool isRemoteVideoAvailable, VideocallItem? currentCall, JCMediaDeviceVideoCanvas? localCanvas, diff --git a/modules/legacy/modules/device_management/lib/src/features/videocall/presentation/providers/videocall_state.freezed.dart b/modules/legacy/modules/device_management/lib/src/features/videocall/presentation/providers/videocall_state.freezed.dart index a76e31cb..443b4437 100644 --- a/modules/legacy/modules/device_management/lib/src/features/videocall/presentation/providers/videocall_state.freezed.dart +++ b/modules/legacy/modules/device_management/lib/src/features/videocall/presentation/providers/videocall_state.freezed.dart @@ -14,7 +14,7 @@ T _$identity(T value) => value; /// @nodoc mixin _$VideocallState { - String get deviceId; String get localUserId; String get remoteUserId; VideocallScreenMode get screenMode; VideocallChatType get chatType; bool get isSdkReady; bool get isMicEnabled; bool get isSpeakerEnabled; bool get isFrontCamera; bool get isRemoteVideoAvailable; VideocallItem? get currentCall; JCMediaDeviceVideoCanvas? get localCanvas; JCMediaDeviceVideoCanvas? get remoteCanvas; VideocallErrorEvent? get errorEvent; VideocallSuccessEvent? get successEvent; + String get deviceId; String get localUserId; String get remoteUserId; VideocallScreenMode get screenMode; VideocallChatType get chatType; bool get isSdkReady; bool get isMicEnabled; bool get isSpeakerEnabled; bool get isFrontCamera; bool get isDeviceRinging; bool get isRemoteVideoAvailable; VideocallItem? get currentCall; JCMediaDeviceVideoCanvas? get localCanvas; JCMediaDeviceVideoCanvas? get remoteCanvas; VideocallErrorEvent? get errorEvent; VideocallSuccessEvent? get successEvent; /// Create a copy of VideocallState /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @@ -25,16 +25,16 @@ $VideocallStateCopyWith get copyWith => _$VideocallStateCopyWith @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is VideocallState&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.localUserId, localUserId) || other.localUserId == localUserId)&&(identical(other.remoteUserId, remoteUserId) || other.remoteUserId == remoteUserId)&&(identical(other.screenMode, screenMode) || other.screenMode == screenMode)&&(identical(other.chatType, chatType) || other.chatType == chatType)&&(identical(other.isSdkReady, isSdkReady) || other.isSdkReady == isSdkReady)&&(identical(other.isMicEnabled, isMicEnabled) || other.isMicEnabled == isMicEnabled)&&(identical(other.isSpeakerEnabled, isSpeakerEnabled) || other.isSpeakerEnabled == isSpeakerEnabled)&&(identical(other.isFrontCamera, isFrontCamera) || other.isFrontCamera == isFrontCamera)&&(identical(other.isRemoteVideoAvailable, isRemoteVideoAvailable) || other.isRemoteVideoAvailable == isRemoteVideoAvailable)&&(identical(other.currentCall, currentCall) || other.currentCall == currentCall)&&(identical(other.localCanvas, localCanvas) || other.localCanvas == localCanvas)&&(identical(other.remoteCanvas, remoteCanvas) || other.remoteCanvas == remoteCanvas)&&(identical(other.errorEvent, errorEvent) || other.errorEvent == errorEvent)&&(identical(other.successEvent, successEvent) || other.successEvent == successEvent)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is VideocallState&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.localUserId, localUserId) || other.localUserId == localUserId)&&(identical(other.remoteUserId, remoteUserId) || other.remoteUserId == remoteUserId)&&(identical(other.screenMode, screenMode) || other.screenMode == screenMode)&&(identical(other.chatType, chatType) || other.chatType == chatType)&&(identical(other.isSdkReady, isSdkReady) || other.isSdkReady == isSdkReady)&&(identical(other.isMicEnabled, isMicEnabled) || other.isMicEnabled == isMicEnabled)&&(identical(other.isSpeakerEnabled, isSpeakerEnabled) || other.isSpeakerEnabled == isSpeakerEnabled)&&(identical(other.isFrontCamera, isFrontCamera) || other.isFrontCamera == isFrontCamera)&&(identical(other.isDeviceRinging, isDeviceRinging) || other.isDeviceRinging == isDeviceRinging)&&(identical(other.isRemoteVideoAvailable, isRemoteVideoAvailable) || other.isRemoteVideoAvailable == isRemoteVideoAvailable)&&(identical(other.currentCall, currentCall) || other.currentCall == currentCall)&&(identical(other.localCanvas, localCanvas) || other.localCanvas == localCanvas)&&(identical(other.remoteCanvas, remoteCanvas) || other.remoteCanvas == remoteCanvas)&&(identical(other.errorEvent, errorEvent) || other.errorEvent == errorEvent)&&(identical(other.successEvent, successEvent) || other.successEvent == successEvent)); } @override -int get hashCode => Object.hash(runtimeType,deviceId,localUserId,remoteUserId,screenMode,chatType,isSdkReady,isMicEnabled,isSpeakerEnabled,isFrontCamera,isRemoteVideoAvailable,currentCall,localCanvas,remoteCanvas,errorEvent,successEvent); +int get hashCode => Object.hash(runtimeType,deviceId,localUserId,remoteUserId,screenMode,chatType,isSdkReady,isMicEnabled,isSpeakerEnabled,isFrontCamera,isDeviceRinging,isRemoteVideoAvailable,currentCall,localCanvas,remoteCanvas,errorEvent,successEvent); @override String toString() { - return 'VideocallState(deviceId: $deviceId, localUserId: $localUserId, remoteUserId: $remoteUserId, screenMode: $screenMode, chatType: $chatType, isSdkReady: $isSdkReady, isMicEnabled: $isMicEnabled, isSpeakerEnabled: $isSpeakerEnabled, isFrontCamera: $isFrontCamera, isRemoteVideoAvailable: $isRemoteVideoAvailable, currentCall: $currentCall, localCanvas: $localCanvas, remoteCanvas: $remoteCanvas, errorEvent: $errorEvent, successEvent: $successEvent)'; + return 'VideocallState(deviceId: $deviceId, localUserId: $localUserId, remoteUserId: $remoteUserId, screenMode: $screenMode, chatType: $chatType, isSdkReady: $isSdkReady, isMicEnabled: $isMicEnabled, isSpeakerEnabled: $isSpeakerEnabled, isFrontCamera: $isFrontCamera, isDeviceRinging: $isDeviceRinging, isRemoteVideoAvailable: $isRemoteVideoAvailable, currentCall: $currentCall, localCanvas: $localCanvas, remoteCanvas: $remoteCanvas, errorEvent: $errorEvent, successEvent: $successEvent)'; } @@ -45,7 +45,7 @@ abstract mixin class $VideocallStateCopyWith<$Res> { factory $VideocallStateCopyWith(VideocallState value, $Res Function(VideocallState) _then) = _$VideocallStateCopyWithImpl; @useResult $Res call({ - String deviceId, String localUserId, String remoteUserId, VideocallScreenMode screenMode, VideocallChatType chatType, bool isSdkReady, bool isMicEnabled, bool isSpeakerEnabled, bool isFrontCamera, bool isRemoteVideoAvailable, VideocallItem? currentCall, JCMediaDeviceVideoCanvas? localCanvas, JCMediaDeviceVideoCanvas? remoteCanvas, VideocallErrorEvent? errorEvent, VideocallSuccessEvent? successEvent + String deviceId, String localUserId, String remoteUserId, VideocallScreenMode screenMode, VideocallChatType chatType, bool isSdkReady, bool isMicEnabled, bool isSpeakerEnabled, bool isFrontCamera, bool isDeviceRinging, bool isRemoteVideoAvailable, VideocallItem? currentCall, JCMediaDeviceVideoCanvas? localCanvas, JCMediaDeviceVideoCanvas? remoteCanvas, VideocallErrorEvent? errorEvent, VideocallSuccessEvent? successEvent }); @@ -62,7 +62,7 @@ class _$VideocallStateCopyWithImpl<$Res> /// Create a copy of VideocallState /// with the given fields replaced by the non-null parameter values. -@pragma('vm:prefer-inline') @override $Res call({Object? deviceId = null,Object? localUserId = null,Object? remoteUserId = null,Object? screenMode = null,Object? chatType = null,Object? isSdkReady = null,Object? isMicEnabled = null,Object? isSpeakerEnabled = null,Object? isFrontCamera = null,Object? isRemoteVideoAvailable = null,Object? currentCall = freezed,Object? localCanvas = freezed,Object? remoteCanvas = freezed,Object? errorEvent = freezed,Object? successEvent = freezed,}) { +@pragma('vm:prefer-inline') @override $Res call({Object? deviceId = null,Object? localUserId = null,Object? remoteUserId = null,Object? screenMode = null,Object? chatType = null,Object? isSdkReady = null,Object? isMicEnabled = null,Object? isSpeakerEnabled = null,Object? isFrontCamera = null,Object? isDeviceRinging = null,Object? isRemoteVideoAvailable = null,Object? currentCall = freezed,Object? localCanvas = freezed,Object? remoteCanvas = freezed,Object? errorEvent = freezed,Object? successEvent = freezed,}) { return _then(_self.copyWith( deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable as String,localUserId: null == localUserId ? _self.localUserId : localUserId // ignore: cast_nullable_to_non_nullable @@ -73,6 +73,7 @@ as VideocallChatType,isSdkReady: null == isSdkReady ? _self.isSdkReady : isSdkRe as bool,isMicEnabled: null == isMicEnabled ? _self.isMicEnabled : isMicEnabled // ignore: cast_nullable_to_non_nullable as bool,isSpeakerEnabled: null == isSpeakerEnabled ? _self.isSpeakerEnabled : isSpeakerEnabled // ignore: cast_nullable_to_non_nullable as bool,isFrontCamera: null == isFrontCamera ? _self.isFrontCamera : isFrontCamera // ignore: cast_nullable_to_non_nullable +as bool,isDeviceRinging: null == isDeviceRinging ? _self.isDeviceRinging : isDeviceRinging // ignore: cast_nullable_to_non_nullable as bool,isRemoteVideoAvailable: null == isRemoteVideoAvailable ? _self.isRemoteVideoAvailable : isRemoteVideoAvailable // ignore: cast_nullable_to_non_nullable as bool,currentCall: freezed == currentCall ? _self.currentCall : currentCall // ignore: cast_nullable_to_non_nullable as VideocallItem?,localCanvas: freezed == localCanvas ? _self.localCanvas : localCanvas // ignore: cast_nullable_to_non_nullable @@ -176,10 +177,10 @@ return $default(_that);case _: /// } /// ``` -@optionalTypeArgs TResult maybeWhen(TResult Function( String deviceId, String localUserId, String remoteUserId, VideocallScreenMode screenMode, VideocallChatType chatType, bool isSdkReady, bool isMicEnabled, bool isSpeakerEnabled, bool isFrontCamera, bool isRemoteVideoAvailable, VideocallItem? currentCall, JCMediaDeviceVideoCanvas? localCanvas, JCMediaDeviceVideoCanvas? remoteCanvas, VideocallErrorEvent? errorEvent, VideocallSuccessEvent? successEvent)? $default,{required TResult orElse(),}) {final _that = this; +@optionalTypeArgs TResult maybeWhen(TResult Function( String deviceId, String localUserId, String remoteUserId, VideocallScreenMode screenMode, VideocallChatType chatType, bool isSdkReady, bool isMicEnabled, bool isSpeakerEnabled, bool isFrontCamera, bool isDeviceRinging, bool isRemoteVideoAvailable, VideocallItem? currentCall, JCMediaDeviceVideoCanvas? localCanvas, JCMediaDeviceVideoCanvas? remoteCanvas, VideocallErrorEvent? errorEvent, VideocallSuccessEvent? successEvent)? $default,{required TResult orElse(),}) {final _that = this; switch (_that) { case _VideocallState() when $default != null: -return $default(_that.deviceId,_that.localUserId,_that.remoteUserId,_that.screenMode,_that.chatType,_that.isSdkReady,_that.isMicEnabled,_that.isSpeakerEnabled,_that.isFrontCamera,_that.isRemoteVideoAvailable,_that.currentCall,_that.localCanvas,_that.remoteCanvas,_that.errorEvent,_that.successEvent);case _: +return $default(_that.deviceId,_that.localUserId,_that.remoteUserId,_that.screenMode,_that.chatType,_that.isSdkReady,_that.isMicEnabled,_that.isSpeakerEnabled,_that.isFrontCamera,_that.isDeviceRinging,_that.isRemoteVideoAvailable,_that.currentCall,_that.localCanvas,_that.remoteCanvas,_that.errorEvent,_that.successEvent);case _: return orElse(); } @@ -197,10 +198,10 @@ return $default(_that.deviceId,_that.localUserId,_that.remoteUserId,_that.screen /// } /// ``` -@optionalTypeArgs TResult when(TResult Function( String deviceId, String localUserId, String remoteUserId, VideocallScreenMode screenMode, VideocallChatType chatType, bool isSdkReady, bool isMicEnabled, bool isSpeakerEnabled, bool isFrontCamera, bool isRemoteVideoAvailable, VideocallItem? currentCall, JCMediaDeviceVideoCanvas? localCanvas, JCMediaDeviceVideoCanvas? remoteCanvas, VideocallErrorEvent? errorEvent, VideocallSuccessEvent? successEvent) $default,) {final _that = this; +@optionalTypeArgs TResult when(TResult Function( String deviceId, String localUserId, String remoteUserId, VideocallScreenMode screenMode, VideocallChatType chatType, bool isSdkReady, bool isMicEnabled, bool isSpeakerEnabled, bool isFrontCamera, bool isDeviceRinging, bool isRemoteVideoAvailable, VideocallItem? currentCall, JCMediaDeviceVideoCanvas? localCanvas, JCMediaDeviceVideoCanvas? remoteCanvas, VideocallErrorEvent? errorEvent, VideocallSuccessEvent? successEvent) $default,) {final _that = this; switch (_that) { case _VideocallState(): -return $default(_that.deviceId,_that.localUserId,_that.remoteUserId,_that.screenMode,_that.chatType,_that.isSdkReady,_that.isMicEnabled,_that.isSpeakerEnabled,_that.isFrontCamera,_that.isRemoteVideoAvailable,_that.currentCall,_that.localCanvas,_that.remoteCanvas,_that.errorEvent,_that.successEvent);case _: +return $default(_that.deviceId,_that.localUserId,_that.remoteUserId,_that.screenMode,_that.chatType,_that.isSdkReady,_that.isMicEnabled,_that.isSpeakerEnabled,_that.isFrontCamera,_that.isDeviceRinging,_that.isRemoteVideoAvailable,_that.currentCall,_that.localCanvas,_that.remoteCanvas,_that.errorEvent,_that.successEvent);case _: throw StateError('Unexpected subclass'); } @@ -217,10 +218,10 @@ return $default(_that.deviceId,_that.localUserId,_that.remoteUserId,_that.screen /// } /// ``` -@optionalTypeArgs TResult? whenOrNull(TResult? Function( String deviceId, String localUserId, String remoteUserId, VideocallScreenMode screenMode, VideocallChatType chatType, bool isSdkReady, bool isMicEnabled, bool isSpeakerEnabled, bool isFrontCamera, bool isRemoteVideoAvailable, VideocallItem? currentCall, JCMediaDeviceVideoCanvas? localCanvas, JCMediaDeviceVideoCanvas? remoteCanvas, VideocallErrorEvent? errorEvent, VideocallSuccessEvent? successEvent)? $default,) {final _that = this; +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String deviceId, String localUserId, String remoteUserId, VideocallScreenMode screenMode, VideocallChatType chatType, bool isSdkReady, bool isMicEnabled, bool isSpeakerEnabled, bool isFrontCamera, bool isDeviceRinging, bool isRemoteVideoAvailable, VideocallItem? currentCall, JCMediaDeviceVideoCanvas? localCanvas, JCMediaDeviceVideoCanvas? remoteCanvas, VideocallErrorEvent? errorEvent, VideocallSuccessEvent? successEvent)? $default,) {final _that = this; switch (_that) { case _VideocallState() when $default != null: -return $default(_that.deviceId,_that.localUserId,_that.remoteUserId,_that.screenMode,_that.chatType,_that.isSdkReady,_that.isMicEnabled,_that.isSpeakerEnabled,_that.isFrontCamera,_that.isRemoteVideoAvailable,_that.currentCall,_that.localCanvas,_that.remoteCanvas,_that.errorEvent,_that.successEvent);case _: +return $default(_that.deviceId,_that.localUserId,_that.remoteUserId,_that.screenMode,_that.chatType,_that.isSdkReady,_that.isMicEnabled,_that.isSpeakerEnabled,_that.isFrontCamera,_that.isDeviceRinging,_that.isRemoteVideoAvailable,_that.currentCall,_that.localCanvas,_that.remoteCanvas,_that.errorEvent,_that.successEvent);case _: return null; } @@ -232,7 +233,7 @@ return $default(_that.deviceId,_that.localUserId,_that.remoteUserId,_that.screen class _VideocallState implements VideocallState { - const _VideocallState({this.deviceId = '', this.localUserId = '', this.remoteUserId = '', this.screenMode = VideocallScreenMode.idle, this.chatType = VideocallChatType.single, this.isSdkReady = false, this.isMicEnabled = true, this.isSpeakerEnabled = true, this.isFrontCamera = true, this.isRemoteVideoAvailable = false, this.currentCall, this.localCanvas, this.remoteCanvas, this.errorEvent, this.successEvent}); + const _VideocallState({this.deviceId = '', this.localUserId = '', this.remoteUserId = '', this.screenMode = VideocallScreenMode.idle, this.chatType = VideocallChatType.single, this.isSdkReady = false, this.isMicEnabled = true, this.isSpeakerEnabled = true, this.isFrontCamera = true, this.isDeviceRinging = false, this.isRemoteVideoAvailable = false, this.currentCall, this.localCanvas, this.remoteCanvas, this.errorEvent, this.successEvent}); @override@JsonKey() final String deviceId; @@ -244,6 +245,7 @@ class _VideocallState implements VideocallState { @override@JsonKey() final bool isMicEnabled; @override@JsonKey() final bool isSpeakerEnabled; @override@JsonKey() final bool isFrontCamera; +@override@JsonKey() final bool isDeviceRinging; @override@JsonKey() final bool isRemoteVideoAvailable; @override final VideocallItem? currentCall; @override final JCMediaDeviceVideoCanvas? localCanvas; @@ -261,16 +263,16 @@ _$VideocallStateCopyWith<_VideocallState> get copyWith => __$VideocallStateCopyW @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is _VideocallState&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.localUserId, localUserId) || other.localUserId == localUserId)&&(identical(other.remoteUserId, remoteUserId) || other.remoteUserId == remoteUserId)&&(identical(other.screenMode, screenMode) || other.screenMode == screenMode)&&(identical(other.chatType, chatType) || other.chatType == chatType)&&(identical(other.isSdkReady, isSdkReady) || other.isSdkReady == isSdkReady)&&(identical(other.isMicEnabled, isMicEnabled) || other.isMicEnabled == isMicEnabled)&&(identical(other.isSpeakerEnabled, isSpeakerEnabled) || other.isSpeakerEnabled == isSpeakerEnabled)&&(identical(other.isFrontCamera, isFrontCamera) || other.isFrontCamera == isFrontCamera)&&(identical(other.isRemoteVideoAvailable, isRemoteVideoAvailable) || other.isRemoteVideoAvailable == isRemoteVideoAvailable)&&(identical(other.currentCall, currentCall) || other.currentCall == currentCall)&&(identical(other.localCanvas, localCanvas) || other.localCanvas == localCanvas)&&(identical(other.remoteCanvas, remoteCanvas) || other.remoteCanvas == remoteCanvas)&&(identical(other.errorEvent, errorEvent) || other.errorEvent == errorEvent)&&(identical(other.successEvent, successEvent) || other.successEvent == successEvent)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is _VideocallState&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.localUserId, localUserId) || other.localUserId == localUserId)&&(identical(other.remoteUserId, remoteUserId) || other.remoteUserId == remoteUserId)&&(identical(other.screenMode, screenMode) || other.screenMode == screenMode)&&(identical(other.chatType, chatType) || other.chatType == chatType)&&(identical(other.isSdkReady, isSdkReady) || other.isSdkReady == isSdkReady)&&(identical(other.isMicEnabled, isMicEnabled) || other.isMicEnabled == isMicEnabled)&&(identical(other.isSpeakerEnabled, isSpeakerEnabled) || other.isSpeakerEnabled == isSpeakerEnabled)&&(identical(other.isFrontCamera, isFrontCamera) || other.isFrontCamera == isFrontCamera)&&(identical(other.isDeviceRinging, isDeviceRinging) || other.isDeviceRinging == isDeviceRinging)&&(identical(other.isRemoteVideoAvailable, isRemoteVideoAvailable) || other.isRemoteVideoAvailable == isRemoteVideoAvailable)&&(identical(other.currentCall, currentCall) || other.currentCall == currentCall)&&(identical(other.localCanvas, localCanvas) || other.localCanvas == localCanvas)&&(identical(other.remoteCanvas, remoteCanvas) || other.remoteCanvas == remoteCanvas)&&(identical(other.errorEvent, errorEvent) || other.errorEvent == errorEvent)&&(identical(other.successEvent, successEvent) || other.successEvent == successEvent)); } @override -int get hashCode => Object.hash(runtimeType,deviceId,localUserId,remoteUserId,screenMode,chatType,isSdkReady,isMicEnabled,isSpeakerEnabled,isFrontCamera,isRemoteVideoAvailable,currentCall,localCanvas,remoteCanvas,errorEvent,successEvent); +int get hashCode => Object.hash(runtimeType,deviceId,localUserId,remoteUserId,screenMode,chatType,isSdkReady,isMicEnabled,isSpeakerEnabled,isFrontCamera,isDeviceRinging,isRemoteVideoAvailable,currentCall,localCanvas,remoteCanvas,errorEvent,successEvent); @override String toString() { - return 'VideocallState(deviceId: $deviceId, localUserId: $localUserId, remoteUserId: $remoteUserId, screenMode: $screenMode, chatType: $chatType, isSdkReady: $isSdkReady, isMicEnabled: $isMicEnabled, isSpeakerEnabled: $isSpeakerEnabled, isFrontCamera: $isFrontCamera, isRemoteVideoAvailable: $isRemoteVideoAvailable, currentCall: $currentCall, localCanvas: $localCanvas, remoteCanvas: $remoteCanvas, errorEvent: $errorEvent, successEvent: $successEvent)'; + return 'VideocallState(deviceId: $deviceId, localUserId: $localUserId, remoteUserId: $remoteUserId, screenMode: $screenMode, chatType: $chatType, isSdkReady: $isSdkReady, isMicEnabled: $isMicEnabled, isSpeakerEnabled: $isSpeakerEnabled, isFrontCamera: $isFrontCamera, isDeviceRinging: $isDeviceRinging, isRemoteVideoAvailable: $isRemoteVideoAvailable, currentCall: $currentCall, localCanvas: $localCanvas, remoteCanvas: $remoteCanvas, errorEvent: $errorEvent, successEvent: $successEvent)'; } @@ -281,7 +283,7 @@ abstract mixin class _$VideocallStateCopyWith<$Res> implements $VideocallStateCo factory _$VideocallStateCopyWith(_VideocallState value, $Res Function(_VideocallState) _then) = __$VideocallStateCopyWithImpl; @override @useResult $Res call({ - String deviceId, String localUserId, String remoteUserId, VideocallScreenMode screenMode, VideocallChatType chatType, bool isSdkReady, bool isMicEnabled, bool isSpeakerEnabled, bool isFrontCamera, bool isRemoteVideoAvailable, VideocallItem? currentCall, JCMediaDeviceVideoCanvas? localCanvas, JCMediaDeviceVideoCanvas? remoteCanvas, VideocallErrorEvent? errorEvent, VideocallSuccessEvent? successEvent + String deviceId, String localUserId, String remoteUserId, VideocallScreenMode screenMode, VideocallChatType chatType, bool isSdkReady, bool isMicEnabled, bool isSpeakerEnabled, bool isFrontCamera, bool isDeviceRinging, bool isRemoteVideoAvailable, VideocallItem? currentCall, JCMediaDeviceVideoCanvas? localCanvas, JCMediaDeviceVideoCanvas? remoteCanvas, VideocallErrorEvent? errorEvent, VideocallSuccessEvent? successEvent }); @@ -298,7 +300,7 @@ class __$VideocallStateCopyWithImpl<$Res> /// Create a copy of VideocallState /// with the given fields replaced by the non-null parameter values. -@override @pragma('vm:prefer-inline') $Res call({Object? deviceId = null,Object? localUserId = null,Object? remoteUserId = null,Object? screenMode = null,Object? chatType = null,Object? isSdkReady = null,Object? isMicEnabled = null,Object? isSpeakerEnabled = null,Object? isFrontCamera = null,Object? isRemoteVideoAvailable = null,Object? currentCall = freezed,Object? localCanvas = freezed,Object? remoteCanvas = freezed,Object? errorEvent = freezed,Object? successEvent = freezed,}) { +@override @pragma('vm:prefer-inline') $Res call({Object? deviceId = null,Object? localUserId = null,Object? remoteUserId = null,Object? screenMode = null,Object? chatType = null,Object? isSdkReady = null,Object? isMicEnabled = null,Object? isSpeakerEnabled = null,Object? isFrontCamera = null,Object? isDeviceRinging = null,Object? isRemoteVideoAvailable = null,Object? currentCall = freezed,Object? localCanvas = freezed,Object? remoteCanvas = freezed,Object? errorEvent = freezed,Object? successEvent = freezed,}) { return _then(_VideocallState( deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable as String,localUserId: null == localUserId ? _self.localUserId : localUserId // ignore: cast_nullable_to_non_nullable @@ -309,6 +311,7 @@ as VideocallChatType,isSdkReady: null == isSdkReady ? _self.isSdkReady : isSdkRe as bool,isMicEnabled: null == isMicEnabled ? _self.isMicEnabled : isMicEnabled // ignore: cast_nullable_to_non_nullable as bool,isSpeakerEnabled: null == isSpeakerEnabled ? _self.isSpeakerEnabled : isSpeakerEnabled // ignore: cast_nullable_to_non_nullable as bool,isFrontCamera: null == isFrontCamera ? _self.isFrontCamera : isFrontCamera // ignore: cast_nullable_to_non_nullable +as bool,isDeviceRinging: null == isDeviceRinging ? _self.isDeviceRinging : isDeviceRinging // ignore: cast_nullable_to_non_nullable as bool,isRemoteVideoAvailable: null == isRemoteVideoAvailable ? _self.isRemoteVideoAvailable : isRemoteVideoAvailable // ignore: cast_nullable_to_non_nullable as bool,currentCall: freezed == currentCall ? _self.currentCall : currentCall // ignore: cast_nullable_to_non_nullable as VideocallItem?,localCanvas: freezed == localCanvas ? _self.localCanvas : localCanvas // ignore: cast_nullable_to_non_nullable diff --git a/modules/legacy/modules/device_management/lib/src/features/videocall/presentation/videocall_screen.dart b/modules/legacy/modules/device_management/lib/src/features/videocall/presentation/videocall_screen.dart index 7cfd453f..4a70808b 100644 --- a/modules/legacy/modules/device_management/lib/src/features/videocall/presentation/videocall_screen.dart +++ b/modules/legacy/modules/device_management/lib/src/features/videocall/presentation/videocall_screen.dart @@ -44,6 +44,7 @@ class _VideocallScreenState extends ConsumerState { VideocallErrorEvent.missedCall => I18n.videocallErrorMissedCall, VideocallErrorEvent.cameraPermission => I18n.videocallErrorCamera, VideocallErrorEvent.microphonePermission => I18n.videocallErrorMic, + VideocallErrorEvent.deviceBusy => I18n.videocallErrorDeviceBusy, VideocallErrorEvent.network || VideocallErrorEvent.generic => I18n.errorGeneric, }; showErrorDialog(context, key); @@ -282,7 +283,9 @@ class _ActiveCallView extends StatelessWidget { ), if (isOutgoing) Text( - context.translate(I18n.videocallConnecting), + state.isDeviceRinging + ? context.translate(I18n.videocallDeviceRinging) + : context.translate(I18n.videocallConnecting), style: TextStyle( color: Colors.white.withValues(alpha: 0.7), fontSize: 12, diff --git a/modules/legacy/modules/device_management/lib/src/features/videocall/presentation/widgets/call_status_indicator.dart b/modules/legacy/modules/device_management/lib/src/features/videocall/presentation/widgets/call_status_indicator.dart index 730a2fa1..4822a9cc 100644 --- a/modules/legacy/modules/device_management/lib/src/features/videocall/presentation/widgets/call_status_indicator.dart +++ b/modules/legacy/modules/device_management/lib/src/features/videocall/presentation/widgets/call_status_indicator.dart @@ -8,17 +8,24 @@ class CallStatusIndicator extends StatelessWidget { super.key, required this.screenMode, required this.remoteUserId, + required this.isDeviceRinging, required this.onCancel, }); final VideocallScreenMode screenMode; final String remoteUserId; + final bool isDeviceRinging; final VoidCallback onCancel; @override Widget build(BuildContext context) { final (text, showCancel) = switch (screenMode) { - VideocallScreenMode.outgoing => (context.translate(I18n.videocallCalling, args: {'userId': remoteUserId}), true), + VideocallScreenMode.outgoing => ( + isDeviceRinging + ? context.translate(I18n.videocallDeviceRinging) + : context.translate(I18n.videocallCalling, args: {'userId': remoteUserId}), + true, + ), VideocallScreenMode.incoming => (context.translate(I18n.videocallUserCalling, args: {'userId': remoteUserId}), false), _ => ('', false), }; diff --git a/packages/sf_infrastructure/lib/src/websocket/websocket_event.dart b/packages/sf_infrastructure/lib/src/websocket/websocket_event.dart index 9de5504d..b79d4703 100644 --- a/packages/sf_infrastructure/lib/src/websocket/websocket_event.dart +++ b/packages/sf_infrastructure/lib/src/websocket/websocket_event.dart @@ -168,6 +168,17 @@ class VideoCallRoomCountEvent extends WebSocketEvent { }) : super(type: 'video-call-room-count'); } +class VideoCallRequestResponseEvent extends WebSocketEvent { + final String status; + + const VideoCallRequestResponseEvent({ + required this.status, + required super.timestamp, + }) : super(type: 'video_call_request_response'); + + bool get isOk => status == 'ok'; +} + class UnknownEvent extends WebSocketEvent { final Map rawData; diff --git a/packages/sf_infrastructure/lib/src/websocket/websocket_event_parser.dart b/packages/sf_infrastructure/lib/src/websocket/websocket_event_parser.dart index fc0a8817..7e93609d 100644 --- a/packages/sf_infrastructure/lib/src/websocket/websocket_event_parser.dart +++ b/packages/sf_infrastructure/lib/src/websocket/websocket_event_parser.dart @@ -41,6 +41,13 @@ WebSocketEvent? parseWebSocketEvent(String raw) { ? (jsonDecode(rawData) as Map? ?? {}) : (rawData as Map? ?? {}); + if (type == 'video_call_request_response') { + return VideoCallRequestResponseEvent( + status: json['status'] as String? ?? '', + timestamp: timestamp, + ); + } + return switch (type) { 'position' => PositionEvent( positioningData: data['positioning_data'] as Map? ?? {}, diff --git a/packages/sf_localizations/assets/l10n/de.json b/packages/sf_localizations/assets/l10n/de.json index 1f60729e..ea7ee472 100644 --- a/packages/sf_localizations/assets/l10n/de.json +++ b/packages/sf_localizations/assets/l10n/de.json @@ -711,6 +711,8 @@ "videocallErrorCamera": "Kameraberechtigung erforderlich", "videocallErrorMic": "Mikrofonberechtigung erforderlich", "videocallErrorMissedCall": "Verpasster Anruf", + "videocallErrorDeviceBusy": "Das Gerät ist beschäftigt", + "videocallDeviceRinging": "Gerät klingelt...", "videocallCallEnded": "Anruf beendet", "videocallGroupCall": "Gruppen-Videoanruf", "videocallDisclaimer": "*Für einen optimalen Videoanruf stellen Sie sicher, dass Ihre Uhr über mobile Daten mit Internetverbindung, guter Abdeckung oder WLAN-Verbindung verfügt.", diff --git a/packages/sf_localizations/assets/l10n/en.json b/packages/sf_localizations/assets/l10n/en.json index 73310cb2..f0cd40d6 100755 --- a/packages/sf_localizations/assets/l10n/en.json +++ b/packages/sf_localizations/assets/l10n/en.json @@ -898,6 +898,8 @@ "videocallErrorCamera": "Camera permission required", "videocallErrorMic": "Microphone permission required", "videocallErrorMissedCall": "Missed call", + "videocallErrorDeviceBusy": "Device is busy", + "videocallDeviceRinging": "Device ringing...", "videocallCallEnded": "Call ended", "videocallGroupCall": "Group video call", "videocallDisclaimer": "*For an optimal video call, make sure your watch has mobile data with Internet connection, good coverage or WiFi connection.", diff --git a/packages/sf_localizations/assets/l10n/es.json b/packages/sf_localizations/assets/l10n/es.json index dce1d964..d53f3b6e 100644 --- a/packages/sf_localizations/assets/l10n/es.json +++ b/packages/sf_localizations/assets/l10n/es.json @@ -899,6 +899,8 @@ "videocallErrorCamera": "Se requiere permiso de cámara", "videocallErrorMic": "Se requiere permiso de micrófono", "videocallErrorMissedCall": "Llamada perdida", + "videocallErrorDeviceBusy": "El dispositivo está ocupado", + "videocallDeviceRinging": "Dispositivo sonando...", "videocallCallEnded": "Llamada finalizada", "videocallGroupCall": "Videollamada grupal", "videocallDisclaimer": "*Para una llamada de video óptima, asegúrate de que tu reloj tenga datos móviles con conexión a Internet, buena cobertura o conexión wifi.", diff --git a/packages/sf_localizations/assets/l10n/fr.json b/packages/sf_localizations/assets/l10n/fr.json index 06fcad5c..8da7d346 100644 --- a/packages/sf_localizations/assets/l10n/fr.json +++ b/packages/sf_localizations/assets/l10n/fr.json @@ -711,6 +711,8 @@ "videocallErrorCamera": "Autorisation de la caméra requise", "videocallErrorMic": "Autorisation du microphone requise", "videocallErrorMissedCall": "Appel manqué", + "videocallErrorDeviceBusy": "L'appareil est occupé", + "videocallDeviceRinging": "Appareil en train de sonner...", "videocallCallEnded": "Appel terminé", "videocallGroupCall": "Appel vidéo de groupe", "videocallDisclaimer": "*Pour un appel vidéo optimal, assurez-vous que votre montre dispose de données mobiles avec connexion Internet, bonne couverture ou connexion WiFi.", diff --git a/packages/sf_localizations/assets/l10n/it.json b/packages/sf_localizations/assets/l10n/it.json index 3f5e26b2..119f5288 100644 --- a/packages/sf_localizations/assets/l10n/it.json +++ b/packages/sf_localizations/assets/l10n/it.json @@ -711,6 +711,8 @@ "videocallErrorCamera": "Permesso fotocamera richiesto", "videocallErrorMic": "Permesso microfono richiesto", "videocallErrorMissedCall": "Chiamata persa", + "videocallErrorDeviceBusy": "Il dispositivo è occupato", + "videocallDeviceRinging": "Dispositivo in chiamata...", "videocallCallEnded": "Chiamata terminata", "videocallGroupCall": "Videochiamata di gruppo", "videocallDisclaimer": "*Per una videochiamata ottimale, assicurati che il tuo orologio abbia dati mobili con connessione Internet, buona copertura o connessione WiFi.", diff --git a/packages/sf_localizations/assets/l10n/pt.json b/packages/sf_localizations/assets/l10n/pt.json index 34c4ecae..573b4ec0 100644 --- a/packages/sf_localizations/assets/l10n/pt.json +++ b/packages/sf_localizations/assets/l10n/pt.json @@ -711,6 +711,8 @@ "videocallErrorCamera": "Permissão de câmara necessária", "videocallErrorMic": "Permissão de microfone necessária", "videocallErrorMissedCall": "Chamada perdida", + "videocallErrorDeviceBusy": "O dispositivo está ocupado", + "videocallDeviceRinging": "Dispositivo a tocar...", "videocallCallEnded": "Chamada terminada", "videocallGroupCall": "Videochamada em grupo", "videocallDisclaimer": "*Para uma videochamada ideal, certifique-se de que o seu relógio tenha dados móveis com conexão à Internet, boa cobertura ou conexão WiFi.", diff --git a/packages/sf_localizations/lib/src/generated/i18n.dart b/packages/sf_localizations/lib/src/generated/i18n.dart index 1b6a2972..f6e1bf82 100755 --- a/packages/sf_localizations/lib/src/generated/i18n.dart +++ b/packages/sf_localizations/lib/src/generated/i18n.dart @@ -1032,6 +1032,8 @@ class I18n { static const String videocallErrorCamera = 'videocallErrorCamera'; static const String videocallErrorMic = 'videocallErrorMic'; static const String videocallErrorMissedCall = 'videocallErrorMissedCall'; + static const String videocallErrorDeviceBusy = 'videocallErrorDeviceBusy'; + static const String videocallDeviceRinging = 'videocallDeviceRinging'; static const String videocallErrorSdkInit = 'videocallErrorSdkInit'; static const String videocallHangUp = 'videocallHangUp'; static const String videocallIncomingAudio = 'videocallIncomingAudio';