🐛 Bug fixes
This commit is contained in:
		| @@ -5,6 +5,8 @@ PODS: | |||||||
|   - device_info_plus (0.0.1): |   - device_info_plus (0.0.1): | ||||||
|     - Flutter |     - Flutter | ||||||
|   - Flutter (1.0.0) |   - Flutter (1.0.0) | ||||||
|  |   - flutter_local_notifications (0.0.1): | ||||||
|  |     - Flutter | ||||||
|   - flutter_secure_storage (6.0.0): |   - flutter_secure_storage (6.0.0): | ||||||
|     - Flutter |     - Flutter | ||||||
|   - flutter_webrtc (0.9.36): |   - flutter_webrtc (0.9.36): | ||||||
| @@ -44,6 +46,7 @@ DEPENDENCIES: | |||||||
|   - connectivity_plus (from `.symlinks/plugins/connectivity_plus/darwin`) |   - connectivity_plus (from `.symlinks/plugins/connectivity_plus/darwin`) | ||||||
|   - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) |   - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) | ||||||
|   - Flutter (from `Flutter`) |   - Flutter (from `Flutter`) | ||||||
|  |   - flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`) | ||||||
|   - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) |   - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) | ||||||
|   - flutter_webrtc (from `.symlinks/plugins/flutter_webrtc/ios`) |   - flutter_webrtc (from `.symlinks/plugins/flutter_webrtc/ios`) | ||||||
|   - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) |   - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) | ||||||
| @@ -71,6 +74,8 @@ EXTERNAL SOURCES: | |||||||
|     :path: ".symlinks/plugins/device_info_plus/ios" |     :path: ".symlinks/plugins/device_info_plus/ios" | ||||||
|   Flutter: |   Flutter: | ||||||
|     :path: Flutter |     :path: Flutter | ||||||
|  |   flutter_local_notifications: | ||||||
|  |     :path: ".symlinks/plugins/flutter_local_notifications/ios" | ||||||
|   flutter_secure_storage: |   flutter_secure_storage: | ||||||
|     :path: ".symlinks/plugins/flutter_secure_storage/ios" |     :path: ".symlinks/plugins/flutter_secure_storage/ios" | ||||||
|   flutter_webrtc: |   flutter_webrtc: | ||||||
| @@ -106,6 +111,7 @@ SPEC CHECKSUMS: | |||||||
|   connectivity_plus: ddd7f30999e1faaef5967c23d5b6d503d10434db |   connectivity_plus: ddd7f30999e1faaef5967c23d5b6d503d10434db | ||||||
|   device_info_plus: 97af1d7e84681a90d0693e63169a5d50e0839a0d |   device_info_plus: 97af1d7e84681a90d0693e63169a5d50e0839a0d | ||||||
|   Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 |   Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 | ||||||
|  |   flutter_local_notifications: 4cde75091f6327eb8517fa068a0a5950212d2086 | ||||||
|   flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be |   flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be | ||||||
|   flutter_webrtc: 9bc044b0b5bcaabd0fb7d52c90421fb540f8c35e |   flutter_webrtc: 9bc044b0b5bcaabd0fb7d52c90421fb540f8c35e | ||||||
|   image_picker_ios: b545a5f16c0fa88e3ecbbce3ed4de45567a8ec18 |   image_picker_ios: b545a5f16c0fa88e3ecbbce3ed4de45567a8ec18 | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| { | { | ||||||
|   "solian": "Solian", |   "appName": "Solar Network", | ||||||
|   "explore": "Explore", |   "explore": "Explore", | ||||||
|   "chat": "Chat", |   "chat": "Chat", | ||||||
|   "account": "Account", |   "account": "Account", | ||||||
| @@ -28,6 +28,7 @@ | |||||||
|   "report": "Report", |   "report": "Report", | ||||||
|   "reply": "Reply", |   "reply": "Reply", | ||||||
|   "settings": "Settings", |   "settings": "Settings", | ||||||
|  |   "errorHappened": "An Error Occurred", | ||||||
|   "notification": "Notification", |   "notification": "Notification", | ||||||
|   "notifyDone": "You're done!", |   "notifyDone": "You're done!", | ||||||
|   "notifyDoneCaption": "There are no notifications unread for you.", |   "notifyDoneCaption": "There are no notifications unread for you.", | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| { | { | ||||||
|   "solian": "索链", |   "appName": "Solar", | ||||||
|   "explore": "探索", |   "explore": "探索", | ||||||
|   "chat": "聊天", |   "chat": "聊天", | ||||||
|   "account": "账号", |   "account": "账号", | ||||||
| @@ -28,6 +28,7 @@ | |||||||
|   "report": "举报", |   "report": "举报", | ||||||
|   "reply": "回复", |   "reply": "回复", | ||||||
|   "settings": "设置", |   "settings": "设置", | ||||||
|  |   "errorHappened": "发生了错误", | ||||||
|   "notification": "通知", |   "notification": "通知", | ||||||
|   "notifyDone": "所有通知已读!", |   "notifyDone": "所有通知已读!", | ||||||
|   "notifyDoneCaption": "这里没有什么东西可以给你看的了~", |   "notifyDoneCaption": "这里没有什么东西可以给你看的了~", | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ import 'dart:convert'; | |||||||
|  |  | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:flutter_local_notifications/flutter_local_notifications.dart'; | import 'package:flutter_local_notifications/flutter_local_notifications.dart'; | ||||||
|  | import 'package:livekit_client/livekit_client.dart'; | ||||||
| import 'package:permission_handler/permission_handler.dart'; | import 'package:permission_handler/permission_handler.dart'; | ||||||
| import 'package:solian/models/pagination.dart'; | import 'package:solian/models/pagination.dart'; | ||||||
| import 'package:solian/providers/auth.dart'; | import 'package:solian/providers/auth.dart'; | ||||||
| @@ -24,17 +25,25 @@ class NotifyProvider extends ChangeNotifier { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   void initNotify() { |   void initNotify() { | ||||||
|  |     const androidSettings = AndroidInitializationSettings('app_icon'); | ||||||
|  |     const darwinSettings = DarwinInitializationSettings( | ||||||
|  |       notificationCategories: [ | ||||||
|  |         DarwinNotificationCategory("general"), | ||||||
|  |       ], | ||||||
|  |     ); | ||||||
|  |     const linuxSettings = LinuxInitializationSettings(defaultActionName: 'Open notification'); | ||||||
|     const InitializationSettings initializationSettings = InitializationSettings( |     const InitializationSettings initializationSettings = InitializationSettings( | ||||||
|       android: AndroidInitializationSettings('app_icon'), |       android: androidSettings, | ||||||
|       iOS: DarwinInitializationSettings(), |       iOS: darwinSettings, | ||||||
|       macOS: DarwinInitializationSettings(), |       macOS: darwinSettings, | ||||||
|       linux: LinuxInitializationSettings(defaultActionName: 'Open notification'), |       linux: linuxSettings, | ||||||
|     ); |     ); | ||||||
|  |  | ||||||
|     localNotify.initialize(initializationSettings); |     localNotify.initialize(initializationSettings); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   Future<void> requestPermissions() async { |   Future<void> requestPermissions() async { | ||||||
|  |     if (lkPlatformIs(PlatformType.macOS) || lkPlatformIs(PlatformType.linux)) return; | ||||||
|     await Permission.notification.request(); |     await Permission.notification.request(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -78,20 +87,30 @@ class NotifyProvider extends ChangeNotifier { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   void notifyMessage(String title, String body) { |   void notifyMessage(String title, String body) { | ||||||
|  |     const androidSettings = AndroidNotificationDetails( | ||||||
|  |       'general', | ||||||
|  |       'General', | ||||||
|  |       importance: Importance.high, | ||||||
|  |       priority: Priority.high, | ||||||
|  |       silent: true, | ||||||
|  |     ); | ||||||
|  |     const darwinSettings = DarwinNotificationDetails( | ||||||
|  |       presentAlert: true, | ||||||
|  |       presentBanner: true, | ||||||
|  |       presentBadge: true, | ||||||
|  |       presentSound: false, | ||||||
|  |     ); | ||||||
|  |     const linuxSettings = LinuxNotificationDetails(); | ||||||
|  |  | ||||||
|     localNotify.show( |     localNotify.show( | ||||||
|       math.max(1, math.Random().nextInt(100000000)), |       math.max(1, math.Random().nextInt(100000000)), | ||||||
|       title, |       title, | ||||||
|       body, |       body, | ||||||
|       const NotificationDetails( |       const NotificationDetails( | ||||||
|         android: AndroidNotificationDetails( |         android: androidSettings, | ||||||
|           'general', |         iOS: darwinSettings, | ||||||
|           'General', |         macOS: darwinSettings, | ||||||
|           importance: Importance.high, |         linux: linuxSettings, | ||||||
|           priority: Priority.high, |  | ||||||
|         ), |  | ||||||
|         iOS: DarwinNotificationDetails(), |  | ||||||
|         macOS: DarwinNotificationDetails(), |  | ||||||
|         linux: LinuxNotificationDetails(), |  | ||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ import 'package:solian/models/friendship.dart'; | |||||||
| import 'package:solian/providers/auth.dart'; | import 'package:solian/providers/auth.dart'; | ||||||
| import 'package:solian/utils/service_url.dart'; | import 'package:solian/utils/service_url.dart'; | ||||||
| import 'package:solian/widgets/account/avatar.dart'; | import 'package:solian/widgets/account/avatar.dart'; | ||||||
|  | import 'package:solian/widgets/exts.dart'; | ||||||
| import 'package:solian/widgets/indent_wrapper.dart'; | import 'package:solian/widgets/indent_wrapper.dart'; | ||||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | ||||||
|  |  | ||||||
| @@ -40,9 +41,7 @@ class _FriendScreenState extends State<FriendScreen> { | |||||||
|       }); |       }); | ||||||
|     } else { |     } else { | ||||||
|       var message = utf8.decode(res.bodyBytes); |       var message = utf8.decode(res.bodyBytes); | ||||||
|       ScaffoldMessenger.of(context).showSnackBar( |       context.showErrorDialog(message); | ||||||
|         SnackBar(content: Text("Something went wrong... $message")), |  | ||||||
|       ); |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -65,9 +64,7 @@ class _FriendScreenState extends State<FriendScreen> { | |||||||
|       await fetchFriendships(); |       await fetchFriendships(); | ||||||
|     } else { |     } else { | ||||||
|       var message = utf8.decode(res.bodyBytes); |       var message = utf8.decode(res.bodyBytes); | ||||||
|       ScaffoldMessenger.of(context).showSnackBar( |       context.showErrorDialog(message); | ||||||
|         SnackBar(content: Text("Something went wrong... $message")), |  | ||||||
|       ); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     setState(() => _isSubmitting = false); |     setState(() => _isSubmitting = false); | ||||||
| @@ -97,9 +94,7 @@ class _FriendScreenState extends State<FriendScreen> { | |||||||
|       await fetchFriendships(); |       await fetchFriendships(); | ||||||
|     } else { |     } else { | ||||||
|       var message = utf8.decode(res.bodyBytes); |       var message = utf8.decode(res.bodyBytes); | ||||||
|       ScaffoldMessenger.of(context).showSnackBar( |       context.showErrorDialog(message); | ||||||
|         SnackBar(content: Text("Something went wrong... $message")), |  | ||||||
|       ); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     setState(() => _isSubmitting = false); |     setState(() => _isSubmitting = false); | ||||||
|   | |||||||
| @@ -12,6 +12,7 @@ import 'package:solian/widgets/chat/call/controls.dart'; | |||||||
| import 'package:solian/widgets/chat/call/exts.dart'; | import 'package:solian/widgets/chat/call/exts.dart'; | ||||||
| import 'package:solian/widgets/chat/call/participant.dart'; | import 'package:solian/widgets/chat/call/participant.dart'; | ||||||
| import 'package:solian/widgets/chat/call/participant_menu.dart'; | import 'package:solian/widgets/chat/call/participant_menu.dart'; | ||||||
|  | import 'package:solian/widgets/exts.dart'; | ||||||
| import 'package:solian/widgets/indent_wrapper.dart'; | import 'package:solian/widgets/indent_wrapper.dart'; | ||||||
| import 'package:permission_handler/permission_handler.dart'; | import 'package:permission_handler/permission_handler.dart'; | ||||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | ||||||
| @@ -81,9 +82,7 @@ class _ChatCallState extends State<ChatCall> { | |||||||
|       return (_token!, _endpoint!); |       return (_token!, _endpoint!); | ||||||
|     } else { |     } else { | ||||||
|       var message = utf8.decode(res.bodyBytes); |       var message = utf8.decode(res.bodyBytes); | ||||||
|       ScaffoldMessenger.of(context).showSnackBar( |       context.showErrorDialog(message); | ||||||
|         SnackBar(content: Text("Something went wrong... $message")), |  | ||||||
|       ); |  | ||||||
|       throw Exception(message); |       throw Exception(message); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @@ -138,10 +137,7 @@ class _ChatCallState extends State<ChatCall> { | |||||||
|  |  | ||||||
|       setupRoom(); |       setupRoom(); | ||||||
|     } catch (e) { |     } catch (e) { | ||||||
|       final message = e.toString(); |       context.showErrorDialog(e); | ||||||
|       ScaffoldMessenger.of(context).showSnackBar( |  | ||||||
|         SnackBar(content: Text("Something went wrong... $message")), |  | ||||||
|       ); |  | ||||||
|     } finally { |     } finally { | ||||||
|       notify.close(); |       notify.close(); | ||||||
|     } |     } | ||||||
| @@ -182,9 +178,6 @@ class _ChatCallState extends State<ChatCall> { | |||||||
|         if (router.canPop()) router.pop(); |         if (router.canPop()) router.pop(); | ||||||
|       }) |       }) | ||||||
|       ..on<ParticipantEvent>((event) => sortParticipants()) |       ..on<ParticipantEvent>((event) => sortParticipants()) | ||||||
|       ..on<RoomRecordingStatusChanged>((event) { |  | ||||||
|         context.showRecordingStatusChangedDialog(event.activeRecording); |  | ||||||
|       }) |  | ||||||
|       ..on<LocalTrackPublishedEvent>((_) => sortParticipants()) |       ..on<LocalTrackPublishedEvent>((_) => sortParticipants()) | ||||||
|       ..on<LocalTrackUnpublishedEvent>((_) => sortParticipants()) |       ..on<LocalTrackUnpublishedEvent>((_) => sortParticipants()) | ||||||
|       ..on<TrackSubscribedEvent>((_) => sortParticipants()) |       ..on<TrackSubscribedEvent>((_) => sortParticipants()) | ||||||
| @@ -203,30 +196,22 @@ class _ChatCallState extends State<ChatCall> { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   void sortParticipants() { |   void sortParticipants() { | ||||||
|     List<ParticipantTrack> screenTracks = []; |     Map<String, ParticipantTrack> mediaTracks = {}; | ||||||
|     Map<String, ParticipantTrack> userMediaTracks = {}; |  | ||||||
|     for (var participant in _callRoom.remoteParticipants.values) { |     for (var participant in _callRoom.remoteParticipants.values) { | ||||||
|       userMediaTracks[participant.sid] = ParticipantTrack( |       mediaTracks[participant.sid] = ParticipantTrack( | ||||||
|         participant: participant, |         participant: participant, | ||||||
|         videoTrack: null, |         videoTrack: null, | ||||||
|         isScreenShare: false, |         isScreenShare: false, | ||||||
|       ); |       ); | ||||||
|  |  | ||||||
|       for (var t in participant.videoTrackPublications) { |       for (var t in participant.videoTrackPublications) { | ||||||
|         if (t.isScreenShare) { |         mediaTracks[participant.sid]?.videoTrack = t.track; | ||||||
|           screenTracks.add(ParticipantTrack( |         mediaTracks[participant.sid]?.isScreenShare = t.isScreenShare; | ||||||
|             participant: participant, |  | ||||||
|             videoTrack: t.track as VideoTrack, |  | ||||||
|             isScreenShare: true, |  | ||||||
|           )); |  | ||||||
|         } else { |  | ||||||
|           userMediaTracks[participant.sid]?.videoTrack = t.track; |  | ||||||
|         } |  | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     final userMediaTrackList = userMediaTracks.values.toList(); |     final mediaTrackList = mediaTracks.values.toList(); | ||||||
|     userMediaTrackList.sort((a, b) { |     mediaTrackList.sort((a, b) { | ||||||
|       // Loudest people first |       // Loudest people first | ||||||
|       if (a.participant.isSpeaking && b.participant.isSpeaking) { |       if (a.participant.isSpeaking && b.participant.isSpeaking) { | ||||||
|         if (a.participant.audioLevel > b.participant.audioLevel) { |         if (a.participant.audioLevel > b.participant.audioLevel) { | ||||||
| @@ -262,22 +247,20 @@ class _ChatCallState extends State<ChatCall> { | |||||||
|       final localParticipantTracks = _callRoom.localParticipant?.videoTrackPublications; |       final localParticipantTracks = _callRoom.localParticipant?.videoTrackPublications; | ||||||
|       if (localParticipantTracks != null) { |       if (localParticipantTracks != null) { | ||||||
|         for (var t in localParticipantTracks) { |         for (var t in localParticipantTracks) { | ||||||
|           if (t.isScreenShare) { |  | ||||||
|             screenTracks.add(ParticipantTrack( |  | ||||||
|               participant: _callRoom.localParticipant!, |  | ||||||
|               videoTrack: t.track as VideoTrack, |  | ||||||
|               isScreenShare: true, |  | ||||||
|             )); |  | ||||||
|           } else { |  | ||||||
|           localTrack.videoTrack = t.track; |           localTrack.videoTrack = t.track; | ||||||
|           } |           localTrack.isScreenShare = t.isScreenShare; | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     setState(() { |     setState(() { | ||||||
|       _participantTracks = [...screenTracks, localTrack, ...userMediaTrackList]; |       _participantTracks = [localTrack, ...mediaTrackList]; | ||||||
|       _focusParticipant ??= _participantTracks.first; |       if (_focusParticipant == null) { | ||||||
|  |         _focusParticipant = _participantTracks.first; | ||||||
|  |       } else { | ||||||
|  |         final idx = _participantTracks.indexWhere((x) => _focusParticipant!.participant.sid == x.participant.sid); | ||||||
|  |         _focusParticipant = _participantTracks[idx]; | ||||||
|  |       } | ||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -466,6 +449,7 @@ class InteractiveParticipantWidget extends StatelessWidget { | |||||||
|   final double? width; |   final double? width; | ||||||
|   final double? height; |   final double? height; | ||||||
|   final Color? color; |   final Color? color; | ||||||
|  |   final bool? isFixed; | ||||||
|   final ParticipantTrack participant; |   final ParticipantTrack participant; | ||||||
|   final Function() onTap; |   final Function() onTap; | ||||||
|  |  | ||||||
| @@ -474,6 +458,7 @@ class InteractiveParticipantWidget extends StatelessWidget { | |||||||
|     this.width, |     this.width, | ||||||
|     this.height, |     this.height, | ||||||
|     this.color, |     this.color, | ||||||
|  |     this.isFixed = false, | ||||||
|     required this.participant, |     required this.participant, | ||||||
|     required this.onTap, |     required this.onTap, | ||||||
|   }); |   }); | ||||||
| @@ -485,7 +470,7 @@ class InteractiveParticipantWidget extends StatelessWidget { | |||||||
|         width: width, |         width: width, | ||||||
|         height: height, |         height: height, | ||||||
|         color: color, |         color: color, | ||||||
|         child: ParticipantWidget.widgetFor(participant), |         child: ParticipantWidget.widgetFor(participant, isFixed: true), | ||||||
|       ), |       ), | ||||||
|       onTap: () => onTap(), |       onTap: () => onTap(), | ||||||
|       onLongPress: () { |       onLongPress: () { | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ import 'package:solian/models/channel.dart'; | |||||||
| import 'package:solian/providers/auth.dart'; | import 'package:solian/providers/auth.dart'; | ||||||
| import 'package:solian/router.dart'; | import 'package:solian/router.dart'; | ||||||
| import 'package:solian/utils/service_url.dart'; | import 'package:solian/utils/service_url.dart'; | ||||||
|  | import 'package:solian/widgets/exts.dart'; | ||||||
| import 'package:solian/widgets/indent_wrapper.dart'; | import 'package:solian/widgets/indent_wrapper.dart'; | ||||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | ||||||
| import 'package:uuid/uuid.dart'; | import 'package:uuid/uuid.dart'; | ||||||
| @@ -52,9 +53,7 @@ class _ChannelEditorScreenState extends State<ChannelEditorScreen> { | |||||||
|     var res = await Response.fromStream(await auth.client!.send(req)); |     var res = await Response.fromStream(await auth.client!.send(req)); | ||||||
|     if (res.statusCode != 200) { |     if (res.statusCode != 200) { | ||||||
|       var message = utf8.decode(res.bodyBytes); |       var message = utf8.decode(res.bodyBytes); | ||||||
|       ScaffoldMessenger.of(context).showSnackBar( |       context.showErrorDialog(message); | ||||||
|         SnackBar(content: Text("Something went wrong... $message")), |  | ||||||
|       ); |  | ||||||
|     } else { |     } else { | ||||||
|       if (router.canPop()) { |       if (router.canPop()) { | ||||||
|         router.pop(true); |         router.pop(true); | ||||||
|   | |||||||
| @@ -9,6 +9,7 @@ import 'package:solian/providers/auth.dart'; | |||||||
| import 'package:solian/utils/service_url.dart'; | import 'package:solian/utils/service_url.dart'; | ||||||
| import 'package:solian/widgets/account/avatar.dart'; | import 'package:solian/widgets/account/avatar.dart'; | ||||||
| import 'package:solian/widgets/account/friend_picker.dart'; | import 'package:solian/widgets/account/friend_picker.dart'; | ||||||
|  | import 'package:solian/widgets/exts.dart'; | ||||||
| import 'package:solian/widgets/indent_wrapper.dart'; | import 'package:solian/widgets/indent_wrapper.dart'; | ||||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | ||||||
|  |  | ||||||
| @@ -45,9 +46,7 @@ class _ChatMemberScreenState extends State<ChatMemberScreen> { | |||||||
|       }); |       }); | ||||||
|     } else { |     } else { | ||||||
|       var message = utf8.decode(res.bodyBytes); |       var message = utf8.decode(res.bodyBytes); | ||||||
|       ScaffoldMessenger.of(context).showSnackBar( |       context.showErrorDialog(message); | ||||||
|         SnackBar(content: Text("Something went wrong... $message")), |  | ||||||
|       ); |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -75,9 +74,7 @@ class _ChatMemberScreenState extends State<ChatMemberScreen> { | |||||||
|       await fetchMemberships(); |       await fetchMemberships(); | ||||||
|     } else { |     } else { | ||||||
|       var message = utf8.decode(res.bodyBytes); |       var message = utf8.decode(res.bodyBytes); | ||||||
|       ScaffoldMessenger.of(context).showSnackBar( |       context.showErrorDialog(message); | ||||||
|         SnackBar(content: Text("Something went wrong... $message")), |  | ||||||
|       ); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     setState(() => _isSubmitting = false); |     setState(() => _isSubmitting = false); | ||||||
| @@ -107,9 +104,7 @@ class _ChatMemberScreenState extends State<ChatMemberScreen> { | |||||||
|       await fetchMemberships(); |       await fetchMemberships(); | ||||||
|     } else { |     } else { | ||||||
|       var message = utf8.decode(res.bodyBytes); |       var message = utf8.decode(res.bodyBytes); | ||||||
|       ScaffoldMessenger.of(context).showSnackBar( |       context.showErrorDialog(message); | ||||||
|         SnackBar(content: Text("Something went wrong... $message")), |  | ||||||
|       ); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     setState(() => _isSubmitting = false); |     setState(() => _isSubmitting = false); | ||||||
|   | |||||||
| @@ -16,6 +16,7 @@ import 'package:solian/widgets/chat/maintainer.dart'; | |||||||
| import 'package:solian/widgets/chat/message.dart'; | import 'package:solian/widgets/chat/message.dart'; | ||||||
| import 'package:solian/widgets/chat/message_action.dart'; | import 'package:solian/widgets/chat/message_action.dart'; | ||||||
| import 'package:solian/widgets/chat/message_editor.dart'; | import 'package:solian/widgets/chat/message_editor.dart'; | ||||||
|  | import 'package:solian/widgets/exts.dart'; | ||||||
| import 'package:solian/widgets/indent_wrapper.dart'; | import 'package:solian/widgets/indent_wrapper.dart'; | ||||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | ||||||
| import 'package:http/http.dart' as http; | import 'package:http/http.dart' as http; | ||||||
| @@ -46,9 +47,7 @@ class _ChatScreenState extends State<ChatScreen> { | |||||||
|       return _channelMeta!; |       return _channelMeta!; | ||||||
|     } else { |     } else { | ||||||
|       var message = utf8.decode(res.bodyBytes); |       var message = utf8.decode(res.bodyBytes); | ||||||
|       ScaffoldMessenger.of(context).showSnackBar( |       context.showErrorDialog(message); | ||||||
|         SnackBar(content: Text("Something went wrong... $message")), |  | ||||||
|       ); |  | ||||||
|       throw Exception(message); |       throw Exception(message); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @@ -62,9 +61,7 @@ class _ChatScreenState extends State<ChatScreen> { | |||||||
|       return _ongoingCall; |       return _ongoingCall; | ||||||
|     } else if (res.statusCode != 404) { |     } else if (res.statusCode != 404) { | ||||||
|       var message = utf8.decode(res.bodyBytes); |       var message = utf8.decode(res.bodyBytes); | ||||||
|       ScaffoldMessenger.of(context).showSnackBar( |       context.showErrorDialog(message); | ||||||
|         SnackBar(content: Text("Something went wrong... $message")), |  | ||||||
|       ); |  | ||||||
|       throw Exception(message); |       throw Exception(message); | ||||||
|     } else { |     } else { | ||||||
|       return null; |       return null; | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ import 'package:solian/providers/auth.dart'; | |||||||
| import 'package:solian/router.dart'; | import 'package:solian/router.dart'; | ||||||
| import 'package:solian/utils/service_url.dart'; | import 'package:solian/utils/service_url.dart'; | ||||||
| import 'package:solian/widgets/chat/chat_new.dart'; | import 'package:solian/widgets/chat/chat_new.dart'; | ||||||
|  | import 'package:solian/widgets/exts.dart'; | ||||||
| import 'package:solian/widgets/indent_wrapper.dart'; | import 'package:solian/widgets/indent_wrapper.dart'; | ||||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | ||||||
| import 'package:solian/widgets/notification_notifier.dart'; | import 'package:solian/widgets/notification_notifier.dart'; | ||||||
| @@ -36,9 +37,7 @@ class _ChatIndexScreenState extends State<ChatIndexScreen> { | |||||||
|       }); |       }); | ||||||
|     } else { |     } else { | ||||||
|       var message = utf8.decode(res.bodyBytes); |       var message = utf8.decode(res.bodyBytes); | ||||||
|       ScaffoldMessenger.of(context).showSnackBar( |       context.showErrorDialog(message); | ||||||
|         SnackBar(content: Text("Something went wrong... $message")), |  | ||||||
|       ); |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -21,6 +21,10 @@ class _NotificationScreenState extends State<NotificationScreen> { | |||||||
|     final auth = context.read<AuthProvider>(); |     final auth = context.read<AuthProvider>(); | ||||||
|     final nty = context.watch<NotifyProvider>(); |     final nty = context.watch<NotifyProvider>(); | ||||||
|  |  | ||||||
|  |     WidgetsBinding.instance.addPostFrameCallback((_) { | ||||||
|  |       nty.allRead(); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|     return IndentWrapper( |     return IndentWrapper( | ||||||
|       noSafeArea: true, |       noSafeArea: true, | ||||||
|       hideDrawer: true, |       hideDrawer: true, | ||||||
| @@ -48,9 +52,7 @@ class _NotificationScreenState extends State<NotificationScreen> { | |||||||
|                       return NotificationItem( |                       return NotificationItem( | ||||||
|                         index: index, |                         index: index, | ||||||
|                         item: element, |                         item: element, | ||||||
|                         onDismiss: () => setState(() { |                         onDismiss: () => nty.clearAt(index), | ||||||
|                           nty.clearAt(index); |  | ||||||
|                         }), |  | ||||||
|                       ); |                       ); | ||||||
|                     }, |                     }, | ||||||
|                   ), |                   ), | ||||||
| @@ -69,14 +71,6 @@ class _NotificationScreenState extends State<NotificationScreen> { | |||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |  | ||||||
|   void dispose() { |  | ||||||
|     final nty = context.read<NotifyProvider>(); |  | ||||||
|     nty.allRead(); |  | ||||||
|     nty.clearRealtime(); |  | ||||||
|     super.dispose(); |  | ||||||
|   } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| class NotificationItem extends StatelessWidget { | class NotificationItem extends StatelessWidget { | ||||||
| @@ -141,7 +135,7 @@ class NotificationItem extends StatelessWidget { | |||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     return Dismissible( |     return Dismissible( | ||||||
|       key: Key('n$index'), |       key: Key((DateTime.now().millisecondsSinceEpoch << 10).toString()), | ||||||
|       onDismissed: (direction) { |       onDismissed: (direction) { | ||||||
|         markAsRead(item, context).then((value) { |         markAsRead(item, context).then((value) { | ||||||
|           ScaffoldMessenger.of(context).showSnackBar( |           ScaffoldMessenger.of(context).showSnackBar( | ||||||
|   | |||||||
| @@ -10,6 +10,7 @@ import 'package:solian/router.dart'; | |||||||
| import 'package:solian/utils/service_url.dart'; | import 'package:solian/utils/service_url.dart'; | ||||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | ||||||
| import 'package:solian/widgets/account/avatar.dart'; | import 'package:solian/widgets/account/avatar.dart'; | ||||||
|  | import 'package:solian/widgets/exts.dart'; | ||||||
| import 'package:solian/widgets/indent_wrapper.dart'; | import 'package:solian/widgets/indent_wrapper.dart'; | ||||||
| import 'package:solian/widgets/posts/attachment_editor.dart'; | import 'package:solian/widgets/posts/attachment_editor.dart'; | ||||||
|  |  | ||||||
| @@ -75,9 +76,7 @@ class _CommentEditorScreenState extends State<CommentEditorScreen> { | |||||||
|     var res = await Response.fromStream(await auth.client!.send(req)); |     var res = await Response.fromStream(await auth.client!.send(req)); | ||||||
|     if (res.statusCode != 200) { |     if (res.statusCode != 200) { | ||||||
|       var message = utf8.decode(res.bodyBytes); |       var message = utf8.decode(res.bodyBytes); | ||||||
|       ScaffoldMessenger.of(context).showSnackBar( |       context.showErrorDialog(message); | ||||||
|         SnackBar(content: Text("Something went wrong... $message")), |  | ||||||
|       ); |  | ||||||
|     } else { |     } else { | ||||||
|       if (router.canPop()) { |       if (router.canPop()) { | ||||||
|         router.pop(true); |         router.pop(true); | ||||||
|   | |||||||
| @@ -10,6 +10,7 @@ import 'package:solian/router.dart'; | |||||||
| import 'package:solian/utils/service_url.dart'; | import 'package:solian/utils/service_url.dart'; | ||||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | ||||||
| import 'package:solian/widgets/account/avatar.dart'; | import 'package:solian/widgets/account/avatar.dart'; | ||||||
|  | import 'package:solian/widgets/exts.dart'; | ||||||
| import 'package:solian/widgets/indent_wrapper.dart'; | import 'package:solian/widgets/indent_wrapper.dart'; | ||||||
| import 'package:solian/widgets/posts/attachment_editor.dart'; | import 'package:solian/widgets/posts/attachment_editor.dart'; | ||||||
|  |  | ||||||
| @@ -65,9 +66,7 @@ class _MomentEditorScreenState extends State<MomentEditorScreen> { | |||||||
|     var res = await Response.fromStream(await auth.client!.send(req)); |     var res = await Response.fromStream(await auth.client!.send(req)); | ||||||
|     if (res.statusCode != 200) { |     if (res.statusCode != 200) { | ||||||
|       var message = utf8.decode(res.bodyBytes); |       var message = utf8.decode(res.bodyBytes); | ||||||
|       ScaffoldMessenger.of(context).showSnackBar( |       context.showErrorDialog(message); | ||||||
|         SnackBar(content: Text("Something went wrong... $message")), |  | ||||||
|       ); |  | ||||||
|     } else { |     } else { | ||||||
|       if (router.canPop()) { |       if (router.canPop()) { | ||||||
|         router.pop(true); |         router.pop(true); | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ import 'package:http/http.dart' as http; | |||||||
| import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; | import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; | ||||||
| import 'package:solian/models/post.dart'; | import 'package:solian/models/post.dart'; | ||||||
| import 'package:solian/utils/service_url.dart'; | import 'package:solian/utils/service_url.dart'; | ||||||
|  | import 'package:solian/widgets/exts.dart'; | ||||||
| import 'package:solian/widgets/indent_wrapper.dart'; | import 'package:solian/widgets/indent_wrapper.dart'; | ||||||
| import 'package:solian/widgets/posts/comment_list.dart'; | import 'package:solian/widgets/posts/comment_list.dart'; | ||||||
| import 'package:solian/widgets/posts/item.dart'; | import 'package:solian/widgets/posts/item.dart'; | ||||||
| @@ -30,9 +31,7 @@ class _PostScreenState extends State<PostScreen> { | |||||||
|     final res = await _client.get(uri); |     final res = await _client.get(uri); | ||||||
|     if (res.statusCode != 200) { |     if (res.statusCode != 200) { | ||||||
|       final err = utf8.decode(res.bodyBytes); |       final err = utf8.decode(res.bodyBytes); | ||||||
|       ScaffoldMessenger.of(context).showSnackBar( |       context.showErrorDialog(err); | ||||||
|         SnackBar(content: Text("Something went wrong... $err")), |  | ||||||
|       ); |  | ||||||
|       return null; |       return null; | ||||||
|     } else { |     } else { | ||||||
|       return Post.fromJson(jsonDecode(utf8.decode(res.bodyBytes))); |       return Post.fromJson(jsonDecode(utf8.decode(res.bodyBytes))); | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ import 'package:flutter_background/flutter_background.dart'; | |||||||
| import 'package:flutter_webrtc/flutter_webrtc.dart'; | import 'package:flutter_webrtc/flutter_webrtc.dart'; | ||||||
| import 'package:livekit_client/livekit_client.dart'; | import 'package:livekit_client/livekit_client.dart'; | ||||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | ||||||
|  | import 'package:solian/widgets/exts.dart'; | ||||||
|  |  | ||||||
| class ControlsWidget extends StatefulWidget { | class ControlsWidget extends StatefulWidget { | ||||||
|   final Room room; |   final Room room; | ||||||
| @@ -134,9 +135,7 @@ class _ControlsWidgetState extends State<ControlsWidget> { | |||||||
|         await participant.publishVideoTrack(track); |         await participant.publishVideoTrack(track); | ||||||
|       } catch (e) { |       } catch (e) { | ||||||
|         final message = e.toString(); |         final message = e.toString(); | ||||||
|         ScaffoldMessenger.of(context).showSnackBar(SnackBar( |         context.showErrorDialog(message); | ||||||
|           content: Text('Something went wrong... $message'), |  | ||||||
|         )); |  | ||||||
|       } |       } | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -1,30 +1,13 @@ | |||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
|  |  | ||||||
| extension SolianCallExt on BuildContext { | extension SolianCallExt on BuildContext { | ||||||
|   Future<bool?> showPublishDialog() => showDialog<bool>( |  | ||||||
|     context: this, |  | ||||||
|     builder: (ctx) => AlertDialog( |  | ||||||
|       title: const Text('Publish'), |  | ||||||
|       content: const Text('Would you like to publish your Camera & Mic ?'), |  | ||||||
|       actions: [ |  | ||||||
|         TextButton( |  | ||||||
|           onPressed: () => Navigator.pop(ctx, false), |  | ||||||
|           child: const Text('NO'), |  | ||||||
|         ), |  | ||||||
|         TextButton( |  | ||||||
|           onPressed: () => Navigator.pop(ctx, true), |  | ||||||
|           child: const Text('YES'), |  | ||||||
|         ), |  | ||||||
|       ], |  | ||||||
|     ), |  | ||||||
|   ); |  | ||||||
|  |  | ||||||
|   Future<bool?> showPlayAudioManuallyDialog() => showDialog<bool>( |   Future<bool?> showPlayAudioManuallyDialog() => showDialog<bool>( | ||||||
|         context: this, |         context: this, | ||||||
|         builder: (ctx) => AlertDialog( |         builder: (ctx) => AlertDialog( | ||||||
|           title: const Text('Play Audio'), |           title: const Text('Play Audio'), | ||||||
|           content: const Text( |           content: const Text( | ||||||
|           'You need to manually activate audio PlayBack for iOS Safari !'), |             'You need to manually activate audio PlayBack for iOS Safari!', | ||||||
|  |           ), | ||||||
|           actions: [ |           actions: [ | ||||||
|             TextButton( |             TextButton( | ||||||
|               onPressed: () => Navigator.pop(ctx, false), |               onPressed: () => Navigator.pop(ctx, false), | ||||||
| @@ -38,39 +21,6 @@ extension SolianCallExt on BuildContext { | |||||||
|         ), |         ), | ||||||
|       ); |       ); | ||||||
|  |  | ||||||
|   Future<bool?> showUnPublishDialog() => showDialog<bool>( |  | ||||||
|     context: this, |  | ||||||
|     builder: (ctx) => AlertDialog( |  | ||||||
|       title: const Text('UnPublish'), |  | ||||||
|       content: |  | ||||||
|       const Text('Would you like to un-publish your Camera & Mic ?'), |  | ||||||
|       actions: [ |  | ||||||
|         TextButton( |  | ||||||
|           onPressed: () => Navigator.pop(ctx, false), |  | ||||||
|           child: const Text('NO'), |  | ||||||
|         ), |  | ||||||
|         TextButton( |  | ||||||
|           onPressed: () => Navigator.pop(ctx, true), |  | ||||||
|           child: const Text('YES'), |  | ||||||
|         ), |  | ||||||
|       ], |  | ||||||
|     ), |  | ||||||
|   ); |  | ||||||
|  |  | ||||||
|   Future<void> showErrorDialog(dynamic exception) => showDialog<void>( |  | ||||||
|     context: this, |  | ||||||
|     builder: (ctx) => AlertDialog( |  | ||||||
|       title: const Text('Error'), |  | ||||||
|       content: Text(exception.toString()), |  | ||||||
|       actions: [ |  | ||||||
|         TextButton( |  | ||||||
|           onPressed: () => Navigator.pop(ctx), |  | ||||||
|           child: const Text('OK'), |  | ||||||
|         ) |  | ||||||
|       ], |  | ||||||
|     ), |  | ||||||
|   ); |  | ||||||
|  |  | ||||||
|   Future<bool?> showDisconnectDialog() => showDialog<bool>( |   Future<bool?> showDisconnectDialog() => showDialog<bool>( | ||||||
|         context: this, |         context: this, | ||||||
|         builder: (ctx) => AlertDialog( |         builder: (ctx) => AlertDialog( | ||||||
| @@ -120,87 +70,4 @@ extension SolianCallExt on BuildContext { | |||||||
|           ], |           ], | ||||||
|         ), |         ), | ||||||
|       ); |       ); | ||||||
|  |  | ||||||
|   Future<bool?> showSendDataDialog() => showDialog<bool>( |  | ||||||
|     context: this, |  | ||||||
|     builder: (ctx) => AlertDialog( |  | ||||||
|       title: const Text('Send data'), |  | ||||||
|       content: const Text( |  | ||||||
|           'This will send a sample data to all participants in the room'), |  | ||||||
|       actions: [ |  | ||||||
|         TextButton( |  | ||||||
|           onPressed: () => Navigator.pop(ctx, false), |  | ||||||
|           child: const Text('Cancel'), |  | ||||||
|         ), |  | ||||||
|         TextButton( |  | ||||||
|           onPressed: () => Navigator.pop(ctx, true), |  | ||||||
|           child: const Text('Send'), |  | ||||||
|         ), |  | ||||||
|       ], |  | ||||||
|     ), |  | ||||||
|   ); |  | ||||||
|  |  | ||||||
|   Future<bool?> showDataReceivedDialog(String data) => showDialog<bool>( |  | ||||||
|     context: this, |  | ||||||
|     builder: (ctx) => AlertDialog( |  | ||||||
|       title: const Text('Received data'), |  | ||||||
|       content: Text(data), |  | ||||||
|       actions: [ |  | ||||||
|         TextButton( |  | ||||||
|           onPressed: () => Navigator.pop(ctx, true), |  | ||||||
|           child: const Text('OK'), |  | ||||||
|         ), |  | ||||||
|       ], |  | ||||||
|     ), |  | ||||||
|   ); |  | ||||||
|  |  | ||||||
|   Future<bool?> showRecordingStatusChangedDialog(bool isActiveRecording) => |  | ||||||
|       showDialog<bool>( |  | ||||||
|         context: this, |  | ||||||
|         builder: (ctx) => AlertDialog( |  | ||||||
|           title: const Text('Room recording reminder'), |  | ||||||
|           content: Text(isActiveRecording |  | ||||||
|               ? 'Room recording is active.' |  | ||||||
|               : 'Room recording is stoped.'), |  | ||||||
|           actions: [ |  | ||||||
|             TextButton( |  | ||||||
|               onPressed: () => Navigator.pop(ctx, true), |  | ||||||
|               child: const Text('OK'), |  | ||||||
|             ), |  | ||||||
|           ], |  | ||||||
|         ), |  | ||||||
|       ); |  | ||||||
|  |  | ||||||
|   Future<bool?> showSubscribePermissionDialog() => showDialog<bool>( |  | ||||||
|     context: this, |  | ||||||
|     builder: (ctx) => AlertDialog( |  | ||||||
|       title: const Text('Allow subscription'), |  | ||||||
|       content: const Text( |  | ||||||
|           'Allow all participants to subscribe tracks published by local participant?'), |  | ||||||
|       actions: [ |  | ||||||
|         TextButton( |  | ||||||
|           onPressed: () => Navigator.pop(ctx, false), |  | ||||||
|           child: const Text('NO'), |  | ||||||
|         ), |  | ||||||
|         TextButton( |  | ||||||
|           onPressed: () => Navigator.pop(ctx, true), |  | ||||||
|           child: const Text('YES'), |  | ||||||
|         ), |  | ||||||
|       ], |  | ||||||
|     ), |  | ||||||
|   ); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| enum SimulateScenarioResult { |  | ||||||
|   signalReconnect, |  | ||||||
|   fullReconnect, |  | ||||||
|   speakerUpdate, |  | ||||||
|   nodeFailure, |  | ||||||
|   migration, |  | ||||||
|   serverLeave, |  | ||||||
|   switchCandidate, |  | ||||||
|   e2eeKeyRatchet, |  | ||||||
|   participantName, |  | ||||||
|   participantMetadata, |  | ||||||
|   clear, |  | ||||||
| } | } | ||||||
| @@ -7,8 +7,14 @@ import 'dart:math' as math; | |||||||
| class NoContentWidget extends StatefulWidget { | class NoContentWidget extends StatefulWidget { | ||||||
|   final Account? userinfo; |   final Account? userinfo; | ||||||
|   final bool isSpeaking; |   final bool isSpeaking; | ||||||
|  |   final bool isFixed; | ||||||
|  |  | ||||||
|   const NoContentWidget({super.key, this.userinfo, required this.isSpeaking}); |   const NoContentWidget({ | ||||||
|  |     super.key, | ||||||
|  |     this.userinfo, | ||||||
|  |     this.isFixed = false, | ||||||
|  |     required this.isSpeaking, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   State<NoContentWidget> createState() => _NoContentWidgetState(); |   State<NoContentWidget> createState() => _NoContentWidgetState(); | ||||||
| @@ -35,7 +41,12 @@ class _NoContentWidgetState extends State<NoContentWidget> with SingleTickerProv | |||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     final radius = math.min(MediaQuery.of(context).size.width, MediaQuery.of(context).size.height) * 0.1; |     final double radius = widget.isFixed | ||||||
|  |         ? 16 | ||||||
|  |         : math.min( | ||||||
|  |             MediaQuery.of(context).size.width * 0.1, | ||||||
|  |             MediaQuery.of(context).size.height * 0.1, | ||||||
|  |           ); | ||||||
|  |  | ||||||
|     return Container( |     return Container( | ||||||
|       alignment: Alignment.center, |       alignment: Alignment.center, | ||||||
| @@ -63,7 +74,8 @@ class _NoContentWidgetState extends State<NoContentWidget> with SingleTickerProv | |||||||
|             backgroundColor: Colors.transparent, |             backgroundColor: Colors.transparent, | ||||||
|             radius: radius, |             radius: radius, | ||||||
|             direct: true, |             direct: true, | ||||||
|             )), |           ), | ||||||
|  |         ), | ||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -10,13 +10,24 @@ import 'package:solian/widgets/chat/call/participant_info.dart'; | |||||||
| import 'package:solian/widgets/chat/call/participant_stats.dart'; | import 'package:solian/widgets/chat/call/participant_stats.dart'; | ||||||
|  |  | ||||||
| abstract class ParticipantWidget extends StatefulWidget { | abstract class ParticipantWidget extends StatefulWidget { | ||||||
|   static ParticipantWidget widgetFor(ParticipantTrack participantTrack, {bool showStatsLayer = false}) { |   static ParticipantWidget widgetFor(ParticipantTrack participantTrack, | ||||||
|  |       {bool isFixed = false, bool showStatsLayer = false}) { | ||||||
|     if (participantTrack.participant is LocalParticipant) { |     if (participantTrack.participant is LocalParticipant) { | ||||||
|       return LocalParticipantWidget(participantTrack.participant as LocalParticipant, participantTrack.videoTrack, |       return LocalParticipantWidget( | ||||||
|           participantTrack.isScreenShare, showStatsLayer); |         participantTrack.participant as LocalParticipant, | ||||||
|  |         participantTrack.videoTrack, | ||||||
|  |         isFixed, | ||||||
|  |         participantTrack.isScreenShare, | ||||||
|  |         showStatsLayer, | ||||||
|  |       ); | ||||||
|     } else if (participantTrack.participant is RemoteParticipant) { |     } else if (participantTrack.participant is RemoteParticipant) { | ||||||
|       return RemoteParticipantWidget(participantTrack.participant as RemoteParticipant, participantTrack.videoTrack, |       return RemoteParticipantWidget( | ||||||
|           participantTrack.isScreenShare, showStatsLayer); |         participantTrack.participant as RemoteParticipant, | ||||||
|  |         participantTrack.videoTrack, | ||||||
|  |         isFixed, | ||||||
|  |         participantTrack.isScreenShare, | ||||||
|  |         showStatsLayer, | ||||||
|  |       ); | ||||||
|     } |     } | ||||||
|     throw UnimplementedError('Unknown participant type'); |     throw UnimplementedError('Unknown participant type'); | ||||||
|   } |   } | ||||||
| @@ -24,6 +35,7 @@ abstract class ParticipantWidget extends StatefulWidget { | |||||||
|   abstract final Participant participant; |   abstract final Participant participant; | ||||||
|   abstract final VideoTrack? videoTrack; |   abstract final VideoTrack? videoTrack; | ||||||
|   abstract final bool isScreenShare; |   abstract final bool isScreenShare; | ||||||
|  |   abstract final bool isFixed; | ||||||
|   abstract final bool showStatsLayer; |   abstract final bool showStatsLayer; | ||||||
|   final VideoQuality quality; |   final VideoQuality quality; | ||||||
|  |  | ||||||
| @@ -39,6 +51,8 @@ class LocalParticipantWidget extends ParticipantWidget { | |||||||
|   @override |   @override | ||||||
|   final VideoTrack? videoTrack; |   final VideoTrack? videoTrack; | ||||||
|   @override |   @override | ||||||
|  |   final bool isFixed; | ||||||
|  |   @override | ||||||
|   final bool isScreenShare; |   final bool isScreenShare; | ||||||
|   @override |   @override | ||||||
|   final bool showStatsLayer; |   final bool showStatsLayer; | ||||||
| @@ -46,6 +60,7 @@ class LocalParticipantWidget extends ParticipantWidget { | |||||||
|   const LocalParticipantWidget( |   const LocalParticipantWidget( | ||||||
|     this.participant, |     this.participant, | ||||||
|     this.videoTrack, |     this.videoTrack, | ||||||
|  |     this.isFixed, | ||||||
|     this.isScreenShare, |     this.isScreenShare, | ||||||
|     this.showStatsLayer, { |     this.showStatsLayer, { | ||||||
|     super.key, |     super.key, | ||||||
| @@ -61,6 +76,8 @@ class RemoteParticipantWidget extends ParticipantWidget { | |||||||
|   @override |   @override | ||||||
|   final VideoTrack? videoTrack; |   final VideoTrack? videoTrack; | ||||||
|   @override |   @override | ||||||
|  |   final bool isFixed; | ||||||
|  |   @override | ||||||
|   final bool isScreenShare; |   final bool isScreenShare; | ||||||
|   @override |   @override | ||||||
|   final bool showStatsLayer; |   final bool showStatsLayer; | ||||||
| @@ -68,6 +85,7 @@ class RemoteParticipantWidget extends ParticipantWidget { | |||||||
|   const RemoteParticipantWidget( |   const RemoteParticipantWidget( | ||||||
|     this.participant, |     this.participant, | ||||||
|     this.videoTrack, |     this.videoTrack, | ||||||
|  |     this.isFixed, | ||||||
|     this.isScreenShare, |     this.isScreenShare, | ||||||
|     this.showStatsLayer, { |     this.showStatsLayer, { | ||||||
|     super.key, |     super.key, | ||||||
| @@ -80,8 +98,6 @@ class RemoteParticipantWidget extends ParticipantWidget { | |||||||
| abstract class _ParticipantWidgetState<T extends ParticipantWidget> extends State<T> { | abstract class _ParticipantWidgetState<T extends ParticipantWidget> extends State<T> { | ||||||
|   VideoTrack? get _activeVideoTrack; |   VideoTrack? get _activeVideoTrack; | ||||||
|  |  | ||||||
|   TrackPublication? get _videoPublication; |  | ||||||
|  |  | ||||||
|   TrackPublication? get _firstAudioPublication; |   TrackPublication? get _firstAudioPublication; | ||||||
|  |  | ||||||
|   Account? _userinfoMetadata; |   Account? _userinfoMetadata; | ||||||
| @@ -126,15 +142,14 @@ abstract class _ParticipantWidgetState<T extends ParticipantWidget> extends Stat | |||||||
|               ) |               ) | ||||||
|             : NoContentWidget( |             : NoContentWidget( | ||||||
|                 userinfo: _userinfoMetadata, |                 userinfo: _userinfoMetadata, | ||||||
|  |                 isFixed: widget.isFixed, | ||||||
|                 isSpeaking: widget.participant.isSpeaking, |                 isSpeaking: widget.participant.isSpeaking, | ||||||
|               ), |               ), | ||||||
|         if (widget.showStatsLayer) |         if (widget.showStatsLayer) | ||||||
|           Positioned( |           Positioned( | ||||||
|             top: 30, |             top: 30, | ||||||
|             right: 30, |             right: 30, | ||||||
|             child: ParticipantStatsWidget( |             child: ParticipantStatsWidget(participant: widget.participant), | ||||||
|               participant: widget.participant, |  | ||||||
|             ), |  | ||||||
|           ), |           ), | ||||||
|         Align( |         Align( | ||||||
|           alignment: Alignment.bottomCenter, |           alignment: Alignment.bottomCenter, | ||||||
| @@ -143,9 +158,7 @@ abstract class _ParticipantWidgetState<T extends ParticipantWidget> extends Stat | |||||||
|             mainAxisSize: MainAxisSize.min, |             mainAxisSize: MainAxisSize.min, | ||||||
|             children: [ |             children: [ | ||||||
|               ParticipantInfoWidget( |               ParticipantInfoWidget( | ||||||
|                 title: widget.participant.name.isNotEmpty |                 title: widget.participant.name.isNotEmpty ? widget.participant.name : widget.participant.identity, | ||||||
|                     ? widget.participant.name |  | ||||||
|                     : widget.participant.identity, |  | ||||||
|                 audioAvailable: _firstAudioPublication?.muted == false && _firstAudioPublication?.subscribed == true, |                 audioAvailable: _firstAudioPublication?.muted == false && _firstAudioPublication?.subscribed == true, | ||||||
|                 connectionQuality: widget.participant.connectionQuality, |                 connectionQuality: widget.participant.connectionQuality, | ||||||
|                 isScreenShare: widget.isScreenShare, |                 isScreenShare: widget.isScreenShare, | ||||||
| @@ -159,10 +172,6 @@ abstract class _ParticipantWidgetState<T extends ParticipantWidget> extends Stat | |||||||
| } | } | ||||||
|  |  | ||||||
| class _LocalParticipantWidgetState extends _ParticipantWidgetState<LocalParticipantWidget> { | class _LocalParticipantWidgetState extends _ParticipantWidgetState<LocalParticipantWidget> { | ||||||
|   @override |  | ||||||
|   LocalTrackPublication<LocalVideoTrack>? get _videoPublication => |  | ||||||
|       widget.participant.videoTrackPublications.where((element) => element.sid == widget.videoTrack?.sid).firstOrNull; |  | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   LocalTrackPublication<LocalAudioTrack>? get _firstAudioPublication => |   LocalTrackPublication<LocalAudioTrack>? get _firstAudioPublication => | ||||||
|       widget.participant.audioTrackPublications.firstOrNull; |       widget.participant.audioTrackPublications.firstOrNull; | ||||||
| @@ -172,10 +181,6 @@ class _LocalParticipantWidgetState extends _ParticipantWidgetState<LocalParticip | |||||||
| } | } | ||||||
|  |  | ||||||
| class _RemoteParticipantWidgetState extends _ParticipantWidgetState<RemoteParticipantWidget> { | class _RemoteParticipantWidgetState extends _ParticipantWidgetState<RemoteParticipantWidget> { | ||||||
|   @override |  | ||||||
|   RemoteTrackPublication<RemoteVideoTrack>? get _videoPublication => |  | ||||||
|       widget.participant.videoTrackPublications.where((element) => element.sid == widget.videoTrack?.sid).firstOrNull; |  | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   RemoteTrackPublication<RemoteAudioTrack>? get _firstAudioPublication => |   RemoteTrackPublication<RemoteAudioTrack>? get _firstAudioPublication => | ||||||
|       widget.participant.audioTrackPublications.firstOrNull; |       widget.participant.audioTrackPublications.firstOrNull; | ||||||
|   | |||||||
| @@ -21,17 +21,12 @@ class ParticipantMenu extends StatefulWidget { | |||||||
| } | } | ||||||
|  |  | ||||||
| class _ParticipantMenuState extends State<ParticipantMenu> { | class _ParticipantMenuState extends State<ParticipantMenu> { | ||||||
|   @override |  | ||||||
|   RemoteTrackPublication<RemoteVideoTrack>? get _videoPublication => |   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; | ||||||
|  |  | ||||||
|   @override |  | ||||||
|   RemoteTrackPublication<RemoteAudioTrack>? get _firstAudioPublication => |   RemoteTrackPublication<RemoteAudioTrack>? get _firstAudioPublication => | ||||||
|       widget.participant.audioTrackPublications.firstOrNull; |       widget.participant.audioTrackPublications.firstOrNull; | ||||||
|  |  | ||||||
|   @override |  | ||||||
|   VideoTrack? get _activeVideoTrack => widget.videoTrack; |  | ||||||
|  |  | ||||||
|   void tookAction() { |   void tookAction() { | ||||||
|     if (Navigator.canPop(context)) { |     if (Navigator.canPop(context)) { | ||||||
|       Navigator.pop(context); |       Navigator.pop(context); | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ import 'package:solian/models/channel.dart'; | |||||||
| import 'package:solian/providers/auth.dart'; | import 'package:solian/providers/auth.dart'; | ||||||
| import 'package:solian/router.dart'; | import 'package:solian/router.dart'; | ||||||
| import 'package:solian/utils/service_url.dart'; | import 'package:solian/utils/service_url.dart'; | ||||||
|  | import 'package:solian/widgets/exts.dart'; | ||||||
|  |  | ||||||
| class ChannelCallAction extends StatefulWidget { | class ChannelCallAction extends StatefulWidget { | ||||||
|   final Call? call; |   final Call? call; | ||||||
| @@ -36,9 +37,7 @@ class _ChannelCallActionState extends State<ChannelCallAction> { | |||||||
|     var res = await auth.client!.post(uri); |     var res = await auth.client!.post(uri); | ||||||
|     if (res.statusCode != 200) { |     if (res.statusCode != 200) { | ||||||
|       var message = utf8.decode(res.bodyBytes); |       var message = utf8.decode(res.bodyBytes); | ||||||
|       ScaffoldMessenger.of(context).showSnackBar( |       context.showErrorDialog(message); | ||||||
|         SnackBar(content: Text("Something went wrong... $message")), |  | ||||||
|       ); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     setState(() => _isSubmitting = false); |     setState(() => _isSubmitting = false); | ||||||
| @@ -58,9 +57,7 @@ class _ChannelCallActionState extends State<ChannelCallAction> { | |||||||
|     var res = await auth.client!.delete(uri); |     var res = await auth.client!.delete(uri); | ||||||
|     if (res.statusCode != 200) { |     if (res.statusCode != 200) { | ||||||
|       var message = utf8.decode(res.bodyBytes); |       var message = utf8.decode(res.bodyBytes); | ||||||
|       ScaffoldMessenger.of(context).showSnackBar( |       context.showErrorDialog(message); | ||||||
|         SnackBar(content: Text("Something went wrong... $message")), |  | ||||||
|       ); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     setState(() => _isSubmitting = false); |     setState(() => _isSubmitting = false); | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ import 'package:solian/models/channel.dart'; | |||||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | ||||||
| import 'package:solian/providers/auth.dart'; | import 'package:solian/providers/auth.dart'; | ||||||
| import 'package:solian/utils/service_url.dart'; | import 'package:solian/utils/service_url.dart'; | ||||||
|  | import 'package:solian/widgets/exts.dart'; | ||||||
|  |  | ||||||
| class ChannelDeletion extends StatefulWidget { | class ChannelDeletion extends StatefulWidget { | ||||||
|   final Channel channel; |   final Channel channel; | ||||||
| @@ -34,9 +35,7 @@ class _ChannelDeletionState extends State<ChannelDeletion> { | |||||||
|     ); |     ); | ||||||
|     if (res.statusCode != 200) { |     if (res.statusCode != 200) { | ||||||
|       var message = utf8.decode(res.bodyBytes); |       var message = utf8.decode(res.bodyBytes); | ||||||
|       ScaffoldMessenger.of(context).showSnackBar( |       context.showErrorDialog(message); | ||||||
|         SnackBar(content: Text("Something went wrong... $message")), |  | ||||||
|       ); |  | ||||||
|     } else if (Navigator.canPop(context)) { |     } else if (Navigator.canPop(context)) { | ||||||
|       Navigator.pop(context, true); |       Navigator.pop(context, true); | ||||||
|     } |     } | ||||||
| @@ -58,9 +57,7 @@ class _ChannelDeletionState extends State<ChannelDeletion> { | |||||||
|     ); |     ); | ||||||
|     if (res.statusCode != 200) { |     if (res.statusCode != 200) { | ||||||
|       var message = utf8.decode(res.bodyBytes); |       var message = utf8.decode(res.bodyBytes); | ||||||
|       ScaffoldMessenger.of(context).showSnackBar( |       context.showErrorDialog(message); | ||||||
|         SnackBar(content: Text("Something went wrong... $message")), |  | ||||||
|       ); |  | ||||||
|     } else if (Navigator.canPop(context)) { |     } else if (Navigator.canPop(context)) { | ||||||
|       Navigator.pop(context, true); |       Navigator.pop(context, true); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ import 'package:solian/models/message.dart'; | |||||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | ||||||
| import 'package:solian/providers/auth.dart'; | import 'package:solian/providers/auth.dart'; | ||||||
| import 'package:solian/utils/service_url.dart'; | import 'package:solian/utils/service_url.dart'; | ||||||
|  | import 'package:solian/widgets/exts.dart'; | ||||||
|  |  | ||||||
| class ChatMessageDeletionDialog extends StatefulWidget { | class ChatMessageDeletionDialog extends StatefulWidget { | ||||||
|   final String channel; |   final String channel; | ||||||
| @@ -34,9 +35,7 @@ class _ChatMessageDeletionDialogState extends State<ChatMessageDeletionDialog> { | |||||||
|     final res = await auth.client!.delete(uri); |     final res = await auth.client!.delete(uri); | ||||||
|     if (res.statusCode != 200) { |     if (res.statusCode != 200) { | ||||||
|       var message = utf8.decode(res.bodyBytes); |       var message = utf8.decode(res.bodyBytes); | ||||||
|       ScaffoldMessenger.of(context).showSnackBar( |       context.showErrorDialog(message); | ||||||
|         SnackBar(content: Text("Something went wrong... $message")), |  | ||||||
|       ); |  | ||||||
|       setState(() => _isSubmitting = false); |       setState(() => _isSubmitting = false); | ||||||
|     } else { |     } else { | ||||||
|       Navigator.pop(context, true); |       Navigator.pop(context, true); | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ import 'package:solian/models/message.dart'; | |||||||
| import 'package:solian/models/post.dart'; | import 'package:solian/models/post.dart'; | ||||||
| import 'package:solian/providers/auth.dart'; | import 'package:solian/providers/auth.dart'; | ||||||
| import 'package:solian/utils/service_url.dart'; | import 'package:solian/utils/service_url.dart'; | ||||||
|  | import 'package:solian/widgets/exts.dart'; | ||||||
| import 'package:solian/widgets/posts/attachment_editor.dart'; | import 'package:solian/widgets/posts/attachment_editor.dart'; | ||||||
| import 'package:badges/badges.dart' as badge; | import 'package:badges/badges.dart' as badge; | ||||||
|  |  | ||||||
| @@ -64,9 +65,7 @@ class _ChatMessageEditorState extends State<ChatMessageEditor> { | |||||||
|     var res = await Response.fromStream(await auth.client!.send(req)); |     var res = await Response.fromStream(await auth.client!.send(req)); | ||||||
|     if (res.statusCode != 200) { |     if (res.statusCode != 200) { | ||||||
|       var message = utf8.decode(res.bodyBytes); |       var message = utf8.decode(res.bodyBytes); | ||||||
|       ScaffoldMessenger.of(context).showSnackBar( |       context.showErrorDialog(message); | ||||||
|         SnackBar(content: Text("Something went wrong... $message")), |  | ||||||
|       ); |  | ||||||
|     } else { |     } else { | ||||||
|       reset(); |       reset(); | ||||||
|     } |     } | ||||||
|   | |||||||
							
								
								
									
										18
									
								
								lib/widgets/exts.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								lib/widgets/exts.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | ||||||
|  |  | ||||||
|  | extension SolianCommonExtensions on BuildContext { | ||||||
|  |   Future<void> showErrorDialog(dynamic exception) => showDialog<void>( | ||||||
|  |     context: this, | ||||||
|  |     builder: (ctx) => AlertDialog( | ||||||
|  |       title: Text(AppLocalizations.of(this)!.errorHappened), | ||||||
|  |       content: Text(exception.toString()), | ||||||
|  |       actions: [ | ||||||
|  |         TextButton( | ||||||
|  |           onPressed: () => Navigator.pop(ctx), | ||||||
|  |           child: Text(AppLocalizations.of(this)!.confirmOkay), | ||||||
|  |         ) | ||||||
|  |       ], | ||||||
|  |     ), | ||||||
|  |   ); | ||||||
|  | } | ||||||
| @@ -72,7 +72,7 @@ class _SolianNavigationDrawerState extends State<SolianNavigationDrawer> { | |||||||
|               Image.asset("assets/logo.png", width: 26, height: 26), |               Image.asset("assets/logo.png", width: 26, height: 26), | ||||||
|               const SizedBox(width: 10), |               const SizedBox(width: 10), | ||||||
|               Text( |               Text( | ||||||
|                 AppLocalizations.of(context)!.solian, |                 AppLocalizations.of(context)!.appName, | ||||||
|                 style: const TextStyle(fontWeight: FontWeight.w900), |                 style: const TextStyle(fontWeight: FontWeight.w900), | ||||||
|               ), |               ), | ||||||
|             ], |             ], | ||||||
|   | |||||||
| @@ -12,6 +12,7 @@ import 'package:solian/models/post.dart'; | |||||||
| import 'package:solian/providers/auth.dart'; | import 'package:solian/providers/auth.dart'; | ||||||
| import 'package:solian/utils/service_url.dart'; | import 'package:solian/utils/service_url.dart'; | ||||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | ||||||
|  | import 'package:solian/widgets/exts.dart'; | ||||||
|  |  | ||||||
| class AttachmentEditor extends StatefulWidget { | class AttachmentEditor extends StatefulWidget { | ||||||
|   final String provider; |   final String provider; | ||||||
| @@ -67,9 +68,7 @@ class _AttachmentEditorState extends State<AttachmentEditor> { | |||||||
|     try { |     try { | ||||||
|       await uploadAttachment(file, hashcode); |       await uploadAttachment(file, hashcode); | ||||||
|     } catch (err) { |     } catch (err) { | ||||||
|       ScaffoldMessenger.of(context).showSnackBar( |       context.showErrorDialog(err); | ||||||
|         SnackBar(content: Text("Something went wrong... $err")), |  | ||||||
|       ); |  | ||||||
|     } finally { |     } finally { | ||||||
|       setState(() => _isSubmitting = false); |       setState(() => _isSubmitting = false); | ||||||
|     } |     } | ||||||
| @@ -94,9 +93,7 @@ class _AttachmentEditorState extends State<AttachmentEditor> { | |||||||
|     try { |     try { | ||||||
|       await uploadAttachment(file, hashcode); |       await uploadAttachment(file, hashcode); | ||||||
|     } catch (err) { |     } catch (err) { | ||||||
|       ScaffoldMessenger.of(context).showSnackBar( |       context.showErrorDialog(err); | ||||||
|         SnackBar(content: Text("Something went wrong... $err")), |  | ||||||
|       ); |  | ||||||
|     } finally { |     } finally { | ||||||
|       setState(() => _isSubmitting = false); |       setState(() => _isSubmitting = false); | ||||||
|     } |     } | ||||||
| @@ -133,9 +130,7 @@ class _AttachmentEditorState extends State<AttachmentEditor> { | |||||||
|       widget.onUpdate(_attachments); |       widget.onUpdate(_attachments); | ||||||
|     } else { |     } else { | ||||||
|       final err = utf8.decode(await res.stream.toBytes()); |       final err = utf8.decode(await res.stream.toBytes()); | ||||||
|       ScaffoldMessenger.of(context).showSnackBar( |       context.showErrorDialog(err); | ||||||
|         SnackBar(content: Text("Something went wrong... $err")), |  | ||||||
|       ); |  | ||||||
|     } |     } | ||||||
|     setState(() => _isSubmitting = false); |     setState(() => _isSubmitting = false); | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ import 'package:solian/models/post.dart'; | |||||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | ||||||
| import 'package:solian/providers/auth.dart'; | import 'package:solian/providers/auth.dart'; | ||||||
| import 'package:solian/utils/service_url.dart'; | import 'package:solian/utils/service_url.dart'; | ||||||
|  | import 'package:solian/widgets/exts.dart'; | ||||||
|  |  | ||||||
| class ItemDeletionDialog extends StatefulWidget { | class ItemDeletionDialog extends StatefulWidget { | ||||||
|   final Post item; |   final Post item; | ||||||
| @@ -35,9 +36,7 @@ class _ItemDeletionDialogState extends State<ItemDeletionDialog> { | |||||||
|     final res = await auth.client!.delete(uri); |     final res = await auth.client!.delete(uri); | ||||||
|     if (res.statusCode != 200) { |     if (res.statusCode != 200) { | ||||||
|       var message = utf8.decode(res.bodyBytes); |       var message = utf8.decode(res.bodyBytes); | ||||||
|       ScaffoldMessenger.of(context).showSnackBar( |       context.showErrorDialog(message); | ||||||
|         SnackBar(content: Text("Something went wrong... $message")), |  | ||||||
|       ); |  | ||||||
|       setState(() => _isSubmitting = false); |       setState(() => _isSubmitting = false); | ||||||
|     } else { |     } else { | ||||||
|       Navigator.pop(context, true); |       Navigator.pop(context, true); | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ import 'package:solian/models/reaction.dart'; | |||||||
| import 'package:solian/providers/auth.dart'; | import 'package:solian/providers/auth.dart'; | ||||||
| import 'package:solian/utils/service_url.dart'; | import 'package:solian/utils/service_url.dart'; | ||||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | ||||||
|  | import 'package:solian/widgets/exts.dart'; | ||||||
|  |  | ||||||
| Future<void> doReact( | Future<void> doReact( | ||||||
|   String dataset, |   String dataset, | ||||||
| @@ -51,9 +52,7 @@ Future<void> doReact( | |||||||
|     ); |     ); | ||||||
|   } else { |   } else { | ||||||
|     final message = utf8.decode(res.bodyBytes); |     final message = utf8.decode(res.bodyBytes); | ||||||
|     ScaffoldMessenger.of(context).showSnackBar( |     context.showErrorDialog(message); | ||||||
|       SnackBar(content: Text("Something went wrong... $message")), |  | ||||||
|     ); |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (Navigator.canPop(context)) { |   if (Navigator.canPop(context)) { | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ | |||||||
| <plist version="1.0"> | <plist version="1.0"> | ||||||
| <dict> | <dict> | ||||||
| 	<key>ITSAppUsesNonExemptEncryption</key> | 	<key>ITSAppUsesNonExemptEncryption</key> | ||||||
| 	<true/> | 	<false/> | ||||||
| 	<key>CFBundleDevelopmentRegion</key> | 	<key>CFBundleDevelopmentRegion</key> | ||||||
| 	<string>$(DEVELOPMENT_LANGUAGE)</string> | 	<string>$(DEVELOPMENT_LANGUAGE)</string> | ||||||
| 	<key>CFBundleExecutable</key> | 	<key>CFBundleExecutable</key> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user