Skip to content

Commit 09868d7

Browse files
committed
chore: improve timeline, event UI and invites (#75)
* chore: improve timeline, event UI and invites * extract * don't preserve state * .
1 parent 0099a66 commit 09868d7

23 files changed

+358
-255
lines changed

lib/chat_room/common/view/chat_room_page.dart

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'package:super_drag_and_drop/super_drag_and_drop.dart';
77
import 'package:watch_it/watch_it.dart';
88

99
import '../../../common/chat_model.dart';
10+
import '../../../common/room_x.dart';
1011
import '../../../common/view/build_context_x.dart';
1112
import '../../../common/view/common_widgets.dart';
1213
import '../../../common/view/confirm.dart';
@@ -20,6 +21,7 @@ import '../../input/view/chat_input.dart';
2021
import '../../timeline/chat_room_timeline_list.dart';
2122
import '../../timeline/timeline_model.dart';
2223
import '../../titlebar/chat_room_title_bar.dart';
24+
import 'chat_room_unaccepted_direct_chat_body.dart';
2325

2426
final GlobalKey<ScaffoldState> chatRoomScaffoldKey = GlobalKey();
2527

@@ -82,6 +84,14 @@ class _ChatRoomPageState extends State<ChatRoomPage> {
8284
},
8385
);
8486

87+
final unAcceptedDirectChat = watchStream(
88+
(ChatModel m) => m
89+
.getJoinedRoomUpdate(widget.room.id)
90+
.map((room) => widget.room.isUnacceptedDirectChat),
91+
initialValue: widget.room.isUnacceptedDirectChat,
92+
preserveState: false,
93+
).data;
94+
8595
return DropRegion(
8696
formats: Formats.standardFormats,
8797
hitTestBehavior: HitTestBehavior.opaque,
@@ -117,29 +127,36 @@ class _ChatRoomPageState extends State<ChatRoomPage> {
117127
key: chatRoomScaffoldKey,
118128
endDrawer: ChatRoomInfoDrawer(room: widget.room),
119129
appBar: ChatRoomTitleBar(room: widget.room),
120-
bottomNavigationBar: widget.room.isArchived
130+
bottomNavigationBar:
131+
widget.room.isArchived || unAcceptedDirectChat != false
121132
? null
122133
: ChatInput(
123134
key: ValueKey('${widget.room.id}input'),
124135
room: widget.room,
125136
),
126-
body: FutureBuilder<Timeline>(
127-
key: ValueKey(widget.room.id),
128-
future: _timelineFuture,
129-
builder: (context, snapshot) {
130-
if (snapshot.hasData) {
131-
return Padding(
132-
padding: const EdgeInsets.only(bottom: kMediumPadding),
133-
child: ChatRoomTimelineList(
134-
timeline: snapshot.data!,
135-
listKey: _roomListKey,
136-
),
137-
);
138-
} else {
139-
return const Center(child: Progress());
140-
}
141-
},
142-
),
137+
body: unAcceptedDirectChat == null
138+
? const Center(child: Progress())
139+
: unAcceptedDirectChat == true
140+
? const ChatRoomUnacceptedDirectChatBody()
141+
: FutureBuilder<Timeline>(
142+
key: ValueKey(widget.room.id),
143+
future: _timelineFuture,
144+
builder: (context, snapshot) {
145+
if (snapshot.hasData) {
146+
return Padding(
147+
padding: const EdgeInsets.only(
148+
bottom: kMediumPadding,
149+
),
150+
child: ChatRoomTimelineList(
151+
timeline: snapshot.data!,
152+
listKey: _roomListKey,
153+
),
154+
);
155+
} else {
156+
return const Center(child: Progress());
157+
}
158+
},
159+
),
143160
),
144161
if (updating &&
145162
chatRoomScaffoldKey.currentState?.isEndDrawerOpen != true)
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:yaru/yaru.dart';
3+
import '../../../common/view/build_context_x.dart';
4+
import '../../../common/view/ui_constants.dart';
5+
import '../../../l10n/l10n.dart';
6+
7+
class ChatRoomUnacceptedDirectChatBody extends StatelessWidget {
8+
const ChatRoomUnacceptedDirectChatBody({super.key});
9+
10+
@override
11+
Widget build(BuildContext context) {
12+
final l10n = context.l10n;
13+
final colorScheme = context.colorScheme;
14+
return Center(
15+
child: Padding(
16+
padding: const EdgeInsets.all(kMediumPadding),
17+
child: Column(
18+
mainAxisSize: MainAxisSize.min,
19+
spacing: kMediumPadding,
20+
children: [
21+
Icon(YaruIcons.send, size: 48, color: colorScheme.error),
22+
Text(
23+
l10n.waitingPartnerAcceptRequest,
24+
textAlign: TextAlign.center,
25+
style: context.theme.textTheme.bodyLarge,
26+
),
27+
],
28+
),
29+
),
30+
);
31+
}
32+
}
Lines changed: 48 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import 'package:flutter/material.dart';
22
import 'package:matrix/matrix.dart';
3+
import 'package:watch_it/watch_it.dart';
34

5+
import '../../common/chat_model.dart';
6+
import '../../common/room_x.dart';
47
import '../../common/view/ui_constants.dart';
58
import 'chat_room_info_drawer_direct_chat_content.dart';
69
import 'chat_room_info_drawer_direct_chat_header.dart';
@@ -9,44 +12,56 @@ import 'chat_room_info_drawer_group_header.dart';
912
import 'chat_room_info_drawer_leave_button.dart';
1013
import 'chat_room_join_or_leave_button.dart';
1114

12-
class ChatRoomInfoDrawer extends StatelessWidget {
15+
class ChatRoomInfoDrawer extends StatelessWidget with WatchItMixin {
1316
const ChatRoomInfoDrawer({super.key, required this.room});
1417

1518
final Room room;
1619

1720
@override
18-
Widget build(BuildContext context) => Drawer(
19-
child: SizedBox(
20-
width: kSideBarWith,
21-
child: Column(
22-
mainAxisSize: MainAxisSize.min,
23-
mainAxisAlignment: MainAxisAlignment.spaceBetween,
24-
children: [
25-
if (!room.isDirectChat)
26-
ChatRoomInfoDrawerGroupHeader(
27-
key: ValueKey('${room.id}_header'),
28-
room: room,
29-
)
30-
else
31-
ChatRoomInfoDrawerDirectChatHeader(
32-
key: ValueKey('${room.id}_header_'),
33-
room: room,
34-
),
35-
if (room.isArchived)
36-
const Expanded(child: Text(''))
37-
else
38-
Expanded(
39-
child: room.isDirectChat
40-
? ChatRoomInfoDrawerDirectChatContent(room: room)
41-
: ChatRoomInfoDrawerGroupContent(room: room),
21+
Widget build(BuildContext context) {
22+
final unAcceptedDirectChat = watchStream(
23+
(ChatModel m) => m
24+
.getJoinedRoomUpdate(room.id)
25+
.map((_) => room.isUnacceptedDirectChat),
26+
initialValue: room.isUnacceptedDirectChat,
27+
preserveState: false,
28+
).data;
29+
30+
return Drawer(
31+
child: SizedBox(
32+
width: kSideBarWith,
33+
child: Column(
34+
mainAxisSize: MainAxisSize.min,
35+
mainAxisAlignment: MainAxisAlignment.spaceBetween,
36+
children: [
37+
if (!room.isDirectChat)
38+
ChatRoomInfoDrawerGroupHeader(
39+
key: ValueKey('${room.id}_header'),
40+
room: room,
41+
)
42+
else if (unAcceptedDirectChat != true)
43+
ChatRoomInfoDrawerDirectChatHeader(
44+
key: ValueKey('${room.id}_header_'),
45+
room: room,
46+
),
47+
if (room.isArchived)
48+
const Expanded(child: Text(''))
49+
else
50+
Expanded(
51+
child: room.isDirectChat
52+
? unAcceptedDirectChat != true
53+
? ChatRoomInfoDrawerDirectChatContent(room: room)
54+
: const SizedBox.shrink()
55+
: ChatRoomInfoDrawerGroupContent(room: room),
56+
),
57+
if (room.isArchived) ChatRoomInfoDrawerForgetButton(room: room),
58+
Align(
59+
alignment: Alignment.bottomCenter,
60+
child: ChatRoomJoinOrLeaveButton(room: room),
4261
),
43-
if (room.isArchived) ChatRoomInfoDrawerLeaveButton(room: room),
44-
Align(
45-
alignment: Alignment.bottomCenter,
46-
child: ChatRoomJoinOrLeaveButton(room: room),
47-
),
48-
],
62+
],
63+
),
4964
),
50-
),
51-
);
65+
);
66+
}
5267
}

lib/chat_room/info_drawer/chat_room_info_drawer_leave_button.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import '../../common/view/snackbars.dart';
1010
import '../../common/view/ui_constants.dart';
1111
import '../../l10n/l10n.dart';
1212

13-
class ChatRoomInfoDrawerLeaveButton extends StatelessWidget {
14-
const ChatRoomInfoDrawerLeaveButton({super.key, required this.room});
13+
class ChatRoomInfoDrawerForgetButton extends StatelessWidget {
14+
const ChatRoomInfoDrawerForgetButton({super.key, required this.room});
1515

1616
final Room room;
1717

@@ -37,8 +37,10 @@ class ChatRoomInfoDrawerLeaveButton extends StatelessWidget {
3737
)
3838
: null,
3939
onPressed: () => showDialog(
40+
barrierDismissible: false,
4041
context: context,
4142
builder: (context) => ConfirmationDialog(
43+
showCloseIcon: false,
4244
onConfirm: () async => di<ChatModel>().leaveSelectedRoom(
4345
onFail: (error) => showSnackBar(context, content: Text(error)),
4446
forget: true,

lib/chat_room/info_drawer/chat_room_info_media_grid.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,9 @@ class ChatRoomInfoMediaGrid extends StatelessWidget with WatchItMixin {
139139

140140
return switch (messageType) {
141141
MessageTypes.Image => ChatImage(
142-
dimension: 200,
142+
height: 90,
143+
fit: BoxFit.cover,
144+
showDescription: false,
143145
event: event,
144146
onTap: event.isSvgImage
145147
? null

lib/chat_room/info_drawer/chat_room_join_or_leave_button.dart

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -45,32 +45,31 @@ class ChatRoomJoinOrLeaveButton extends StatelessWidget {
4545
: context.colorScheme.primary,
4646
)
4747
: null,
48-
onPressed: notReJoinable
49-
? null
50-
: () => showDialog(
51-
context: context,
52-
builder: (context) => ConfirmationDialog(
53-
title: Text(message),
54-
onConfirm: () {
55-
void onFail(error) =>
56-
showSnackBar(context, content: Text(error));
48+
onPressed: () => showDialog(
49+
barrierDismissible: false,
50+
context: context,
51+
builder: (context) => ConfirmationDialog(
52+
showCloseIcon: false,
53+
title: Text(message),
54+
onConfirm: () async {
55+
void onFail(error) => showSnackBar(context, content: Text(error));
5756

58-
if (joinedRoom) {
59-
chatModel.leaveSelectedRoom(
60-
onFail: onFail,
61-
forget: room.isDirectChat,
62-
);
63-
} else {
64-
chatModel.joinRoom(
65-
room,
66-
onFail: onFail,
67-
clear: true,
68-
select: false,
69-
);
70-
}
71-
},
72-
),
73-
),
57+
if (joinedRoom) {
58+
await chatModel.leaveSelectedRoom(
59+
onFail: onFail,
60+
forget: room.isDirectChat,
61+
);
62+
} else if (!notReJoinable) {
63+
await chatModel.joinRoom(
64+
room,
65+
onFail: onFail,
66+
clear: true,
67+
select: false,
68+
);
69+
}
70+
},
71+
),
72+
),
7473
icon: !room.isArchived
7574
? Icon(
7675
YaruIcons.log_out,

lib/chat_room/input/view/chat_input.dart

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ class _ChatInputState extends State<ChatInput> {
117117
widget.room.getParticipants().any(
118118
(e) => e.membership == Membership.invite,
119119
);
120+
120121
return Stack(
121122
clipBehavior: Clip.none,
122123
children: [
@@ -192,7 +193,11 @@ class _ChatInputState extends State<ChatInput> {
192193
children: [
193194
IconButton(
194195
padding: EdgeInsets.zero,
195-
onPressed: attaching || sending || archiveActive
196+
onPressed:
197+
attaching ||
198+
sending ||
199+
archiveActive ||
200+
unAcceptedDirectChat
196201
? null
197202
: () => draftModel.addAttachment(
198203
widget.room.id,
@@ -210,7 +215,10 @@ class _ChatInputState extends State<ChatInput> {
210215
),
211216
ChatInputEmojiPicker(
212217
onEmojiSelected:
213-
attaching || sending || archiveActive
218+
attaching ||
219+
sending ||
220+
archiveActive ||
221+
unAcceptedDirectChat
214222
? null
215223
: (cat, emo) {
216224
_sendController.text =
@@ -233,7 +241,11 @@ class _ChatInputState extends State<ChatInput> {
233241
tooltip: l10n.send,
234242
padding: EdgeInsets.zero,
235243
icon: transform,
236-
onPressed: attaching || sending || archiveActive
244+
onPressed:
245+
attaching ||
246+
sending ||
247+
archiveActive ||
248+
unAcceptedDirectChat
237249
? null
238250
: send,
239251
),

lib/chat_room/timeline/chat_room_pinned_events_dialog.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import 'package:matrix/matrix.dart';
33
import 'package:watch_it/watch_it.dart';
44
import 'package:yaru/yaru.dart';
55

6+
import '../../common/event_x.dart';
67
import '../../common/view/ui_constants.dart';
78
import '../../l10n/l10n.dart';
89
import '../../common/chat_model.dart';
@@ -80,6 +81,7 @@ class _ChatRoomPinnedEventTileState extends State<ChatRoomPinnedEventTile> {
8081
event: s.data!,
8182
timeline: widget.timeline,
8283
onReplyOriginClick: (p0) async {},
84+
eventPosition: EventPosition.top,
8385
)
8486
: const Text(''),
8587
);

0 commit comments

Comments
 (0)