diff --git a/lib/config/routes.dart b/lib/config/routes.dart index 0e9c0a78a..1438efa58 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -221,18 +221,6 @@ abstract class AppRoutes { if (resp != null) return resp; final isColumnMode = FluffyThemes.isColumnMode(context); - final roomId = state.pathParameters['roomid']; - final room = roomId != null - ? Matrix.of(context).client.getRoomById(roomId) - : null; - - if (room != null && room.isSpace) { - if (isColumnMode && - (state.fullPath?.endsWith(':roomid') ?? false)) { - return '/rooms/${room.id}/details?spaceId=${room.id}'; - } - } - final spaceId = state.uri.queryParameters['spaceId']; if (spaceId != null && spaceId != 'clear' && diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index 88785cfa8..cc016a335 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -88,7 +88,8 @@ class ChatPage extends StatelessWidget { final room = Matrix.of(context).client.getRoomById(roomId); // #Pangea - if (room?.isSpace ?? false) { + if (room?.isSpace == true && + GoRouterState.of(context).fullPath?.endsWith(":roomid") == true) { ErrorHandler.logError( e: "Space chat opened", s: StackTrace.current, diff --git a/lib/pages/chat_list/chat_list.dart b/lib/pages/chat_list/chat_list.dart index 130163462..f7486b5cf 100644 --- a/lib/pages/chat_list/chat_list.dart +++ b/lib/pages/chat_list/chat_list.dart @@ -121,7 +121,7 @@ class ChatListController extends State // #Pangea if (FluffyThemes.isColumnMode(context)) { - context.push("/rooms/$spaceId"); + context.push("/rooms/$spaceId/details"); } // Pangea# diff --git a/lib/pangea/activity_planner/activity_plan_card.dart b/lib/pangea/activity_planner/activity_plan_card.dart index cc1e3b1a4..d85bcaeb1 100644 --- a/lib/pangea/activity_planner/activity_plan_card.dart +++ b/lib/pangea/activity_planner/activity_plan_card.dart @@ -66,7 +66,7 @@ class ActivityPlanCardState extends State { } Future _onLaunch() async { - if (widget.controller.room != null) { + if (widget.controller.room != null && !widget.controller.room!.isSpace) { final resp = await showFutureLoadingDialog( context: context, future: widget.controller.launchToRoom, diff --git a/lib/pangea/activity_planner/activity_planner_builder.dart b/lib/pangea/activity_planner/activity_planner_builder.dart index 36e72c0c9..cb0bf261b 100644 --- a/lib/pangea/activity_planner/activity_planner_builder.dart +++ b/lib/pangea/activity_planner/activity_planner_builder.dart @@ -220,7 +220,8 @@ class ActivityPlannerBuilderState extends State { } Future launchToRoom() async { - return widget.room?.sendActivityPlan( + if (room == null || room!.isSpace) return; + return room?.sendActivityPlan( updatedActivity, avatar: avatar, filename: filename, diff --git a/lib/pangea/activity_suggestions/activity_suggestion_dialog.dart b/lib/pangea/activity_suggestions/activity_suggestion_dialog.dart index 47b9aee4e..8d47a3f30 100644 --- a/lib/pangea/activity_suggestions/activity_suggestion_dialog.dart +++ b/lib/pangea/activity_suggestions/activity_suggestion_dialog.dart @@ -49,7 +49,8 @@ class ActivitySuggestionDialogState extends State { await widget.controller.updateImageURL(); widget.onLaunch!.call(); Navigator.of(context).pop(); - } else if (widget.controller.room != null) { + } else if (widget.controller.room != null && + !widget.controller.room!.isSpace) { final resp = await showFutureLoadingDialog( context: context, future: widget.controller.launchToRoom, diff --git a/lib/pangea/chat_settings/pages/pangea_chat_details.dart b/lib/pangea/chat_settings/pages/pangea_chat_details.dart index e973971eb..5a742e648 100644 --- a/lib/pangea/chat_settings/pages/pangea_chat_details.dart +++ b/lib/pangea/chat_settings/pages/pangea_chat_details.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:math'; import 'package:flutter/material.dart'; @@ -10,6 +9,7 @@ import 'package:go_router/go_router.dart'; import 'package:matrix/matrix.dart'; import 'package:fluffychat/config/app_config.dart'; +import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/pages/chat_details/chat_details.dart'; import 'package:fluffychat/pages/chat_details/participant_list_item.dart'; import 'package:fluffychat/pangea/analytics_misc/level_display_name.dart'; @@ -17,7 +17,6 @@ import 'package:fluffychat/pangea/bot/utils/bot_name.dart'; import 'package:fluffychat/pangea/bot/widgets/bot_face_svg.dart'; import 'package:fluffychat/pangea/chat_settings/models/bot_options_model.dart'; import 'package:fluffychat/pangea/chat_settings/utils/delete_room.dart'; -import 'package:fluffychat/pangea/chat_settings/widgets/class_name_header.dart'; import 'package:fluffychat/pangea/chat_settings/widgets/conversation_bot/conversation_bot_settings.dart'; import 'package:fluffychat/pangea/chat_settings/widgets/delete_space_dialog.dart'; import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart'; @@ -64,7 +63,6 @@ class PangeaChatDetailsView extends StatelessWidget { members = members.take(10).toList(); final actualMembersCount = (room.summary.mInvitedMemberCount ?? 0) + (room.summary.mJoinedMemberCount ?? 0); - final canRequestMoreMembers = members.length < actualMembersCount; final displayname = room.getLocalizedDisplayname( MatrixLocals(L10n.of(context)), ); @@ -72,17 +70,17 @@ class PangeaChatDetailsView extends StatelessWidget { appBar: AppBar( leading: controller.widget.embeddedCloseButton ?? (room.isSpace - ? const SizedBox() + ? FluffyThemes.isColumnMode(context) + ? const SizedBox() + : BackButton( + onPressed: () => + context.go("/rooms?spaceId=${room.id}"), + ) : const Center(child: BackButton())), - elevation: theme.appBarTheme.elevation, - title: ClassNameHeader( - controller: controller, - room: room, - ), - centerTitle: true, - backgroundColor: theme.appBarTheme.backgroundColor, ), body: MaxWidthBody( + maxWidth: 800, + showBorder: false, child: ListView.builder( physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, @@ -106,10 +104,11 @@ class PangeaChatDetailsView extends StatelessWidget { child: Avatar( mxContent: room.avatar, name: displayname, - // #Pangea userId: room.directChatMatrixID, - // Pangea# size: Avatar.defaultSize * 2.5, + borderRadius: room.isSpace + ? BorderRadius.circular(24.0) + : null, ), ), if (!room.isDirectChat && @@ -197,7 +196,6 @@ class PangeaChatDetailsView extends StatelessWidget { ), ], ), - Divider(color: theme.dividerColor, height: 1), Stack( children: [ if (room.isRoomAdmin) @@ -211,8 +209,8 @@ class PangeaChatDetailsView extends StatelessWidget { ), Padding( padding: const EdgeInsets.only( - left: 24.0, - right: 24.0, + left: 32.0, + right: 32.0, top: 16.0, bottom: 16.0, ), @@ -242,9 +240,12 @@ class PangeaChatDetailsView extends StatelessWidget { ), ], ), - RoomDetailsButtonRow( - controller: controller, - room: room, + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: RoomDetailsButtonRow( + controller: controller, + room: room, + ), ), ], ) @@ -302,14 +303,9 @@ class RoomDetailsButtonRowState extends State { super.dispose(); } - final double _buttonWidth = 130.0; - final double _buttonHeight = 80.0; - + final double _buttonWidth = 120.0; + final double _buttonHeight = 70.0; final double _miniButtonWidth = 50.0; - final double _buttonPadding = 4.0; - - double get _fullButtonWidth => _buttonWidth + (_buttonPadding * 2); - double get _fullMiniButtonWidth => _miniButtonWidth + (_buttonPadding * 2); Room get room => widget.room; @@ -319,22 +315,23 @@ class RoomDetailsButtonRowState extends State { ButtonDetails( title: l10n.activities, icon: const Icon(Icons.event_note_outlined), - onPressed: () => room.isSpace - ? context.go("/rooms/homepage/planner") - : context.go("/rooms/${room.id}/details/planner"), - visible: (room) => room.canSendDefaultStates, + onPressed: () => context.go("/rooms/${room.id}/details/planner"), + visible: room.canSendDefaultStates || room.isSpace, + enabled: room.canSendDefaultStates, ), ButtonDetails( title: l10n.permissions, icon: const Icon(Icons.edit_attributes_outlined), onPressed: () => context.go('/rooms/${room.id}/details/permissions'), - visible: (room) => room.isRoomAdmin && !room.isDirectChat, + visible: (room.isRoomAdmin && !room.isDirectChat) || room.isSpace, + enabled: room.isRoomAdmin && !room.isDirectChat, ), ButtonDetails( title: l10n.access, icon: const Icon(Icons.shield_outlined), onPressed: () => context.go('/rooms/${room.id}/details/access'), - visible: (room) => room.isSpace && room.isRoomAdmin, + visible: room.isSpace, + enabled: room.isSpace && room.isRoomAdmin, ), ButtonDetails( title: room.pushRuleState == PushRuleState.notify @@ -353,23 +350,24 @@ class RoomDetailsButtonRowState extends State { : PushRuleState.notify, ), ), - visible: (room) => !room.isSpace, + visible: !room.isSpace, ), ButtonDetails( title: l10n.invite, icon: const Icon(Icons.person_add_outlined), onPressed: () => context.go('/rooms/${room.id}/details/invite'), - visible: (room) => room.canInvite && !room.isDirectChat, + visible: (room.canInvite && !room.isDirectChat) || room.isSpace, + enabled: room.canInvite && !room.isDirectChat, ), ButtonDetails( title: l10n.addSubspace, icon: const Icon(Icons.add_outlined), onPressed: widget.controller.addSubspace, - visible: (room) => - room.isSpace && + visible: room.isSpace && room.canSendEvent( EventTypes.SpaceChild, ), + showInMainView: false, ), ButtonDetails( title: l10n.downloadSpaceAnalytics, @@ -380,13 +378,14 @@ class RoomDetailsButtonRowState extends State { builder: (context) => DownloadAnalyticsDialog(space: room), ); }, - visible: (room) => room.isSpace && room.isRoomAdmin, + visible: room.isSpace && room.isRoomAdmin, + showInMainView: false, ), ButtonDetails( title: l10n.download, icon: const Icon(Icons.download_outlined), onPressed: widget.controller.downloadChatAction, - visible: (room) => room.ownPowerLevel >= 50 && !room.isSpace, + visible: room.ownPowerLevel >= 50 && !room.isSpace, ), ButtonDetails( title: l10n.botSettings, @@ -401,14 +400,13 @@ class RoomDetailsButtonRowState extends State { onSubmit: widget.controller.setBotOptions, ), ), - visible: (room) => - !room.isSpace && !room.isDirectChat && room.canInvite, + visible: !room.isSpace && !room.isDirectChat && room.canInvite, ), ButtonDetails( title: l10n.chatCapacity, icon: const Icon(Icons.reduce_capacity), onPressed: widget.controller.setRoomCapacity, - visible: (room) => + visible: !room.isSpace && !room.isDirectChat && room.canSendDefaultStates, ), ButtonDetails( @@ -435,7 +433,8 @@ class RoomDetailsButtonRowState extends State { context.go("/rooms?spaceId=clear"); } }, - visible: (room) => room.membership == Membership.join, + visible: room.membership == Membership.join, + showInMainView: false, ), ButtonDetails( title: l10n.delete, @@ -471,7 +470,8 @@ class RoomDetailsButtonRowState extends State { context.go("/rooms?spaceId=clear"); } }, - visible: (room) => room.isRoomAdmin, + visible: room.isRoomAdmin, + showInMainView: false, ), ]; } @@ -480,7 +480,7 @@ class RoomDetailsButtonRowState extends State { Widget build(BuildContext context) { final buttons = _buttons(context) .where( - (button) => button.visible(room), + (button) => button.visible, ) .toList(); @@ -490,37 +490,35 @@ class RoomDetailsButtonRowState extends State { builder: (context, constraints) { final availableWidth = constraints.maxWidth; final fullButtonCapacity = - (availableWidth / _fullButtonWidth).floor() - 1; + (availableWidth / _buttonWidth).floor() - 1; final miniButtonCapacity = - (availableWidth / _fullMiniButtonWidth).floor() - 1; + (availableWidth / _miniButtonWidth).floor() - 1; - final mini = fullButtonCapacity < 3; + final mini = fullButtonCapacity < 4; final capacity = mini ? miniButtonCapacity : fullButtonCapacity; - final numVisibleButtons = min(buttons.length, capacity); + List mainViewButtons = + buttons.where((button) => button.showInMainView).toList(); + final List otherButtons = + buttons.where((button) => !button.showInMainView).toList(); + + if (capacity < mainViewButtons.length) { + otherButtons.addAll(mainViewButtons.skip(capacity)); + mainViewButtons = mainViewButtons.take(capacity).toList(); + } return Row( mainAxisAlignment: MainAxisAlignment.center, - children: List.generate(numVisibleButtons + 1, (index) { - if (index == numVisibleButtons) { - if (buttons.length == numVisibleButtons) { + children: List.generate(mainViewButtons.length + 1, (index) { + if (index == mainViewButtons.length) { + if (otherButtons.isEmpty) { return const SizedBox(); - } else if (buttons.length == numVisibleButtons + 1) { - return RoomDetailsButton( - mini: mini, - visible: true, - title: buttons[index].title, - icon: buttons[index].icon, - onPressed: buttons[index].onPressed, - width: mini ? _miniButtonWidth : _buttonWidth, - height: mini ? _miniButtonWidth : _buttonHeight, - ); } + return PopupMenuButton( - onSelected: (button) => button.onPressed(), + onSelected: (button) => button.onPressed?.call(), itemBuilder: (context) { - return buttons - .skip(numVisibleButtons) + return otherButtons .map( (button) => PopupMenuItem( value: button, @@ -537,9 +535,11 @@ class RoomDetailsButtonRowState extends State { }, child: RoomDetailsButton( mini: mini, - visible: true, - title: L10n.of(context).more, - icon: const Icon(Icons.more_horiz_outlined), + buttonDetails: ButtonDetails( + title: L10n.of(context).more, + icon: const Icon(Icons.more_horiz_outlined), + visible: true, + ), width: mini ? _miniButtonWidth : _buttonWidth, height: mini ? _miniButtonWidth : _buttonHeight, ), @@ -547,17 +547,11 @@ class RoomDetailsButtonRowState extends State { } final button = buttons[index]; - return Padding( - padding: EdgeInsets.symmetric(horizontal: _buttonPadding), - child: RoomDetailsButton( - mini: mini, - visible: button.visible(room), - title: button.title, - icon: button.icon, - onPressed: button.onPressed, - width: mini ? _miniButtonWidth : _buttonWidth, - height: mini ? _miniButtonWidth : _buttonHeight, - ), + return RoomDetailsButton( + mini: mini, + buttonDetails: button, + width: mini ? _miniButtonWidth : _buttonWidth, + height: mini ? _miniButtonWidth : _buttonHeight, ); }), ); @@ -569,64 +563,75 @@ class RoomDetailsButtonRowState extends State { class RoomDetailsButton extends StatelessWidget { final bool mini; - final bool visible; + // final bool visible; + // final bool enabled; - final String title; - final Widget icon; - final VoidCallback? onPressed; + // final String title; + // final Widget icon; + // final VoidCallback? onPressed; final double width; final double height; + final ButtonDetails buttonDetails; + const RoomDetailsButton({ super.key, - required this.visible, - required this.title, - required this.icon, + required this.buttonDetails, + // required this.visible, + // required this.title, + // required this.icon, required this.mini, required this.width, required this.height, - this.onPressed, + // this.enabled = true, + // this.onPressed, }); @override Widget build(BuildContext context) { - if (!visible) { + if (!buttonDetails.visible) { return const SizedBox(); } - return MouseRegion( - cursor: SystemMouseCursors.click, - child: HoverBuilder( - builder: (context, hovered) { - return GestureDetector( - onTap: onPressed, - child: Container( - width: width, - height: height, - decoration: BoxDecoration( - color: hovered - ? Theme.of(context).colorScheme.primary.withAlpha(50) - : Colors.transparent, - borderRadius: BorderRadius.circular(8), - ), - padding: const EdgeInsets.all(8.0), - child: mini - ? icon - : Column( - spacing: 8.0, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - icon, - Text( - title, - textAlign: TextAlign.center, + return AbsorbPointer( + absorbing: !buttonDetails.enabled, + child: MouseRegion( + cursor: SystemMouseCursors.click, + child: HoverBuilder( + builder: (context, hovered) { + return GestureDetector( + onTap: buttonDetails.onPressed, + child: Opacity( + opacity: buttonDetails.enabled ? 1.0 : 0.5, + child: Container( + width: width, + height: height, + decoration: BoxDecoration( + color: hovered + ? Theme.of(context).colorScheme.primary.withAlpha(50) + : Colors.transparent, + borderRadius: BorderRadius.circular(8), + ), + padding: const EdgeInsets.all(8.0), + child: mini + ? buttonDetails.icon + : Column( + spacing: 8.0, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + buttonDetails.icon, + Text( + buttonDetails.title, + textAlign: TextAlign.center, + ), + ], ), - ], - ), - ), - ); - }, + ), + ), + ); + }, + ), ), ); } @@ -635,14 +640,18 @@ class RoomDetailsButton extends StatelessWidget { class ButtonDetails { final String title; final Widget icon; - final VoidCallback onPressed; - final bool Function(Room) visible; + final VoidCallback? onPressed; + final bool visible; + final bool enabled; + final bool showInMainView; const ButtonDetails({ required this.title, required this.icon, - required this.onPressed, required this.visible, + this.onPressed, + this.enabled = true, + this.showInMainView = true, }); } @@ -654,7 +663,7 @@ class RoomParticipantsSection extends StatelessWidget { super.key, }); - final double _width = 90.0; + final double _width = 80.0; final double _padding = 12.0; double get _fullWidth => _width + (_padding * 2); @@ -792,6 +801,7 @@ class RoomParticipantsSection extends StatelessWidget { color: Theme.of(context).colorScheme.primary, fontWeight: FontWeight.bold, ), + overflow: TextOverflow.ellipsis, ), LevelDisplayName( userId: user.id, diff --git a/lib/pangea/chat_settings/widgets/class_name_header.dart b/lib/pangea/chat_settings/widgets/class_name_header.dart deleted file mode 100644 index 7388ffa5a..000000000 --- a/lib/pangea/chat_settings/widgets/class_name_header.dart +++ /dev/null @@ -1,65 +0,0 @@ -// ignore_for_file: implementation_imports - -import 'package:flutter/material.dart'; -import 'package:flutter/src/widgets/visibility.dart' as visible; - -import 'package:flutter_gen/gen_l10n/l10n.dart'; -import 'package:matrix/matrix.dart'; - -import 'package:fluffychat/pages/chat_details/chat_details.dart'; -import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart'; - -class ClassNameHeader extends StatelessWidget { - final Room room; - final ChatDetailsController controller; - const ClassNameHeader({ - super.key, - required this.room, - required this.controller, - }); - - @override - Widget build(BuildContext context) { - return TextButton.icon( - onPressed: !room.isDirectChat && room.canSendDefaultStates - ? controller.setDisplaynameAction - : null, - onHover: !room.isDirectChat && room.canSendDefaultStates - ? controller.hoverEditNameIcon - : null, - style: TextButton.styleFrom( - padding: const EdgeInsets.symmetric(horizontal: 25), - ), - icon: visible.Visibility( - visible: controller.showEditNameIcon, - child: Icon( - Icons.edit, - color: Theme.of(context).colorScheme.onSurface, - ), - ), - label: room.isDirectChat - ? Text( - L10n.of(context).chatDetails, - style: TextStyle( - fontSize: 20, - color: Theme.of(context).textTheme.bodyLarge!.color, - ), - ) - : room.nameAndRoomTypeIcon( - TextStyle( - fontSize: 20, - color: Theme.of(context).textTheme.bodyLarge!.color, - ), - ), - // icon: Text( - // room.getLocalizedDisplayname( - // MatrixLocals(L10n.of(context)), - // ), - // style: TextStyle( - // fontSize: 20, - // color: Theme.of(context).textTheme.bodyText1!.color, - // ), - // ), - ); - } -} diff --git a/lib/widgets/layouts/max_width_body.dart b/lib/widgets/layouts/max_width_body.dart index 534dfc46d..0a8631cc8 100644 --- a/lib/widgets/layouts/max_width_body.dart +++ b/lib/widgets/layouts/max_width_body.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:fluffychat/config/app_config.dart'; -import 'package:fluffychat/config/themes.dart'; class MaxWidthBody extends StatelessWidget { final Widget child; @@ -31,7 +30,10 @@ class MaxWidthBody extends StatelessWidget { builder: (context, constraints) { final theme = Theme.of(context); - const desiredWidth = FluffyThemes.columnWidth * 1.5; + // #Pangea + // const desiredWidth = FluffyThemes.columnWidth * 1.5; + final desiredWidth = maxWidth; + // Pangea# final body = constraints.maxWidth <= desiredWidth ? child : Container( @@ -41,9 +43,14 @@ class MaxWidthBody extends StatelessWidget { padding: padding ?? const EdgeInsets.all(32), // Pangea# child: ConstrainedBox( - constraints: const BoxConstraints( - maxWidth: FluffyThemes.columnWidth * 1.5, + // #Pangea + // constraints: const BoxConstraints( + // maxWidth: FluffyThemes.columnWidth * 1.5, + // ), + constraints: BoxConstraints( + maxWidth: maxWidth, ), + // Pangea# child: Material( shape: RoundedRectangleBorder( borderRadius: