diff --git a/lib/pages/user_bottom_sheet.dart b/lib/pages/user_bottom_sheet.dart index 61e7c45a..8e048fb9 100644 --- a/lib/pages/user_bottom_sheet.dart +++ b/lib/pages/user_bottom_sheet.dart @@ -9,18 +9,15 @@ import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:vrouter/vrouter.dart'; import 'views/user_bottom_sheet_view.dart'; -import '../widgets/matrix.dart'; class UserBottomSheet extends StatefulWidget { final User user; - final Profile profile; final Function onMention; final BuildContext outerContext; const UserBottomSheet({ Key key, - this.user, - this.profile, + @required this.user, @required this.outerContext, this.onMention, }) : super(key: key); @@ -86,28 +83,14 @@ class UserBottomSheetController extends State { } break; case 'message': - if (widget.user != null) { - final roomIdResult = await showFutureLoadingDialog( - context: context, - future: () => widget.user.startDirectChat(), - ); - if (roomIdResult.error != null) return; - VRouter.of(widget.outerContext) - .toSegments(['rooms', roomIdResult.result]); - Navigator.of(context, rootNavigator: false).pop(); - } else { - final result = await showFutureLoadingDialog( - context: context, - future: () => Matrix.of(context).client.startDirectChat( - widget.profile.userId, - ), - ); - if (result.error == null) { - VRouter.of(context).toSegments(['rooms', result.result]); - Navigator.of(context, rootNavigator: false).pop(); - return; - } - } + final roomIdResult = await showFutureLoadingDialog( + context: context, + future: () => widget.user.startDirectChat(), + ); + if (roomIdResult.error != null) return; + VRouter.of(widget.outerContext) + .toSegments(['rooms', roomIdResult.result]); + Navigator.of(context, rootNavigator: false).pop(); break; } } diff --git a/lib/pages/views/user_bottom_sheet_view.dart b/lib/pages/views/user_bottom_sheet_view.dart index edf52118..66713d41 100644 --- a/lib/pages/views/user_bottom_sheet_view.dart +++ b/lib/pages/views/user_bottom_sheet_view.dart @@ -18,12 +18,8 @@ class UserBottomSheetView extends StatelessWidget { @override Widget build(BuildContext context) { final user = controller.widget.user; - final client = user?.room?.client ?? Matrix.of(context).client; - final mxid = user?.id ?? controller.widget.profile?.userId ?? ''; - final presence = client.presences[mxid]; - final displayname = - user?.calcDisplayname() ?? controller.widget.profile?.displayName ?? ''; - final avatarUrl = user?.avatarUrl ?? controller.widget.profile?.avatarUrl; + final client = Matrix.of(context).client; + final presence = client.presences[user.id]; return Center( child: Container( width: min( @@ -42,12 +38,12 @@ class UserBottomSheetView extends StatelessWidget { onPressed: Navigator.of(context, rootNavigator: false).pop, tooltip: L10n.of(context).close, ), - title: Text(displayname), + title: Text(user.calcDisplayname()), actions: [ - if (mxid != client.userID) + if (user.id != client.userID) PopupMenuButton( itemBuilder: (_) => [ - if (user != null && controller.widget.onMention != null) + if (controller.widget.onMention != null) PopupMenuItem( value: 'mention', child: _TextWithIcon( @@ -55,8 +51,7 @@ class UserBottomSheetView extends StatelessWidget { Icons.alternate_email_outlined, ), ), - if (mxid != client.userID && - (user == null || !user.room.isDirectChat)) + if (user.id != client.userID && !user.room.isDirectChat) PopupMenuItem( value: 'message', child: _TextWithIcon( @@ -64,7 +59,7 @@ class UserBottomSheetView extends StatelessWidget { Icons.send_outlined, ), ), - if (user != null && user.canChangePowerLevel) + if (user.canChangePowerLevel) PopupMenuItem( value: 'permission', child: _TextWithIcon( @@ -72,7 +67,7 @@ class UserBottomSheetView extends StatelessWidget { Icons.edit_attributes_outlined, ), ), - if (user != null && user.canKick) + if (user.canKick) PopupMenuItem( value: 'kick', child: _TextWithIcon( @@ -80,9 +75,7 @@ class UserBottomSheetView extends StatelessWidget { Icons.exit_to_app_outlined, ), ), - if (user != null && - user.canBan && - user.membership != Membership.ban) + if (user.canBan && user.membership != Membership.ban) PopupMenuItem( value: 'ban', child: _TextWithIcon( @@ -90,8 +83,7 @@ class UserBottomSheetView extends StatelessWidget { Icons.warning_sharp, ), ) - else if (user != null && - user.canBan && + else if (user.canBan && user.membership == Membership.ban) PopupMenuItem( value: 'unban', @@ -109,17 +101,17 @@ class UserBottomSheetView extends StatelessWidget { children: [ Expanded( child: ContentBanner( - avatarUrl, + user.avatarUrl, defaultIcon: Icons.person_outline, client: client, ), ), ListTile( title: Text(L10n.of(context).username), - subtitle: Text(mxid), + subtitle: Text(user.id), trailing: Icon(Icons.share_outlined), - onTap: () => - FluffyShare.share(mxid, controller.widget.outerContext), + onTap: () => FluffyShare.share( + user.id, controller.widget.outerContext), ), if (presence != null) ListTile( diff --git a/lib/utils/url_launcher.dart b/lib/utils/url_launcher.dart index fe40bd91..9d11c7a5 100644 --- a/lib/utils/url_launcher.dart +++ b/lib/utils/url_launcher.dart @@ -1,4 +1,5 @@ import 'package:adaptive_dialog/adaptive_dialog.dart'; +import 'package:fluffychat/widgets/profile_bottom_sheet.dart'; import 'package:matrix/matrix.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart'; @@ -11,7 +12,6 @@ import 'package:punycode/punycode.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'platform_infos.dart'; -import '../pages/user_bottom_sheet.dart'; class UrlLauncher { final String url; @@ -83,7 +83,7 @@ class UrlLauncher { launch(uri.replace(host: newHost).toString()); } - void openMatrixToUrl() async { + void openMatrixToUrl([bool startDirectChat = false]) async { final matrix = Matrix.of(context); // The identifier might be a matrix.to url and needs escaping. Or, it might have multiple // identifiers (room id & event id), or it might also have a query part. @@ -167,12 +167,10 @@ class UrlLauncher { }); } } else if (identityParts.primaryIdentifier.sigil == '@') { - final profile = await matrix.client - .getProfileFromUserId(identityParts.primaryIdentifier); await showModalBottomSheet( context: context, - builder: (c) => UserBottomSheet( - profile: profile, + builder: (c) => ProfileBottomSheet( + userId: identityParts.primaryIdentifier, outerContext: context, ), ); diff --git a/lib/widgets/profile_bottom_sheet.dart b/lib/widgets/profile_bottom_sheet.dart new file mode 100644 index 00000000..5e12cbfb --- /dev/null +++ b/lib/widgets/profile_bottom_sheet.dart @@ -0,0 +1,101 @@ +import 'dart:math'; + +import 'package:fluffychat/config/themes.dart'; +import 'package:fluffychat/widgets/matrix.dart'; +import 'package:flutter_gen/gen_l10n/l10n.dart'; +import 'package:fluffychat/widgets/content_banner.dart'; +import 'package:flutter/material.dart'; +import 'package:future_loading_dialog/future_loading_dialog.dart'; +import 'package:matrix/matrix.dart'; +import 'package:vrouter/vrouter.dart'; +import '../utils/localized_exception_extension.dart'; + +class ProfileBottomSheet extends StatelessWidget { + final String userId; + final BuildContext outerContext; + const ProfileBottomSheet({ + @required this.userId, + @required this.outerContext, + Key key, + }) : super(key: key); + + void _startDirectChat(BuildContext context) async { + final result = await showFutureLoadingDialog( + context: context, + future: () => Matrix.of(context).client.startDirectChat(userId), + ); + if (result.error == null) { + VRouter.of(context).toSegments(['rooms', result.result]); + Navigator.of(context, rootNavigator: false).pop(); + return; + } + } + + @override + Widget build(BuildContext context) { + return Center( + child: Container( + width: min( + MediaQuery.of(context).size.width, FluffyThemes.columnWidth * 1.5), + child: Material( + elevation: 4, + child: SafeArea( + child: Scaffold( + extendBodyBehindAppBar: true, + appBar: AppBar( + elevation: 0, + backgroundColor: + Theme.of(context).scaffoldBackgroundColor.withOpacity(0.5), + leading: IconButton( + icon: Icon(Icons.arrow_downward_outlined), + onPressed: Navigator.of(context, rootNavigator: false).pop, + tooltip: L10n.of(context).close, + ), + ), + body: FutureBuilder( + future: + Matrix.of(context).client.getProfileFromUserId(userId), + builder: (context, snapshot) { + final profile = snapshot.data; + + return Column( + children: [ + Expanded( + child: profile == null + ? Container( + alignment: Alignment.center, + color: Theme.of(context).secondaryHeaderColor, + child: snapshot.hasError + ? Text(snapshot.error + .toLocalizedString(context)) + : CircularProgressIndicator(), + ) + : ContentBanner( + profile.avatarUrl, + defaultIcon: Icons.person_outline, + client: Matrix.of(context).client, + ), + ), + ListTile( + title: Text(profile?.displayName ?? userId.localpart), + subtitle: Text(userId), + trailing: Icon(Icons.account_box_outlined), + ), + Center( + child: FloatingActionButton.extended( + onPressed: () => _startDirectChat(context), + label: Text(L10n.of(context).newChat), + icon: Icon(Icons.send_outlined), + ), + ), + SizedBox(height: 8), + ], + ); + }), + ), + ), + ), + ), + ); + } +}