style: New modal bottom sheets

This commit is contained in:
Krille 2023-01-07 10:29:34 +01:00
parent 8513d74cc1
commit fbb68686ea
19 changed files with 333 additions and 360 deletions

View File

@ -61,12 +61,14 @@ void main() {
await tester.pumpAndSettle(); await tester.pumpAndSettle();
await tester.scrollUntilVisible( await tester.scrollUntilVisible(
find.text('Chats'), find.text('Chats').first,
500, 500,
scrollable: find.descendant( scrollable: find
.descendant(
of: find.byType(ChatListViewBody), of: find.byType(ChatListViewBody),
matching: find.byType(Scrollable), matching: find.byType(Scrollable),
), )
.first,
); );
await tester.pumpAndSettle(); await tester.pumpAndSettle();
await tester.tap(find.text('Chats')); await tester.tap(find.text('Chats'));
@ -77,10 +79,12 @@ void main() {
await tester.scrollUntilVisible( await tester.scrollUntilVisible(
find.text(Users.user2.name).first, find.text(Users.user2.name).first,
500, 500,
scrollable: find.descendant( scrollable: find
.descendant(
of: find.byType(ChatListViewBody), of: find.byType(ChatListViewBody),
matching: find.byType(Scrollable), matching: find.byType(Scrollable),
), )
.first,
); );
await tester.pumpAndSettle(); await tester.pumpAndSettle();
await tester.tap(find.text(Users.user2.name).first); await tester.tap(find.text(Users.user2.name).first);

View File

@ -22,6 +22,7 @@ import 'package:vrouter/vrouter.dart';
import 'package:fluffychat/pages/chat/chat_view.dart'; import 'package:fluffychat/pages/chat/chat_view.dart';
import 'package:fluffychat/pages/chat/event_info_dialog.dart'; import 'package:fluffychat/pages/chat/event_info_dialog.dart';
import 'package:fluffychat/pages/chat/recording_dialog.dart'; import 'package:fluffychat/pages/chat/recording_dialog.dart';
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/event_extension.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/event_extension.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/ios_badge_client_extension.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/ios_badge_client_extension.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
@ -422,9 +423,8 @@ class ChatController extends State<Chat> {
} }
void sendStickerAction() async { void sendStickerAction() async {
final sticker = await showModalBottomSheet<ImagePackImageContent>( final sticker = await showAdaptiveBottomSheet<ImagePackImageContent>(
context: context, context: context,
useRootNavigator: false,
builder: (c) => StickerPickerDialog(room: room!), builder: (c) => StickerPickerDialog(room: room!),
); );
if (sticker == null) return; if (sticker == null) return;

View File

@ -5,6 +5,7 @@ import 'package:vrouter/vrouter.dart';
import 'package:fluffychat/pages/chat/chat.dart'; import 'package:fluffychat/pages/chat/chat.dart';
import 'package:fluffychat/pages/user_bottom_sheet/user_bottom_sheet.dart'; import 'package:fluffychat/pages/user_bottom_sheet/user_bottom_sheet.dart';
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
import 'package:fluffychat/widgets/avatar.dart'; import 'package:fluffychat/widgets/avatar.dart';
@ -26,7 +27,7 @@ class ChatAppBarTitle extends StatelessWidget {
splashColor: Colors.transparent, splashColor: Colors.transparent,
highlightColor: Colors.transparent, highlightColor: Colors.transparent,
onTap: directChatMatrixID != null onTap: directChatMatrixID != null
? () => showModalBottomSheet( ? () => showAdaptiveBottomSheet(
context: context, context: context,
builder: (c) => UserBottomSheet( builder: (c) => UserBottomSheet(
user: room user: room

View File

@ -10,6 +10,7 @@ import 'package:fluffychat/pages/chat/events/message.dart';
import 'package:fluffychat/pages/chat/seen_by_row.dart'; import 'package:fluffychat/pages/chat/seen_by_row.dart';
import 'package:fluffychat/pages/chat/typing_indicators.dart'; import 'package:fluffychat/pages/chat/typing_indicators.dart';
import 'package:fluffychat/pages/user_bottom_sheet/user_bottom_sheet.dart'; import 'package:fluffychat/pages/user_bottom_sheet/user_bottom_sheet.dart';
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/filtered_timeline_extension.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/filtered_timeline_extension.dart';
import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/utils/platform_infos.dart';
@ -89,7 +90,7 @@ class ChatEventList extends StatelessWidget {
onSwipe: (direction) => onSwipe: (direction) =>
controller.replyAction(replyTo: event), controller.replyAction(replyTo: event),
onInfoTab: controller.showEventInfo, onInfoTab: controller.showEventInfo,
onAvatarTab: (Event event) => showModalBottomSheet( onAvatarTab: (Event event) => showAdaptiveBottomSheet(
context: context, context: context,
builder: (c) => UserBottomSheet( builder: (c) => UserBottomSheet(
user: event.senderFromMemoryOrFallback, user: event.senderFromMemoryOrFallback,

View File

@ -6,11 +6,12 @@ import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:matrix/matrix.dart'; import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
import 'package:fluffychat/utils/date_time_extension.dart'; import 'package:fluffychat/utils/date_time_extension.dart';
import 'package:fluffychat/widgets/avatar.dart'; import 'package:fluffychat/widgets/avatar.dart';
extension EventInfoDialogExtension on Event { extension EventInfoDialogExtension on Event {
void showInfoDialog(BuildContext context) => showModalBottomSheet( void showInfoDialog(BuildContext context) => showAdaptiveBottomSheet(
context: context, context: context,
builder: (context) => builder: (context) =>
EventInfoDialog(l10n: L10n.of(context)!, event: this), EventInfoDialog(l10n: L10n.of(context)!, event: this),

View File

@ -5,6 +5,7 @@ import 'package:matrix/matrix.dart';
import 'package:matrix_link_text/link_text.dart'; import 'package:matrix_link_text/link_text.dart';
import 'package:fluffychat/pages/chat/events/video_player.dart'; import 'package:fluffychat/pages/chat/events/video_player.dart';
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
import 'package:fluffychat/utils/date_time_extension.dart'; import 'package:fluffychat/utils/date_time_extension.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
import 'package:fluffychat/widgets/avatar.dart'; import 'package:fluffychat/widgets/avatar.dart';
@ -52,7 +53,7 @@ class MessageContent extends StatelessWidget {
} }
event.requestKey(); event.requestKey();
final sender = event.senderFromMemoryOrFallback; final sender = event.senderFromMemoryOrFallback;
await showModalBottomSheet( await showAdaptiveBottomSheet(
context: context, context: context,
builder: (context) => Scaffold( builder: (context) => Scaffold(
appBar: AppBar( appBar: AppBar(

View File

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:matrix/matrix.dart'; import 'package:matrix/matrix.dart';
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
import '../../widgets/avatar.dart'; import '../../widgets/avatar.dart';
import '../user_bottom_sheet/user_bottom_sheet.dart'; import '../user_bottom_sheet/user_bottom_sheet.dart';
@ -28,7 +29,7 @@ class ParticipantListItem extends StatelessWidget {
return Opacity( return Opacity(
opacity: user.membership == Membership.join ? 1 : 0.5, opacity: user.membership == Membership.join ? 1 : 0.5,
child: ListTile( child: ListTile(
onTap: () => showModalBottomSheet( onTap: () => showAdaptiveBottomSheet(
context: context, context: context,
builder: (c) => UserBottomSheet( builder: (c) => UserBottomSheet(
user: user, user: user,

View File

@ -9,6 +9,7 @@ import 'package:fluffychat/pages/chat_list/chat_list_item.dart';
import 'package:fluffychat/pages/chat_list/search_title.dart'; import 'package:fluffychat/pages/chat_list/search_title.dart';
import 'package:fluffychat/pages/chat_list/space_view.dart'; import 'package:fluffychat/pages/chat_list/space_view.dart';
import 'package:fluffychat/pages/chat_list/stories_header.dart'; import 'package:fluffychat/pages/chat_list/stories_header.dart';
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/client_stories_extension.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/client_stories_extension.dart';
import 'package:fluffychat/utils/stream_extension.dart'; import 'package:fluffychat/utils/stream_extension.dart';
import 'package:fluffychat/widgets/avatar.dart'; import 'package:fluffychat/widgets/avatar.dart';
@ -101,7 +102,7 @@ class ChatListViewBody extends StatelessWidget {
L10n.of(context)!.group, L10n.of(context)!.group,
avatar: avatar:
roomSearchResult.chunk[i].avatarUrl, roomSearchResult.chunk[i].avatarUrl,
onPressed: () => showModalBottomSheet( onPressed: () => showAdaptiveBottomSheet(
context: context, context: context,
builder: (c) => PublicRoomBottomSheet( builder: (c) => PublicRoomBottomSheet(
roomAlias: roomSearchResult roomAlias: roomSearchResult
@ -140,7 +141,7 @@ class ChatListViewBody extends StatelessWidget {
L10n.of(context)!.unknownDevice, L10n.of(context)!.unknownDevice,
avatar: avatar:
userSearchResult.results[i].avatarUrl, userSearchResult.results[i].avatarUrl,
onPressed: () => showModalBottomSheet( onPressed: () => showAdaptiveBottomSheet(
context: context, context: context,
builder: (c) => ProfileBottomSheet( builder: (c) => ProfileBottomSheet(
userId: userSearchResult userId: userSearchResult

View File

@ -15,6 +15,7 @@ import 'package:vrouter/vrouter.dart';
import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pages/homeserver_picker/homeserver_bottom_sheet.dart'; import 'package:fluffychat/pages/homeserver_picker/homeserver_bottom_sheet.dart';
import 'package:fluffychat/pages/homeserver_picker/homeserver_picker_view.dart'; import 'package:fluffychat/pages/homeserver_picker/homeserver_picker_view.dart';
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
import 'package:fluffychat/widgets/matrix.dart'; import 'package:fluffychat/widgets/matrix.dart';
import '../../utils/localized_exception_extension.dart'; import '../../utils/localized_exception_extension.dart';
@ -71,7 +72,8 @@ class HomeserverPickerController extends State<HomeserverPicker> {
} }
} }
void showServerInfo(HomeserverBenchmarkResult server) => showModalBottomSheet( void showServerInfo(HomeserverBenchmarkResult server) =>
showAdaptiveBottomSheet(
context: context, context: context,
builder: (_) => HomeserverBottomSheet( builder: (_) => HomeserverBottomSheet(
homeserver: server, homeserver: server,

View File

@ -10,13 +10,13 @@ import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:matrix/encryption.dart'; import 'package:matrix/encryption.dart';
import 'package:matrix/matrix.dart'; import 'package:matrix/matrix.dart';
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
import 'package:fluffychat/widgets/avatar.dart'; import 'package:fluffychat/widgets/avatar.dart';
class KeyVerificationDialog extends StatefulWidget { class KeyVerificationDialog extends StatefulWidget {
Future<void> show(BuildContext context) => showModalBottomSheet( Future<void> show(BuildContext context) => showAdaptiveBottomSheet(
context: context, context: context,
builder: (context) => this, builder: (context) => this,
useRootNavigator: false,
isDismissible: false, isDismissible: false,
); );

View File

@ -7,6 +7,7 @@ import 'package:matrix/matrix.dart';
import 'package:fluffychat/pages/new_private_chat/new_private_chat_view.dart'; import 'package:fluffychat/pages/new_private_chat/new_private_chat_view.dart';
import 'package:fluffychat/pages/new_private_chat/qr_scanner_modal.dart'; import 'package:fluffychat/pages/new_private_chat/qr_scanner_modal.dart';
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
import 'package:fluffychat/utils/fluffy_share.dart'; import 'package:fluffychat/utils/fluffy_share.dart';
import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/utils/url_launcher.dart'; import 'package:fluffychat/utils/url_launcher.dart';
@ -75,10 +76,8 @@ class NewPrivateChatController extends State<NewPrivateChat> {
return; return;
} }
} }
await showModalBottomSheet( await showAdaptiveBottomSheet(
context: context, context: context,
useRootNavigator: false,
//useSafeArea: false,
builder: (_) => const QrScannerModal(), builder: (_) => const QrScannerModal(),
); );
} }

View File

@ -13,6 +13,7 @@ import 'package:video_player/video_player.dart';
import 'package:vrouter/vrouter.dart'; import 'package:vrouter/vrouter.dart';
import 'package:fluffychat/pages/story/story_view.dart'; import 'package:fluffychat/pages/story/story_view.dart';
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
import 'package:fluffychat/utils/date_time_extension.dart'; import 'package:fluffychat/utils/date_time_extension.dart';
import 'package:fluffychat/utils/localized_exception_extension.dart'; import 'package:fluffychat/utils/localized_exception_extension.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/client_stories_extension.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/client_stories_extension.dart';
@ -58,7 +59,7 @@ class StoryPageController extends State<StoryPage> {
void replyEmojiAction() async { void replyEmojiAction() async {
if (replyLoading) return; if (replyLoading) return;
_modalOpened = true; _modalOpened = true;
await showModalBottomSheet( await showAdaptiveBottomSheet(
context: context, context: context,
builder: (context) => EmojiPicker( builder: (context) => EmojiPicker(
onEmojiSelected: (c, e) { onEmojiSelected: (c, e) {
@ -123,7 +124,7 @@ class StoryPageController extends State<StoryPage> {
void displaySeenByUsers() async { void displaySeenByUsers() async {
_modalOpened = true; _modalOpened = true;
await showModalBottomSheet( await showAdaptiveBottomSheet(
context: context, context: context,
builder: (context) => Scaffold( builder: (context) => Scaffold(
appBar: AppBar( appBar: AppBar(

View File

@ -10,6 +10,17 @@ import 'package:fluffychat/widgets/permission_slider_dialog.dart';
import '../../widgets/matrix.dart'; import '../../widgets/matrix.dart';
import 'user_bottom_sheet_view.dart'; import 'user_bottom_sheet_view.dart';
enum UserBottomSheetAction {
report,
mention,
ban,
kick,
unban,
permission,
message,
ignore,
}
class UserBottomSheet extends StatefulWidget { class UserBottomSheet extends StatefulWidget {
final User user; final User user;
final Function? onMention; final Function? onMention;
@ -27,7 +38,7 @@ class UserBottomSheet extends StatefulWidget {
} }
class UserBottomSheetController extends State<UserBottomSheet> { class UserBottomSheetController extends State<UserBottomSheet> {
void participantAction(String action) async { void participantAction(UserBottomSheetAction action) async {
// ignore: prefer_function_declarations_over_variables // ignore: prefer_function_declarations_over_variables
final Function askConfirmation = () async => (await showOkCancelAlertDialog( final Function askConfirmation = () async => (await showOkCancelAlertDialog(
useRootNavigator: false, useRootNavigator: false,
@ -38,7 +49,7 @@ class UserBottomSheetController extends State<UserBottomSheet> {
) == ) ==
OkCancelResult.ok); OkCancelResult.ok);
switch (action) { switch (action) {
case 'report': case UserBottomSheetAction.report:
final event = widget.user; final event = widget.user;
final score = await showConfirmationDialog<int>( final score = await showConfirmationDialog<int>(
context: context, context: context,
@ -82,11 +93,11 @@ class UserBottomSheetController extends State<UserBottomSheet> {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(L10n.of(context)!.contentHasBeenReported))); SnackBar(content: Text(L10n.of(context)!.contentHasBeenReported)));
break; break;
case 'mention': case UserBottomSheetAction.mention:
Navigator.of(context, rootNavigator: false).pop(); Navigator.of(context, rootNavigator: false).pop();
widget.onMention!(); widget.onMention!();
break; break;
case 'ban': case UserBottomSheetAction.ban:
if (await askConfirmation()) { if (await askConfirmation()) {
await showFutureLoadingDialog( await showFutureLoadingDialog(
context: context, context: context,
@ -95,7 +106,7 @@ class UserBottomSheetController extends State<UserBottomSheet> {
Navigator.of(context, rootNavigator: false).pop(); Navigator.of(context, rootNavigator: false).pop();
} }
break; break;
case 'unban': case UserBottomSheetAction.unban:
if (await askConfirmation()) { if (await askConfirmation()) {
await showFutureLoadingDialog( await showFutureLoadingDialog(
context: context, context: context,
@ -104,7 +115,7 @@ class UserBottomSheetController extends State<UserBottomSheet> {
Navigator.of(context, rootNavigator: false).pop(); Navigator.of(context, rootNavigator: false).pop();
} }
break; break;
case 'kick': case UserBottomSheetAction.kick:
if (await askConfirmation()) { if (await askConfirmation()) {
await showFutureLoadingDialog( await showFutureLoadingDialog(
context: context, context: context,
@ -113,7 +124,7 @@ class UserBottomSheetController extends State<UserBottomSheet> {
Navigator.of(context, rootNavigator: false).pop(); Navigator.of(context, rootNavigator: false).pop();
} }
break; break;
case 'permission': case UserBottomSheetAction.permission:
final newPermission = await showPermissionChooser( final newPermission = await showPermissionChooser(
context, context,
currentLevel: widget.user.powerLevel, currentLevel: widget.user.powerLevel,
@ -127,7 +138,7 @@ class UserBottomSheetController extends State<UserBottomSheet> {
Navigator.of(context, rootNavigator: false).pop(); Navigator.of(context, rootNavigator: false).pop();
} }
break; break;
case 'message': case UserBottomSheetAction.message:
final roomIdResult = await showFutureLoadingDialog( final roomIdResult = await showFutureLoadingDialog(
context: context, context: context,
future: () => widget.user.startDirectChat(), future: () => widget.user.startDirectChat(),
@ -137,7 +148,7 @@ class UserBottomSheetController extends State<UserBottomSheet> {
.toSegments(['rooms', roomIdResult.result!]); .toSegments(['rooms', roomIdResult.result!]);
Navigator.of(context, rootNavigator: false).pop(); Navigator.of(context, rootNavigator: false).pop();
break; break;
case 'ignore': case UserBottomSheetAction.ignore:
if (await askConfirmation()) { if (await askConfirmation()) {
await showFutureLoadingDialog( await showFutureLoadingDialog(
context: context, context: context,

View File

@ -1,15 +1,11 @@
import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:matrix/matrix.dart'; import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/utils/fluffy_share.dart'; import 'package:fluffychat/utils/fluffy_share.dart';
import 'package:fluffychat/widgets/avatar.dart';
import '../../utils/matrix_sdk_extensions/presence_extension.dart'; import '../../utils/matrix_sdk_extensions/presence_extension.dart';
import '../../widgets/content_banner.dart';
import '../../widgets/m2_popup_menu_button.dart';
import '../../widgets/matrix.dart'; import '../../widgets/matrix.dart';
import 'user_bottom_sheet.dart'; import 'user_bottom_sheet.dart';
@ -23,155 +19,114 @@ class UserBottomSheetView extends StatelessWidget {
final user = controller.widget.user; final user = controller.widget.user;
final client = Matrix.of(context).client; final client = Matrix.of(context).client;
final presence = client.presences[user.id]; final presence = client.presences[user.id];
return Center( return SafeArea(
child: SizedBox(
width: min(
MediaQuery.of(context).size.width, FluffyThemes.columnWidth * 1.5),
child: Material(
elevation: 4,
child: SafeArea(
child: Scaffold( child: Scaffold(
extendBodyBehindAppBar: true,
appBar: AppBar( appBar: AppBar(
elevation: 0, leading: CloseButton(
backgroundColor:
Theme.of(context).scaffoldBackgroundColor.withOpacity(0.5),
leading: IconButton(
icon: const Icon(Icons.arrow_downward_outlined),
onPressed: Navigator.of(context, rootNavigator: false).pop, onPressed: Navigator.of(context, rootNavigator: false).pop,
tooltip: L10n.of(context)!.close,
), ),
title: Text(user.calcDisplayname()), title: Text(user.calcDisplayname()),
actions: [ actions: [
if (user.id != client.userID) if (user.id != client.userID)
M2PopupMenuButton( Padding(
itemBuilder: (_) => [ padding: const EdgeInsets.all(8.0),
if (controller.widget.onMention != null) child: OutlinedButton.icon(
PopupMenuItem( onPressed: () => controller
value: 'mention', .participantAction(UserBottomSheetAction.message),
child: _TextWithIcon( icon: const Icon(Icons.chat_outlined),
L10n.of(context)!.mention, label: Text(L10n.of(context)!.newChat),
Icons.alternate_email_outlined,
),
),
if (user.id != client.userID && !user.room.isDirectChat)
PopupMenuItem(
value: 'message',
child: _TextWithIcon(
L10n.of(context)!.sendAMessage,
Icons.send_outlined,
),
),
if (user.canChangePowerLevel)
PopupMenuItem(
value: 'permission',
child: _TextWithIcon(
L10n.of(context)!.setPermissionsLevel,
Icons.edit_attributes_outlined,
),
),
if (user.canKick)
PopupMenuItem(
value: 'kick',
child: _TextWithIcon(
L10n.of(context)!.kickFromChat,
Icons.exit_to_app_outlined,
),
),
if (user.canBan && user.membership != Membership.ban)
PopupMenuItem(
value: 'ban',
child: _TextWithIcon(
L10n.of(context)!.banFromChat,
Icons.warning_sharp,
),
)
else if (user.canBan &&
user.membership == Membership.ban)
PopupMenuItem(
value: 'unban',
child: _TextWithIcon(
L10n.of(context)!.unbanFromChat,
Icons.warning_outlined,
),
),
if (!client.ignoredUsers.contains(user.id))
PopupMenuItem(
value: 'ignore',
child: _TextWithIcon(
L10n.of(context)!.ignore,
Icons.block,
),
),
PopupMenuItem(
value: 'report',
child: _TextWithIcon(
L10n.of(context)!.reportUser,
Icons.shield_outlined,
), ),
), ),
], ],
onSelected: controller.participantAction,
), ),
], body: ListView(
),
body: Column(
children: [ children: [
Expanded( Row(
child: ContentBanner( children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: Avatar(
mxContent: user.avatarUrl, mxContent: user.avatarUrl,
defaultIcon: Icons.account_circle_outlined, name: user.calcDisplayname(),
client: client, size: Avatar.defaultSize * 2,
fontSize: 24,
), ),
), ),
ListTile( Expanded(
title: Text(L10n.of(context)!.username), child: ListTile(
subtitle: Text(user.id), contentPadding: const EdgeInsets.only(right: 16.0),
trailing: Icon(Icons.adaptive.share_outlined), title: Text(user.id),
onTap: () => FluffyShare.share( subtitle: presence == null
? null
: Text(presence.getLocalizedLastActiveAgo(context)),
trailing: IconButton(
icon: Icon(Icons.adaptive.share),
onPressed: () => FluffyShare.share(
user.id, user.id,
context, context,
), ),
), ),
if (presence != null) ),
),
],
),
if (controller.widget.onMention != null)
ListTile( ListTile(
title: Text(presence.getLocalizedStatusMessage(context)), trailing: const Icon(Icons.alternate_email_outlined),
subtitle: title: Text(L10n.of(context)!.mention),
Text(presence.getLocalizedLastActiveAgo(context)), onTap: () =>
trailing: Icon(Icons.circle, controller.participantAction(UserBottomSheetAction.mention),
color: presence.presence == PresenceType.online ),
? Colors.green if (user.canChangePowerLevel)
: Colors.grey), ListTile(
title: Text(L10n.of(context)!.setPermissionsLevel),
trailing: const Icon(Icons.edit_attributes_outlined),
onTap: () => controller
.participantAction(UserBottomSheetAction.permission),
),
if (user.canKick)
ListTile(
title: Text(L10n.of(context)!.kickFromChat),
trailing: const Icon(Icons.exit_to_app_outlined),
onTap: () =>
controller.participantAction(UserBottomSheetAction.kick),
),
if (user.canBan && user.membership != Membership.ban)
ListTile(
title: Text(L10n.of(context)!.banFromChat),
trailing: const Icon(Icons.warning_sharp),
onTap: () =>
controller.participantAction(UserBottomSheetAction.ban),
)
else if (user.canBan && user.membership == Membership.ban)
ListTile(
title: Text(L10n.of(context)!.unbanFromChat),
trailing: const Icon(Icons.warning_outlined),
onTap: () =>
controller.participantAction(UserBottomSheetAction.unban),
),
if (user.id != client.userID &&
!client.ignoredUsers.contains(user.id))
ListTile(
textColor: Theme.of(context).colorScheme.onErrorContainer,
iconColor: Theme.of(context).colorScheme.onErrorContainer,
title: Text(L10n.of(context)!.ignore),
trailing: const Icon(Icons.block),
onTap: () =>
controller.participantAction(UserBottomSheetAction.ignore),
),
if (user.id != client.userID)
ListTile(
textColor: Theme.of(context).colorScheme.error,
iconColor: Theme.of(context).colorScheme.error,
title: Text(L10n.of(context)!.reportUser),
trailing: const Icon(Icons.shield_outlined),
onTap: () =>
controller.participantAction(UserBottomSheetAction.report),
), ),
], ],
), ),
), ),
),
),
),
);
}
}
class _TextWithIcon extends StatelessWidget {
final String text;
final IconData iconData;
const _TextWithIcon(
this.text,
this.iconData, {
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(iconData),
const SizedBox(width: 16),
Text(text),
],
); );
} }
} }

View File

@ -0,0 +1,28 @@
import 'package:flutter/material.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/utils/platform_infos.dart';
Future<T?> showAdaptiveBottomSheet<T>({
required BuildContext context,
required Widget Function(BuildContext) builder,
bool isDismissible = true,
}) =>
showModalBottomSheet(
context: context,
builder: builder,
useRootNavigator: !PlatformInfos.isMobile,
isDismissible: isDismissible,
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height - 128,
maxWidth: FluffyThemes.columnWidth * 1.5,
),
clipBehavior: Clip.hardEdge,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(AppConfig.borderRadius),
topRight: Radius.circular(AppConfig.borderRadius),
),
),
);

View File

@ -10,6 +10,7 @@ import 'package:url_launcher/url_launcher.dart';
import 'package:vrouter/vrouter.dart'; import 'package:vrouter/vrouter.dart';
import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
import 'package:fluffychat/widgets/matrix.dart'; import 'package:fluffychat/widgets/matrix.dart';
import 'package:fluffychat/widgets/profile_bottom_sheet.dart'; import 'package:fluffychat/widgets/profile_bottom_sheet.dart';
import 'package:fluffychat/widgets/public_room_bottom_sheet.dart'; import 'package:fluffychat/widgets/public_room_bottom_sheet.dart';
@ -145,7 +146,7 @@ class UrlLauncher {
} }
return; return;
} else { } else {
await showModalBottomSheet( await showAdaptiveBottomSheet(
context: context, context: context,
builder: (c) => PublicRoomBottomSheet( builder: (c) => PublicRoomBottomSheet(
roomAlias: identityParts.primaryIdentifier, roomAlias: identityParts.primaryIdentifier,
@ -182,7 +183,7 @@ class UrlLauncher {
} }
} }
} else if (identityParts.primaryIdentifier.sigil == '@') { } else if (identityParts.primaryIdentifier.sigil == '@') {
await showModalBottomSheet( await showAdaptiveBottomSheet(
context: context, context: context,
builder: (c) => ProfileBottomSheet( builder: (c) => ProfileBottomSheet(
userId: identityParts.primaryIdentifier, userId: identityParts.primaryIdentifier,

View File

@ -14,6 +14,7 @@ import 'package:vrouter/vrouter.dart';
import 'package:fluffychat/pages/chat/cupertino_widgets_bottom_sheet.dart'; import 'package:fluffychat/pages/chat/cupertino_widgets_bottom_sheet.dart';
import 'package:fluffychat/pages/chat/edit_widgets_dialog.dart'; import 'package:fluffychat/pages/chat/edit_widgets_dialog.dart';
import 'package:fluffychat/pages/chat/widgets_bottom_sheet.dart'; import 'package:fluffychat/pages/chat/widgets_bottom_sheet.dart';
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
import 'm2_popup_menu_button.dart'; import 'm2_popup_menu_button.dart';
import 'matrix.dart'; import 'matrix.dart';
@ -185,7 +186,7 @@ class ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> {
context: context, context: context,
builder: (context) => CupertinoWidgetsBottomSheet(room: widget.room), builder: (context) => CupertinoWidgetsBottomSheet(room: widget.room),
) )
: showModalBottomSheet( : showAdaptiveBottomSheet(
context: context, context: context,
builder: (context) => WidgetsBottomSheet(room: widget.room), builder: (context) => WidgetsBottomSheet(room: widget.room),
); );

View File

@ -1,5 +1,3 @@
import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
@ -7,10 +5,8 @@ import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:matrix/matrix.dart'; import 'package:matrix/matrix.dart';
import 'package:vrouter/vrouter.dart'; import 'package:vrouter/vrouter.dart';
import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/widgets/avatar.dart';
import 'package:fluffychat/widgets/content_banner.dart';
import 'package:fluffychat/widgets/matrix.dart'; import 'package:fluffychat/widgets/matrix.dart';
import '../utils/localized_exception_extension.dart';
class ProfileBottomSheet extends StatelessWidget { class ProfileBottomSheet extends StatelessWidget {
final String userId; final String userId;
@ -37,67 +33,55 @@ class ProfileBottomSheet extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Center( return SafeArea(
child: SizedBox( child: FutureBuilder<Profile>(
width: min( future: Matrix.of(context).client.getProfileFromUserId(userId),
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: const Icon(Icons.arrow_downward_outlined),
onPressed: Navigator.of(context, rootNavigator: false).pop,
tooltip: L10n.of(context)!.close,
),
),
body: FutureBuilder<Profile>(
future:
Matrix.of(context).client.getProfileFromUserId(userId),
builder: (context, snapshot) { builder: (context, snapshot) {
final profile = snapshot.data; final profile = snapshot.data;
return Scaffold(
return Column( appBar: AppBar(
children: [ leading: CloseButton(
Expanded( onPressed: Navigator.of(context, rootNavigator: false).pop,
child: profile == null
? Container(
alignment: Alignment.center,
color: Theme.of(context).secondaryHeaderColor,
child: snapshot.hasError
? Text(snapshot.error!
.toLocalizedString(context))
: const CircularProgressIndicator
.adaptive(strokeWidth: 2),
)
: ContentBanner(
mxContent: profile.avatarUrl,
defaultIcon: Icons.account_circle_outlined,
client: Matrix.of(context).client,
placeholder: (context) => Center(
child: Text(
userId.localpart ?? userId,
style:
Theme.of(context).textTheme.headline3,
), ),
), title: ListTile(
), contentPadding: const EdgeInsets.only(right: 16.0),
),
ListTile(
title: Text( title: Text(
profile?.displayName ?? userId.localpart ?? ''), profile?.displayName ?? userId.localpart ?? userId,
subtitle: Text(userId), style: const TextStyle(fontSize: 18),
trailing: const Icon(Icons.account_box_outlined), ),
subtitle: Text(
userId,
style: const TextStyle(fontSize: 12),
),
),
actions: [
Padding(
padding: const EdgeInsets.all(8.0),
child: OutlinedButton.icon(
onPressed: () => _startDirectChat(context),
icon: Icon(Icons.adaptive.share_outlined),
label: Text(L10n.of(context)!.share),
),
),
],
),
body: ListView(
children: [
Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Avatar(
mxContent: profile?.avatarUrl,
name: profile?.displayName ?? userId,
size: Avatar.defaultSize * 3,
fontSize: 36,
),
),
), ),
Container( Container(
width: double.infinity, width: double.infinity,
padding: const EdgeInsets.all(12), padding: const EdgeInsets.all(12),
child: ElevatedButton.icon( child: FloatingActionButton.extended(
onPressed: () => _startDirectChat(context), onPressed: () => _startDirectChat(context),
label: Text(L10n.of(context)!.newChat), label: Text(L10n.of(context)!.newChat),
icon: const Icon(Icons.send_outlined), icon: const Icon(Icons.send_outlined),
@ -105,11 +89,9 @@ class ProfileBottomSheet extends StatelessWidget {
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
], ],
),
); );
}), },
),
),
),
), ),
); );
} }

View File

@ -1,5 +1,3 @@
import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
@ -8,7 +6,6 @@ import 'package:matrix/matrix.dart';
import 'package:matrix_link_text/link_text.dart'; import 'package:matrix_link_text/link_text.dart';
import 'package:vrouter/vrouter.dart'; import 'package:vrouter/vrouter.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/utils/url_launcher.dart'; import 'package:fluffychat/utils/url_launcher.dart';
import 'package:fluffychat/widgets/content_banner.dart'; import 'package:fluffychat/widgets/content_banner.dart';
import 'package:fluffychat/widgets/matrix.dart'; import 'package:fluffychat/widgets/matrix.dart';
@ -72,13 +69,7 @@ class PublicRoomBottomSheet extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final roomAlias = this.roomAlias; final roomAlias = this.roomAlias;
return Center( return SafeArea(
child: SizedBox(
width: min(
MediaQuery.of(context).size.width, FluffyThemes.columnWidth * 1.5),
child: Material(
elevation: 4,
child: SafeArea(
child: Scaffold( child: Scaffold(
extendBodyBehindAppBar: true, extendBodyBehindAppBar: true,
appBar: AppBar( appBar: AppBar(
@ -116,8 +107,7 @@ class PublicRoomBottomSheet extends StatelessWidget {
alignment: Alignment.center, alignment: Alignment.center,
color: Theme.of(context).secondaryHeaderColor, color: Theme.of(context).secondaryHeaderColor,
child: snapshot.hasError child: snapshot.hasError
? Text( ? Text(snapshot.error!.toLocalizedString(context))
snapshot.error!.toLocalizedString(context))
: const CircularProgressIndicator.adaptive( : const CircularProgressIndicator.adaptive(
strokeWidth: 2), strokeWidth: 2),
) )
@ -148,14 +138,10 @@ class PublicRoomBottomSheet extends StatelessWidget {
), ),
subtitle: LinkText( subtitle: LinkText(
text: profile!.topic!, text: profile!.topic!,
linkStyle: linkStyle: const TextStyle(color: Colors.blueAccent),
const TextStyle(color: Colors.blueAccent),
textStyle: TextStyle( textStyle: TextStyle(
fontSize: 14, fontSize: 14,
color: Theme.of(context) color: Theme.of(context).textTheme.bodyText2!.color,
.textTheme
.bodyText2!
.color,
), ),
onLinkTap: (url) => onLinkTap: (url) =>
UrlLauncher(context, url).launchUrl(), UrlLauncher(context, url).launchUrl(),
@ -165,9 +151,6 @@ class PublicRoomBottomSheet extends StatelessWidget {
); );
}), }),
), ),
),
),
),
); );
} }
} }