mirror of
				https://gitlab.com/famedly/fluffychat.git
				synced 2025-11-03 22:07:23 +01:00 
			
		
		
		
	feat: Redesign multiaccounts and spaces
This commit is contained in:
		
							parent
							
								
									055b99bc85
								
							
						
					
					
						commit
						e7a3e78712
					
				@ -63,12 +63,10 @@ class ChatListController extends State<ChatList> {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void setActiveSpaceId(BuildContext context, String spaceId) {
 | 
			
		||||
    Scaffold.of(context).openEndDrawer();
 | 
			
		||||
    setState(() => _activeSpaceId = spaceId);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void editSpace(BuildContext context, String spaceId) async {
 | 
			
		||||
    Scaffold.of(context).openEndDrawer();
 | 
			
		||||
    await Matrix.of(context).client.getRoomById(spaceId).postLoad();
 | 
			
		||||
    VRouter.of(context).toSegments(['spaces', spaceId]);
 | 
			
		||||
  }
 | 
			
		||||
@ -412,6 +410,7 @@ class ChatListController extends State<ChatList> {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void setActiveClient(Client client) {
 | 
			
		||||
    if (client == null) return;
 | 
			
		||||
    VRouter.of(context).to('/rooms');
 | 
			
		||||
    setState(() {
 | 
			
		||||
      _activeSpaceId = null;
 | 
			
		||||
@ -435,7 +434,7 @@ class ChatListController extends State<ChatList> {
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void editBundlesForAccount(String userId) async {
 | 
			
		||||
  void editBundlesForAccount(String userId, String activeBundle) async {
 | 
			
		||||
    final client = Matrix.of(context)
 | 
			
		||||
        .widget
 | 
			
		||||
        .clients[Matrix.of(context).getClientIndexByMatrixId(userId)];
 | 
			
		||||
@ -447,7 +446,7 @@ class ChatListController extends State<ChatList> {
 | 
			
		||||
          key: EditBundleAction.addToBundle,
 | 
			
		||||
          label: L10n.of(context).addToBundle,
 | 
			
		||||
        ),
 | 
			
		||||
        if (Matrix.of(context).activeBundle != null)
 | 
			
		||||
        if (activeBundle != client.userID)
 | 
			
		||||
          AlertDialogAction(
 | 
			
		||||
            key: EditBundleAction.removeFromBundle,
 | 
			
		||||
            label: L10n.of(context).removeFromBundle,
 | 
			
		||||
@ -463,7 +462,7 @@ class ChatListController extends State<ChatList> {
 | 
			
		||||
            textFields: [
 | 
			
		||||
              DialogTextField(hintText: L10n.of(context).bundleName)
 | 
			
		||||
            ]);
 | 
			
		||||
        if (bundle.isEmpty && bundle.single.isEmpty) return;
 | 
			
		||||
        if (bundle == null || bundle.isEmpty || bundle.single.isEmpty) return;
 | 
			
		||||
        await showFutureLoadingDialog(
 | 
			
		||||
          context: context,
 | 
			
		||||
          future: () => client.setAccountBundle(bundle.single),
 | 
			
		||||
@ -472,8 +471,7 @@ class ChatListController extends State<ChatList> {
 | 
			
		||||
      case EditBundleAction.removeFromBundle:
 | 
			
		||||
        await showFutureLoadingDialog(
 | 
			
		||||
          context: context,
 | 
			
		||||
          future: () =>
 | 
			
		||||
              client.removeFromAccountBundle(Matrix.of(context).activeBundle),
 | 
			
		||||
          future: () => client.removeFromAccountBundle(activeBundle),
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -1,22 +1,18 @@
 | 
			
		||||
import 'dart:math';
 | 
			
		||||
 | 
			
		||||
import 'package:flutter/cupertino.dart';
 | 
			
		||||
import 'package:flutter/foundation.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter/widgets.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:async/async.dart';
 | 
			
		||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
 | 
			
		||||
import 'package:matrix/matrix.dart';
 | 
			
		||||
import 'package:vrouter/vrouter.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:fluffychat/config/app_config.dart';
 | 
			
		||||
import 'package:fluffychat/config/themes.dart';
 | 
			
		||||
import 'package:fluffychat/pages/chat_list/chat_list.dart';
 | 
			
		||||
import 'package:fluffychat/pages/chat_list/chat_list_item.dart';
 | 
			
		||||
import 'package:fluffychat/widgets/avatar.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 '../../utils/account_bundles.dart';
 | 
			
		||||
import '../../utils/stream_extension.dart';
 | 
			
		||||
import '../../widgets/matrix.dart';
 | 
			
		||||
 | 
			
		||||
@ -25,59 +21,6 @@ class ChatListView extends StatelessWidget {
 | 
			
		||||
 | 
			
		||||
  const ChatListView(this.controller, {Key key}) : super(key: key);
 | 
			
		||||
 | 
			
		||||
  List<BottomNavigationBarItem> getBottomBarItems(BuildContext context) {
 | 
			
		||||
    final displayClients = Matrix.of(context).currentBundle;
 | 
			
		||||
    if (displayClients.isEmpty) {
 | 
			
		||||
      displayClients.addAll(Matrix.of(context).widget.clients);
 | 
			
		||||
      controller.resetActiveBundle();
 | 
			
		||||
    }
 | 
			
		||||
    final items = displayClients.map((client) {
 | 
			
		||||
      return BottomNavigationBarItem(
 | 
			
		||||
        label: client.userID,
 | 
			
		||||
        icon: FutureBuilder<Profile>(
 | 
			
		||||
            future: client.ownProfile,
 | 
			
		||||
            builder: (context, snapshot) {
 | 
			
		||||
              return InkWell(
 | 
			
		||||
                borderRadius: BorderRadius.circular(32),
 | 
			
		||||
                onTap: () => controller.setActiveClient(client),
 | 
			
		||||
                onLongPress: () =>
 | 
			
		||||
                    controller.editBundlesForAccount(client.userID),
 | 
			
		||||
                child: Avatar(
 | 
			
		||||
                  snapshot.data?.avatarUrl,
 | 
			
		||||
                  snapshot.data?.displayName ?? client.userID.localpart,
 | 
			
		||||
                  size: 32,
 | 
			
		||||
                ),
 | 
			
		||||
              );
 | 
			
		||||
            }),
 | 
			
		||||
      );
 | 
			
		||||
    }).toList();
 | 
			
		||||
 | 
			
		||||
    if (controller.displayBundles && false) {
 | 
			
		||||
      items.insert(
 | 
			
		||||
          0,
 | 
			
		||||
          BottomNavigationBarItem(
 | 
			
		||||
              label: 'Bundles',
 | 
			
		||||
              icon: PopupMenuButton(
 | 
			
		||||
                icon: Icon(
 | 
			
		||||
                  Icons.menu,
 | 
			
		||||
                  color: Theme.of(context).textTheme.bodyText1.color,
 | 
			
		||||
                ),
 | 
			
		||||
                onSelected: controller.setActiveBundle,
 | 
			
		||||
                itemBuilder: (context) => Matrix.of(context)
 | 
			
		||||
                    .accountBundles
 | 
			
		||||
                    .keys
 | 
			
		||||
                    .map(
 | 
			
		||||
                      (bundle) => PopupMenuItem(
 | 
			
		||||
                        value: bundle,
 | 
			
		||||
                        child: Text(bundle),
 | 
			
		||||
                      ),
 | 
			
		||||
                    )
 | 
			
		||||
                    .toList(),
 | 
			
		||||
              )));
 | 
			
		||||
    }
 | 
			
		||||
    return items;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    return StreamBuilder<Object>(
 | 
			
		||||
@ -99,13 +42,9 @@ class ChatListView extends StatelessWidget {
 | 
			
		||||
                      : Theme.of(context).colorScheme.primary,
 | 
			
		||||
                ),
 | 
			
		||||
                leading: selectMode == SelectMode.normal
 | 
			
		||||
                    ? controller.spaces.isEmpty
 | 
			
		||||
                        ? null
 | 
			
		||||
                        : Builder(
 | 
			
		||||
                            builder: (context) => IconButton(
 | 
			
		||||
                                  icon: const Icon(Icons.group_work_outlined),
 | 
			
		||||
                                  onPressed: Scaffold.of(context).openDrawer,
 | 
			
		||||
                                ))
 | 
			
		||||
                    ? Matrix.of(context).isMultiAccount
 | 
			
		||||
                        ? ClientChooserButton(controller)
 | 
			
		||||
                        : null
 | 
			
		||||
                    : IconButton(
 | 
			
		||||
                        tooltip: L10n.of(context).cancel,
 | 
			
		||||
                        icon: const Icon(Icons.close_outlined),
 | 
			
		||||
@ -113,7 +52,6 @@ class ChatListView extends StatelessWidget {
 | 
			
		||||
                        color: Theme.of(context).colorScheme.primary,
 | 
			
		||||
                      ),
 | 
			
		||||
                centerTitle: false,
 | 
			
		||||
                titleSpacing: controller.spaces.isEmpty ? null : 0,
 | 
			
		||||
                actions: selectMode == SelectMode.share
 | 
			
		||||
                    ? null
 | 
			
		||||
                    : selectMode == SelectMode.select
 | 
			
		||||
@ -275,139 +213,9 @@ class ChatListView extends StatelessWidget {
 | 
			
		||||
                          child: const Icon(CupertinoIcons.chat_bubble),
 | 
			
		||||
                        )
 | 
			
		||||
                  : null,
 | 
			
		||||
              bottomNavigationBar: Matrix.of(context).isMultiAccount
 | 
			
		||||
                  ? StreamBuilder(
 | 
			
		||||
                      stream: StreamGroup.merge(Matrix.of(context)
 | 
			
		||||
                          .widget
 | 
			
		||||
                          .clients
 | 
			
		||||
                          .map((client) => client.onSync.stream.where((s) =>
 | 
			
		||||
                              s.accountData != null &&
 | 
			
		||||
                              s.accountData
 | 
			
		||||
                                  .any((e) => e.type == accountBundlesType)))),
 | 
			
		||||
                      builder: (context, _) => Material(
 | 
			
		||||
                        color: Theme.of(context)
 | 
			
		||||
                            .bottomNavigationBarTheme
 | 
			
		||||
                            .backgroundColor,
 | 
			
		||||
                        child: Column(
 | 
			
		||||
                          mainAxisSize: MainAxisSize.min,
 | 
			
		||||
                          children: [
 | 
			
		||||
                            const Divider(height: 1),
 | 
			
		||||
                            Builder(builder: (context) {
 | 
			
		||||
                              final items = getBottomBarItems(context);
 | 
			
		||||
                              if (items.length == 1) {
 | 
			
		||||
                                return Padding(
 | 
			
		||||
                                  padding: const EdgeInsets.all(7.0),
 | 
			
		||||
                                  child: Column(
 | 
			
		||||
                                    mainAxisSize: MainAxisSize.min,
 | 
			
		||||
                                    children: [
 | 
			
		||||
                                      items.single.icon,
 | 
			
		||||
                                      Text(items.single.label),
 | 
			
		||||
                                    ],
 | 
			
		||||
                                  ),
 | 
			
		||||
                                );
 | 
			
		||||
                              }
 | 
			
		||||
                              return SingleChildScrollView(
 | 
			
		||||
                                scrollDirection: Axis.horizontal,
 | 
			
		||||
                                child: SizedBox(
 | 
			
		||||
                                  width: max(
 | 
			
		||||
                                    FluffyThemes.isColumnMode(context)
 | 
			
		||||
                                        ? FluffyThemes.columnWidth
 | 
			
		||||
                                        : MediaQuery.of(context).size.width,
 | 
			
		||||
                                    Matrix.of(context).widget.clients.length *
 | 
			
		||||
                                        84.0,
 | 
			
		||||
                                  ),
 | 
			
		||||
                                  child: BottomNavigationBar(
 | 
			
		||||
                                    elevation: 0,
 | 
			
		||||
                                    onTap: (i) => controller.setActiveClient(
 | 
			
		||||
                                        Matrix.of(context).currentBundle[i]),
 | 
			
		||||
                                    currentIndex: Matrix.of(context)
 | 
			
		||||
                                        .currentBundle
 | 
			
		||||
                                        .indexWhere(
 | 
			
		||||
                                          (client) =>
 | 
			
		||||
                                              client ==
 | 
			
		||||
                                              Matrix.of(context).client,
 | 
			
		||||
                                        ),
 | 
			
		||||
                                    showUnselectedLabels: false,
 | 
			
		||||
                                    showSelectedLabels: true,
 | 
			
		||||
                                    type: BottomNavigationBarType.shifting,
 | 
			
		||||
                                    selectedItemColor:
 | 
			
		||||
                                        Theme.of(context).colorScheme.secondary,
 | 
			
		||||
                                    items: items,
 | 
			
		||||
                                  ),
 | 
			
		||||
                                ),
 | 
			
		||||
                              );
 | 
			
		||||
                            }),
 | 
			
		||||
                            if (controller.displayBundles)
 | 
			
		||||
                              Padding(
 | 
			
		||||
                                padding: const EdgeInsets.symmetric(
 | 
			
		||||
                                  vertical: 4.0,
 | 
			
		||||
                                  horizontal: 12,
 | 
			
		||||
                                ),
 | 
			
		||||
                                child: SizedBox(
 | 
			
		||||
                                  width: double.infinity,
 | 
			
		||||
                                  child: CupertinoSlidingSegmentedControl(
 | 
			
		||||
                                    groupValue: controller.secureActiveBundle,
 | 
			
		||||
                                    onValueChanged: controller.setActiveBundle,
 | 
			
		||||
                                    children: Map.fromEntries(Matrix.of(context)
 | 
			
		||||
                                        .accountBundles
 | 
			
		||||
                                        .keys
 | 
			
		||||
                                        .map((bundle) =>
 | 
			
		||||
                                            MapEntry(bundle, Text(bundle)))),
 | 
			
		||||
                                  ),
 | 
			
		||||
                                ),
 | 
			
		||||
                              ),
 | 
			
		||||
                          ],
 | 
			
		||||
                        ),
 | 
			
		||||
                      ),
 | 
			
		||||
                    )
 | 
			
		||||
                  : null,
 | 
			
		||||
              drawer: controller.spaces.isEmpty
 | 
			
		||||
              bottomNavigationBar: controller.spaces.isEmpty
 | 
			
		||||
                  ? null
 | 
			
		||||
                  : Drawer(
 | 
			
		||||
                      child: SafeArea(
 | 
			
		||||
                        child: ListView.builder(
 | 
			
		||||
                          itemCount: controller.spaces.length + 1,
 | 
			
		||||
                          itemBuilder: (context, i) {
 | 
			
		||||
                            if (i == 0) {
 | 
			
		||||
                              return ListTile(
 | 
			
		||||
                                selected: controller.activeSpaceId == null,
 | 
			
		||||
                                selectedTileColor:
 | 
			
		||||
                                    Theme.of(context).secondaryHeaderColor,
 | 
			
		||||
                                leading: CircleAvatar(
 | 
			
		||||
                                  foregroundColor: Colors.white,
 | 
			
		||||
                                  backgroundColor:
 | 
			
		||||
                                      Theme.of(context).primaryColor,
 | 
			
		||||
                                  radius: Avatar.defaultSize / 2,
 | 
			
		||||
                                  child: const Icon(Icons.home_outlined),
 | 
			
		||||
                                ),
 | 
			
		||||
                                title: Text(L10n.of(context).allChats),
 | 
			
		||||
                                onTap: () =>
 | 
			
		||||
                                    controller.setActiveSpaceId(context, null),
 | 
			
		||||
                              );
 | 
			
		||||
                            }
 | 
			
		||||
                            final space = controller.spaces[i - 1];
 | 
			
		||||
                            return ListTile(
 | 
			
		||||
                              selected: controller.activeSpaceId == space.id,
 | 
			
		||||
                              selectedTileColor:
 | 
			
		||||
                                  Theme.of(context).secondaryHeaderColor,
 | 
			
		||||
                              leading: Avatar(space.avatar, space.displayname),
 | 
			
		||||
                              title: Text(space.displayname, maxLines: 1),
 | 
			
		||||
                              subtitle: Text(L10n.of(context).countParticipants(
 | 
			
		||||
                                  (space.summary.mJoinedMemberCount +
 | 
			
		||||
                                          space.summary.mInvitedMemberCount)
 | 
			
		||||
                                      .toString())),
 | 
			
		||||
                              onTap: () => controller.setActiveSpaceId(
 | 
			
		||||
                                  context, space.id),
 | 
			
		||||
                              trailing: IconButton(
 | 
			
		||||
                                icon: const Icon(Icons.edit_outlined),
 | 
			
		||||
                                onPressed: () =>
 | 
			
		||||
                                    controller.editSpace(context, space.id),
 | 
			
		||||
                              ),
 | 
			
		||||
                            );
 | 
			
		||||
                          },
 | 
			
		||||
                        ),
 | 
			
		||||
                      ),
 | 
			
		||||
                    ),
 | 
			
		||||
                  : SpacesBottomBar(controller),
 | 
			
		||||
            ),
 | 
			
		||||
          );
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										104
									
								
								lib/pages/chat_list/client_chooser_button.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								lib/pages/chat_list/client_chooser_button.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,104 @@
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:matrix/matrix.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:fluffychat/widgets/avatar.dart';
 | 
			
		||||
import 'package:fluffychat/widgets/matrix.dart';
 | 
			
		||||
import 'chat_list.dart';
 | 
			
		||||
 | 
			
		||||
class ClientChooserButton extends StatelessWidget {
 | 
			
		||||
  final ChatListController controller;
 | 
			
		||||
  const ClientChooserButton(this.controller, {Key key}) : super(key: key);
 | 
			
		||||
 | 
			
		||||
  List<PopupMenuEntry<Object>> _bundleMenuItems(BuildContext context) {
 | 
			
		||||
    final matrix = Matrix.of(context);
 | 
			
		||||
    final bundles = matrix.accountBundles.keys.toList()
 | 
			
		||||
      ..sort((a, b) => a.isValidMatrixId == b.isValidMatrixId
 | 
			
		||||
          ? 0
 | 
			
		||||
          : a.isValidMatrixId && !b.isValidMatrixId
 | 
			
		||||
              ? -1
 | 
			
		||||
              : 1);
 | 
			
		||||
    return <PopupMenuEntry<Object>>[
 | 
			
		||||
      for (final bundle in bundles) ...[
 | 
			
		||||
        if (matrix.accountBundles[bundle].length != 1 ||
 | 
			
		||||
            matrix.accountBundles[bundle].single.userID != bundle)
 | 
			
		||||
          PopupMenuItem(
 | 
			
		||||
            value: null,
 | 
			
		||||
            child: Column(
 | 
			
		||||
              crossAxisAlignment: CrossAxisAlignment.start,
 | 
			
		||||
              mainAxisSize: MainAxisSize.min,
 | 
			
		||||
              children: [
 | 
			
		||||
                Text(
 | 
			
		||||
                  bundle,
 | 
			
		||||
                  style: TextStyle(
 | 
			
		||||
                    color: Theme.of(context).textTheme.subtitle1.color,
 | 
			
		||||
                    fontSize: 14,
 | 
			
		||||
                  ),
 | 
			
		||||
                ),
 | 
			
		||||
                const Divider(height: 1),
 | 
			
		||||
              ],
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
        ...matrix.accountBundles[bundle]
 | 
			
		||||
            .map(
 | 
			
		||||
              (client) => PopupMenuItem(
 | 
			
		||||
                value: client,
 | 
			
		||||
                child: FutureBuilder<Profile>(
 | 
			
		||||
                  future: client.ownProfile,
 | 
			
		||||
                  builder: (context, snapshot) => Row(
 | 
			
		||||
                    children: [
 | 
			
		||||
                      Avatar(
 | 
			
		||||
                        snapshot.data?.avatarUrl,
 | 
			
		||||
                        snapshot.data?.displayName ?? client.userID.localpart,
 | 
			
		||||
                        size: 28,
 | 
			
		||||
                        fontSize: 12,
 | 
			
		||||
                      ),
 | 
			
		||||
                      const SizedBox(width: 12),
 | 
			
		||||
                      Expanded(
 | 
			
		||||
                        child: Text(
 | 
			
		||||
                          snapshot.data?.displayName ?? client.userID.localpart,
 | 
			
		||||
                          overflow: TextOverflow.ellipsis,
 | 
			
		||||
                        ),
 | 
			
		||||
                      ),
 | 
			
		||||
                      const SizedBox(width: 12),
 | 
			
		||||
                      IconButton(
 | 
			
		||||
                        icon: const Icon(Icons.edit_outlined),
 | 
			
		||||
                        onPressed: () => controller.editBundlesForAccount(
 | 
			
		||||
                            client.userID, bundle),
 | 
			
		||||
                      ),
 | 
			
		||||
                    ],
 | 
			
		||||
                  ),
 | 
			
		||||
                ),
 | 
			
		||||
              ),
 | 
			
		||||
            )
 | 
			
		||||
            .toList(),
 | 
			
		||||
      ],
 | 
			
		||||
    ];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    final matrix = Matrix.of(context);
 | 
			
		||||
    return Center(
 | 
			
		||||
      child: FutureBuilder<Profile>(
 | 
			
		||||
        future: matrix.client.ownProfile,
 | 
			
		||||
        builder: (context, snapshot) => PopupMenuButton<Object>(
 | 
			
		||||
          child: Avatar(
 | 
			
		||||
            snapshot.data?.avatarUrl,
 | 
			
		||||
            snapshot.data?.displayName ?? matrix.client.userID.localpart,
 | 
			
		||||
            size: 28,
 | 
			
		||||
            fontSize: 12,
 | 
			
		||||
          ),
 | 
			
		||||
          onSelected: (Object object) {
 | 
			
		||||
            if (object is Client) {
 | 
			
		||||
              controller.setActiveClient(object);
 | 
			
		||||
            } else if (object is String) {
 | 
			
		||||
              controller.setActiveBundle(object);
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          itemBuilder: _bundleMenuItems,
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										56
									
								
								lib/pages/chat_list/spaces_bottom_bar.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								lib/pages/chat_list/spaces_bottom_bar.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,56 @@
 | 
			
		||||
import 'package:flutter/cupertino.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:fluffychat/pages/chat_list/chat_list.dart';
 | 
			
		||||
import 'package:fluffychat/widgets/avatar.dart';
 | 
			
		||||
 | 
			
		||||
class SpacesBottomBar extends StatelessWidget {
 | 
			
		||||
  final ChatListController controller;
 | 
			
		||||
  const SpacesBottomBar(this.controller, {Key key}) : super(key: key);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    final currentIndex = controller.activeSpaceId == null
 | 
			
		||||
        ? 0
 | 
			
		||||
        : controller.spaces
 | 
			
		||||
                .indexWhere((space) => controller.activeSpaceId == space.id) +
 | 
			
		||||
            1;
 | 
			
		||||
    return BottomNavigationBar(
 | 
			
		||||
      currentIndex: currentIndex,
 | 
			
		||||
      backgroundColor: Theme.of(context).scaffoldBackgroundColor,
 | 
			
		||||
      landscapeLayout: BottomNavigationBarLandscapeLayout.spread,
 | 
			
		||||
      onTap: (i) => controller.setActiveSpaceId(
 | 
			
		||||
        context,
 | 
			
		||||
        i == 0 ? null : controller.spaces[i - 1].id,
 | 
			
		||||
      ),
 | 
			
		||||
      items: [
 | 
			
		||||
        BottomNavigationBarItem(
 | 
			
		||||
          backgroundColor: Theme.of(context).scaffoldBackgroundColor,
 | 
			
		||||
          icon: const Icon(CupertinoIcons.chat_bubble_2),
 | 
			
		||||
          label: L10n.of(context).allChats,
 | 
			
		||||
        ),
 | 
			
		||||
        ...controller.spaces
 | 
			
		||||
            .map((space) => BottomNavigationBarItem(
 | 
			
		||||
                  icon: InkWell(
 | 
			
		||||
                    borderRadius: BorderRadius.circular(28),
 | 
			
		||||
                    onTap: () => controller.setActiveSpaceId(
 | 
			
		||||
                      context,
 | 
			
		||||
                      space.id,
 | 
			
		||||
                    ),
 | 
			
		||||
                    onLongPress: () => controller.editSpace(context, space.id),
 | 
			
		||||
                    child: Avatar(
 | 
			
		||||
                      space.avatar,
 | 
			
		||||
                      space.displayname,
 | 
			
		||||
                      size: 24,
 | 
			
		||||
                      fontSize: 12,
 | 
			
		||||
                    ),
 | 
			
		||||
                  ),
 | 
			
		||||
                  label: space.displayname,
 | 
			
		||||
                ))
 | 
			
		||||
            .toList(),
 | 
			
		||||
      ],
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,6 +1,5 @@
 | 
			
		||||
import 'dart:async';
 | 
			
		||||
 | 
			
		||||
import 'package:fluffychat/widgets/public_room_bottom_sheet.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:adaptive_dialog/adaptive_dialog.dart';
 | 
			
		||||
@ -9,6 +8,7 @@ import 'package:matrix/matrix.dart';
 | 
			
		||||
import 'package:vrouter/vrouter.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:fluffychat/widgets/matrix.dart';
 | 
			
		||||
import 'package:fluffychat/widgets/public_room_bottom_sheet.dart';
 | 
			
		||||
import 'search_view.dart';
 | 
			
		||||
 | 
			
		||||
class Search extends StatefulWidget {
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
import 'package:fluffychat/widgets/public_room_bottom_sheet.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:adaptive_dialog/adaptive_dialog.dart';
 | 
			
		||||
@ -12,6 +11,7 @@ import 'package:vrouter/vrouter.dart';
 | 
			
		||||
import 'package:fluffychat/config/app_config.dart';
 | 
			
		||||
import 'package:fluffychat/widgets/matrix.dart';
 | 
			
		||||
import 'package:fluffychat/widgets/profile_bottom_sheet.dart';
 | 
			
		||||
import 'package:fluffychat/widgets/public_room_bottom_sheet.dart';
 | 
			
		||||
import 'platform_infos.dart';
 | 
			
		||||
 | 
			
		||||
class UrlLauncher {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user