mirror of
				https://gitlab.com/famedly/fluffychat.git
				synced 2025-10-31 03:57:27 +01:00 
			
		
		
		
	Merge branch 'master' into desktop-support
This commit is contained in:
		
						commit
						26dbfb70cc
					
				| @ -1,3 +1,8 @@ | ||||
| # Version 0.13.0 - 2020-??-?? | ||||
| ### Features: | ||||
| - New status feature | ||||
| - Enhanced chat list design | ||||
| 
 | ||||
| # Version 0.12.4 - 2020-04-17 | ||||
| ### Fixed | ||||
| - Login without google services | ||||
|  | ||||
| @ -7,7 +7,7 @@ import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_sound/flutter_sound.dart'; | ||||
| import 'package:intl/intl.dart'; | ||||
| 
 | ||||
| import 'matrix.dart'; | ||||
| import 'dialogs/simple_dialogs.dart'; | ||||
| 
 | ||||
| class AudioPlayer extends StatefulWidget { | ||||
|   final Color color; | ||||
| @ -48,7 +48,7 @@ class _AudioPlayerState extends State<AudioPlayer> { | ||||
|   _downloadAction() async { | ||||
|     if (status != AudioPlayerStatus.NOT_DOWNLOADED) return; | ||||
|     setState(() => status = AudioPlayerStatus.DOWNLOADING); | ||||
|     final matrixFile = await Matrix.of(context) | ||||
|     final matrixFile = await SimpleDialogs(context) | ||||
|         .tryRequestWithErrorToast(widget.event.downloadAndDecryptAttachment()); | ||||
|     setState(() { | ||||
|       audioFile = matrixFile.bytes; | ||||
|  | ||||
| @ -33,7 +33,7 @@ class _ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> { | ||||
|   void startCallAction(BuildContext context) async { | ||||
|     final url = | ||||
|         '${Matrix.of(context).jitsiInstance}${Uri.encodeComponent(widget.room.id.localpart)}'; | ||||
|     final success = await Matrix.of(context) | ||||
|     final success = await SimpleDialogs(context) | ||||
|         .tryRequestWithLoadingDialog(widget.room.sendEvent({ | ||||
|       'msgtype': Matrix.callNamespace, | ||||
|       'body': url, | ||||
| @ -86,7 +86,7 @@ class _ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> { | ||||
|           case "leave": | ||||
|             bool confirmed = await SimpleDialogs(context).askConfirmation(); | ||||
|             if (confirmed) { | ||||
|               final success = await Matrix.of(context) | ||||
|               final success = await SimpleDialogs(context) | ||||
|                   .tryRequestWithLoadingDialog(widget.room.leave()); | ||||
|               if (success != false) { | ||||
|                 await Navigator.of(context).pushAndRemoveUntil( | ||||
| @ -96,11 +96,11 @@ class _ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> { | ||||
|             } | ||||
|             break; | ||||
|           case "mute": | ||||
|             await Matrix.of(context).tryRequestWithLoadingDialog( | ||||
|             await SimpleDialogs(context).tryRequestWithLoadingDialog( | ||||
|                 widget.room.setPushRuleState(PushRuleState.mentions_only)); | ||||
|             break; | ||||
|           case "unmute": | ||||
|             await Matrix.of(context).tryRequestWithLoadingDialog( | ||||
|             await SimpleDialogs(context).tryRequestWithLoadingDialog( | ||||
|                 widget.room.setPushRuleState(PushRuleState.notify)); | ||||
|             break; | ||||
|           case "call": | ||||
|  | ||||
| @ -1,5 +1,7 @@ | ||||
| import 'package:fluffychat/i18n/i18n.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:famedlysdk/famedlysdk.dart'; | ||||
| import 'package:flutter_styled_toast/flutter_styled_toast.dart'; | ||||
| 
 | ||||
| class SimpleDialogs { | ||||
|   final BuildContext context; | ||||
| @ -22,7 +24,7 @@ class SimpleDialogs { | ||||
|     await showDialog( | ||||
|       context: context, | ||||
|       builder: (c) => AlertDialog( | ||||
|         title: Text(titleText ?? I18n.of(context).enterAUsername), | ||||
|         title: Text(titleText ?? 'Please enter a text'), | ||||
|         content: TextField( | ||||
|           controller: controller, | ||||
|           autofocus: true, | ||||
| @ -104,4 +106,46 @@ class SimpleDialogs { | ||||
|     ); | ||||
|     return confirmed; | ||||
|   } | ||||
| 
 | ||||
|   Future<dynamic> tryRequestWithLoadingDialog(Future<dynamic> request, | ||||
|       {Function(MatrixException) onAdditionalAuth}) async { | ||||
|     showLoadingDialog(context); | ||||
|     final dynamic = await tryRequestWithErrorToast(request, | ||||
|         onAdditionalAuth: onAdditionalAuth); | ||||
|     Navigator.of(context)?.pop(); | ||||
|     return dynamic; | ||||
|   } | ||||
| 
 | ||||
|   Future<dynamic> tryRequestWithErrorToast(Future<dynamic> request, | ||||
|       {Function(MatrixException) onAdditionalAuth}) async { | ||||
|     try { | ||||
|       return await request; | ||||
|     } on MatrixException catch (exception) { | ||||
|       if (exception.requireAdditionalAuthentication && | ||||
|           onAdditionalAuth != null) { | ||||
|         return await tryRequestWithErrorToast(onAdditionalAuth(exception)); | ||||
|       } else { | ||||
|         showToast(exception.errorMessage); | ||||
|       } | ||||
|     } catch (exception) { | ||||
|       showToast(exception.toString()); | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   showLoadingDialog(BuildContext context) { | ||||
|     showDialog( | ||||
|       context: context, | ||||
|       barrierDismissible: false, | ||||
|       builder: (BuildContext context) => AlertDialog( | ||||
|         content: Row( | ||||
|           children: <Widget>[ | ||||
|             CircularProgressIndicator(), | ||||
|             SizedBox(width: 16), | ||||
|             Text(I18n.of(context).loadingPleaseWait), | ||||
|           ], | ||||
|         ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -43,7 +43,7 @@ class _EncryptionButtonState extends State<EncryptionButton> { | ||||
|           confirmText: I18n.of(context).yes, | ||||
|         ) == | ||||
|         true) { | ||||
|       await Matrix.of(context).tryRequestWithLoadingDialog( | ||||
|       await SimpleDialogs(context).tryRequestWithLoadingDialog( | ||||
|         widget.room.enableEncryption(), | ||||
|       ); | ||||
|     } | ||||
|  | ||||
| @ -26,7 +26,8 @@ class ChatListItem extends StatelessWidget { | ||||
|   void clickAction(BuildContext context) async { | ||||
|     if (!activeChat) { | ||||
|       if (room.membership == Membership.invite && | ||||
|           await Matrix.of(context).tryRequestWithLoadingDialog(room.join()) == | ||||
|           await SimpleDialogs(context) | ||||
|                   .tryRequestWithLoadingDialog(room.join()) == | ||||
|               false) { | ||||
|         return; | ||||
|       } | ||||
| @ -60,7 +61,7 @@ class ChatListItem extends StatelessWidget { | ||||
|                 child: Text(I18n.of(context).rejoin.toUpperCase(), | ||||
|                     style: TextStyle(color: Colors.blue)), | ||||
|                 onPressed: () async { | ||||
|                   await Matrix.of(context) | ||||
|                   await SimpleDialogs(context) | ||||
|                       .tryRequestWithLoadingDialog(room.join()); | ||||
|                   await Navigator.of(context).pop(); | ||||
|                 }, | ||||
| @ -74,7 +75,7 @@ class ChatListItem extends StatelessWidget { | ||||
|         if (Matrix.of(context).shareContent != null) { | ||||
|           if (Matrix.of(context).shareContent["msgtype"] == | ||||
|               "chat.fluffy.shared_file") { | ||||
|             await Matrix.of(context).tryRequestWithErrorToast( | ||||
|             await SimpleDialogs(context).tryRequestWithErrorToast( | ||||
|               room.sendFileEvent( | ||||
|                 Matrix.of(context).shareContent["file"], | ||||
|               ), | ||||
| @ -96,8 +97,8 @@ class ChatListItem extends StatelessWidget { | ||||
|   Future<bool> archiveAction(BuildContext context) async { | ||||
|     { | ||||
|       if ([Membership.leave, Membership.ban].contains(room.membership)) { | ||||
|         final success = | ||||
|             await Matrix.of(context).tryRequestWithLoadingDialog(room.forget()); | ||||
|         final success = await SimpleDialogs(context) | ||||
|             .tryRequestWithLoadingDialog(room.forget()); | ||||
|         if (success != false) { | ||||
|           if (this.onForget != null) this.onForget(); | ||||
|         } | ||||
| @ -107,8 +108,8 @@ class ChatListItem extends StatelessWidget { | ||||
|       if (!confirmed) { | ||||
|         return false; | ||||
|       } | ||||
|       final success = | ||||
|           await Matrix.of(context).tryRequestWithLoadingDialog(room.leave()); | ||||
|       final success = await SimpleDialogs(context) | ||||
|           .tryRequestWithLoadingDialog(room.leave()); | ||||
|       if (success == false) { | ||||
|         return false; | ||||
|       } | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| import 'package:bubble/bubble.dart'; | ||||
| import 'package:famedlysdk/famedlysdk.dart'; | ||||
| import 'package:fluffychat/components/dialogs/simple_dialogs.dart'; | ||||
| import 'package:fluffychat/components/message_content.dart'; | ||||
| import 'package:fluffychat/components/reply_content.dart'; | ||||
| import 'package:fluffychat/i18n/i18n.dart'; | ||||
| @ -116,7 +117,7 @@ class Message extends StatelessWidget { | ||||
|                         I18n.of(context).requestPermission, | ||||
|                         style: TextStyle(color: textColor), | ||||
|                       ), | ||||
|                       onPressed: () => Matrix.of(context) | ||||
|                       onPressed: () => SimpleDialogs(context) | ||||
|                           .tryRequestWithLoadingDialog(event.requestKey()), | ||||
|                     ), | ||||
|                   SizedBox(height: 4), | ||||
|  | ||||
| @ -14,36 +14,39 @@ class ParticipantListItem extends StatelessWidget { | ||||
|   const ParticipantListItem(this.user); | ||||
| 
 | ||||
|   participantAction(BuildContext context, String action) async { | ||||
|     final MatrixState matrix = Matrix.of(context); | ||||
|     switch (action) { | ||||
|       case "ban": | ||||
|         if (await SimpleDialogs(context).askConfirmation()) { | ||||
|           await matrix.tryRequestWithLoadingDialog(user.ban()); | ||||
|           await SimpleDialogs(context).tryRequestWithLoadingDialog(user.ban()); | ||||
|         } | ||||
|         break; | ||||
|       case "unban": | ||||
|         if (await SimpleDialogs(context).askConfirmation()) { | ||||
|           await matrix.tryRequestWithLoadingDialog(user.unban()); | ||||
|           await SimpleDialogs(context) | ||||
|               .tryRequestWithLoadingDialog(user.unban()); | ||||
|         } | ||||
|         break; | ||||
|       case "kick": | ||||
|         if (await SimpleDialogs(context).askConfirmation()) { | ||||
|           await matrix.tryRequestWithLoadingDialog(user.kick()); | ||||
|           await SimpleDialogs(context).tryRequestWithLoadingDialog(user.kick()); | ||||
|         } | ||||
|         break; | ||||
|       case "admin": | ||||
|         if (await SimpleDialogs(context).askConfirmation()) { | ||||
|           await matrix.tryRequestWithLoadingDialog(user.setPower(100)); | ||||
|           await SimpleDialogs(context) | ||||
|               .tryRequestWithLoadingDialog(user.setPower(100)); | ||||
|         } | ||||
|         break; | ||||
|       case "moderator": | ||||
|         if (await SimpleDialogs(context).askConfirmation()) { | ||||
|           await matrix.tryRequestWithLoadingDialog(user.setPower(50)); | ||||
|           await SimpleDialogs(context) | ||||
|               .tryRequestWithLoadingDialog(user.setPower(50)); | ||||
|         } | ||||
|         break; | ||||
|       case "user": | ||||
|         if (await SimpleDialogs(context).askConfirmation()) { | ||||
|           await matrix.tryRequestWithLoadingDialog(user.setPower(0)); | ||||
|           await SimpleDialogs(context) | ||||
|               .tryRequestWithLoadingDialog(user.setPower(0)); | ||||
|         } | ||||
|         break; | ||||
|       case "message": | ||||
|  | ||||
							
								
								
									
										93
									
								
								lib/components/list_items/presence_list_item.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								lib/components/list_items/presence_list_item.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,93 @@ | ||||
| import 'package:famedlysdk/famedlysdk.dart'; | ||||
| import 'package:fluffychat/i18n/i18n.dart'; | ||||
| import 'package:fluffychat/utils/app_route.dart'; | ||||
| import 'package:fluffychat/utils/date_time_extension.dart'; | ||||
| import 'package:fluffychat/views/chat.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| 
 | ||||
| import '../avatar.dart'; | ||||
| import '../matrix.dart'; | ||||
| import 'package:fluffychat/utils/presence_extension.dart'; | ||||
| 
 | ||||
| class PresenceListItem extends StatelessWidget { | ||||
|   final Presence presence; | ||||
| 
 | ||||
|   const PresenceListItem(this.presence); | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return FutureBuilder<Profile>( | ||||
|         future: Matrix.of(context).client.getProfileFromUserId(presence.sender), | ||||
|         builder: (context, snapshot) { | ||||
|           MxContent avatarUrl = MxContent(''); | ||||
|           String displayname = presence.sender.localpart; | ||||
|           if (snapshot.hasData) { | ||||
|             avatarUrl = snapshot.data.avatarUrl; | ||||
|             displayname = snapshot.data.displayname; | ||||
|           } | ||||
|           return InkWell( | ||||
|             onTap: () => showDialog( | ||||
|               context: context, | ||||
|               builder: (c) => AlertDialog( | ||||
|                 title: ListTile( | ||||
|                   contentPadding: EdgeInsets.zero, | ||||
|                   leading: Avatar(avatarUrl, displayname), | ||||
|                   title: Text(displayname), | ||||
|                   subtitle: Text(presence.sender), | ||||
|                 ), | ||||
|                 content: Column( | ||||
|                   mainAxisSize: MainAxisSize.min, | ||||
|                   crossAxisAlignment: CrossAxisAlignment.start, | ||||
|                   children: <Widget>[ | ||||
|                     Text(presence.getLocalizedStatusMessage(context)), | ||||
|                     Text( | ||||
|                       presence.time.localizedTime(context), | ||||
|                       style: TextStyle(fontSize: 12), | ||||
|                     ), | ||||
|                   ], | ||||
|                 ), | ||||
|                 actions: <Widget>[ | ||||
|                   if (presence.sender != Matrix.of(context).client.userID) | ||||
|                     FlatButton( | ||||
|                       child: Text(I18n.of(context).sendAMessage), | ||||
|                       onPressed: () async { | ||||
|                         final String roomId = await User( | ||||
|                           presence.sender, | ||||
|                           room: Room(id: '', client: Matrix.of(context).client), | ||||
|                         ).startDirectChat(); | ||||
|                         await Navigator.of(context).pushAndRemoveUntil( | ||||
|                             AppRoute.defaultRoute( | ||||
|                               context, | ||||
|                               ChatView(roomId), | ||||
|                             ), | ||||
|                             (Route r) => r.isFirst); | ||||
|                       }, | ||||
|                     ), | ||||
|                   FlatButton( | ||||
|                     child: Text(I18n.of(context).close), | ||||
|                     onPressed: () => Navigator.of(context).pop(), | ||||
|                   ), | ||||
|                 ], | ||||
|               ), | ||||
|             ), | ||||
|             child: Container( | ||||
|               width: 80, | ||||
|               child: Column( | ||||
|                 children: <Widget>[ | ||||
|                   SizedBox(height: 9), | ||||
|                   Avatar(avatarUrl, displayname), | ||||
|                   Padding( | ||||
|                     padding: const EdgeInsets.all(6.0), | ||||
|                     child: Text( | ||||
|                       displayname, | ||||
|                       overflow: TextOverflow.ellipsis, | ||||
|                       maxLines: 1, | ||||
|                     ), | ||||
|                   ), | ||||
|                 ], | ||||
|               ), | ||||
|             ), | ||||
|           ); | ||||
|         }); | ||||
|   } | ||||
| } | ||||
| @ -1,11 +1,11 @@ | ||||
| import 'package:famedlysdk/famedlysdk.dart'; | ||||
| import 'package:fluffychat/components/dialogs/simple_dialogs.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| 
 | ||||
| import '../../i18n/i18n.dart'; | ||||
| import '../../utils/app_route.dart'; | ||||
| import '../../views/chat.dart'; | ||||
| import '../avatar.dart'; | ||||
| import '../matrix.dart'; | ||||
| 
 | ||||
| class PublicRoomListItem extends StatelessWidget { | ||||
|   final PublicRoomEntry publicRoomEntry; | ||||
| @ -13,7 +13,7 @@ class PublicRoomListItem extends StatelessWidget { | ||||
|   const PublicRoomListItem(this.publicRoomEntry, {Key key}) : super(key: key); | ||||
| 
 | ||||
|   void joinAction(BuildContext context) async { | ||||
|     final success = await Matrix.of(context) | ||||
|     final success = await SimpleDialogs(context) | ||||
|         .tryRequestWithLoadingDialog(publicRoomEntry.join()); | ||||
|     if (success != false) { | ||||
|       await Navigator.of(context).push( | ||||
|  | ||||
| @ -78,53 +78,6 @@ class MatrixState extends State<Matrix> { | ||||
|     await storage.remove(widget.clientName); | ||||
|   } | ||||
| 
 | ||||
|   BuildContext _loadingDialogContext; | ||||
| 
 | ||||
|   Future<dynamic> tryRequestWithLoadingDialog(Future<dynamic> request, | ||||
|       {Function(MatrixException) onAdditionalAuth}) async { | ||||
|     showLoadingDialog(context); | ||||
|     final dynamic = await tryRequestWithErrorToast(request, | ||||
|         onAdditionalAuth: onAdditionalAuth); | ||||
|     hideLoadingDialog(); | ||||
|     return dynamic; | ||||
|   } | ||||
| 
 | ||||
|   Future<dynamic> tryRequestWithErrorToast(Future<dynamic> request, | ||||
|       {Function(MatrixException) onAdditionalAuth}) async { | ||||
|     try { | ||||
|       return await request; | ||||
|     } on MatrixException catch (exception) { | ||||
|       if (exception.requireAdditionalAuthentication && | ||||
|           onAdditionalAuth != null) { | ||||
|         return await tryRequestWithErrorToast(onAdditionalAuth(exception)); | ||||
|       } else { | ||||
|         showToast(exception.errorMessage); | ||||
|       } | ||||
|     } catch (exception) { | ||||
|       showToast(exception.toString()); | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   showLoadingDialog(BuildContext context) { | ||||
|     _loadingDialogContext = context; | ||||
|     showDialog( | ||||
|       context: _loadingDialogContext, | ||||
|       barrierDismissible: false, | ||||
|       builder: (BuildContext context) => AlertDialog( | ||||
|         content: Row( | ||||
|           children: <Widget>[ | ||||
|             CircularProgressIndicator(), | ||||
|             SizedBox(width: 16), | ||||
|             Text(I18n.of(context).loadingPleaseWait), | ||||
|           ], | ||||
|         ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   hideLoadingDialog() => Navigator.of(_loadingDialogContext)?.pop(); | ||||
| 
 | ||||
|   Future<String> downloadAndSaveContent(MxContent content, | ||||
|       {int width, int height, ThumbnailMethod method}) async { | ||||
|     final bool thumbnail = width == null && height == null ? false : true; | ||||
|  | ||||
| @ -10,6 +10,7 @@ import 'package:link_text/link_text.dart'; | ||||
| import 'package:fluffychat/utils/cross_url_launcher.dart'; | ||||
| import 'package:fluffychat/utils/matrix_file_extension.dart'; | ||||
| 
 | ||||
| import 'dialogs/simple_dialogs.dart'; | ||||
| import 'matrix.dart'; | ||||
| 
 | ||||
| class MessageContent extends StatelessWidget { | ||||
| @ -60,8 +61,9 @@ class MessageContent extends StatelessWidget { | ||||
|                           ); | ||||
|                           return; | ||||
|                         } | ||||
|                         final MatrixFile matrixFile = await Matrix.of(context) | ||||
|                             .tryRequestWithLoadingDialog( | ||||
|                         final MatrixFile matrixFile = | ||||
|                             await SimpleDialogs(context) | ||||
|                                 .tryRequestWithLoadingDialog( | ||||
|                           event.downloadAndDecryptAttachment(), | ||||
|                         ); | ||||
|                         matrixFile.open(); | ||||
|  | ||||
| @ -624,6 +624,8 @@ class I18n { | ||||
| 
 | ||||
|   String get setInvitationLink => Intl.message("Set invitation link"); | ||||
| 
 | ||||
|   String get setStatus => Intl.message('Set status'); | ||||
| 
 | ||||
|   String get settings => Intl.message("Settings"); | ||||
| 
 | ||||
|   String get signUp => Intl.message("Sign up"); | ||||
| @ -632,6 +634,8 @@ class I18n { | ||||
| 
 | ||||
|   String get systemTheme => Intl.message("System"); | ||||
| 
 | ||||
|   String get statusExampleMessage => Intl.message("How are you today?"); | ||||
| 
 | ||||
|   String get lightTheme => Intl.message("Light"); | ||||
| 
 | ||||
|   String get darkTheme => Intl.message("Dark"); | ||||
|  | ||||
							
								
								
									
										11
									
								
								lib/utils/client_presence_extension.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								lib/utils/client_presence_extension.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| import 'package:famedlysdk/famedlysdk.dart'; | ||||
| import 'presence_extension.dart'; | ||||
| 
 | ||||
| extension ClientPresenceExtension on Client { | ||||
|   List<Presence> get statusList { | ||||
|     final statusList = presences.values.toList(); | ||||
|     statusList.removeWhere((Presence p) => !p.isStatus); | ||||
|     statusList.sort((a, b) => b.time.compareTo(a.time)); | ||||
|     return statusList; | ||||
|   } | ||||
| } | ||||
							
								
								
									
										23
									
								
								lib/utils/presence_extension.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								lib/utils/presence_extension.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | ||||
| import 'package:famedlysdk/famedlysdk.dart'; | ||||
| import 'package:fluffychat/i18n/i18n.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| 
 | ||||
| extension PresenceExtension on Presence { | ||||
|   bool get isStatus => | ||||
|       (statusMsg?.isNotEmpty ?? false) || this.displayname != null; | ||||
| 
 | ||||
|   String getLocalizedStatusMessage(BuildContext context) { | ||||
|     if (!isStatus) return null; | ||||
|     if (statusMsg?.isNotEmpty ?? false) { | ||||
|       return statusMsg; | ||||
|     } | ||||
|     if (displayname != null) { | ||||
|       return I18n.of(context) | ||||
|           .changedTheDisplaynameTo(sender.localpart, displayname); | ||||
|     } | ||||
|     if (avatarUrl != null) { | ||||
|       return I18n.of(context).changedTheProfileAvatar(sender.localpart); | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
| } | ||||
| @ -1,4 +1,5 @@ | ||||
| import 'package:famedlysdk/famedlysdk.dart'; | ||||
| import 'package:fluffychat/components/dialogs/simple_dialogs.dart'; | ||||
| import 'package:fluffychat/components/matrix.dart'; | ||||
| import 'package:fluffychat/utils/app_route.dart'; | ||||
| import 'package:fluffychat/views/chat.dart'; | ||||
| @ -21,7 +22,7 @@ class UrlLauncher { | ||||
|     final matrix = Matrix.of(context); | ||||
|     final String identifier = url.replaceAll("https://matrix.to/#/", ""); | ||||
|     if (identifier.substring(0, 1) == "#") { | ||||
|       final response = await matrix.tryRequestWithLoadingDialog( | ||||
|       final response = await SimpleDialogs(context).tryRequestWithLoadingDialog( | ||||
|         matrix.client.joinRoomById( | ||||
|           Uri.encodeComponent(identifier), | ||||
|         ), | ||||
| @ -37,8 +38,8 @@ class UrlLauncher { | ||||
|         identifier, | ||||
|         room: Room(id: "", client: matrix.client), | ||||
|       ); | ||||
|       final String roomID = | ||||
|           await matrix.tryRequestWithLoadingDialog(user.startDirectChat()); | ||||
|       final String roomID = await SimpleDialogs(context) | ||||
|           .tryRequestWithLoadingDialog(user.startDirectChat()); | ||||
|       Navigator.of(context).pop(); | ||||
| 
 | ||||
|       if (roomID != null) { | ||||
|  | ||||
| @ -178,7 +178,7 @@ class _ChatState extends State<_Chat> { | ||||
|   void sendFileAction(BuildContext context) async { | ||||
|     File file = await FilePicker.getFile(); | ||||
|     if (file == null) return; | ||||
|     await matrix.tryRequestWithLoadingDialog( | ||||
|     await SimpleDialogs(context).tryRequestWithLoadingDialog( | ||||
|       room.sendFileEvent( | ||||
|         MatrixFile(bytes: await file.readAsBytes(), path: file.path), | ||||
|       ), | ||||
| @ -192,7 +192,7 @@ class _ChatState extends State<_Chat> { | ||||
|         maxWidth: 1600, | ||||
|         maxHeight: 1600); | ||||
|     if (file == null) return; | ||||
|     await matrix.tryRequestWithLoadingDialog( | ||||
|     await SimpleDialogs(context).tryRequestWithLoadingDialog( | ||||
|       room.sendImageEvent( | ||||
|         MatrixFile(bytes: await file.readAsBytes(), path: file.path), | ||||
|       ), | ||||
| @ -206,7 +206,7 @@ class _ChatState extends State<_Chat> { | ||||
|         maxWidth: 1600, | ||||
|         maxHeight: 1600); | ||||
|     if (file == null) return; | ||||
|     await matrix.tryRequestWithLoadingDialog( | ||||
|     await SimpleDialogs(context).tryRequestWithLoadingDialog( | ||||
|       room.sendImageEvent( | ||||
|         MatrixFile(bytes: await file.readAsBytes(), path: file.path), | ||||
|       ), | ||||
| @ -222,7 +222,7 @@ class _ChatState extends State<_Chat> { | ||||
|             )); | ||||
|     if (result == null) return; | ||||
|     final File audioFile = File(result); | ||||
|     await Matrix.of(context).tryRequestWithLoadingDialog( | ||||
|     await SimpleDialogs(context).tryRequestWithLoadingDialog( | ||||
|       room.sendAudioEvent( | ||||
|         MatrixFile(bytes: audioFile.readAsBytesSync(), path: audioFile.path), | ||||
|       ), | ||||
| @ -253,7 +253,7 @@ class _ChatState extends State<_Chat> { | ||||
|     ); | ||||
|     if (!confirmed) return; | ||||
|     for (Event event in selectedEvents) { | ||||
|       await Matrix.of(context).tryRequestWithLoadingDialog( | ||||
|       await SimpleDialogs(context).tryRequestWithLoadingDialog( | ||||
|           event.status > 0 ? event.redact() : event.remove()); | ||||
|     } | ||||
|     setState(() => selectedEvents.clear()); | ||||
| @ -310,7 +310,7 @@ class _ChatState extends State<_Chat> { | ||||
|     matrix.activeRoomId = widget.id; | ||||
| 
 | ||||
|     if (room.membership == Membership.invite) { | ||||
|       matrix.tryRequestWithLoadingDialog(room.join()); | ||||
|       SimpleDialogs(context).tryRequestWithLoadingDialog(room.join()); | ||||
|     } | ||||
| 
 | ||||
|     String typingText = ""; | ||||
|  | ||||
| @ -7,7 +7,6 @@ import 'package:fluffychat/components/chat_settings_popup_menu.dart'; | ||||
| import 'package:fluffychat/components/content_banner.dart'; | ||||
| import 'package:fluffychat/components/dialogs/simple_dialogs.dart'; | ||||
| import 'package:fluffychat/components/list_items/participant_list_item.dart'; | ||||
| import 'package:fluffychat/components/matrix.dart'; | ||||
| import 'package:fluffychat/i18n/i18n.dart'; | ||||
| import 'package:fluffychat/utils/app_route.dart'; | ||||
| import 'package:fluffychat/utils/room_extension.dart'; | ||||
| @ -39,8 +38,7 @@ class _ChatDetailsState extends State<ChatDetails> { | ||||
|       hintText: widget.room.getLocalizedDisplayname(context), | ||||
|     ); | ||||
|     if (displayname == null) return; | ||||
|     final MatrixState matrix = Matrix.of(context); | ||||
|     final success = await matrix.tryRequestWithLoadingDialog( | ||||
|     final success = await SimpleDialogs(context).tryRequestWithLoadingDialog( | ||||
|       widget.room.setName(displayname), | ||||
|     ); | ||||
|     if (success != false) { | ||||
| @ -65,14 +63,15 @@ class _ChatDetailsState extends State<ChatDetails> { | ||||
|     if (aliases.indexWhere((s) => s == canonicalAlias) == -1) { | ||||
|       List<String> newAliases = List.from(aliases); | ||||
|       newAliases.add(canonicalAlias); | ||||
|       final response = await Matrix.of(context).tryRequestWithLoadingDialog( | ||||
|       final response = await SimpleDialogs(context).tryRequestWithLoadingDialog( | ||||
|         widget.room.client.jsonRequest( | ||||
|           type: HTTPType.GET, | ||||
|           action: "/client/r0/directory/room/$canonicalAlias", | ||||
|         ), | ||||
|       ); | ||||
|       if (response == false) { | ||||
|         final success = await Matrix.of(context).tryRequestWithLoadingDialog( | ||||
|         final success = | ||||
|             await SimpleDialogs(context).tryRequestWithLoadingDialog( | ||||
|           widget.room.client.jsonRequest( | ||||
|               type: HTTPType.PUT, | ||||
|               action: "/client/r0/directory/room/$canonicalAlias", | ||||
| @ -81,7 +80,7 @@ class _ChatDetailsState extends State<ChatDetails> { | ||||
|         if (success == false) return; | ||||
|       } | ||||
|     } | ||||
|     await Matrix.of(context).tryRequestWithLoadingDialog( | ||||
|     await SimpleDialogs(context).tryRequestWithLoadingDialog( | ||||
|       widget.room.client.jsonRequest( | ||||
|           type: HTTPType.PUT, | ||||
|           action: | ||||
| @ -100,8 +99,7 @@ class _ChatDetailsState extends State<ChatDetails> { | ||||
|       multiLine: true, | ||||
|     ); | ||||
|     if (displayname == null) return; | ||||
|     final MatrixState matrix = Matrix.of(context); | ||||
|     final success = await matrix.tryRequestWithLoadingDialog( | ||||
|     final success = await SimpleDialogs(context).tryRequestWithLoadingDialog( | ||||
|       widget.room.setDescription(displayname), | ||||
|     ); | ||||
|     if (success != false) { | ||||
| @ -116,8 +114,7 @@ class _ChatDetailsState extends State<ChatDetails> { | ||||
|         maxWidth: 1600, | ||||
|         maxHeight: 1600); | ||||
|     if (tempFile == null) return; | ||||
|     final MatrixState matrix = Matrix.of(context); | ||||
|     final success = await matrix.tryRequestWithLoadingDialog( | ||||
|     final success = await SimpleDialogs(context).tryRequestWithLoadingDialog( | ||||
|       widget.room.setAvatar( | ||||
|         MatrixFile( | ||||
|           bytes: await tempFile.readAsBytes(), | ||||
| @ -131,7 +128,7 @@ class _ChatDetailsState extends State<ChatDetails> { | ||||
|   } | ||||
| 
 | ||||
|   void requestMoreMembersAction(BuildContext context) async { | ||||
|     final List<User> participants = await Matrix.of(context) | ||||
|     final List<User> participants = await SimpleDialogs(context) | ||||
|         .tryRequestWithLoadingDialog(widget.room.requestParticipants()); | ||||
|     if (participants != null) setState(() => members = participants); | ||||
|   } | ||||
| @ -288,7 +285,7 @@ class _ChatDetailsState extends State<ChatDetails> { | ||||
|                           ), | ||||
|                         ), | ||||
|                         onSelected: (JoinRules joinRule) => | ||||
|                             Matrix.of(context).tryRequestWithLoadingDialog( | ||||
|                             SimpleDialogs(context).tryRequestWithLoadingDialog( | ||||
|                           widget.room.setJoinRules(joinRule), | ||||
|                         ), | ||||
|                         itemBuilder: (BuildContext context) => | ||||
| @ -323,7 +320,7 @@ class _ChatDetailsState extends State<ChatDetails> { | ||||
|                           ), | ||||
|                         ), | ||||
|                         onSelected: (HistoryVisibility historyVisibility) => | ||||
|                             Matrix.of(context).tryRequestWithLoadingDialog( | ||||
|                             SimpleDialogs(context).tryRequestWithLoadingDialog( | ||||
|                           widget.room.setHistoryVisibility(historyVisibility), | ||||
|                         ), | ||||
|                         itemBuilder: (BuildContext context) => | ||||
| @ -371,7 +368,8 @@ class _ChatDetailsState extends State<ChatDetails> { | ||||
|                             ), | ||||
|                           ), | ||||
|                           onSelected: (GuestAccess guestAccess) => | ||||
|                               Matrix.of(context).tryRequestWithLoadingDialog( | ||||
|                               SimpleDialogs(context) | ||||
|                                   .tryRequestWithLoadingDialog( | ||||
|                             widget.room.setGuestAccess(guestAccess), | ||||
|                           ), | ||||
|                           itemBuilder: (BuildContext context) => | ||||
|  | ||||
| @ -2,13 +2,15 @@ import 'dart:async'; | ||||
| import 'dart:io'; | ||||
| 
 | ||||
| import 'package:famedlysdk/famedlysdk.dart'; | ||||
| import 'package:fluffychat/components/dialogs/simple_dialogs.dart'; | ||||
| import 'package:fluffychat/components/list_items/presence_list_item.dart'; | ||||
| import 'package:fluffychat/components/list_items/public_room_list_item.dart'; | ||||
| import 'package:flutter/foundation.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_speed_dial/flutter_speed_dial.dart'; | ||||
| import 'package:receive_sharing_intent/receive_sharing_intent.dart'; | ||||
| import 'package:share/share.dart'; | ||||
| 
 | ||||
| import '../components/dialogs/simple_dialogs.dart'; | ||||
| import '../components/theme_switcher.dart'; | ||||
| import '../components/adaptive_page_layout.dart'; | ||||
| import '../components/list_items/chat_list_item.dart'; | ||||
| @ -16,6 +18,7 @@ import '../components/matrix.dart'; | ||||
| import '../i18n/i18n.dart'; | ||||
| import '../utils/app_route.dart'; | ||||
| import '../utils/url_launcher.dart'; | ||||
| import '../utils/client_presence_extension.dart'; | ||||
| import 'archive.dart'; | ||||
| import 'new_group.dart'; | ||||
| import 'new_private_chat.dart'; | ||||
| @ -48,7 +51,7 @@ class ChatList extends StatefulWidget { | ||||
| } | ||||
| 
 | ||||
| class _ChatListState extends State<ChatList> { | ||||
|   bool searchMode = false; | ||||
|   bool get searchMode => searchController.text?.isNotEmpty ?? false; | ||||
|   StreamSubscription sub; | ||||
|   final TextEditingController searchController = TextEditingController(); | ||||
|   SelectMode selectMode = SelectMode.normal; | ||||
| @ -71,10 +74,17 @@ class _ChatListState extends State<ChatList> { | ||||
|   void initState() { | ||||
|     searchController.addListener(() { | ||||
|       coolDown?.cancel(); | ||||
|       if (searchController.text.isEmpty) { | ||||
|         setState(() { | ||||
|           loadingPublicRooms = false; | ||||
|           publicRoomsResponse = null; | ||||
|         }); | ||||
|         return; | ||||
|       } | ||||
|       coolDown = Timer(Duration(seconds: 1), () async { | ||||
|         setState(() => loadingPublicRooms = true); | ||||
|         final newPublicRoomsResponse = | ||||
|             await Matrix.of(context).tryRequestWithErrorToast( | ||||
|             await SimpleDialogs(context).tryRequestWithErrorToast( | ||||
|           Matrix.of(context).client.requestPublicRooms( | ||||
|                 limit: 30, | ||||
|                 includeAllNetworks: true, | ||||
| @ -160,6 +170,39 @@ class _ChatListState extends State<ChatList> { | ||||
|     ReceiveSharingIntent.getInitialText().then(_processIncomingSharedText); | ||||
|   } | ||||
| 
 | ||||
|   void _drawerTapAction(Widget view) { | ||||
|     Navigator.of(context).pop(); | ||||
|     Navigator.of(context).pushAndRemoveUntil( | ||||
|       AppRoute.defaultRoute( | ||||
|         context, | ||||
|         view, | ||||
|       ), | ||||
|       (r) => r.isFirst, | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   void _setStatus(BuildContext context) async { | ||||
|     Navigator.of(context).pop(); | ||||
|     final status = await SimpleDialogs(context).enterText( | ||||
|       multiLine: true, | ||||
|       titleText: I18n.of(context).setStatus, | ||||
|       labelText: I18n.of(context).setStatus, | ||||
|       hintText: I18n.of(context).statusExampleMessage, | ||||
|     ); | ||||
|     if (status?.isEmpty ?? true) return; | ||||
|     await SimpleDialogs(context).tryRequestWithLoadingDialog( | ||||
|       Matrix.of(context).client.jsonRequest( | ||||
|         type: HTTPType.PUT, | ||||
|         action: | ||||
|             '/client/r0/presence/${Matrix.of(context).client.userID}/status', | ||||
|         data: { | ||||
|           "presence": "online", | ||||
|           "status_msg": status, | ||||
|         }, | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   void dispose() { | ||||
|     sub?.cancel(); | ||||
| @ -186,109 +229,100 @@ class _ChatListState extends State<ChatList> { | ||||
|       setState(() => selectMode = SelectMode.normal); | ||||
|     } | ||||
|     return Scaffold( | ||||
|       appBar: AppBar( | ||||
|         title: searchMode | ||||
|             ? TextField( | ||||
|                 autofocus: true, | ||||
|                 autocorrect: false, | ||||
|                 controller: searchController, | ||||
|                 decoration: InputDecoration( | ||||
|                   border: InputBorder.none, | ||||
|                   hintText: I18n.of(context).searchForAChat, | ||||
|                 ), | ||||
|               ) | ||||
|             : Text( | ||||
|                 selectMode == SelectMode.share | ||||
|                     ? I18n.of(context).share | ||||
|                     : I18n.of(context).fluffychat, | ||||
|               ), | ||||
|         leading: searchMode | ||||
|             ? IconButton( | ||||
|                 icon: Icon(Icons.arrow_back), | ||||
|                 onPressed: () => setState(() { | ||||
|                   publicRoomsResponse = null; | ||||
|                   loadingPublicRooms = false; | ||||
|                   searchMode = false; | ||||
|                 }), | ||||
|               ) | ||||
|             : selectMode == SelectMode.share | ||||
|                 ? IconButton( | ||||
|                     icon: Icon(Icons.close), | ||||
|                     onPressed: () { | ||||
|                       Matrix.of(context).shareContent = null; | ||||
|                       setState(() => selectMode = SelectMode.normal); | ||||
|                     }, | ||||
|                   ) | ||||
|                 : null, | ||||
|         automaticallyImplyLeading: false, | ||||
|         actions: searchMode | ||||
|             ? <Widget>[ | ||||
|                 if (loadingPublicRooms) | ||||
|                   Padding( | ||||
|                     padding: const EdgeInsets.only(right: 8.0), | ||||
|                     child: Center( | ||||
|                       child: CircularProgressIndicator(strokeWidth: 2), | ||||
|       drawer: selectMode == SelectMode.share | ||||
|           ? null | ||||
|           : Drawer( | ||||
|               child: SafeArea( | ||||
|                 child: ListView( | ||||
|                   padding: EdgeInsets.zero, | ||||
|                   children: <Widget>[ | ||||
|                     ListTile( | ||||
|                       leading: Icon(Icons.edit), | ||||
|                       title: Text(I18n.of(context).setStatus), | ||||
|                       onTap: () => _setStatus(context), | ||||
|                     ), | ||||
|                   ), | ||||
|                 IconButton( | ||||
|                   icon: Icon(Icons.domain), | ||||
|                   onPressed: () async { | ||||
|                     final String newSearchServer = await SimpleDialogs(context) | ||||
|                         .enterText( | ||||
|                             titleText: I18n.of(context).changeTheServer, | ||||
|                             labelText: I18n.of(context).changeTheServer, | ||||
|                             hintText: Matrix.of(context).client.userID.domain, | ||||
|                             prefixText: "https://"); | ||||
|                     if (newSearchServer?.isNotEmpty ?? false) { | ||||
|                       searchServer = newSearchServer; | ||||
|                     } | ||||
|                   }, | ||||
|                 ) | ||||
|               ] | ||||
|             : <Widget>[ | ||||
|                 IconButton( | ||||
|                   icon: Icon(Icons.search), | ||||
|                   onPressed: () => setState(() => searchMode = true), | ||||
|                     Divider(height: 1), | ||||
|                     ListTile( | ||||
|                       leading: Icon(Icons.people_outline), | ||||
|                       title: Text(I18n.of(context).createNewGroup), | ||||
|                       onTap: () => _drawerTapAction(NewGroupView()), | ||||
|                     ), | ||||
|                     ListTile( | ||||
|                       leading: Icon(Icons.person_add), | ||||
|                       title: Text(I18n.of(context).newPrivateChat), | ||||
|                       onTap: () => _drawerTapAction(NewPrivateChatView()), | ||||
|                     ), | ||||
|                     Divider(height: 1), | ||||
|                     ListTile( | ||||
|                       leading: Icon(Icons.archive), | ||||
|                       title: Text(I18n.of(context).archive), | ||||
|                       onTap: () => _drawerTapAction( | ||||
|                         Archive(), | ||||
|                       ), | ||||
|                     ), | ||||
|                     ListTile( | ||||
|                       leading: Icon(Icons.settings), | ||||
|                       title: Text(I18n.of(context).settings), | ||||
|                       onTap: () => _drawerTapAction( | ||||
|                         SettingsView(), | ||||
|                       ), | ||||
|                     ), | ||||
|                     Divider(height: 1), | ||||
|                     ListTile( | ||||
|                       leading: Icon(Icons.share), | ||||
|                       title: Text(I18n.of(context).inviteContact), | ||||
|                       onTap: () { | ||||
|                         Navigator.of(context).pop(); | ||||
|                         Share.share(I18n.of(context).inviteText( | ||||
|                             Matrix.of(context).client.userID, | ||||
|                             "https://matrix.to/#/${Matrix.of(context).client.userID}")); | ||||
|                       }, | ||||
|                     ), | ||||
|                   ], | ||||
|                 ), | ||||
|                 if (selectMode == SelectMode.normal) | ||||
|                   PopupMenuButton( | ||||
|                     onSelected: (String choice) { | ||||
|                       switch (choice) { | ||||
|                         case "settings": | ||||
|                           Navigator.of(context).pushAndRemoveUntil( | ||||
|                             AppRoute.defaultRoute( | ||||
|                               context, | ||||
|                               SettingsView(), | ||||
|               ), | ||||
|             ), | ||||
|       appBar: AppBar( | ||||
|         leading: selectMode != SelectMode.share | ||||
|             ? null | ||||
|             : IconButton( | ||||
|                 icon: Icon(Icons.close), | ||||
|                 onPressed: () => Matrix.of(context).shareContent = null, | ||||
|               ), | ||||
|         titleSpacing: 0, | ||||
|         title: selectMode == SelectMode.share | ||||
|             ? Text(I18n.of(context).share) | ||||
|             : Container( | ||||
|                 padding: EdgeInsets.all(8), | ||||
|                 height: 42, | ||||
|                 margin: EdgeInsets.only(right: 8), | ||||
|                 decoration: BoxDecoration( | ||||
|                   color: Theme.of(context).secondaryHeaderColor, | ||||
|                   borderRadius: BorderRadius.circular(90), | ||||
|                 ), | ||||
|                 child: TextField( | ||||
|                   autocorrect: false, | ||||
|                   controller: searchController, | ||||
|                   decoration: InputDecoration( | ||||
|                     suffixIcon: loadingPublicRooms | ||||
|                         ? Container( | ||||
|                             alignment: Alignment.centerRight, | ||||
|                             child: Container( | ||||
|                               width: 20, | ||||
|                               height: 20, | ||||
|                               child: CircularProgressIndicator(), | ||||
|                             ), | ||||
|                             (r) => r.isFirst, | ||||
|                           ); | ||||
|                           break; | ||||
|                         case "archive": | ||||
|                           Navigator.of(context).pushAndRemoveUntil( | ||||
|                             AppRoute.defaultRoute( | ||||
|                               context, | ||||
|                               Archive(), | ||||
|                             ), | ||||
|                             (r) => r.isFirst, | ||||
|                           ); | ||||
|                           break; | ||||
|                       } | ||||
|                     }, | ||||
|                     itemBuilder: (BuildContext context) => | ||||
|                         <PopupMenuEntry<String>>[ | ||||
|                       PopupMenuItem<String>( | ||||
|                         value: "archive", | ||||
|                         child: Text(I18n.of(context).archive), | ||||
|                       ), | ||||
|                       PopupMenuItem<String>( | ||||
|                         value: "settings", | ||||
|                         child: Text(I18n.of(context).settings), | ||||
|                       ), | ||||
|                     ], | ||||
|                           ) | ||||
|                         : Icon(Icons.search), | ||||
|                     contentPadding: EdgeInsets.all(9), | ||||
|                     border: InputBorder.none, | ||||
|                     hintText: I18n.of(context).searchForAChat, | ||||
|                   ), | ||||
|               ], | ||||
|                 ), | ||||
|               ), | ||||
|       ), | ||||
|       floatingActionButton: selectMode == SelectMode.share | ||||
|       floatingActionButton: (AdaptivePageLayout.columnMode(context) || | ||||
|               selectMode == SelectMode.share) | ||||
|           ? null | ||||
|           : SpeedDial( | ||||
|               child: Icon(Icons.add), | ||||
| @ -349,24 +383,45 @@ class _ChatListState extends State<ChatList> { | ||||
|                 (publicRoomsResponse?.publicRooms?.length ?? 0); | ||||
|             final int totalCount = rooms.length + publicRoomsCount; | ||||
|             return ListView.separated( | ||||
|               separatorBuilder: (BuildContext context, int i) => | ||||
|                   i == totalCount - publicRoomsCount - 1 | ||||
|                       ? Material( | ||||
|                           elevation: 2, | ||||
|                           child: ListTile( | ||||
|                             title: Text(I18n.of(context).publicRooms), | ||||
|                           ), | ||||
|                 separatorBuilder: (BuildContext context, int i) => | ||||
|                     i == totalCount - publicRoomsCount - 1 | ||||
|                         ? Material( | ||||
|                             elevation: 2, | ||||
|                             child: ListTile( | ||||
|                               title: Text(I18n.of(context).publicRooms), | ||||
|                             ), | ||||
|                           ) | ||||
|                         : Container(), | ||||
|                 itemCount: totalCount + 1, | ||||
|                 itemBuilder: (BuildContext context, int i) { | ||||
|                   if (i == 0) { | ||||
|                     return Matrix.of(context).client.statusList.isEmpty | ||||
|                         ? Container() | ||||
|                         : PreferredSize( | ||||
|                             preferredSize: Size.fromHeight(89), | ||||
|                             child: Container( | ||||
|                               height: 81, | ||||
|                               child: ListView.builder( | ||||
|                                 scrollDirection: Axis.horizontal, | ||||
|                                 itemCount: | ||||
|                                     Matrix.of(context).client.statusList.length, | ||||
|                                 itemBuilder: (BuildContext context, int i) => | ||||
|                                     PresenceListItem(Matrix.of(context) | ||||
|                                         .client | ||||
|                                         .statusList[i]), | ||||
|                               ), | ||||
|                             ), | ||||
|                           ); | ||||
|                   } | ||||
|                   i--; | ||||
|                   return i < rooms.length | ||||
|                       ? ChatListItem( | ||||
|                           rooms[i], | ||||
|                           activeChat: widget.activeChat == rooms[i].id, | ||||
|                         ) | ||||
|                       : Container(), | ||||
|               itemCount: totalCount, | ||||
|               itemBuilder: (BuildContext context, int i) => i < rooms.length | ||||
|                   ? ChatListItem( | ||||
|                       rooms[i], | ||||
|                       activeChat: widget.activeChat == rooms[i].id, | ||||
|                     ) | ||||
|                   : PublicRoomListItem( | ||||
|                       publicRoomsResponse.publicRooms[i - rooms.length]), | ||||
|             ); | ||||
|                       : PublicRoomListItem( | ||||
|                           publicRoomsResponse.publicRooms[i - rooms.length]); | ||||
|                 }); | ||||
|           } else { | ||||
|             return Center( | ||||
|               child: CircularProgressIndicator(), | ||||
|  | ||||
| @ -21,7 +21,7 @@ class HomeserverPicker extends StatelessWidget { | ||||
|     if (!homeserver.startsWith('https://')) { | ||||
|       homeserver = 'https://$homeserver'; | ||||
|     } | ||||
|     final success = await Matrix.of(context).tryRequestWithLoadingDialog( | ||||
|     final success = await SimpleDialogs(context).tryRequestWithLoadingDialog( | ||||
|         Matrix.of(context).client.checkServer(homeserver)); | ||||
|     if (success != false) { | ||||
|       await Navigator.of(context).push(AppRoute(SignUp())); | ||||
|  | ||||
| @ -3,6 +3,7 @@ import 'dart:async'; | ||||
| import 'package:famedlysdk/famedlysdk.dart'; | ||||
| import 'package:fluffychat/components/adaptive_page_layout.dart'; | ||||
| import 'package:fluffychat/components/avatar.dart'; | ||||
| import 'package:fluffychat/components/dialogs/simple_dialogs.dart'; | ||||
| import 'package:fluffychat/components/matrix.dart'; | ||||
| import 'package:fluffychat/i18n/i18n.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| @ -53,7 +54,7 @@ class _InvitationSelectionState extends State<InvitationSelection> { | ||||
|   } | ||||
| 
 | ||||
|   void inviteAction(BuildContext context, String id) async { | ||||
|     final success = await Matrix.of(context).tryRequestWithLoadingDialog( | ||||
|     final success = await SimpleDialogs(context).tryRequestWithLoadingDialog( | ||||
|       widget.room.invite(id), | ||||
|     ); | ||||
|     if (success != false) { | ||||
| @ -81,7 +82,7 @@ class _InvitationSelectionState extends State<InvitationSelection> { | ||||
|     if (loading) return; | ||||
|     setState(() => loading = true); | ||||
|     final MatrixState matrix = Matrix.of(context); | ||||
|     final response = await matrix.tryRequestWithErrorToast( | ||||
|     final response = await SimpleDialogs(context).tryRequestWithErrorToast( | ||||
|       matrix.client.jsonRequest( | ||||
|           type: HTTPType.POST, | ||||
|           action: "/client/r0/user_directory/search", | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| import 'package:fluffychat/components/adaptive_page_layout.dart'; | ||||
| import 'package:fluffychat/components/dialogs/simple_dialogs.dart'; | ||||
| import 'package:fluffychat/components/matrix.dart'; | ||||
| import 'package:fluffychat/i18n/i18n.dart'; | ||||
| import 'package:fluffychat/utils/app_route.dart'; | ||||
| @ -42,7 +43,8 @@ class _NewGroupState extends State<_NewGroup> { | ||||
|       params["preset"] = "private_chat"; | ||||
|     } | ||||
|     if (controller.text.isNotEmpty) params["name"] = controller.text; | ||||
|     final String roomID = await matrix.tryRequestWithLoadingDialog( | ||||
|     final String roomID = | ||||
|         await SimpleDialogs(context).tryRequestWithLoadingDialog( | ||||
|       matrix.client.createRoom(params: params), | ||||
|     ); | ||||
|     Navigator.of(context).pop(); | ||||
|  | ||||
| @ -3,6 +3,7 @@ import 'dart:async'; | ||||
| import 'package:famedlysdk/famedlysdk.dart'; | ||||
| import 'package:fluffychat/components/adaptive_page_layout.dart'; | ||||
| import 'package:fluffychat/components/avatar.dart'; | ||||
| import 'package:fluffychat/components/dialogs/simple_dialogs.dart'; | ||||
| import 'package:fluffychat/components/matrix.dart'; | ||||
| import 'package:fluffychat/i18n/i18n.dart'; | ||||
| import 'package:fluffychat/utils/app_route.dart'; | ||||
| @ -54,8 +55,8 @@ class _NewPrivateChatState extends State<_NewPrivateChat> { | ||||
|       "@" + controller.text.trim(), | ||||
|       room: Room(id: "", client: matrix.client), | ||||
|     ); | ||||
|     final String roomID = | ||||
|         await matrix.tryRequestWithLoadingDialog(user.startDirectChat()); | ||||
|     final String roomID = await SimpleDialogs(context) | ||||
|         .tryRequestWithLoadingDialog(user.startDirectChat()); | ||||
|     Navigator.of(context).pop(); | ||||
| 
 | ||||
|     if (roomID != null) { | ||||
| @ -87,7 +88,7 @@ class _NewPrivateChatState extends State<_NewPrivateChat> { | ||||
|     if (loading) return; | ||||
|     setState(() => loading = true); | ||||
|     final MatrixState matrix = Matrix.of(context); | ||||
|     final response = await matrix.tryRequestWithErrorToast( | ||||
|     final response = await SimpleDialogs(context).tryRequestWithErrorToast( | ||||
|       matrix.client.jsonRequest( | ||||
|           type: HTTPType.POST, | ||||
|           action: "/client/r0/user_directory/search", | ||||
|  | ||||
| @ -43,7 +43,8 @@ class _SettingsState extends State<Settings> { | ||||
|       return; | ||||
|     } | ||||
|     MatrixState matrix = Matrix.of(context); | ||||
|     await matrix.tryRequestWithLoadingDialog(matrix.client.logout()); | ||||
|     await SimpleDialogs(context) | ||||
|         .tryRequestWithLoadingDialog(matrix.client.logout()); | ||||
|     matrix.clean(); | ||||
|     await Navigator.of(context).pushAndRemoveUntil( | ||||
|         AppRoute.defaultRoute(context, HomeserverPicker()), (r) => false); | ||||
| @ -73,7 +74,7 @@ class _SettingsState extends State<Settings> { | ||||
|     ); | ||||
|     if (displayname == null) return; | ||||
|     final MatrixState matrix = Matrix.of(context); | ||||
|     final success = await matrix.tryRequestWithLoadingDialog( | ||||
|     final success = await SimpleDialogs(context).tryRequestWithLoadingDialog( | ||||
|       matrix.client.setDisplayname(displayname), | ||||
|     ); | ||||
|     if (success != false) { | ||||
| @ -92,7 +93,7 @@ class _SettingsState extends State<Settings> { | ||||
|         maxHeight: 1600); | ||||
|     if (tempFile == null) return; | ||||
|     final MatrixState matrix = Matrix.of(context); | ||||
|     final success = await matrix.tryRequestWithLoadingDialog( | ||||
|     final success = await SimpleDialogs(context).tryRequestWithLoadingDialog( | ||||
|       matrix.client.setAvatar( | ||||
|         MatrixFile( | ||||
|           bytes: await tempFile.readAsBytes(), | ||||
|  | ||||
| @ -42,7 +42,7 @@ class DevicesSettingsState extends State<DevicesSettings> { | ||||
|     for (UserDevice userDevice in devices) { | ||||
|       deviceIds.add(userDevice.deviceId); | ||||
|     } | ||||
|     final success = await matrix | ||||
|     final success = await SimpleDialogs(context) | ||||
|         .tryRequestWithLoadingDialog(matrix.client.deleteDevices(deviceIds), | ||||
|             onAdditionalAuth: (MatrixException exception) async { | ||||
|       final String password = await SimpleDialogs(context).enterText( | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Christian Pauly
						Christian Pauly