🐛 Bug fixes
This commit is contained in:
parent
e665b44507
commit
5922d325e5
@ -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) {
|
localTrack.videoTrack = t.track;
|
||||||
screenTracks.add(ParticipantTrack(
|
localTrack.isScreenShare = t.isScreenShare;
|
||||||
participant: _callRoom.localParticipant!,
|
|
||||||
videoTrack: t.track as VideoTrack,
|
|
||||||
isScreenShare: true,
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
localTrack.videoTrack = t.track;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,206 +1,73 @@
|
|||||||
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,
|
|
||||||
builder: (ctx) => AlertDialog(
|
|
||||||
title: const Text('Play Audio'),
|
|
||||||
content: const Text(
|
|
||||||
'You need to manually activate audio PlayBack for iOS Safari !'),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.pop(ctx, false),
|
|
||||||
child: const Text('Ignore'),
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.pop(ctx, true),
|
|
||||||
child: const Text('Play Audio'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
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>(
|
|
||||||
context: this,
|
|
||||||
builder: (ctx) => AlertDialog(
|
|
||||||
title: const Text('Disconnect'),
|
|
||||||
content: const Text('Are you sure to disconnect?'),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.pop(ctx, false),
|
|
||||||
child: const Text('Cancel'),
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.pop(ctx, true),
|
|
||||||
child: const Text('Disconnect'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
Future<bool?> showReconnectDialog() => showDialog<bool>(
|
|
||||||
context: this,
|
|
||||||
builder: (ctx) => AlertDialog(
|
|
||||||
title: const Text('Reconnect'),
|
|
||||||
content: const Text('This will force a reconnection'),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.pop(ctx, false),
|
|
||||||
child: const Text('Cancel'),
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.pop(ctx, true),
|
|
||||||
child: const Text('Reconnect'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
Future<void> showReconnectSuccessDialog() => showDialog<void>(
|
|
||||||
context: this,
|
|
||||||
builder: (ctx) => AlertDialog(
|
|
||||||
title: const Text('Reconnect'),
|
|
||||||
content: const Text('Reconnection was successful.'),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.pop(ctx),
|
|
||||||
child: const Text('OK'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
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,
|
context: this,
|
||||||
builder: (ctx) => AlertDialog(
|
builder: (ctx) => AlertDialog(
|
||||||
title: const Text('Room recording reminder'),
|
title: const Text('Play Audio'),
|
||||||
content: Text(isActiveRecording
|
content: const Text(
|
||||||
? 'Room recording is active.'
|
'You need to manually activate audio PlayBack for iOS Safari!',
|
||||||
: 'Room recording is stoped.'),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.pop(ctx, false),
|
||||||
|
child: const Text('Ignore'),
|
||||||
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.pop(ctx, true),
|
onPressed: () => Navigator.pop(ctx, true),
|
||||||
child: const Text('OK'),
|
child: const Text('Play Audio'),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Future<bool?> showSubscribePermissionDialog() => showDialog<bool>(
|
Future<bool?> showDisconnectDialog() => showDialog<bool>(
|
||||||
context: this,
|
context: this,
|
||||||
builder: (ctx) => AlertDialog(
|
builder: (ctx) => AlertDialog(
|
||||||
title: const Text('Allow subscription'),
|
title: const Text('Disconnect'),
|
||||||
content: const Text(
|
content: const Text('Are you sure to disconnect?'),
|
||||||
'Allow all participants to subscribe tracks published by local participant?'),
|
actions: [
|
||||||
actions: [
|
TextButton(
|
||||||
TextButton(
|
onPressed: () => Navigator.pop(ctx, false),
|
||||||
onPressed: () => Navigator.pop(ctx, false),
|
child: const Text('Cancel'),
|
||||||
child: const Text('NO'),
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.pop(ctx, true),
|
||||||
|
child: const Text('Disconnect'),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
TextButton(
|
);
|
||||||
onPressed: () => Navigator.pop(ctx, true),
|
|
||||||
child: const Text('YES'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
enum SimulateScenarioResult {
|
Future<bool?> showReconnectDialog() => showDialog<bool>(
|
||||||
signalReconnect,
|
context: this,
|
||||||
fullReconnect,
|
builder: (ctx) => AlertDialog(
|
||||||
speakerUpdate,
|
title: const Text('Reconnect'),
|
||||||
nodeFailure,
|
content: const Text('This will force a reconnection'),
|
||||||
migration,
|
actions: [
|
||||||
serverLeave,
|
TextButton(
|
||||||
switchCandidate,
|
onPressed: () => Navigator.pop(ctx, false),
|
||||||
e2eeKeyRatchet,
|
child: const Text('Cancel'),
|
||||||
participantName,
|
),
|
||||||
participantMetadata,
|
TextButton(
|
||||||
clear,
|
onPressed: () => Navigator.pop(ctx, true),
|
||||||
|
child: const Text('Reconnect'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
Future<void> showReconnectSuccessDialog() => showDialog<void>(
|
||||||
|
context: this,
|
||||||
|
builder: (ctx) => AlertDialog(
|
||||||
|
title: const Text('Reconnect'),
|
||||||
|
content: const Text('Reconnection was successful.'),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.pop(ctx),
|
||||||
|
child: const Text('OK'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
@ -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,35 +41,41 @@ 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,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Animate(
|
child: Animate(
|
||||||
autoPlay: false,
|
autoPlay: false,
|
||||||
controller: _animationController,
|
controller: _animationController,
|
||||||
effects: [
|
effects: [
|
||||||
CustomEffect(
|
CustomEffect(
|
||||||
begin: widget.isSpeaking ? 2 : 0,
|
begin: widget.isSpeaking ? 2 : 0,
|
||||||
end: 8,
|
end: 8,
|
||||||
curve: Curves.easeInOut,
|
curve: Curves.easeInOut,
|
||||||
duration: 1250.ms,
|
duration: 1250.ms,
|
||||||
builder: (context, value, child) => Container(
|
builder: (context, value, child) => Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.all(Radius.circular(radius + 8)),
|
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,
|
|
||||||
),
|
),
|
||||||
)
|
child: child,
|
||||||
],
|
),
|
||||||
child: AccountAvatar(
|
)
|
||||||
source: widget.userinfo!.avatar,
|
],
|
||||||
backgroundColor: Colors.transparent,
|
child: AccountAvatar(
|
||||||
radius: radius,
|
source: widget.userinfo!.avatar,
|
||||||
direct: true,
|
backgroundColor: Colors.transparent,
|
||||||
)),
|
radius: radius,
|
||||||
|
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>
|
||||||
|
Loading…
Reference in New Issue
Block a user