🐛 Fixes call
This commit is contained in:
@@ -728,5 +728,8 @@
|
|||||||
"selectCamera": "Select Camera",
|
"selectCamera": "Select Camera",
|
||||||
"switchedTo": "Switched to {}",
|
"switchedTo": "Switched to {}",
|
||||||
"connecting": "Connecting",
|
"connecting": "Connecting",
|
||||||
|
"reconnecting": "Reconnecting",
|
||||||
|
"disconnected": "Disconnected",
|
||||||
|
"connected": "Connected",
|
||||||
"repliesLoadMore": "Load more replies"
|
"repliesLoadMore": "Load more replies"
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,8 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter_webrtc/flutter_webrtc.dart';
|
||||||
import 'package:island/widgets/chat/call_button.dart';
|
import 'package:island/widgets/chat/call_button.dart';
|
||||||
import 'package:livekit_client/livekit_client.dart';
|
import 'package:livekit_client/livekit_client.dart';
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
@@ -25,6 +28,7 @@ sealed class CallState with _$CallState {
|
|||||||
required bool isMicrophoneEnabled,
|
required bool isMicrophoneEnabled,
|
||||||
required bool isCameraEnabled,
|
required bool isCameraEnabled,
|
||||||
required bool isScreenSharing,
|
required bool isScreenSharing,
|
||||||
|
required bool isSpeakerphone,
|
||||||
@Default(Duration(seconds: 0)) Duration duration,
|
@Default(Duration(seconds: 0)) Duration duration,
|
||||||
String? error,
|
String? error,
|
||||||
}) = _CallState;
|
}) = _CallState;
|
||||||
@@ -62,6 +66,8 @@ class CallNotifier extends _$CallNotifier {
|
|||||||
List.unmodifiable(_participants);
|
List.unmodifiable(_participants);
|
||||||
LocalParticipant? get localParticipant => _localParticipant;
|
LocalParticipant? get localParticipant => _localParticipant;
|
||||||
|
|
||||||
|
Map<String, double> participantsVolumes = {};
|
||||||
|
|
||||||
Timer? _durationTimer;
|
Timer? _durationTimer;
|
||||||
|
|
||||||
Room? get room => _room;
|
Room? get room => _room;
|
||||||
@@ -74,6 +80,7 @@ class CallNotifier extends _$CallNotifier {
|
|||||||
isMicrophoneEnabled: true,
|
isMicrophoneEnabled: true,
|
||||||
isCameraEnabled: false,
|
isCameraEnabled: false,
|
||||||
isScreenSharing: false,
|
isScreenSharing: false,
|
||||||
|
isSpeakerphone: true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,6 +271,10 @@ class CallNotifier extends _$CallNotifier {
|
|||||||
_initRoomListeners();
|
_initRoomListeners();
|
||||||
_updateLiveParticipants(participants);
|
_updateLiveParticipants(participants);
|
||||||
|
|
||||||
|
if (!kIsWeb && (Platform.isIOS || Platform.isAndroid)) {
|
||||||
|
Hardware.instance.setSpeakerphoneOn(true);
|
||||||
|
}
|
||||||
|
|
||||||
// Listen for connection updates
|
// Listen for connection updates
|
||||||
_room!.addListener(() {
|
_room!.addListener(() {
|
||||||
state = state.copyWith(
|
state = state.copyWith(
|
||||||
@@ -318,6 +329,12 @@ class CallNotifier extends _$CallNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> toggleSpeakerphone() async {
|
||||||
|
state = state.copyWith(isSpeakerphone: !state.isSpeakerphone);
|
||||||
|
await Hardware.instance.setSpeakerphoneOn(state.isSpeakerphone);
|
||||||
|
state = state.copyWith();
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> disconnect() async {
|
Future<void> disconnect() async {
|
||||||
if (_room != null) {
|
if (_room != null) {
|
||||||
await _room!.disconnect();
|
await _room!.disconnect();
|
||||||
@@ -330,6 +347,26 @@ class CallNotifier extends _$CallNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setParticipantVolume(CallParticipantLive live, double volume) {
|
||||||
|
if (participantsVolumes[live.remoteParticipant.sid] == null) {
|
||||||
|
participantsVolumes[live.remoteParticipant.sid] = 1;
|
||||||
|
}
|
||||||
|
Helper.setVolume(
|
||||||
|
volume,
|
||||||
|
live
|
||||||
|
.remoteParticipant
|
||||||
|
.audioTrackPublications
|
||||||
|
.first
|
||||||
|
.track!
|
||||||
|
.mediaStreamTrack,
|
||||||
|
);
|
||||||
|
participantsVolumes[live.remoteParticipant.sid] = volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
double getParticipantVolume(CallParticipantLive live) {
|
||||||
|
return participantsVolumes[live.remoteParticipant.sid] ?? 1;
|
||||||
|
}
|
||||||
|
|
||||||
void dispose() {
|
void dispose() {
|
||||||
state = state.copyWith(
|
state = state.copyWith(
|
||||||
error: null,
|
error: null,
|
||||||
@@ -343,5 +380,6 @@ class CallNotifier extends _$CallNotifier {
|
|||||||
_room?.dispose();
|
_room?.dispose();
|
||||||
_durationTimer?.cancel();
|
_durationTimer?.cancel();
|
||||||
_roomId = null;
|
_roomId = null;
|
||||||
|
participantsVolumes = {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -12,9 +12,9 @@ part of 'call.dart';
|
|||||||
// dart format off
|
// dart format off
|
||||||
T _$identity<T>(T value) => value;
|
T _$identity<T>(T value) => value;
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
mixin _$CallState {
|
mixin _$CallState implements DiagnosticableTreeMixin {
|
||||||
|
|
||||||
bool get isConnected; bool get isMicrophoneEnabled; bool get isCameraEnabled; bool get isScreenSharing; Duration get duration; String? get error;
|
bool get isConnected; bool get isMicrophoneEnabled; bool get isCameraEnabled; bool get isScreenSharing; bool get isSpeakerphone; Duration get duration; String? get error;
|
||||||
/// Create a copy of CallState
|
/// Create a copy of CallState
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@@ -22,19 +22,25 @@ mixin _$CallState {
|
|||||||
$CallStateCopyWith<CallState> get copyWith => _$CallStateCopyWithImpl<CallState>(this as CallState, _$identity);
|
$CallStateCopyWith<CallState> get copyWith => _$CallStateCopyWithImpl<CallState>(this as CallState, _$identity);
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||||
|
properties
|
||||||
|
..add(DiagnosticsProperty('type', 'CallState'))
|
||||||
|
..add(DiagnosticsProperty('isConnected', isConnected))..add(DiagnosticsProperty('isMicrophoneEnabled', isMicrophoneEnabled))..add(DiagnosticsProperty('isCameraEnabled', isCameraEnabled))..add(DiagnosticsProperty('isScreenSharing', isScreenSharing))..add(DiagnosticsProperty('isSpeakerphone', isSpeakerphone))..add(DiagnosticsProperty('duration', duration))..add(DiagnosticsProperty('error', error));
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is CallState&&(identical(other.isConnected, isConnected) || other.isConnected == isConnected)&&(identical(other.isMicrophoneEnabled, isMicrophoneEnabled) || other.isMicrophoneEnabled == isMicrophoneEnabled)&&(identical(other.isCameraEnabled, isCameraEnabled) || other.isCameraEnabled == isCameraEnabled)&&(identical(other.isScreenSharing, isScreenSharing) || other.isScreenSharing == isScreenSharing)&&(identical(other.duration, duration) || other.duration == duration)&&(identical(other.error, error) || other.error == error));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is CallState&&(identical(other.isConnected, isConnected) || other.isConnected == isConnected)&&(identical(other.isMicrophoneEnabled, isMicrophoneEnabled) || other.isMicrophoneEnabled == isMicrophoneEnabled)&&(identical(other.isCameraEnabled, isCameraEnabled) || other.isCameraEnabled == isCameraEnabled)&&(identical(other.isScreenSharing, isScreenSharing) || other.isScreenSharing == isScreenSharing)&&(identical(other.isSpeakerphone, isSpeakerphone) || other.isSpeakerphone == isSpeakerphone)&&(identical(other.duration, duration) || other.duration == duration)&&(identical(other.error, error) || other.error == error));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType,isConnected,isMicrophoneEnabled,isCameraEnabled,isScreenSharing,duration,error);
|
int get hashCode => Object.hash(runtimeType,isConnected,isMicrophoneEnabled,isCameraEnabled,isScreenSharing,isSpeakerphone,duration,error);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString({ DiagnosticLevel minLevel = DiagnosticLevel.info }) {
|
||||||
return 'CallState(isConnected: $isConnected, isMicrophoneEnabled: $isMicrophoneEnabled, isCameraEnabled: $isCameraEnabled, isScreenSharing: $isScreenSharing, duration: $duration, error: $error)';
|
return 'CallState(isConnected: $isConnected, isMicrophoneEnabled: $isMicrophoneEnabled, isCameraEnabled: $isCameraEnabled, isScreenSharing: $isScreenSharing, isSpeakerphone: $isSpeakerphone, duration: $duration, error: $error)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -45,7 +51,7 @@ abstract mixin class $CallStateCopyWith<$Res> {
|
|||||||
factory $CallStateCopyWith(CallState value, $Res Function(CallState) _then) = _$CallStateCopyWithImpl;
|
factory $CallStateCopyWith(CallState value, $Res Function(CallState) _then) = _$CallStateCopyWithImpl;
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, Duration duration, String? error
|
bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, bool isSpeakerphone, Duration duration, String? error
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -62,12 +68,13 @@ class _$CallStateCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of CallState
|
/// Create a copy of CallState
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline') @override $Res call({Object? isConnected = null,Object? isMicrophoneEnabled = null,Object? isCameraEnabled = null,Object? isScreenSharing = null,Object? duration = null,Object? error = freezed,}) {
|
@pragma('vm:prefer-inline') @override $Res call({Object? isConnected = null,Object? isMicrophoneEnabled = null,Object? isCameraEnabled = null,Object? isScreenSharing = null,Object? isSpeakerphone = null,Object? duration = null,Object? error = freezed,}) {
|
||||||
return _then(_self.copyWith(
|
return _then(_self.copyWith(
|
||||||
isConnected: null == isConnected ? _self.isConnected : isConnected // ignore: cast_nullable_to_non_nullable
|
isConnected: null == isConnected ? _self.isConnected : isConnected // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,isMicrophoneEnabled: null == isMicrophoneEnabled ? _self.isMicrophoneEnabled : isMicrophoneEnabled // ignore: cast_nullable_to_non_nullable
|
as bool,isMicrophoneEnabled: null == isMicrophoneEnabled ? _self.isMicrophoneEnabled : isMicrophoneEnabled // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,isCameraEnabled: null == isCameraEnabled ? _self.isCameraEnabled : isCameraEnabled // ignore: cast_nullable_to_non_nullable
|
as bool,isCameraEnabled: null == isCameraEnabled ? _self.isCameraEnabled : isCameraEnabled // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,isScreenSharing: null == isScreenSharing ? _self.isScreenSharing : isScreenSharing // ignore: cast_nullable_to_non_nullable
|
as bool,isScreenSharing: null == isScreenSharing ? _self.isScreenSharing : isScreenSharing // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,isSpeakerphone: null == isSpeakerphone ? _self.isSpeakerphone : isSpeakerphone // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,duration: null == duration ? _self.duration : duration // ignore: cast_nullable_to_non_nullable
|
as bool,duration: null == duration ? _self.duration : duration // ignore: cast_nullable_to_non_nullable
|
||||||
as Duration,error: freezed == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
|
as Duration,error: freezed == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,
|
as String?,
|
||||||
@@ -152,10 +159,10 @@ return $default(_that);case _:
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, Duration duration, String? error)? $default,{required TResult orElse(),}) {final _that = this;
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, bool isSpeakerphone, Duration duration, String? error)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _CallState() when $default != null:
|
case _CallState() when $default != null:
|
||||||
return $default(_that.isConnected,_that.isMicrophoneEnabled,_that.isCameraEnabled,_that.isScreenSharing,_that.duration,_that.error);case _:
|
return $default(_that.isConnected,_that.isMicrophoneEnabled,_that.isCameraEnabled,_that.isScreenSharing,_that.isSpeakerphone,_that.duration,_that.error);case _:
|
||||||
return orElse();
|
return orElse();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -173,10 +180,10 @@ return $default(_that.isConnected,_that.isMicrophoneEnabled,_that.isCameraEnable
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, Duration duration, String? error) $default,) {final _that = this;
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, bool isSpeakerphone, Duration duration, String? error) $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _CallState():
|
case _CallState():
|
||||||
return $default(_that.isConnected,_that.isMicrophoneEnabled,_that.isCameraEnabled,_that.isScreenSharing,_that.duration,_that.error);}
|
return $default(_that.isConnected,_that.isMicrophoneEnabled,_that.isCameraEnabled,_that.isScreenSharing,_that.isSpeakerphone,_that.duration,_that.error);}
|
||||||
}
|
}
|
||||||
/// A variant of `when` that fallback to returning `null`
|
/// A variant of `when` that fallback to returning `null`
|
||||||
///
|
///
|
||||||
@@ -190,10 +197,10 @@ return $default(_that.isConnected,_that.isMicrophoneEnabled,_that.isCameraEnable
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, Duration duration, String? error)? $default,) {final _that = this;
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, bool isSpeakerphone, Duration duration, String? error)? $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _CallState() when $default != null:
|
case _CallState() when $default != null:
|
||||||
return $default(_that.isConnected,_that.isMicrophoneEnabled,_that.isCameraEnabled,_that.isScreenSharing,_that.duration,_that.error);case _:
|
return $default(_that.isConnected,_that.isMicrophoneEnabled,_that.isCameraEnabled,_that.isScreenSharing,_that.isSpeakerphone,_that.duration,_that.error);case _:
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -204,14 +211,15 @@ return $default(_that.isConnected,_that.isMicrophoneEnabled,_that.isCameraEnable
|
|||||||
/// @nodoc
|
/// @nodoc
|
||||||
|
|
||||||
|
|
||||||
class _CallState implements CallState {
|
class _CallState with DiagnosticableTreeMixin implements CallState {
|
||||||
const _CallState({required this.isConnected, required this.isMicrophoneEnabled, required this.isCameraEnabled, required this.isScreenSharing, this.duration = const Duration(seconds: 0), this.error});
|
const _CallState({required this.isConnected, required this.isMicrophoneEnabled, required this.isCameraEnabled, required this.isScreenSharing, required this.isSpeakerphone, this.duration = const Duration(seconds: 0), this.error});
|
||||||
|
|
||||||
|
|
||||||
@override final bool isConnected;
|
@override final bool isConnected;
|
||||||
@override final bool isMicrophoneEnabled;
|
@override final bool isMicrophoneEnabled;
|
||||||
@override final bool isCameraEnabled;
|
@override final bool isCameraEnabled;
|
||||||
@override final bool isScreenSharing;
|
@override final bool isScreenSharing;
|
||||||
|
@override final bool isSpeakerphone;
|
||||||
@override@JsonKey() final Duration duration;
|
@override@JsonKey() final Duration duration;
|
||||||
@override final String? error;
|
@override final String? error;
|
||||||
|
|
||||||
@@ -222,19 +230,25 @@ class _CallState implements CallState {
|
|||||||
_$CallStateCopyWith<_CallState> get copyWith => __$CallStateCopyWithImpl<_CallState>(this, _$identity);
|
_$CallStateCopyWith<_CallState> get copyWith => __$CallStateCopyWithImpl<_CallState>(this, _$identity);
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||||
|
properties
|
||||||
|
..add(DiagnosticsProperty('type', 'CallState'))
|
||||||
|
..add(DiagnosticsProperty('isConnected', isConnected))..add(DiagnosticsProperty('isMicrophoneEnabled', isMicrophoneEnabled))..add(DiagnosticsProperty('isCameraEnabled', isCameraEnabled))..add(DiagnosticsProperty('isScreenSharing', isScreenSharing))..add(DiagnosticsProperty('isSpeakerphone', isSpeakerphone))..add(DiagnosticsProperty('duration', duration))..add(DiagnosticsProperty('error', error));
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _CallState&&(identical(other.isConnected, isConnected) || other.isConnected == isConnected)&&(identical(other.isMicrophoneEnabled, isMicrophoneEnabled) || other.isMicrophoneEnabled == isMicrophoneEnabled)&&(identical(other.isCameraEnabled, isCameraEnabled) || other.isCameraEnabled == isCameraEnabled)&&(identical(other.isScreenSharing, isScreenSharing) || other.isScreenSharing == isScreenSharing)&&(identical(other.duration, duration) || other.duration == duration)&&(identical(other.error, error) || other.error == error));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is _CallState&&(identical(other.isConnected, isConnected) || other.isConnected == isConnected)&&(identical(other.isMicrophoneEnabled, isMicrophoneEnabled) || other.isMicrophoneEnabled == isMicrophoneEnabled)&&(identical(other.isCameraEnabled, isCameraEnabled) || other.isCameraEnabled == isCameraEnabled)&&(identical(other.isScreenSharing, isScreenSharing) || other.isScreenSharing == isScreenSharing)&&(identical(other.isSpeakerphone, isSpeakerphone) || other.isSpeakerphone == isSpeakerphone)&&(identical(other.duration, duration) || other.duration == duration)&&(identical(other.error, error) || other.error == error));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType,isConnected,isMicrophoneEnabled,isCameraEnabled,isScreenSharing,duration,error);
|
int get hashCode => Object.hash(runtimeType,isConnected,isMicrophoneEnabled,isCameraEnabled,isScreenSharing,isSpeakerphone,duration,error);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString({ DiagnosticLevel minLevel = DiagnosticLevel.info }) {
|
||||||
return 'CallState(isConnected: $isConnected, isMicrophoneEnabled: $isMicrophoneEnabled, isCameraEnabled: $isCameraEnabled, isScreenSharing: $isScreenSharing, duration: $duration, error: $error)';
|
return 'CallState(isConnected: $isConnected, isMicrophoneEnabled: $isMicrophoneEnabled, isCameraEnabled: $isCameraEnabled, isScreenSharing: $isScreenSharing, isSpeakerphone: $isSpeakerphone, duration: $duration, error: $error)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -245,7 +259,7 @@ abstract mixin class _$CallStateCopyWith<$Res> implements $CallStateCopyWith<$Re
|
|||||||
factory _$CallStateCopyWith(_CallState value, $Res Function(_CallState) _then) = __$CallStateCopyWithImpl;
|
factory _$CallStateCopyWith(_CallState value, $Res Function(_CallState) _then) = __$CallStateCopyWithImpl;
|
||||||
@override @useResult
|
@override @useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, Duration duration, String? error
|
bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, bool isSpeakerphone, Duration duration, String? error
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -262,12 +276,13 @@ class __$CallStateCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of CallState
|
/// Create a copy of CallState
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override @pragma('vm:prefer-inline') $Res call({Object? isConnected = null,Object? isMicrophoneEnabled = null,Object? isCameraEnabled = null,Object? isScreenSharing = null,Object? duration = null,Object? error = freezed,}) {
|
@override @pragma('vm:prefer-inline') $Res call({Object? isConnected = null,Object? isMicrophoneEnabled = null,Object? isCameraEnabled = null,Object? isScreenSharing = null,Object? isSpeakerphone = null,Object? duration = null,Object? error = freezed,}) {
|
||||||
return _then(_CallState(
|
return _then(_CallState(
|
||||||
isConnected: null == isConnected ? _self.isConnected : isConnected // ignore: cast_nullable_to_non_nullable
|
isConnected: null == isConnected ? _self.isConnected : isConnected // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,isMicrophoneEnabled: null == isMicrophoneEnabled ? _self.isMicrophoneEnabled : isMicrophoneEnabled // ignore: cast_nullable_to_non_nullable
|
as bool,isMicrophoneEnabled: null == isMicrophoneEnabled ? _self.isMicrophoneEnabled : isMicrophoneEnabled // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,isCameraEnabled: null == isCameraEnabled ? _self.isCameraEnabled : isCameraEnabled // ignore: cast_nullable_to_non_nullable
|
as bool,isCameraEnabled: null == isCameraEnabled ? _self.isCameraEnabled : isCameraEnabled // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,isScreenSharing: null == isScreenSharing ? _self.isScreenSharing : isScreenSharing // ignore: cast_nullable_to_non_nullable
|
as bool,isScreenSharing: null == isScreenSharing ? _self.isScreenSharing : isScreenSharing // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,isSpeakerphone: null == isSpeakerphone ? _self.isSpeakerphone : isSpeakerphone // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,duration: null == duration ? _self.duration : duration // ignore: cast_nullable_to_non_nullable
|
as bool,duration: null == duration ? _self.duration : duration // ignore: cast_nullable_to_non_nullable
|
||||||
as Duration,error: freezed == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
|
as Duration,error: freezed == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,
|
as String?,
|
||||||
@@ -278,7 +293,7 @@ as String?,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
mixin _$CallParticipantLive {
|
mixin _$CallParticipantLive implements DiagnosticableTreeMixin {
|
||||||
|
|
||||||
CallParticipant get participant; Participant get remoteParticipant;
|
CallParticipant get participant; Participant get remoteParticipant;
|
||||||
/// Create a copy of CallParticipantLive
|
/// Create a copy of CallParticipantLive
|
||||||
@@ -288,6 +303,12 @@ mixin _$CallParticipantLive {
|
|||||||
$CallParticipantLiveCopyWith<CallParticipantLive> get copyWith => _$CallParticipantLiveCopyWithImpl<CallParticipantLive>(this as CallParticipantLive, _$identity);
|
$CallParticipantLiveCopyWith<CallParticipantLive> get copyWith => _$CallParticipantLiveCopyWithImpl<CallParticipantLive>(this as CallParticipantLive, _$identity);
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||||
|
properties
|
||||||
|
..add(DiagnosticsProperty('type', 'CallParticipantLive'))
|
||||||
|
..add(DiagnosticsProperty('participant', participant))..add(DiagnosticsProperty('remoteParticipant', remoteParticipant));
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
@@ -299,7 +320,7 @@ bool operator ==(Object other) {
|
|||||||
int get hashCode => Object.hash(runtimeType,participant,remoteParticipant);
|
int get hashCode => Object.hash(runtimeType,participant,remoteParticipant);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString({ DiagnosticLevel minLevel = DiagnosticLevel.info }) {
|
||||||
return 'CallParticipantLive(participant: $participant, remoteParticipant: $remoteParticipant)';
|
return 'CallParticipantLive(participant: $participant, remoteParticipant: $remoteParticipant)';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -475,7 +496,7 @@ return $default(_that.participant,_that.remoteParticipant);case _:
|
|||||||
/// @nodoc
|
/// @nodoc
|
||||||
|
|
||||||
|
|
||||||
class _CallParticipantLive extends CallParticipantLive {
|
class _CallParticipantLive extends CallParticipantLive with DiagnosticableTreeMixin {
|
||||||
const _CallParticipantLive({required this.participant, required this.remoteParticipant}): super._();
|
const _CallParticipantLive({required this.participant, required this.remoteParticipant}): super._();
|
||||||
|
|
||||||
|
|
||||||
@@ -489,6 +510,12 @@ class _CallParticipantLive extends CallParticipantLive {
|
|||||||
_$CallParticipantLiveCopyWith<_CallParticipantLive> get copyWith => __$CallParticipantLiveCopyWithImpl<_CallParticipantLive>(this, _$identity);
|
_$CallParticipantLiveCopyWith<_CallParticipantLive> get copyWith => __$CallParticipantLiveCopyWithImpl<_CallParticipantLive>(this, _$identity);
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||||
|
properties
|
||||||
|
..add(DiagnosticsProperty('type', 'CallParticipantLive'))
|
||||||
|
..add(DiagnosticsProperty('participant', participant))..add(DiagnosticsProperty('remoteParticipant', remoteParticipant));
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
@@ -500,7 +527,7 @@ bool operator ==(Object other) {
|
|||||||
int get hashCode => Object.hash(runtimeType,participant,remoteParticipant);
|
int get hashCode => Object.hash(runtimeType,participant,remoteParticipant);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString({ DiagnosticLevel minLevel = DiagnosticLevel.info }) {
|
||||||
return 'CallParticipantLive(participant: $participant, remoteParticipant: $remoteParticipant)';
|
return 'CallParticipantLive(participant: $participant, remoteParticipant: $remoteParticipant)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -6,7 +6,7 @@ part of 'call.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$callNotifierHash() => r'a67ff053d69b2edbbb13c7c865f8adc3b77c4e86';
|
String _$callNotifierHash() => r'333a1cd566a339644c83932e15dae03f1c5cc24b';
|
||||||
|
|
||||||
/// See also [CallNotifier].
|
/// See also [CallNotifier].
|
||||||
@ProviderFor(CallNotifier)
|
@ProviderFor(CallNotifier)
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart' hide ConnectionState;
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
@@ -68,7 +68,12 @@ class CallScreen extends HookConsumerWidget {
|
|||||||
Text(
|
Text(
|
||||||
callState.isConnected
|
callState.isConnected
|
||||||
? formatDuration(callState.duration)
|
? formatDuration(callState.duration)
|
||||||
: 'connecting',
|
: (switch (callNotifier.room?.connectionState) {
|
||||||
|
ConnectionState.connected => 'connected',
|
||||||
|
ConnectionState.connecting => 'connecting',
|
||||||
|
ConnectionState.reconnecting => 'reconnecting',
|
||||||
|
_ => 'disconnected',
|
||||||
|
}).tr(),
|
||||||
style: const TextStyle(fontSize: 14),
|
style: const TextStyle(fontSize: 14),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@@ -22,8 +22,10 @@ class CallControlsBar extends HookConsumerWidget {
|
|||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16),
|
||||||
child: Row(
|
child: Wrap(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
alignment: WrapAlignment.center,
|
||||||
|
runSpacing: 16,
|
||||||
|
spacing: 16,
|
||||||
children: [
|
children: [
|
||||||
_buildCircularButtonWithDropdown(
|
_buildCircularButtonWithDropdown(
|
||||||
context: context,
|
context: context,
|
||||||
@@ -35,7 +37,6 @@ class CallControlsBar extends HookConsumerWidget {
|
|||||||
hasDropdown: true,
|
hasDropdown: true,
|
||||||
deviceType: 'videoinput',
|
deviceType: 'videoinput',
|
||||||
),
|
),
|
||||||
const Gap(16),
|
|
||||||
_buildCircularButton(
|
_buildCircularButton(
|
||||||
icon:
|
icon:
|
||||||
callState.isScreenSharing
|
callState.isScreenSharing
|
||||||
@@ -44,7 +45,6 @@ class CallControlsBar extends HookConsumerWidget {
|
|||||||
onPressed: () => callNotifier.toggleScreenShare(),
|
onPressed: () => callNotifier.toggleScreenShare(),
|
||||||
backgroundColor: const Color(0xFF424242),
|
backgroundColor: const Color(0xFF424242),
|
||||||
),
|
),
|
||||||
const Gap(16),
|
|
||||||
_buildCircularButtonWithDropdown(
|
_buildCircularButtonWithDropdown(
|
||||||
context: context,
|
context: context,
|
||||||
ref: ref,
|
ref: ref,
|
||||||
@@ -54,7 +54,14 @@ class CallControlsBar extends HookConsumerWidget {
|
|||||||
hasDropdown: true,
|
hasDropdown: true,
|
||||||
deviceType: 'audioinput',
|
deviceType: 'audioinput',
|
||||||
),
|
),
|
||||||
const Gap(16),
|
_buildCircularButton(
|
||||||
|
icon:
|
||||||
|
callState.isSpeakerphone
|
||||||
|
? Symbols.mobile_speaker
|
||||||
|
: Symbols.ear_sound,
|
||||||
|
onPressed: () => callNotifier.toggleSpeakerphone(),
|
||||||
|
backgroundColor: const Color(0xFF424242),
|
||||||
|
),
|
||||||
_buildCircularButton(
|
_buildCircularButton(
|
||||||
icon: Icons.call_end,
|
icon: Icons.call_end,
|
||||||
onPressed:
|
onPressed:
|
||||||
@@ -259,24 +266,14 @@ class CallControlsBar extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
showSnackBar(
|
||||||
SnackBar(
|
'switchedTo'.tr(
|
||||||
content: Text(
|
args: [device.label.isNotEmpty ? device.label : 'device'],
|
||||||
'${'switchedTo'.tr()} ${device.label.isNotEmpty ? device.label : 'selectedDevice'.tr()}',
|
|
||||||
),
|
|
||||||
backgroundColor: Colors.green,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
if (context.mounted) {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text('${'failedToSwitchDevice'.tr()}: $e'),
|
|
||||||
backgroundColor: Colors.red,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
showErrorAlert(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:flutter_popup_card/flutter_popup_card.dart';
|
import 'package:flutter_popup_card/flutter_popup_card.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
@@ -18,6 +19,10 @@ class CallParticipantCard extends HookConsumerWidget {
|
|||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final width =
|
final width =
|
||||||
math.min(MediaQuery.of(context).size.width - 80, 360).toDouble();
|
math.min(MediaQuery.of(context).size.width - 80, 360).toDouble();
|
||||||
|
final callNotifier = ref.watch(callNotifierProvider.notifier);
|
||||||
|
|
||||||
|
final volumeSliderValue = useState(callNotifier.getParticipantVolume(live));
|
||||||
|
|
||||||
return PopupCard(
|
return PopupCard(
|
||||||
elevation: 8,
|
elevation: 8,
|
||||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.0)),
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.0)),
|
||||||
@@ -28,7 +33,31 @@ class CallParticipantCard extends HookConsumerWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
Column(
|
Column(
|
||||||
|
spacing: 4,
|
||||||
children: [
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
const Icon(Symbols.sound_detection_loud_sound, size: 16),
|
||||||
|
const Gap(8),
|
||||||
|
Expanded(
|
||||||
|
child: Slider(
|
||||||
|
value: volumeSliderValue.value,
|
||||||
|
onChanged: (value) {
|
||||||
|
volumeSliderValue.value = value;
|
||||||
|
},
|
||||||
|
onChangeEnd: (value) {
|
||||||
|
callNotifier.setParticipantVolume(live, value);
|
||||||
|
},
|
||||||
|
year2023: true,
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Gap(8),
|
||||||
|
Text(
|
||||||
|
'${(volumeSliderValue.value * 100).toStringAsFixed(0)}%',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Symbols.wifi, size: 16),
|
const Icon(Symbols.wifi, size: 16),
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/file.dart';
|
import 'package:island/models/file.dart';
|
||||||
import 'package:island/pods/config.dart';
|
import 'package:island/pods/config.dart';
|
||||||
|
@@ -81,7 +81,10 @@ class MarkdownTextContent extends HookConsumerWidget {
|
|||||||
if (url != null) {
|
if (url != null) {
|
||||||
if (url.scheme == 'solian') {
|
if (url.scheme == 'solian') {
|
||||||
if (url.host == 'account') {
|
if (url.host == 'account') {
|
||||||
context.pushNamed('accountProfile', pathParameters: {'name': url.pathSegments[0]});
|
context.pushNamed(
|
||||||
|
'accountProfile',
|
||||||
|
pathParameters: {'name': url.pathSegments[0]},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -153,7 +156,7 @@ class MarkdownTextContent extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
child: UniversalImage(
|
child: UniversalImage(
|
||||||
uri:
|
uri:
|
||||||
'$baseUrl/stickers/lookup/${uri.pathSegments[0]}/open',
|
'$baseUrl/sphere/stickers/lookup/${uri.pathSegments[0]}/open',
|
||||||
width: size,
|
width: size,
|
||||||
height: size,
|
height: size,
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
|
Reference in New Issue
Block a user