mirror of
				https://gitlab.com/famedly/fluffychat.git
				synced 2025-11-04 06:17:26 +01:00 
			
		
		
		
	Merge branch 'braid/multi-account-fixes' into 'main'
fix: multi-account related issues See merge request famedly/fluffychat!874
This commit is contained in:
		
						commit
						8c86ff4331
					
				@ -82,7 +82,10 @@ class ChatListController extends State<ChatList> with TickerProviderStateMixin {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void setActiveSpacesEntry(BuildContext context, SpacesEntry? spaceId) {
 | 
			
		||||
    if (snappingSheetController.currentPosition != kSpacesBottomBarHeight) {
 | 
			
		||||
    if ((snappingSheetController.isAttached
 | 
			
		||||
            ? snappingSheetController.currentPosition
 | 
			
		||||
            : 0) !=
 | 
			
		||||
        kSpacesBottomBarHeight) {
 | 
			
		||||
      snapBackSpacesSheet();
 | 
			
		||||
    }
 | 
			
		||||
    setState(() => _activeSpacesEntry = spaceId);
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,7 @@ import 'package:matrix/matrix.dart';
 | 
			
		||||
import 'package:fluffychat/pages/chat_list/chat_list.dart';
 | 
			
		||||
import 'package:fluffychat/pages/chat_list/chat_list_item.dart';
 | 
			
		||||
import 'package:fluffychat/pages/chat_list/spaces_bottom_bar.dart';
 | 
			
		||||
import 'package:fluffychat/pages/chat_list/spaces_entry.dart';
 | 
			
		||||
import 'package:fluffychat/pages/chat_list/stories_header.dart';
 | 
			
		||||
import '../../utils/stream_extension.dart';
 | 
			
		||||
import '../../widgets/matrix.dart';
 | 
			
		||||
@ -28,7 +29,7 @@ class _ChatListViewBodyState extends State<ChatListViewBody> {
 | 
			
		||||
 | 
			
		||||
  // used to check the animation direction
 | 
			
		||||
  String? _lastUserId;
 | 
			
		||||
  String? _lastSpaceId;
 | 
			
		||||
  SpacesEntry? _lastSpace;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  void initState() {
 | 
			
		||||
@ -175,11 +176,13 @@ class _ChatListViewBodyState extends State<ChatListViewBody> {
 | 
			
		||||
        return SharedAxisTransition(
 | 
			
		||||
          animation: primaryAnimation,
 | 
			
		||||
          secondaryAnimation: secondaryAnimation,
 | 
			
		||||
          transitionType:
 | 
			
		||||
              widget.controller.snappingSheetController.currentPosition ==
 | 
			
		||||
                      kSpacesBottomBarHeight
 | 
			
		||||
                  ? SharedAxisTransitionType.horizontal
 | 
			
		||||
                  : SharedAxisTransitionType.vertical,
 | 
			
		||||
          transitionType: (widget.controller.snappingSheetController.isAttached
 | 
			
		||||
                      ? widget
 | 
			
		||||
                          .controller.snappingSheetController.currentPosition
 | 
			
		||||
                      : 0) ==
 | 
			
		||||
                  kSpacesBottomBarHeight
 | 
			
		||||
              ? SharedAxisTransitionType.horizontal
 | 
			
		||||
              : SharedAxisTransitionType.vertical,
 | 
			
		||||
          fillColor: Theme.of(context).scaffoldBackgroundColor,
 | 
			
		||||
          child: child,
 | 
			
		||||
        );
 | 
			
		||||
@ -208,13 +211,13 @@ class _ChatListViewBodyState extends State<ChatListViewBody> {
 | 
			
		||||
    }
 | 
			
		||||
    // otherwise, the space changed...
 | 
			
		||||
    else {
 | 
			
		||||
      reversed = widget.controller.spaces
 | 
			
		||||
              .indexWhere((element) => element.id == _lastSpaceId) <
 | 
			
		||||
          widget.controller.spaces.indexWhere(
 | 
			
		||||
              (element) => element.id == widget.controller.activeSpaceId);
 | 
			
		||||
      reversed = widget.controller.spacesEntries
 | 
			
		||||
              .indexWhere((element) => element == _lastSpace) <
 | 
			
		||||
          widget.controller.spacesEntries.indexWhere(
 | 
			
		||||
              (element) => element == widget.controller.activeSpacesEntry);
 | 
			
		||||
    }
 | 
			
		||||
    _lastUserId = newClient.userID;
 | 
			
		||||
    _lastSpaceId = widget.controller.activeSpaceId;
 | 
			
		||||
    _lastSpace = widget.controller.activeSpacesEntry;
 | 
			
		||||
    return reversed;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										215
									
								
								lib/pages/chat_list/chat_list_header.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										215
									
								
								lib/pages/chat_list/chat_list_header.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,215 @@
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter/services.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:animations/animations.dart';
 | 
			
		||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
 | 
			
		||||
import 'package:keyboard_shortcuts/keyboard_shortcuts.dart';
 | 
			
		||||
import 'package:vrouter/vrouter.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:fluffychat/config/app_config.dart';
 | 
			
		||||
import 'package:fluffychat/pages/chat_list/chat_list.dart';
 | 
			
		||||
import 'package:fluffychat/pages/chat_list/client_chooser_button.dart';
 | 
			
		||||
import '../../widgets/matrix.dart';
 | 
			
		||||
 | 
			
		||||
class ChatListHeader extends StatelessWidget implements PreferredSizeWidget {
 | 
			
		||||
  final ChatListController controller;
 | 
			
		||||
 | 
			
		||||
  const ChatListHeader({Key? key, required this.controller}) : super(key: key);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    final selectMode = controller.selectMode;
 | 
			
		||||
 | 
			
		||||
    return AppBar(
 | 
			
		||||
      elevation: controller.scrolledToTop ? 0 : null,
 | 
			
		||||
      actionsIconTheme: IconThemeData(
 | 
			
		||||
        color: controller.selectedRoomIds.isEmpty
 | 
			
		||||
            ? null
 | 
			
		||||
            : Theme.of(context).colorScheme.primary,
 | 
			
		||||
      ),
 | 
			
		||||
      leading: Matrix.of(context).isMultiAccount
 | 
			
		||||
          ? ClientChooserButton(controller)
 | 
			
		||||
          : selectMode == SelectMode.normal
 | 
			
		||||
              ? null
 | 
			
		||||
              : IconButton(
 | 
			
		||||
                  tooltip: L10n.of(context)!.cancel,
 | 
			
		||||
                  icon: const Icon(Icons.close_outlined),
 | 
			
		||||
                  onPressed: controller.cancelAction,
 | 
			
		||||
                  color: Theme.of(context).colorScheme.primary,
 | 
			
		||||
                ),
 | 
			
		||||
      centerTitle: false,
 | 
			
		||||
      actions: selectMode == SelectMode.share
 | 
			
		||||
          ? null
 | 
			
		||||
          : selectMode == SelectMode.select
 | 
			
		||||
              ? [
 | 
			
		||||
                  if (controller.spaces.isNotEmpty)
 | 
			
		||||
                    IconButton(
 | 
			
		||||
                      tooltip: L10n.of(context)!.addToSpace,
 | 
			
		||||
                      icon: const Icon(Icons.group_work_outlined),
 | 
			
		||||
                      onPressed: controller.addOrRemoveToSpace,
 | 
			
		||||
                    ),
 | 
			
		||||
                  IconButton(
 | 
			
		||||
                    tooltip: L10n.of(context)!.toggleUnread,
 | 
			
		||||
                    icon: Icon(controller.anySelectedRoomNotMarkedUnread
 | 
			
		||||
                        ? Icons.mark_chat_read_outlined
 | 
			
		||||
                        : Icons.mark_chat_unread_outlined),
 | 
			
		||||
                    onPressed: controller.toggleUnread,
 | 
			
		||||
                  ),
 | 
			
		||||
                  IconButton(
 | 
			
		||||
                    tooltip: L10n.of(context)!.toggleFavorite,
 | 
			
		||||
                    icon: Icon(controller.anySelectedRoomNotFavorite
 | 
			
		||||
                        ? Icons.push_pin_outlined
 | 
			
		||||
                        : Icons.push_pin),
 | 
			
		||||
                    onPressed: controller.toggleFavouriteRoom,
 | 
			
		||||
                  ),
 | 
			
		||||
                  IconButton(
 | 
			
		||||
                    icon: Icon(controller.anySelectedRoomNotMuted
 | 
			
		||||
                        ? Icons.notifications_off_outlined
 | 
			
		||||
                        : Icons.notifications_outlined),
 | 
			
		||||
                    tooltip: L10n.of(context)!.toggleMuted,
 | 
			
		||||
                    onPressed: controller.toggleMuted,
 | 
			
		||||
                  ),
 | 
			
		||||
                  IconButton(
 | 
			
		||||
                    icon: const Icon(Icons.delete_outlined),
 | 
			
		||||
                    tooltip: L10n.of(context)!.archive,
 | 
			
		||||
                    onPressed: controller.archiveAction,
 | 
			
		||||
                  ),
 | 
			
		||||
                ]
 | 
			
		||||
              : [
 | 
			
		||||
                  KeyBoardShortcuts(
 | 
			
		||||
                    keysToPress: {
 | 
			
		||||
                      LogicalKeyboardKey.controlLeft,
 | 
			
		||||
                      LogicalKeyboardKey.keyF
 | 
			
		||||
                    },
 | 
			
		||||
                    onKeysPressed: () => VRouter.of(context).to('/search'),
 | 
			
		||||
                    helpLabel: L10n.of(context)!.search,
 | 
			
		||||
                    child: IconButton(
 | 
			
		||||
                      icon: const Icon(Icons.search_outlined),
 | 
			
		||||
                      tooltip: L10n.of(context)!.search,
 | 
			
		||||
                      onPressed: () => VRouter.of(context).to('/search'),
 | 
			
		||||
                    ),
 | 
			
		||||
                  ),
 | 
			
		||||
                  if (selectMode == SelectMode.normal)
 | 
			
		||||
                    IconButton(
 | 
			
		||||
                      icon: const Icon(Icons.camera_alt_outlined),
 | 
			
		||||
                      tooltip: L10n.of(context)!.addToStory,
 | 
			
		||||
                      onPressed: () =>
 | 
			
		||||
                          VRouter.of(context).to('/stories/create'),
 | 
			
		||||
                    ),
 | 
			
		||||
                  PopupMenuButton<PopupMenuAction>(
 | 
			
		||||
                    onSelected: controller.onPopupMenuSelect,
 | 
			
		||||
                    itemBuilder: (_) => [
 | 
			
		||||
                      PopupMenuItem(
 | 
			
		||||
                        value: PopupMenuAction.setStatus,
 | 
			
		||||
                        child: Row(
 | 
			
		||||
                          mainAxisSize: MainAxisSize.min,
 | 
			
		||||
                          children: [
 | 
			
		||||
                            const Icon(Icons.edit_outlined),
 | 
			
		||||
                            const SizedBox(width: 12),
 | 
			
		||||
                            Text(L10n.of(context)!.setStatus),
 | 
			
		||||
                          ],
 | 
			
		||||
                        ),
 | 
			
		||||
                      ),
 | 
			
		||||
                      PopupMenuItem(
 | 
			
		||||
                        value: PopupMenuAction.newGroup,
 | 
			
		||||
                        child: Row(
 | 
			
		||||
                          mainAxisSize: MainAxisSize.min,
 | 
			
		||||
                          children: [
 | 
			
		||||
                            const Icon(Icons.group_add_outlined),
 | 
			
		||||
                            const SizedBox(width: 12),
 | 
			
		||||
                            Text(L10n.of(context)!.createNewGroup),
 | 
			
		||||
                          ],
 | 
			
		||||
                        ),
 | 
			
		||||
                      ),
 | 
			
		||||
                      PopupMenuItem(
 | 
			
		||||
                        value: PopupMenuAction.newSpace,
 | 
			
		||||
                        child: Row(
 | 
			
		||||
                          mainAxisSize: MainAxisSize.min,
 | 
			
		||||
                          children: [
 | 
			
		||||
                            const Icon(Icons.group_work_outlined),
 | 
			
		||||
                            const SizedBox(width: 12),
 | 
			
		||||
                            Text(L10n.of(context)!.createNewSpace),
 | 
			
		||||
                          ],
 | 
			
		||||
                        ),
 | 
			
		||||
                      ),
 | 
			
		||||
                      PopupMenuItem(
 | 
			
		||||
                        value: PopupMenuAction.invite,
 | 
			
		||||
                        child: Row(
 | 
			
		||||
                          mainAxisSize: MainAxisSize.min,
 | 
			
		||||
                          children: [
 | 
			
		||||
                            const Icon(Icons.share_outlined),
 | 
			
		||||
                            const SizedBox(width: 12),
 | 
			
		||||
                            Text(L10n.of(context)!.inviteContact),
 | 
			
		||||
                          ],
 | 
			
		||||
                        ),
 | 
			
		||||
                      ),
 | 
			
		||||
                      PopupMenuItem(
 | 
			
		||||
                        value: PopupMenuAction.archive,
 | 
			
		||||
                        child: Row(
 | 
			
		||||
                          mainAxisSize: MainAxisSize.min,
 | 
			
		||||
                          children: [
 | 
			
		||||
                            const Icon(Icons.archive_outlined),
 | 
			
		||||
                            const SizedBox(width: 12),
 | 
			
		||||
                            Text(L10n.of(context)!.archive),
 | 
			
		||||
                          ],
 | 
			
		||||
                        ),
 | 
			
		||||
                      ),
 | 
			
		||||
                      PopupMenuItem(
 | 
			
		||||
                        value: PopupMenuAction.settings,
 | 
			
		||||
                        child: Row(
 | 
			
		||||
                          mainAxisSize: MainAxisSize.min,
 | 
			
		||||
                          children: [
 | 
			
		||||
                            const Icon(Icons.settings_outlined),
 | 
			
		||||
                            const SizedBox(width: 12),
 | 
			
		||||
                            Text(L10n.of(context)!.settings),
 | 
			
		||||
                          ],
 | 
			
		||||
                        ),
 | 
			
		||||
                      ),
 | 
			
		||||
                    ],
 | 
			
		||||
                  ),
 | 
			
		||||
                ],
 | 
			
		||||
      title: PageTransitionSwitcher(
 | 
			
		||||
        reverse: false,
 | 
			
		||||
        transitionBuilder: (
 | 
			
		||||
          Widget child,
 | 
			
		||||
          Animation<double> primaryAnimation,
 | 
			
		||||
          Animation<double> secondaryAnimation,
 | 
			
		||||
        ) {
 | 
			
		||||
          return SharedAxisTransition(
 | 
			
		||||
            animation: primaryAnimation,
 | 
			
		||||
            secondaryAnimation: secondaryAnimation,
 | 
			
		||||
            transitionType: SharedAxisTransitionType.scaled,
 | 
			
		||||
            fillColor: Colors.transparent,
 | 
			
		||||
            child: child,
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
        layoutBuilder: (children) => Stack(
 | 
			
		||||
          alignment: AlignmentDirectional.centerStart,
 | 
			
		||||
          children: children,
 | 
			
		||||
        ),
 | 
			
		||||
        child: selectMode == SelectMode.share
 | 
			
		||||
            ? Text(
 | 
			
		||||
                L10n.of(context)!.share,
 | 
			
		||||
                key: const ValueKey(SelectMode.share),
 | 
			
		||||
              )
 | 
			
		||||
            : selectMode == SelectMode.select
 | 
			
		||||
                ? Text(
 | 
			
		||||
                    controller.selectedRoomIds.length.toString(),
 | 
			
		||||
                    key: const ValueKey(SelectMode.select),
 | 
			
		||||
                  )
 | 
			
		||||
                : (() {
 | 
			
		||||
                    final name = controller.activeSpaceId == null
 | 
			
		||||
                        ? AppConfig.applicationName
 | 
			
		||||
                        : Matrix.of(context)
 | 
			
		||||
                            .client
 | 
			
		||||
                            .getRoomById(controller.activeSpaceId!)!
 | 
			
		||||
                            .displayname;
 | 
			
		||||
                    return Text(name, key: ValueKey(name));
 | 
			
		||||
                  })(),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Size get preferredSize => const Size.fromHeight(56);
 | 
			
		||||
}
 | 
			
		||||
@ -7,13 +7,12 @@ import 'package:keyboard_shortcuts/keyboard_shortcuts.dart';
 | 
			
		||||
import 'package:snapping_sheet/snapping_sheet.dart';
 | 
			
		||||
import 'package:vrouter/vrouter.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:fluffychat/config/app_config.dart';
 | 
			
		||||
import 'package:fluffychat/pages/chat_list/chat_list.dart';
 | 
			
		||||
import 'package:fluffychat/pages/chat_list/client_chooser_button.dart';
 | 
			
		||||
import 'package:fluffychat/pages/chat_list/spaces_bottom_bar.dart';
 | 
			
		||||
import 'package:fluffychat/widgets/connection_status_header.dart';
 | 
			
		||||
import '../../widgets/matrix.dart';
 | 
			
		||||
import 'chat_list_body.dart';
 | 
			
		||||
import 'chat_list_header.dart';
 | 
			
		||||
 | 
			
		||||
class ChatListView extends StatelessWidget {
 | 
			
		||||
  final ChatListController controller;
 | 
			
		||||
@ -35,167 +34,7 @@ class ChatListView extends StatelessWidget {
 | 
			
		||||
            if (selMode == SelectMode.select) redirector.stopRedirection();
 | 
			
		||||
          },
 | 
			
		||||
          child: Scaffold(
 | 
			
		||||
            appBar: AppBar(
 | 
			
		||||
              elevation: controller.scrolledToTop ? 0 : null,
 | 
			
		||||
              actionsIconTheme: IconThemeData(
 | 
			
		||||
                color: controller.selectedRoomIds.isEmpty
 | 
			
		||||
                    ? null
 | 
			
		||||
                    : Theme.of(context).colorScheme.primary,
 | 
			
		||||
              ),
 | 
			
		||||
              leading: Matrix.of(context).isMultiAccount
 | 
			
		||||
                  ? ClientChooserButton(controller)
 | 
			
		||||
                  : selectMode == SelectMode.normal
 | 
			
		||||
                      ? null
 | 
			
		||||
                      : IconButton(
 | 
			
		||||
                          tooltip: L10n.of(context)!.cancel,
 | 
			
		||||
                          icon: const Icon(Icons.close_outlined),
 | 
			
		||||
                          onPressed: controller.cancelAction,
 | 
			
		||||
                          color: Theme.of(context).colorScheme.primary,
 | 
			
		||||
                        ),
 | 
			
		||||
              centerTitle: false,
 | 
			
		||||
              actions: selectMode == SelectMode.share
 | 
			
		||||
                  ? null
 | 
			
		||||
                  : selectMode == SelectMode.select
 | 
			
		||||
                      ? [
 | 
			
		||||
                          if (controller.spaces.isNotEmpty)
 | 
			
		||||
                            IconButton(
 | 
			
		||||
                              tooltip: L10n.of(context)!.addToSpace,
 | 
			
		||||
                              icon: const Icon(Icons.group_work_outlined),
 | 
			
		||||
                              onPressed: controller.addOrRemoveToSpace,
 | 
			
		||||
                            ),
 | 
			
		||||
                          IconButton(
 | 
			
		||||
                            tooltip: L10n.of(context)!.toggleUnread,
 | 
			
		||||
                            icon: Icon(controller.anySelectedRoomNotMarkedUnread
 | 
			
		||||
                                ? Icons.mark_chat_read_outlined
 | 
			
		||||
                                : Icons.mark_chat_unread_outlined),
 | 
			
		||||
                            onPressed: controller.toggleUnread,
 | 
			
		||||
                          ),
 | 
			
		||||
                          IconButton(
 | 
			
		||||
                            tooltip: L10n.of(context)!.toggleFavorite,
 | 
			
		||||
                            icon: Icon(controller.anySelectedRoomNotFavorite
 | 
			
		||||
                                ? Icons.push_pin_outlined
 | 
			
		||||
                                : Icons.push_pin),
 | 
			
		||||
                            onPressed: controller.toggleFavouriteRoom,
 | 
			
		||||
                          ),
 | 
			
		||||
                          IconButton(
 | 
			
		||||
                            icon: Icon(controller.anySelectedRoomNotMuted
 | 
			
		||||
                                ? Icons.notifications_off_outlined
 | 
			
		||||
                                : Icons.notifications_outlined),
 | 
			
		||||
                            tooltip: L10n.of(context)!.toggleMuted,
 | 
			
		||||
                            onPressed: controller.toggleMuted,
 | 
			
		||||
                          ),
 | 
			
		||||
                          IconButton(
 | 
			
		||||
                            icon: const Icon(Icons.delete_outlined),
 | 
			
		||||
                            tooltip: L10n.of(context)!.archive,
 | 
			
		||||
                            onPressed: controller.archiveAction,
 | 
			
		||||
                          ),
 | 
			
		||||
                        ]
 | 
			
		||||
                      : [
 | 
			
		||||
                          KeyBoardShortcuts(
 | 
			
		||||
                            keysToPress: {
 | 
			
		||||
                              LogicalKeyboardKey.controlLeft,
 | 
			
		||||
                              LogicalKeyboardKey.keyF
 | 
			
		||||
                            },
 | 
			
		||||
                            onKeysPressed: () =>
 | 
			
		||||
                                VRouter.of(context).to('/search'),
 | 
			
		||||
                            helpLabel: L10n.of(context)!.search,
 | 
			
		||||
                            child: IconButton(
 | 
			
		||||
                              icon: const Icon(Icons.search_outlined),
 | 
			
		||||
                              tooltip: L10n.of(context)!.search,
 | 
			
		||||
                              onPressed: () =>
 | 
			
		||||
                                  VRouter.of(context).to('/search'),
 | 
			
		||||
                            ),
 | 
			
		||||
                          ),
 | 
			
		||||
                          if (selectMode == SelectMode.normal)
 | 
			
		||||
                            IconButton(
 | 
			
		||||
                              icon: const Icon(Icons.camera_alt_outlined),
 | 
			
		||||
                              tooltip: L10n.of(context)!.addToStory,
 | 
			
		||||
                              onPressed: () =>
 | 
			
		||||
                                  VRouter.of(context).to('/stories/create'),
 | 
			
		||||
                            ),
 | 
			
		||||
                          PopupMenuButton<PopupMenuAction>(
 | 
			
		||||
                            onSelected: controller.onPopupMenuSelect,
 | 
			
		||||
                            itemBuilder: (_) => [
 | 
			
		||||
                              PopupMenuItem(
 | 
			
		||||
                                value: PopupMenuAction.setStatus,
 | 
			
		||||
                                child: Row(
 | 
			
		||||
                                  mainAxisSize: MainAxisSize.min,
 | 
			
		||||
                                  children: [
 | 
			
		||||
                                    const Icon(Icons.edit_outlined),
 | 
			
		||||
                                    const SizedBox(width: 12),
 | 
			
		||||
                                    Text(L10n.of(context)!.setStatus),
 | 
			
		||||
                                  ],
 | 
			
		||||
                                ),
 | 
			
		||||
                              ),
 | 
			
		||||
                              PopupMenuItem(
 | 
			
		||||
                                value: PopupMenuAction.newGroup,
 | 
			
		||||
                                child: Row(
 | 
			
		||||
                                  mainAxisSize: MainAxisSize.min,
 | 
			
		||||
                                  children: [
 | 
			
		||||
                                    const Icon(Icons.group_add_outlined),
 | 
			
		||||
                                    const SizedBox(width: 12),
 | 
			
		||||
                                    Text(L10n.of(context)!.createNewGroup),
 | 
			
		||||
                                  ],
 | 
			
		||||
                                ),
 | 
			
		||||
                              ),
 | 
			
		||||
                              PopupMenuItem(
 | 
			
		||||
                                value: PopupMenuAction.newSpace,
 | 
			
		||||
                                child: Row(
 | 
			
		||||
                                  mainAxisSize: MainAxisSize.min,
 | 
			
		||||
                                  children: [
 | 
			
		||||
                                    const Icon(Icons.group_work_outlined),
 | 
			
		||||
                                    const SizedBox(width: 12),
 | 
			
		||||
                                    Text(L10n.of(context)!.createNewSpace),
 | 
			
		||||
                                  ],
 | 
			
		||||
                                ),
 | 
			
		||||
                              ),
 | 
			
		||||
                              PopupMenuItem(
 | 
			
		||||
                                value: PopupMenuAction.invite,
 | 
			
		||||
                                child: Row(
 | 
			
		||||
                                  mainAxisSize: MainAxisSize.min,
 | 
			
		||||
                                  children: [
 | 
			
		||||
                                    const Icon(Icons.share_outlined),
 | 
			
		||||
                                    const SizedBox(width: 12),
 | 
			
		||||
                                    Text(L10n.of(context)!.inviteContact),
 | 
			
		||||
                                  ],
 | 
			
		||||
                                ),
 | 
			
		||||
                              ),
 | 
			
		||||
                              PopupMenuItem(
 | 
			
		||||
                                value: PopupMenuAction.archive,
 | 
			
		||||
                                child: Row(
 | 
			
		||||
                                  mainAxisSize: MainAxisSize.min,
 | 
			
		||||
                                  children: [
 | 
			
		||||
                                    const Icon(Icons.archive_outlined),
 | 
			
		||||
                                    const SizedBox(width: 12),
 | 
			
		||||
                                    Text(L10n.of(context)!.archive),
 | 
			
		||||
                                  ],
 | 
			
		||||
                                ),
 | 
			
		||||
                              ),
 | 
			
		||||
                              PopupMenuItem(
 | 
			
		||||
                                value: PopupMenuAction.settings,
 | 
			
		||||
                                child: Row(
 | 
			
		||||
                                  mainAxisSize: MainAxisSize.min,
 | 
			
		||||
                                  children: [
 | 
			
		||||
                                    const Icon(Icons.settings_outlined),
 | 
			
		||||
                                    const SizedBox(width: 12),
 | 
			
		||||
                                    Text(L10n.of(context)!.settings),
 | 
			
		||||
                                  ],
 | 
			
		||||
                                ),
 | 
			
		||||
                              ),
 | 
			
		||||
                            ],
 | 
			
		||||
                          ),
 | 
			
		||||
                        ],
 | 
			
		||||
              title: Text(selectMode == SelectMode.share
 | 
			
		||||
                  ? L10n.of(context)!.share
 | 
			
		||||
                  : selectMode == SelectMode.select
 | 
			
		||||
                      ? controller.selectedRoomIds.length.toString()
 | 
			
		||||
                      : controller.activeSpaceId == null
 | 
			
		||||
                          ? AppConfig.applicationName
 | 
			
		||||
                          : Matrix.of(context)
 | 
			
		||||
                              .client
 | 
			
		||||
                              .getRoomById(controller.activeSpaceId!)!
 | 
			
		||||
                              .displayname),
 | 
			
		||||
            ),
 | 
			
		||||
            appBar: ChatListHeader(controller: controller),
 | 
			
		||||
            body: LayoutBuilder(
 | 
			
		||||
              builder: (context, size) {
 | 
			
		||||
                controller.snappingSheetContainerSize = size;
 | 
			
		||||
 | 
			
		||||
@ -123,12 +123,15 @@ class ClientChooserButton extends StatelessWidget {
 | 
			
		||||
              onKeysPressed: () => _previousAccount(matrix),
 | 
			
		||||
            ),
 | 
			
		||||
            PopupMenuButton<Object>(
 | 
			
		||||
              child: Avatar(
 | 
			
		||||
                mxContent: snapshot.data?.avatarUrl,
 | 
			
		||||
                name: snapshot.data?.displayName ??
 | 
			
		||||
                    matrix.client.userID!.localpart,
 | 
			
		||||
                size: 28,
 | 
			
		||||
                fontSize: 12,
 | 
			
		||||
              child: Material(
 | 
			
		||||
                borderRadius: BorderRadius.zero,
 | 
			
		||||
                child: Avatar(
 | 
			
		||||
                  mxContent: snapshot.data?.avatarUrl,
 | 
			
		||||
                  name: snapshot.data?.displayName ??
 | 
			
		||||
                      matrix.client.userID!.localpart,
 | 
			
		||||
                  size: 28,
 | 
			
		||||
                  fontSize: 12,
 | 
			
		||||
                ),
 | 
			
		||||
              ),
 | 
			
		||||
              onSelected: _clientSelected,
 | 
			
		||||
              itemBuilder: _bundleMenuItems,
 | 
			
		||||
 | 
			
		||||
@ -12,6 +12,8 @@ import 'package:fluffychat/widgets/matrix.dart';
 | 
			
		||||
 | 
			
		||||
const kSpacesBottomBarHeight = 56.0;
 | 
			
		||||
 | 
			
		||||
final GlobalKey _globalKey = GlobalKey();
 | 
			
		||||
 | 
			
		||||
class SpacesBottomBar extends StatelessWidget {
 | 
			
		||||
  final ChatListController controller;
 | 
			
		||||
 | 
			
		||||
@ -37,13 +39,16 @@ class SpacesBottomBar extends StatelessWidget {
 | 
			
		||||
            return SingleChildScrollView(
 | 
			
		||||
              controller: controller.snappingSheetScrollContentController,
 | 
			
		||||
              child: AnimatedBuilder(
 | 
			
		||||
                child: _SpacesBottomNavigation(controller: controller),
 | 
			
		||||
                child: _SpacesBottomNavigation(
 | 
			
		||||
                    key: _globalKey, controller: controller),
 | 
			
		||||
                builder: (context, child) {
 | 
			
		||||
                  if (controller.snappingSheetContainerSize == null) {
 | 
			
		||||
                    return child!;
 | 
			
		||||
                  }
 | 
			
		||||
                  final rawPosition =
 | 
			
		||||
                      controller.snappingSheetController.currentPosition;
 | 
			
		||||
                      controller.snappingSheetController.isAttached
 | 
			
		||||
                          ? controller.snappingSheetController.currentPosition
 | 
			
		||||
                          : 0;
 | 
			
		||||
                  final position = rawPosition /
 | 
			
		||||
                      controller.snappingSheetContainerSize!.maxHeight;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -77,6 +77,14 @@ class AllRoomsSpacesEntry extends SpacesEntry {
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  bool shouldShowStoriesHeader(BuildContext context) => true;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  bool operator ==(Object other) {
 | 
			
		||||
    return runtimeType == other.runtimeType;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  int get hashCode => runtimeType.hashCode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// "Direct Chats" entry.
 | 
			
		||||
@ -101,6 +109,14 @@ class DirectChatsSpacesEntry extends SpacesEntry {
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  bool shouldShowStoriesHeader(BuildContext context) => true;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  bool operator ==(Object other) {
 | 
			
		||||
    return runtimeType == other.runtimeType;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  int get hashCode => runtimeType.hashCode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// "Groups" entry.
 | 
			
		||||
@ -134,6 +150,14 @@ class GroupsSpacesEntry extends SpacesEntry {
 | 
			
		||||
  bool separatedGroup(Room room, List<Room> spaces) {
 | 
			
		||||
    return !spaces.any((space) => _roomInsideSpace(room, space));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  bool operator ==(Object other) {
 | 
			
		||||
    return runtimeType == other.runtimeType;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  int get hashCode => runtimeType.hashCode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// All rooms associated with a specific space.
 | 
			
		||||
@ -179,12 +203,12 @@ class SpaceSpacesEntry extends SpacesEntry {
 | 
			
		||||
  @override
 | 
			
		||||
  bool stillValid(BuildContext context) =>
 | 
			
		||||
      Matrix.of(context).client.getRoomById(space.id) != null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Produces a "rough equivalence" for maintaining the current spaces index.
 | 
			
		||||
bool spacesEntryRoughEquivalence(SpacesEntry a, SpacesEntry b) {
 | 
			
		||||
  if ((a is SpaceSpacesEntry) && (b is SpaceSpacesEntry)) {
 | 
			
		||||
    return a.space.id == b.space.id;
 | 
			
		||||
  @override
 | 
			
		||||
  bool operator ==(Object other) {
 | 
			
		||||
    return hashCode == other.hashCode;
 | 
			
		||||
  }
 | 
			
		||||
  return a == b;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  int get hashCode => space.id.hashCode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -88,12 +88,13 @@ class SignupPageView extends StatelessWidget {
 | 
			
		||||
                    controller.loading ? null : [AutofillHints.username],
 | 
			
		||||
                validator: controller.emailTextFieldValidator,
 | 
			
		||||
                decoration: FluffyThemes.loginTextFieldDecoration(
 | 
			
		||||
                    prefixIcon: const Icon(
 | 
			
		||||
                      Icons.mail_outlined,
 | 
			
		||||
                      color: Colors.black,
 | 
			
		||||
                    ),
 | 
			
		||||
                    hintText: L10n.of(context)!.enterAnEmailAddress,
 | 
			
		||||
                    errorText: controller.error),
 | 
			
		||||
                  prefixIcon: const Icon(
 | 
			
		||||
                    Icons.mail_outlined,
 | 
			
		||||
                    color: Colors.black,
 | 
			
		||||
                  ),
 | 
			
		||||
                  hintText: L10n.of(context)!.enterAnEmailAddress,
 | 
			
		||||
                  errorText: controller.error,
 | 
			
		||||
                ),
 | 
			
		||||
              ),
 | 
			
		||||
            ),
 | 
			
		||||
            Hero(
 | 
			
		||||
 | 
			
		||||
@ -66,6 +66,7 @@ class ContentBanner extends StatelessWidget {
 | 
			
		||||
                        imageUrl: src.toString(),
 | 
			
		||||
                        height: 300,
 | 
			
		||||
                        fit: BoxFit.cover,
 | 
			
		||||
                        errorWidget: (c, m, e) => Icon(defaultIcon, size: 200),
 | 
			
		||||
                      );
 | 
			
		||||
                    })
 | 
			
		||||
                  : Icon(defaultIcon, size: 200),
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user