🎨 Formatted all the code
This commit is contained in:
@ -41,7 +41,8 @@ class _ControlsWidgetState extends State<ControlsWidget> {
|
||||
void initState() {
|
||||
super.initState();
|
||||
participant.addListener(onChange);
|
||||
_subscription = Hardware.instance.onDeviceChange.stream.listen((List<MediaDevice> devices) {
|
||||
_subscription = Hardware.instance.onDeviceChange.stream
|
||||
.listen((List<MediaDevice> devices) {
|
||||
revertDevices(devices);
|
||||
});
|
||||
Hardware.instance.enumerateDevices().then(revertDevices);
|
||||
@ -161,18 +162,23 @@ class _ControlsWidgetState extends State<ControlsWidget> {
|
||||
if (!isRetry) {
|
||||
const androidConfig = FlutterBackgroundAndroidConfig(
|
||||
notificationTitle: 'Screen Sharing',
|
||||
notificationText: 'A Solar Messager\'s Call is sharing your screen',
|
||||
notificationText:
|
||||
'A Solar Messager\'s Call is sharing your screen',
|
||||
notificationImportance: AndroidNotificationImportance.Default,
|
||||
notificationIcon: AndroidResource(name: 'launcher_icon', defType: 'mipmap'),
|
||||
notificationIcon:
|
||||
AndroidResource(name: 'launcher_icon', defType: 'mipmap'),
|
||||
);
|
||||
hasPermissions = await FlutterBackground.initialize(androidConfig: androidConfig);
|
||||
hasPermissions = await FlutterBackground.initialize(
|
||||
androidConfig: androidConfig);
|
||||
}
|
||||
if (hasPermissions && !FlutterBackground.isBackgroundExecutionEnabled) {
|
||||
if (hasPermissions &&
|
||||
!FlutterBackground.isBackgroundExecutionEnabled) {
|
||||
await FlutterBackground.enableBackgroundExecution();
|
||||
}
|
||||
} catch (e) {
|
||||
if (!isRetry) {
|
||||
return await Future<void>.delayed(const Duration(seconds: 1), () => requestBackgroundPermission(true));
|
||||
return await Future<void>.delayed(const Duration(seconds: 1),
|
||||
() => requestBackgroundPermission(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -223,7 +229,8 @@ class _ControlsWidgetState extends State<ControlsWidget> {
|
||||
runSpacing: 5,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Transform.flip(flipX: true, child: const Icon(Icons.exit_to_app)),
|
||||
icon: Transform.flip(
|
||||
flipX: true, child: const Icon(Icons.exit_to_app)),
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
onPressed: disconnect,
|
||||
),
|
||||
@ -253,7 +260,8 @@ class _ControlsWidgetState extends State<ControlsWidget> {
|
||||
return PopupMenuItem<MediaDevice>(
|
||||
value: device,
|
||||
child: ListTile(
|
||||
leading: (device.deviceId == widget.room.selectedAudioInputDeviceId)
|
||||
leading: (device.deviceId ==
|
||||
widget.room.selectedAudioInputDeviceId)
|
||||
? const Icon(Icons.check_box_outlined)
|
||||
: const Icon(Icons.check_box_outline_blank),
|
||||
title: Text(device.label),
|
||||
@ -281,7 +289,8 @@ class _ControlsWidgetState extends State<ControlsWidget> {
|
||||
onTap: disableVideo,
|
||||
child: ListTile(
|
||||
leading: const Icon(Icons.videocam_off),
|
||||
title: Text(AppLocalizations.of(context)!.chatCallVideoOff),
|
||||
title:
|
||||
Text(AppLocalizations.of(context)!.chatCallVideoOff),
|
||||
),
|
||||
),
|
||||
if (_videoInputs != null)
|
||||
@ -289,7 +298,8 @@ class _ControlsWidgetState extends State<ControlsWidget> {
|
||||
return PopupMenuItem<MediaDevice>(
|
||||
value: device,
|
||||
child: ListTile(
|
||||
leading: (device.deviceId == widget.room.selectedVideoInputDeviceId)
|
||||
leading: (device.deviceId ==
|
||||
widget.room.selectedVideoInputDeviceId)
|
||||
? const Icon(Icons.check_box_outlined)
|
||||
: const Icon(Icons.check_box_outline_blank),
|
||||
title: Text(device.label),
|
||||
@ -308,7 +318,9 @@ class _ControlsWidgetState extends State<ControlsWidget> {
|
||||
tooltip: AppLocalizations.of(context)!.chatCallVideoOn,
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(position == CameraPosition.back ? Icons.video_camera_back : Icons.video_camera_front),
|
||||
icon: Icon(position == CameraPosition.back
|
||||
? Icons.video_camera_back
|
||||
: Icons.video_camera_front),
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
onPressed: () => toggleCamera(),
|
||||
tooltip: AppLocalizations.of(context)!.chatCallVideoFlip,
|
||||
@ -330,7 +342,8 @@ class _ControlsWidgetState extends State<ControlsWidget> {
|
||||
return PopupMenuItem<MediaDevice>(
|
||||
value: device,
|
||||
child: ListTile(
|
||||
leading: (device.deviceId == widget.room.selectedAudioOutputDeviceId)
|
||||
leading: (device.deviceId ==
|
||||
widget.room.selectedAudioOutputDeviceId)
|
||||
? const Icon(Icons.check_box_outlined)
|
||||
: const Icon(Icons.check_box_outline_blank),
|
||||
title: Text(device.label),
|
||||
@ -343,9 +356,12 @@ class _ControlsWidgetState extends State<ControlsWidget> {
|
||||
),
|
||||
if (!kIsWeb && lkPlatformIs(PlatformType.iOS))
|
||||
IconButton(
|
||||
onPressed: Hardware.instance.canSwitchSpeakerphone ? setSpeakerphoneOn : null,
|
||||
onPressed: Hardware.instance.canSwitchSpeakerphone
|
||||
? setSpeakerphoneOn
|
||||
: null,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
icon: Icon(_speakerphoneOn ? Icons.speaker_phone : Icons.phone_android),
|
||||
icon: Icon(
|
||||
_speakerphoneOn ? Icons.speaker_phone : Icons.phone_android),
|
||||
tooltip: AppLocalizations.of(context)!.chatCallChangeSpeaker,
|
||||
),
|
||||
if (participant.isScreenShareEnabled())
|
||||
|
@ -20,7 +20,8 @@ class NoContentWidget extends StatefulWidget {
|
||||
State<NoContentWidget> createState() => _NoContentWidgetState();
|
||||
}
|
||||
|
||||
class _NoContentWidgetState extends State<NoContentWidget> with SingleTickerProviderStateMixin {
|
||||
class _NoContentWidgetState extends State<NoContentWidget>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late final AnimationController _animationController;
|
||||
|
||||
@override
|
||||
@ -35,7 +36,9 @@ class _NoContentWidgetState extends State<NoContentWidget> with SingleTickerProv
|
||||
if (widget.isSpeaking) {
|
||||
_animationController.repeat(reverse: true);
|
||||
} else {
|
||||
_animationController.animateTo(0, duration: 300.ms).then((_) => _animationController.reset());
|
||||
_animationController
|
||||
.animateTo(0, duration: 300.ms)
|
||||
.then((_) => _animationController.reset());
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,7 +66,9 @@ class _NoContentWidgetState extends State<NoContentWidget> with SingleTickerProv
|
||||
builder: (context, value, child) => Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(radius + 8)),
|
||||
border: value > 0 ? Border.all(color: Colors.green, width: value) : null,
|
||||
border: value > 0
|
||||
? Border.all(color: Colors.green, width: value)
|
||||
: null,
|
||||
),
|
||||
child: child,
|
||||
),
|
||||
|
@ -95,7 +95,8 @@ class RemoteParticipantWidget extends ParticipantWidget {
|
||||
State<StatefulWidget> createState() => _RemoteParticipantWidgetState();
|
||||
}
|
||||
|
||||
abstract class _ParticipantWidgetState<T extends ParticipantWidget> extends State<T> {
|
||||
abstract class _ParticipantWidgetState<T extends ParticipantWidget>
|
||||
extends State<T> {
|
||||
VideoTrack? get _activeVideoTrack;
|
||||
|
||||
TrackPublication? get _firstAudioPublication;
|
||||
@ -126,7 +127,8 @@ abstract class _ParticipantWidgetState<T extends ParticipantWidget> extends Stat
|
||||
void onParticipantChanged() {
|
||||
setState(() {
|
||||
if (widget.participant.metadata != null) {
|
||||
_userinfoMetadata = Account.fromJson(jsonDecode(widget.participant.metadata!));
|
||||
_userinfoMetadata =
|
||||
Account.fromJson(jsonDecode(widget.participant.metadata!));
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -158,8 +160,11 @@ abstract class _ParticipantWidgetState<T extends ParticipantWidget> extends Stat
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ParticipantInfoWidget(
|
||||
title: widget.participant.name.isNotEmpty ? widget.participant.name : widget.participant.identity,
|
||||
audioAvailable: _firstAudioPublication?.muted == false && _firstAudioPublication?.subscribed == true,
|
||||
title: widget.participant.name.isNotEmpty
|
||||
? widget.participant.name
|
||||
: widget.participant.identity,
|
||||
audioAvailable: _firstAudioPublication?.muted == false &&
|
||||
_firstAudioPublication?.subscribed == true,
|
||||
connectionQuality: widget.participant.connectionQuality,
|
||||
isScreenShare: widget.isScreenShare,
|
||||
),
|
||||
@ -171,7 +176,8 @@ abstract class _ParticipantWidgetState<T extends ParticipantWidget> extends Stat
|
||||
}
|
||||
}
|
||||
|
||||
class _LocalParticipantWidgetState extends _ParticipantWidgetState<LocalParticipantWidget> {
|
||||
class _LocalParticipantWidgetState
|
||||
extends _ParticipantWidgetState<LocalParticipantWidget> {
|
||||
@override
|
||||
LocalTrackPublication<LocalAudioTrack>? get _firstAudioPublication =>
|
||||
widget.participant.audioTrackPublications.firstOrNull;
|
||||
@ -180,7 +186,8 @@ class _LocalParticipantWidgetState extends _ParticipantWidgetState<LocalParticip
|
||||
VideoTrack? get _activeVideoTrack => widget.videoTrack;
|
||||
}
|
||||
|
||||
class _RemoteParticipantWidgetState extends _ParticipantWidgetState<RemoteParticipantWidget> {
|
||||
class _RemoteParticipantWidgetState
|
||||
extends _ParticipantWidgetState<RemoteParticipantWidget> {
|
||||
@override
|
||||
RemoteTrackPublication<RemoteAudioTrack>? get _firstAudioPublication =>
|
||||
widget.participant.audioTrackPublications.firstOrNull;
|
||||
|
@ -55,7 +55,9 @@ class ParticipantInfoWidget extends StatelessWidget {
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 5),
|
||||
child: Icon(
|
||||
connectionQuality == ConnectionQuality.poor ? Icons.wifi_off_outlined : Icons.wifi,
|
||||
connectionQuality == ConnectionQuality.poor
|
||||
? Icons.wifi_off_outlined
|
||||
: Icons.wifi,
|
||||
color: {
|
||||
ConnectionQuality.excellent: Colors.green,
|
||||
ConnectionQuality.good: Colors.orange,
|
||||
|
@ -22,7 +22,9 @@ class ParticipantMenu extends StatefulWidget {
|
||||
|
||||
class _ParticipantMenuState extends State<ParticipantMenu> {
|
||||
RemoteTrackPublication<RemoteVideoTrack>? get _videoPublication =>
|
||||
widget.participant.videoTrackPublications.where((element) => element.sid == widget.videoTrack?.sid).firstOrNull;
|
||||
widget.participant.videoTrackPublications
|
||||
.where((element) => element.sid == widget.videoTrack?.sid)
|
||||
.firstOrNull;
|
||||
|
||||
RemoteTrackPublication<RemoteAudioTrack>? get _firstAudioPublication =>
|
||||
widget.participant.audioTrackPublications.firstOrNull;
|
||||
@ -39,7 +41,8 @@ class _ParticipantMenuState extends State<ParticipantMenu> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.only(left: 8, right: 8, top: 20, bottom: 12),
|
||||
padding:
|
||||
const EdgeInsets.only(left: 8, right: 8, top: 20, bottom: 12),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
@ -59,9 +62,14 @@ class _ParticipantMenuState extends State<ParticipantMenu> {
|
||||
leading: Icon(
|
||||
Icons.volume_up,
|
||||
color: {
|
||||
TrackSubscriptionState.notAllowed: Theme.of(context).colorScheme.error,
|
||||
TrackSubscriptionState.unsubscribed: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
||||
TrackSubscriptionState.subscribed: Theme.of(context).colorScheme.primary,
|
||||
TrackSubscriptionState.notAllowed:
|
||||
Theme.of(context).colorScheme.error,
|
||||
TrackSubscriptionState.unsubscribed: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurface
|
||||
.withOpacity(0.6),
|
||||
TrackSubscriptionState.subscribed:
|
||||
Theme.of(context).colorScheme.primary,
|
||||
}[_firstAudioPublication!.subscriptionState],
|
||||
),
|
||||
title: Text(
|
||||
@ -83,9 +91,14 @@ class _ParticipantMenuState extends State<ParticipantMenu> {
|
||||
leading: Icon(
|
||||
widget.isScreenShare ? Icons.monitor : Icons.videocam,
|
||||
color: {
|
||||
TrackSubscriptionState.notAllowed: Theme.of(context).colorScheme.error,
|
||||
TrackSubscriptionState.unsubscribed: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
||||
TrackSubscriptionState.subscribed: Theme.of(context).colorScheme.primary,
|
||||
TrackSubscriptionState.notAllowed:
|
||||
Theme.of(context).colorScheme.error,
|
||||
TrackSubscriptionState.unsubscribed: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurface
|
||||
.withOpacity(0.6),
|
||||
TrackSubscriptionState.subscribed:
|
||||
Theme.of(context).colorScheme.primary,
|
||||
}[_videoPublication!.subscriptionState],
|
||||
),
|
||||
title: Text(
|
||||
@ -107,7 +120,9 @@ class _ParticipantMenuState extends State<ParticipantMenu> {
|
||||
...[30, 15, 8].map(
|
||||
(x) => ListTile(
|
||||
leading: Icon(
|
||||
_videoPublication?.fps == x ? Icons.check_box_outlined : Icons.check_box_outline_blank,
|
||||
_videoPublication?.fps == x
|
||||
? Icons.check_box_outlined
|
||||
: Icons.check_box_outline_blank,
|
||||
),
|
||||
title: Text('Set preferred frame-per-second to $x'),
|
||||
onTap: () {
|
||||
@ -125,7 +140,9 @@ class _ParticipantMenuState extends State<ParticipantMenu> {
|
||||
].map(
|
||||
(x) => ListTile(
|
||||
leading: Icon(
|
||||
_videoPublication?.videoQuality == x.$2 ? Icons.check_box_outlined : Icons.check_box_outline_blank,
|
||||
_videoPublication?.videoQuality == x.$2
|
||||
? Icons.check_box_outlined
|
||||
: Icons.check_box_outline_blank,
|
||||
),
|
||||
title: Text('Set preferred quality to ${x.$1}'),
|
||||
onTap: () {
|
||||
|
@ -28,11 +28,14 @@ class _ParticipantStatsWidgetState extends State<ParticipantStatsWidget> {
|
||||
stats['layer-$key'] =
|
||||
'${value.frameWidth ?? 0}x${value.frameHeight ?? 0} ${value.framesPerSecond?.toDouble() ?? 0} fps, ${event.bitrateForLayers[key] ?? 0} kbps';
|
||||
});
|
||||
var firstStats = event.stats['f'] ?? event.stats['h'] ?? event.stats['q'];
|
||||
var firstStats =
|
||||
event.stats['f'] ?? event.stats['h'] ?? event.stats['q'];
|
||||
if (firstStats != null) {
|
||||
stats['encoder'] = firstStats.encoderImplementation ?? '';
|
||||
stats['video codec'] = '${firstStats.mimeType}, ${firstStats.clockRate}hz, pt: ${firstStats.payloadType}';
|
||||
stats['qualityLimitationReason'] = firstStats.qualityLimitationReason ?? '';
|
||||
stats['video codec'] =
|
||||
'${firstStats.mimeType}, ${firstStats.clockRate}hz, pt: ${firstStats.payloadType}';
|
||||
stats['qualityLimitationReason'] =
|
||||
firstStats.qualityLimitationReason ?? '';
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -41,7 +44,8 @@ class _ParticipantStatsWidgetState extends State<ParticipantStatsWidget> {
|
||||
listener.on<VideoReceiverStatsEvent>((event) {
|
||||
setState(() {
|
||||
stats['video rx'] = '${event.currentBitrate.toInt()} kpbs';
|
||||
stats['video codec'] = '${event.stats.mimeType}, ${event.stats.clockRate}hz, pt: ${event.stats.payloadType}';
|
||||
stats['video codec'] =
|
||||
'${event.stats.mimeType}, ${event.stats.clockRate}hz, pt: ${event.stats.payloadType}';
|
||||
stats['video size'] =
|
||||
'${event.stats.frameWidth}x${event.stats.frameHeight} ${event.stats.framesPerSecond?.toDouble()}fps';
|
||||
stats['video jitter'] = '${event.stats.jitter} s';
|
||||
@ -70,7 +74,8 @@ class _ParticipantStatsWidgetState extends State<ParticipantStatsWidget> {
|
||||
stats['audio codec'] =
|
||||
'${event.stats.mimeType}, ${event.stats.clockRate}hz, ${event.stats.channels}ch, pt: ${event.stats.payloadType}';
|
||||
stats['audio jitter'] = '${event.stats.jitter} s';
|
||||
stats['audio concealed samples'] = '${event.stats.concealedSamples} / ${event.stats.concealmentEvents}';
|
||||
stats['audio concealed samples'] =
|
||||
'${event.stats.concealedSamples} / ${event.stats.concealmentEvents}';
|
||||
stats['audio packets lost'] = '${event.stats.packetsLost}';
|
||||
stats['audio packets received'] = '${event.stats.packetsReceived}';
|
||||
});
|
||||
@ -83,7 +88,10 @@ class _ParticipantStatsWidgetState extends State<ParticipantStatsWidget> {
|
||||
element.dispose();
|
||||
}
|
||||
listeners.clear();
|
||||
for (var track in [...widget.participant.videoTrackPublications, ...widget.participant.audioTrackPublications]) {
|
||||
for (var track in [
|
||||
...widget.participant.videoTrackPublications,
|
||||
...widget.participant.audioTrackPublications
|
||||
]) {
|
||||
if (track.track != null) {
|
||||
_setUpListener(track.track!);
|
||||
}
|
||||
@ -117,7 +125,8 @@ class _ParticipantStatsWidgetState extends State<ParticipantStatsWidget> {
|
||||
horizontal: 8,
|
||||
),
|
||||
child: Column(
|
||||
children: stats.entries.map((e) => Text('${e.key}: ${e.value}')).toList(),
|
||||
children:
|
||||
stats.entries.map((e) => Text('${e.key}: ${e.value}')).toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -14,7 +14,8 @@ class ChannelCallAction extends StatefulWidget {
|
||||
final Channel channel;
|
||||
final Function onUpdate;
|
||||
|
||||
const ChannelCallAction({super.key, this.call, required this.channel, required this.onUpdate});
|
||||
const ChannelCallAction(
|
||||
{super.key, this.call, required this.channel, required this.onUpdate});
|
||||
|
||||
@override
|
||||
State<ChannelCallAction> createState() => _ChannelCallActionState();
|
||||
@ -32,7 +33,8 @@ class _ChannelCallActionState extends State<ChannelCallAction> {
|
||||
return;
|
||||
}
|
||||
|
||||
var uri = getRequestUri('messaging', '/api/channels/${widget.channel.alias}/calls');
|
||||
var uri = getRequestUri(
|
||||
'messaging', '/api/channels/${widget.channel.alias}/calls');
|
||||
|
||||
var res = await auth.client!.post(uri);
|
||||
if (res.statusCode != 200) {
|
||||
@ -52,7 +54,8 @@ class _ChannelCallActionState extends State<ChannelCallAction> {
|
||||
return;
|
||||
}
|
||||
|
||||
var uri = getRequestUri('messaging', '/api/channels/${widget.channel.alias}/calls/ongoing');
|
||||
var uri = getRequestUri(
|
||||
'messaging', '/api/channels/${widget.channel.alias}/calls/ongoing');
|
||||
|
||||
var res = await auth.client!.delete(uri);
|
||||
if (res.statusCode != 200) {
|
||||
@ -75,7 +78,9 @@ class _ChannelCallActionState extends State<ChannelCallAction> {
|
||||
endsCall();
|
||||
}
|
||||
},
|
||||
icon: widget.call == null ? const Icon(Icons.call) : const Icon(Icons.call_end),
|
||||
icon: widget.call == null
|
||||
? const Icon(Icons.call)
|
||||
: const Icon(Icons.call_end),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -84,7 +89,8 @@ class ChannelManageAction extends StatelessWidget {
|
||||
final Channel channel;
|
||||
final Function onUpdate;
|
||||
|
||||
const ChannelManageAction({super.key, required this.channel, required this.onUpdate});
|
||||
const ChannelManageAction(
|
||||
{super.key, required this.channel, required this.onUpdate});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -12,7 +12,8 @@ class ChannelDeletion extends StatefulWidget {
|
||||
final Channel channel;
|
||||
final bool isOwned;
|
||||
|
||||
const ChannelDeletion({super.key, required this.channel, required this.isOwned});
|
||||
const ChannelDeletion(
|
||||
{super.key, required this.channel, required this.isOwned});
|
||||
|
||||
@override
|
||||
State<ChannelDeletion> createState() => _ChannelDeletionState();
|
||||
|
@ -55,19 +55,23 @@ class _ChatMaintainerState extends State<ChatMaintainer> {
|
||||
switch (result.method) {
|
||||
case 'messages.new':
|
||||
final payload = Message.fromJson(result.payload!);
|
||||
if (payload.channelId == widget.channel.id) widget.onInsertMessage(payload);
|
||||
if (payload.channelId == widget.channel.id)
|
||||
widget.onInsertMessage(payload);
|
||||
break;
|
||||
case 'messages.update':
|
||||
final payload = Message.fromJson(result.payload!);
|
||||
if (payload.channelId == widget.channel.id) widget.onUpdateMessage(payload);
|
||||
if (payload.channelId == widget.channel.id)
|
||||
widget.onUpdateMessage(payload);
|
||||
break;
|
||||
case 'messages.burnt':
|
||||
final payload = Message.fromJson(result.payload!);
|
||||
if (payload.channelId == widget.channel.id) widget.onDeleteMessage(payload);
|
||||
if (payload.channelId == widget.channel.id)
|
||||
widget.onDeleteMessage(payload);
|
||||
break;
|
||||
case 'calls.new':
|
||||
final payload = Call.fromJson(result.payload!);
|
||||
if (payload.channelId == widget.channel.id) widget.onCallStarted(payload);
|
||||
if (payload.channelId == widget.channel.id)
|
||||
widget.onCallStarted(payload);
|
||||
break;
|
||||
case 'calls.end':
|
||||
final payload = Call.fromJson(result.payload!);
|
||||
|
@ -79,7 +79,9 @@ class ChatMessageAction extends StatelessWidget {
|
||||
|
||||
return ListView(
|
||||
children: [
|
||||
...(snapshot.data['id'] == item.sender.account.externalId ? authorizedItems : List.empty()),
|
||||
...(snapshot.data['id'] == item.sender.account.externalId
|
||||
? authorizedItems
|
||||
: List.empty()),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.reply),
|
||||
title: Text(AppLocalizations.of(context)!.reply),
|
||||
|
@ -19,7 +19,8 @@ class ChatMessageDeletionDialog extends StatefulWidget {
|
||||
});
|
||||
|
||||
@override
|
||||
State<ChatMessageDeletionDialog> createState() => _ChatMessageDeletionDialogState();
|
||||
State<ChatMessageDeletionDialog> createState() =>
|
||||
_ChatMessageDeletionDialogState();
|
||||
}
|
||||
|
||||
class _ChatMessageDeletionDialogState extends State<ChatMessageDeletionDialog> {
|
||||
@ -29,7 +30,8 @@ class _ChatMessageDeletionDialogState extends State<ChatMessageDeletionDialog> {
|
||||
final auth = context.read<AuthProvider>();
|
||||
if (!await auth.isAuthorized()) return;
|
||||
|
||||
final uri = getRequestUri('messaging', '/api/channels/${widget.channel}/messages/${widget.item.id}');
|
||||
final uri = getRequestUri('messaging',
|
||||
'/api/channels/${widget.channel}/messages/${widget.item.id}');
|
||||
|
||||
setState(() => _isSubmitting = true);
|
||||
final res = await auth.client!.delete(uri);
|
||||
|
@ -18,7 +18,12 @@ class ChatMessageEditor extends StatefulWidget {
|
||||
final Message? replying;
|
||||
final Function? onReset;
|
||||
|
||||
const ChatMessageEditor({super.key, required this.channel, this.editing, this.replying, this.onReset});
|
||||
const ChatMessageEditor(
|
||||
{super.key,
|
||||
required this.channel,
|
||||
this.editing,
|
||||
this.replying,
|
||||
this.onReset});
|
||||
|
||||
@override
|
||||
State<ChatMessageEditor> createState() => _ChatMessageEditorState();
|
||||
@ -51,7 +56,8 @@ class _ChatMessageEditorState extends State<ChatMessageEditor> {
|
||||
|
||||
final uri = widget.editing == null
|
||||
? getRequestUri('messaging', '/api/channels/${widget.channel}/messages')
|
||||
: getRequestUri('messaging', '/api/channels/${widget.channel}/messages/${widget.editing!.id}');
|
||||
: getRequestUri('messaging',
|
||||
'/api/channels/${widget.channel}/messages/${widget.editing!.id}');
|
||||
|
||||
final req = Request(widget.editing == null ? "POST" : "PUT", uri);
|
||||
req.headers['Content-Type'] = 'application/json';
|
||||
@ -84,7 +90,8 @@ class _ChatMessageEditorState extends State<ChatMessageEditor> {
|
||||
setState(() {
|
||||
_prevEditingId = widget.editing!.id;
|
||||
_textController.text = widget.editing!.content;
|
||||
_attachments = widget.editing!.attachments ?? List.empty(growable: true);
|
||||
_attachments =
|
||||
widget.editing!.attachments ?? List.empty(growable: true);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -147,11 +154,15 @@ class _ChatMessageEditorState extends State<ChatMessageEditor> {
|
||||
children: [
|
||||
badge.Badge(
|
||||
showBadge: _attachments.isNotEmpty,
|
||||
badgeContent: Text(_attachments.length.toString(), style: const TextStyle(color: Colors.white)),
|
||||
badgeContent: Text(_attachments.length.toString(),
|
||||
style: const TextStyle(color: Colors.white)),
|
||||
position: badge.BadgePosition.custom(top: -2, end: 8),
|
||||
child: TextButton(
|
||||
style: TextButton.styleFrom(shape: const CircleBorder(), padding: const EdgeInsets.all(4)),
|
||||
onPressed: !_isSubmitting ? () => viewAttachments(context) : null,
|
||||
style: TextButton.styleFrom(
|
||||
shape: const CircleBorder(),
|
||||
padding: const EdgeInsets.all(4)),
|
||||
onPressed:
|
||||
!_isSubmitting ? () => viewAttachments(context) : null,
|
||||
child: const Icon(Icons.attach_file),
|
||||
),
|
||||
),
|
||||
@ -163,14 +174,18 @@ class _ChatMessageEditorState extends State<ChatMessageEditor> {
|
||||
autocorrect: true,
|
||||
keyboardType: TextInputType.text,
|
||||
decoration: InputDecoration.collapsed(
|
||||
hintText: AppLocalizations.of(context)!.chatMessagePlaceholder,
|
||||
hintText:
|
||||
AppLocalizations.of(context)!.chatMessagePlaceholder,
|
||||
),
|
||||
onSubmitted: (_) => sendMessage(context),
|
||||
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||
onTapOutside: (_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(shape: const CircleBorder(), padding: const EdgeInsets.all(4)),
|
||||
style: TextButton.styleFrom(
|
||||
shape: const CircleBorder(),
|
||||
padding: const EdgeInsets.all(4)),
|
||||
onPressed: !_isSubmitting ? () => sendMessage(context) : null,
|
||||
child: const Icon(Icons.send),
|
||||
)
|
||||
|
Reference in New Issue
Block a user