chore: Follow up add chat or subspace UX
This commit is contained in:
parent
0760acaa40
commit
a500a91b6b
3 changed files with 145 additions and 109 deletions
|
|
@ -105,107 +105,18 @@ class ChatListController extends State<ChatList>
|
||||||
String? _activeSpaceId;
|
String? _activeSpaceId;
|
||||||
String? get activeSpaceId => _activeSpaceId;
|
String? get activeSpaceId => _activeSpaceId;
|
||||||
|
|
||||||
void setActiveSpace(String spaceId) => setState(() {
|
void setActiveSpace(String spaceId) async {
|
||||||
_activeSpaceId = spaceId;
|
await Matrix.of(context).client.getRoomById(spaceId)!.postLoad();
|
||||||
});
|
|
||||||
|
setState(() {
|
||||||
|
_activeSpaceId = spaceId;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void clearActiveSpace() => setState(() {
|
void clearActiveSpace() => setState(() {
|
||||||
_activeSpaceId = null;
|
_activeSpaceId = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
void addChatAction() async {
|
|
||||||
if (activeSpaceId == null) {
|
|
||||||
context.go('/rooms/newprivatechat');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final roomType = await showConfirmationDialog(
|
|
||||||
context: context,
|
|
||||||
title: L10n.of(context)!.addChatOrSubSpace,
|
|
||||||
actions: [
|
|
||||||
AlertDialogAction(
|
|
||||||
key: AddRoomType.subspace,
|
|
||||||
label: L10n.of(context)!.createNewSpace,
|
|
||||||
),
|
|
||||||
AlertDialogAction(
|
|
||||||
key: AddRoomType.chat,
|
|
||||||
label: L10n.of(context)!.createGroup,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
if (roomType == null) return;
|
|
||||||
|
|
||||||
final names = await showTextInputDialog(
|
|
||||||
context: context,
|
|
||||||
title: roomType == AddRoomType.subspace
|
|
||||||
? L10n.of(context)!.createNewSpace
|
|
||||||
: L10n.of(context)!.createGroup,
|
|
||||||
textFields: [
|
|
||||||
DialogTextField(
|
|
||||||
hintText: roomType == AddRoomType.subspace
|
|
||||||
? L10n.of(context)!.spaceName
|
|
||||||
: L10n.of(context)!.groupName,
|
|
||||||
minLines: 1,
|
|
||||||
maxLines: 1,
|
|
||||||
maxLength: 64,
|
|
||||||
validator: (text) {
|
|
||||||
if (text == null || text.isEmpty) {
|
|
||||||
return L10n.of(context)!.pleaseChoose;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
DialogTextField(
|
|
||||||
hintText: L10n.of(context)!.chatDescription,
|
|
||||||
minLines: 4,
|
|
||||||
maxLines: 8,
|
|
||||||
maxLength: 255,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
okLabel: L10n.of(context)!.create,
|
|
||||||
cancelLabel: L10n.of(context)!.cancel,
|
|
||||||
);
|
|
||||||
if (names == null) return;
|
|
||||||
final client = Matrix.of(context).client;
|
|
||||||
final result = await showFutureLoadingDialog(
|
|
||||||
context: context,
|
|
||||||
future: () async {
|
|
||||||
late final String roomId;
|
|
||||||
final activeSpace = client.getRoomById(activeSpaceId!)!;
|
|
||||||
await activeSpace.postLoad();
|
|
||||||
|
|
||||||
if (roomType == AddRoomType.subspace) {
|
|
||||||
roomId = await client.createSpace(
|
|
||||||
name: names.first,
|
|
||||||
topic: names.last.isEmpty ? null : names.last,
|
|
||||||
visibility: activeSpace.joinRules == JoinRules.public
|
|
||||||
? sdk.Visibility.public
|
|
||||||
: sdk.Visibility.private,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
roomId = await client.createGroupChat(
|
|
||||||
groupName: names.first,
|
|
||||||
preset: activeSpace.joinRules == JoinRules.public
|
|
||||||
? CreateRoomPreset.publicChat
|
|
||||||
: CreateRoomPreset.privateChat,
|
|
||||||
visibility: activeSpace.joinRules == JoinRules.public
|
|
||||||
? sdk.Visibility.public
|
|
||||||
: sdk.Visibility.private,
|
|
||||||
initialState: names.length > 1 && names.last.isNotEmpty
|
|
||||||
? [
|
|
||||||
sdk.StateEvent(
|
|
||||||
type: sdk.EventTypes.RoomTopic,
|
|
||||||
content: {'topic': names.last},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
: null,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
await activeSpace.setSpaceChild(roomId);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
if (result.error != null) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void onChatTap(Room room) async {
|
void onChatTap(Room room) async {
|
||||||
if (room.membership == Membership.invite) {
|
if (room.membership == Membership.invite) {
|
||||||
final inviterId =
|
final inviterId =
|
||||||
|
|
@ -1004,8 +915,6 @@ enum InviteActions {
|
||||||
block,
|
block,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum AddRoomType { chat, subspace }
|
|
||||||
|
|
||||||
enum ChatContextAction {
|
enum ChatContextAction {
|
||||||
open,
|
open,
|
||||||
goToSpace,
|
goToSpace,
|
||||||
|
|
|
||||||
|
|
@ -146,9 +146,11 @@ class ChatListView extends StatelessWidget {
|
||||||
onKeysPressed: () => context.go('/rooms/newprivatechat'),
|
onKeysPressed: () => context.go('/rooms/newprivatechat'),
|
||||||
helpLabel: L10n.of(context)!.newChat,
|
helpLabel: L10n.of(context)!.newChat,
|
||||||
child: selectMode == SelectMode.normal &&
|
child: selectMode == SelectMode.normal &&
|
||||||
!controller.isSearchMode
|
!controller.isSearchMode &&
|
||||||
|
controller.activeSpaceId == null
|
||||||
? FloatingActionButton.extended(
|
? FloatingActionButton.extended(
|
||||||
onPressed: controller.addChatAction,
|
onPressed: () =>
|
||||||
|
context.go('/rooms/newprivatechat'),
|
||||||
icon: const Icon(Icons.add_outlined),
|
icon: const Icon(Icons.add_outlined),
|
||||||
label: Text(
|
label: Text(
|
||||||
L10n.of(context)!.chat,
|
L10n.of(context)!.chat,
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import 'package:collection/collection.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||||
import 'package:future_loading_dialog/future_loading_dialog.dart';
|
import 'package:future_loading_dialog/future_loading_dialog.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:matrix/matrix.dart' as sdk;
|
||||||
import 'package:matrix/matrix.dart';
|
import 'package:matrix/matrix.dart';
|
||||||
|
|
||||||
import 'package:fluffychat/config/app_config.dart';
|
import 'package:fluffychat/config/app_config.dart';
|
||||||
|
|
@ -15,6 +16,8 @@ import 'package:fluffychat/utils/stream_extension.dart';
|
||||||
import 'package:fluffychat/widgets/avatar.dart';
|
import 'package:fluffychat/widgets/avatar.dart';
|
||||||
import 'package:fluffychat/widgets/matrix.dart';
|
import 'package:fluffychat/widgets/matrix.dart';
|
||||||
|
|
||||||
|
enum AddRoomType { chat, subspace }
|
||||||
|
|
||||||
class SpaceView extends StatefulWidget {
|
class SpaceView extends StatefulWidget {
|
||||||
final String spaceId;
|
final String spaceId;
|
||||||
final void Function() onBack;
|
final void Function() onBack;
|
||||||
|
|
@ -160,6 +163,95 @@ class _SpaceViewState extends State<SpaceView> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _addChatOrSubspace() async {
|
||||||
|
final roomType = await showConfirmationDialog(
|
||||||
|
context: context,
|
||||||
|
title: L10n.of(context)!.addChatOrSubSpace,
|
||||||
|
actions: [
|
||||||
|
AlertDialogAction(
|
||||||
|
key: AddRoomType.subspace,
|
||||||
|
label: L10n.of(context)!.createNewSpace,
|
||||||
|
),
|
||||||
|
AlertDialogAction(
|
||||||
|
key: AddRoomType.chat,
|
||||||
|
label: L10n.of(context)!.createGroup,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
if (roomType == null) return;
|
||||||
|
|
||||||
|
final names = await showTextInputDialog(
|
||||||
|
context: context,
|
||||||
|
title: roomType == AddRoomType.subspace
|
||||||
|
? L10n.of(context)!.createNewSpace
|
||||||
|
: L10n.of(context)!.createGroup,
|
||||||
|
textFields: [
|
||||||
|
DialogTextField(
|
||||||
|
hintText: roomType == AddRoomType.subspace
|
||||||
|
? L10n.of(context)!.spaceName
|
||||||
|
: L10n.of(context)!.groupName,
|
||||||
|
minLines: 1,
|
||||||
|
maxLines: 1,
|
||||||
|
maxLength: 64,
|
||||||
|
validator: (text) {
|
||||||
|
if (text == null || text.isEmpty) {
|
||||||
|
return L10n.of(context)!.pleaseChoose;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
DialogTextField(
|
||||||
|
hintText: L10n.of(context)!.chatDescription,
|
||||||
|
minLines: 4,
|
||||||
|
maxLines: 8,
|
||||||
|
maxLength: 255,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
okLabel: L10n.of(context)!.create,
|
||||||
|
cancelLabel: L10n.of(context)!.cancel,
|
||||||
|
);
|
||||||
|
if (names == null) return;
|
||||||
|
final client = Matrix.of(context).client;
|
||||||
|
final result = await showFutureLoadingDialog(
|
||||||
|
context: context,
|
||||||
|
future: () async {
|
||||||
|
late final String roomId;
|
||||||
|
final activeSpace = client.getRoomById(widget.spaceId)!;
|
||||||
|
await activeSpace.postLoad();
|
||||||
|
|
||||||
|
if (roomType == AddRoomType.subspace) {
|
||||||
|
roomId = await client.createSpace(
|
||||||
|
name: names.first,
|
||||||
|
topic: names.last.isEmpty ? null : names.last,
|
||||||
|
visibility: activeSpace.joinRules == JoinRules.public
|
||||||
|
? sdk.Visibility.public
|
||||||
|
: sdk.Visibility.private,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
roomId = await client.createGroupChat(
|
||||||
|
groupName: names.first,
|
||||||
|
preset: activeSpace.joinRules == JoinRules.public
|
||||||
|
? CreateRoomPreset.publicChat
|
||||||
|
: CreateRoomPreset.privateChat,
|
||||||
|
visibility: activeSpace.joinRules == JoinRules.public
|
||||||
|
? sdk.Visibility.public
|
||||||
|
: sdk.Visibility.private,
|
||||||
|
initialState: names.length > 1 && names.last.isNotEmpty
|
||||||
|
? [
|
||||||
|
StateEvent(
|
||||||
|
type: EventTypes.RoomTopic,
|
||||||
|
content: {'topic': names.last},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await activeSpace.setSpaceChild(roomId);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (result.error != null) return;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final room = Matrix.of(context).client.getRoomById(widget.spaceId);
|
final room = Matrix.of(context).client.getRoomById(widget.spaceId);
|
||||||
|
|
@ -352,22 +444,55 @@ class _SpaceViewState extends State<SpaceView> {
|
||||||
itemCount: joinedRooms.length + 1,
|
itemCount: joinedRooms.length + 1,
|
||||||
itemBuilder: (context, i) {
|
itemBuilder: (context, i) {
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
return SearchTitle(
|
return Column(
|
||||||
title: L10n.of(context)!.joinedChats,
|
mainAxisSize: MainAxisSize.min,
|
||||||
icon: const Icon(Icons.chat_outlined),
|
children: [
|
||||||
|
if (room.canChangeStateEvent(
|
||||||
|
EventTypes.SpaceChild,
|
||||||
|
) &&
|
||||||
|
filter.isEmpty) ...[
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 8,
|
||||||
|
vertical: 1,
|
||||||
|
),
|
||||||
|
child: Material(
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
AppConfig.borderRadius,
|
||||||
|
),
|
||||||
|
clipBehavior: Clip.hardEdge,
|
||||||
|
child: ListTile(
|
||||||
|
onTap: _addChatOrSubspace,
|
||||||
|
leading: const CircleAvatar(
|
||||||
|
radius: Avatar.defaultSize / 2,
|
||||||
|
child: Icon(Icons.add_outlined),
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
L10n.of(context)!.addChatOrSubSpace,
|
||||||
|
style: const TextStyle(fontSize: 14),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
SearchTitle(
|
||||||
|
title: L10n.of(context)!.joinedChats,
|
||||||
|
icon: const Icon(Icons.chat_outlined),
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
i--;
|
i--;
|
||||||
final room = joinedRooms[i];
|
final joinedRoom = joinedRooms[i];
|
||||||
return ChatListItem(
|
return ChatListItem(
|
||||||
room,
|
joinedRoom,
|
||||||
filter: filter,
|
filter: filter,
|
||||||
onTap: () => widget.onChatTab(room),
|
onTap: () => widget.onChatTab(joinedRoom),
|
||||||
onLongPress: (context) => widget.onChatContext(
|
onLongPress: (context) => widget.onChatContext(
|
||||||
room,
|
joinedRoom,
|
||||||
context,
|
context,
|
||||||
),
|
),
|
||||||
activeChat: widget.activeChat == room.id,
|
activeChat: widget.activeChat == joinedRoom.id,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue