Skip to content

Commit d07309d

Browse files
committed
feat: add new archive animations
1 parent 74e52b8 commit d07309d

9 files changed

Lines changed: 190 additions & 46 deletions

lib/app/view/mouse_and_keyboard_command_wrapper.dart

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import 'package:flutter/material.dart';
22
import 'package:flutter/services.dart';
3-
import 'package:future_loading_dialog/future_loading_dialog.dart';
43
import 'package:flutter_it/flutter_it.dart';
54

65
import '../../chat_room/input/draft_manager.dart';
@@ -25,18 +24,13 @@ class MouseAndKeyboardCommandWrapper extends StatelessWidget {
2524
_PasteIntent: CallbackAction<_PasteIntent>(
2625
onInvoke: (intent) async {
2726
if (di<ChatManager>().selectedRoom != null) {
28-
await showFutureLoadingDialog(
29-
context: context,
30-
backLabel: context.l10n.cancel,
31-
title: context.l10n.loadingPleaseWait,
32-
future: () => di<DraftManager>().addAttachMentFromClipboard(
33-
di<ChatManager>().selectedRoom!.id,
34-
fileIsTooLarge: context.l10n.fileIsTooLarge,
35-
clipboardNotAvailable: context.l10n.clipboardNotAvailable,
36-
noSupportedFormatFoundInClipboard:
37-
context.l10n.noSupportedFormatFoundInClipboard,
38-
),
39-
);
27+
di<DraftManager>().addAttachmentFromClipboardCommand.run((
28+
roomId: di<ChatManager>().selectedRoom!.id,
29+
fileIsTooLarge: context.l10n.fileIsTooLarge,
30+
clipboardNotAvailable: context.l10n.clipboardNotAvailable,
31+
noSupportedFormatFoundInClipboard:
32+
context.l10n.noSupportedFormatFoundInClipboard,
33+
));
4034
}
4135
return null;
4236
},

lib/chat_master/view/chat_edit_room_mixin.dart

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ mixin ChatEditRoomMixin {
2525
..clearSnackBars()
2626
..showSnackBar(
2727
SnackBar(
28+
showCloseIcon: true,
2829
duration: const Duration(seconds: 3),
2930
content: Text(
3031
'Left: ${newValue.data?.getLocalizedDisplayname() ?? ''}',
@@ -89,13 +90,20 @@ mixin ChatEditRoomMixin {
8990
context,
9091
'${context.l10n.oopsSomethingWentWrong}: ${newValue.error}',
9192
);
92-
} else if (newValue.hasData) {
93+
}
94+
},
95+
);
96+
97+
registerHandler(
98+
select: (EditRoomManager m) => m.forgetAllRoomsCommand.progress,
99+
handler: (context, newValue, cancel) {
100+
if (newValue == 1) {
93101
ScaffoldMessenger.of(context)
94102
..clearSnackBars()
95103
..showSnackBar(
96104
const SnackBar(
97105
duration: Duration(seconds: 3),
98-
content: Text('Deleted all archived rooms'),
106+
content: Text('Clearing archive is complete'),
99107
),
100108
);
101109
}

lib/chat_master/view/chat_master_clear_archive_button.dart

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,24 @@ import '../../chat_room/create_or_edit/edit_room_manager.dart';
66
import '../../common/chat_manager.dart';
77
import '../../l10n/l10n.dart';
88

9-
class ChatMasterClearArchiveButton extends StatelessWidget {
9+
class ChatMasterClearArchiveButton extends StatelessWidget with WatchItMixin {
1010
const ChatMasterClearArchiveButton({super.key});
1111

1212
@override
13-
Widget build(BuildContext context) => IconButton(
14-
tooltip: context.l10n.clearArchive,
15-
onPressed: () {
16-
di<ChatManager>().setSelectedRoom(null);
17-
di<EditRoomManager>().forgetAllRoomsCommand.run();
18-
},
19-
icon: const Icon(YaruIcons.edit_clear_all),
20-
);
13+
Widget build(BuildContext context) {
14+
final result = watchValue(
15+
(ChatManager m) => m.toggleArchiveCommand.results,
16+
);
17+
18+
return IconButton(
19+
tooltip: context.l10n.clearArchive,
20+
onPressed: result.isRunning || result.data!.archivedRooms.isEmpty
21+
? null
22+
: () {
23+
di<ChatManager>().setSelectedRoom(null);
24+
di<EditRoomManager>().forgetAllRoomsCommand.run();
25+
},
26+
icon: const Icon(YaruIcons.edit_clear_all),
27+
);
28+
}
2129
}

lib/chat_master/view/chat_master_title_bar.dart

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import 'package:flutter/material.dart';
2-
import 'package:future_loading_dialog/future_loading_dialog.dart';
32
import 'package:flutter_it/flutter_it.dart';
43
import 'package:yaru/yaru.dart';
54

@@ -26,6 +25,11 @@ class ChatMasterTitleBar extends StatelessWidget with WatchItMixin {
2625
final archiveActive = watchPropertyValue(
2726
(ChatManager m) => m.archiveActive,
2827
);
28+
29+
final loadingArchive = watchValue(
30+
(ChatManager m) => m.toggleArchiveCommand.isRunning,
31+
);
32+
2933
return YaruWindowTitleBar(
3034
heroTag: '<Left hero tag>',
3135
title: Text(archiveActive ? l10n.archive : l10n.chats),
@@ -52,10 +56,9 @@ class ChatMasterTitleBar extends StatelessWidget with WatchItMixin {
5256
tooltip: context.l10n.archive,
5357
selectedIcon: const Icon(YaruIcons.trash_filled),
5458
isSelected: watchPropertyValue((ChatManager m) => m.archiveActive),
55-
onPressed: () => showFutureLoadingDialog(
56-
context: context,
57-
future: di<ChatManager>().toggleArchive,
58-
),
59+
onPressed: loadingArchive
60+
? null
61+
: () => di<ChatManager>().toggleArchiveCommand.run(),
5962
icon: const Icon(YaruIcons.trash),
6063
),
6164
],

lib/chat_master/view/chat_rooms_list.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ class ChatRoomsList extends StatelessWidget with WatchItMixin {
99

1010
@override
1111
Widget build(BuildContext context) {
12+
final loadingArchive = watchValue(
13+
(ChatManager m) => m.toggleArchiveCommand.isRunning,
14+
);
15+
16+
if (loadingArchive) {
17+
return const SizedBox.shrink();
18+
}
19+
1220
final filteredRooms =
1321
watchStream(
1422
(ChatManager m) => m.filteredRoomsStream,

lib/chat_room/common/view/chat_no_selected_room_page.dart

Lines changed: 83 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ import 'dart:io';
33
import 'package:flutter/foundation.dart';
44
import 'package:flutter/material.dart';
55
import 'package:flutter_it/flutter_it.dart';
6+
import 'package:liquid_progress_indicator_v2/liquid_progress_indicator.dart';
67
import 'package:yaru/yaru.dart';
78

89
import '../../../common/chat_manager.dart';
910
import '../../../common/view/build_context_x.dart';
1011
import '../../../common/view/ui_constants.dart';
12+
import '../../../l10n/l10n.dart';
1113
import '../../create_or_edit/edit_room_manager.dart';
1214
import '../../titlebar/side_bar_button.dart';
1315

@@ -40,6 +42,18 @@ class ChatNoSelectedRoomPage extends StatelessWidget with WatchItMixin {
4042
},
4143
);
4244

45+
final loadingArchive = watchValue(
46+
(ChatManager m) => m.toggleArchiveCommand.isRunning,
47+
);
48+
49+
final clearingArchive = watchValue(
50+
(EditRoomManager m) => m.forgetAllRoomsCommand.isRunning,
51+
);
52+
53+
final progress = watchValue(
54+
(EditRoomManager m) => m.forgetAllRoomsCommand.progress,
55+
);
56+
4357
return Scaffold(
4458
appBar: YaruWindowTitleBar(
4559
heroTag: '<Right hero tag>',
@@ -61,12 +75,79 @@ class ChatNoSelectedRoomPage extends StatelessWidget with WatchItMixin {
6175
mainAxisSize: MainAxisSize.min,
6276
spacing: kBigPadding,
6377
children: [
64-
Image.asset('assets/nebuchadnezzar.png', width: 100),
65-
const Text('Please select a chatroom from the side panel.'),
78+
loadingArchive
79+
? LiquidCustomProgressIndicator(
80+
backgroundColor:
81+
context.theme.colorScheme.surfaceContainerHighest,
82+
direction: Axis.vertical,
83+
value: 0.5,
84+
shapePath: _buildArchiveIconPath(),
85+
)
86+
: clearingArchive
87+
? LiquidCustomProgressIndicator(
88+
backgroundColor:
89+
context.theme.colorScheme.surfaceContainerHighest,
90+
direction: Axis.vertical,
91+
value: progress,
92+
shapePath: _buildBoatPath(),
93+
)
94+
: Image.asset('assets/nebuchadnezzar.png', width: 100),
95+
Text(
96+
loadingArchive || clearingArchive
97+
? context.l10n.loadingPleaseWait
98+
: 'Please select a chatroom from the side panel.',
99+
),
66100
],
67101
),
68102
),
69103
),
70104
);
71105
}
106+
107+
Path _buildBoatPath() {
108+
return Path()
109+
..moveTo(15, 120)
110+
..lineTo(0, 85)
111+
..lineTo(50, 85)
112+
..lineTo(50, 0)
113+
..lineTo(105, 80)
114+
..lineTo(60, 80)
115+
..lineTo(60, 85)
116+
..lineTo(120, 85)
117+
..lineTo(105, 120)
118+
..close();
119+
}
120+
121+
Path _buildArchiveIconPath() {
122+
final path = Path()
123+
// 1. THE LID (Top Part)
124+
// Starting at the bottom-left of the lid
125+
..moveTo(10, 35)
126+
..lineTo(90, 35) // Bottom edge of lid
127+
..lineTo(90, 20) // Right side
128+
..quadraticBezierTo(90, 10, 80, 10) // Top-right corner
129+
..lineTo(20, 10) // Top edge
130+
..quadraticBezierTo(10, 10, 10, 20) // Top-left corner
131+
..close()
132+
// 2. THE BODY (Bottom Part)
133+
..moveTo(15, 40)
134+
..lineTo(85, 40) // Top edge of body
135+
..lineTo(85, 80) // Right side
136+
..quadraticBezierTo(85, 90, 75, 90) // Bottom-right corner
137+
..lineTo(25, 90) // Bottom edge
138+
..quadraticBezierTo(15, 90, 15, 80) // Bottom-left corner
139+
..close()
140+
// 3. THE HANDLE (Slot)
141+
// Adding a rounded rectangle cutout in the center
142+
..addRRect(
143+
RRect.fromRectAndRadius(
144+
const Rect.fromLTWH(35, 50, 30, 10),
145+
const Radius.circular(5),
146+
),
147+
)
148+
// Set the fill type to evenOdd so the handle appears as a "hole"
149+
..fillType = PathFillType.evenOdd;
150+
151+
return path;
152+
}
72153
}

lib/chat_room/input/draft_manager.dart

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,25 @@ class DraftManager extends SafeChangeNotifier {
395395
bool isMessageSelected({required String eventId}) =>
396396
_selectedMessages[eventId] ?? false;
397397

398+
late final Command<
399+
({
400+
String roomId,
401+
String clipboardNotAvailable,
402+
String noSupportedFormatFoundInClipboard,
403+
String fileIsTooLarge,
404+
}),
405+
List<void>
406+
>
407+
addAttachmentFromClipboardCommand = Command.createAsync(
408+
(param) => addAttachMentFromClipboard(
409+
param.roomId,
410+
clipboardNotAvailable: param.clipboardNotAvailable,
411+
noSupportedFormatFoundInClipboard:
412+
param.noSupportedFormatFoundInClipboard,
413+
fileIsTooLarge: param.fileIsTooLarge,
414+
),
415+
initialValue: [],
416+
);
398417
Future<List<void>> addAttachMentFromClipboard(
399418
String roomId, {
400419
required String clipboardNotAvailable,

lib/chat_room/input/view/chat_input.dart

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,9 @@ class _ChatInputState extends State<ChatInput> {
8686
_sendNode.requestFocus();
8787
});
8888
} else {
89-
di<DraftManager>().sendCommand.run(widget.room);
9089
_sendController.clear();
9190
_sendNode.requestFocus();
91+
di<DraftManager>().sendCommand.run(widget.room);
9292
}
9393
}
9494

@@ -104,6 +104,10 @@ class _ChatInputState extends State<ChatInput> {
104104
(ChatManager m) => m.archiveActive,
105105
);
106106

107+
final isPastingFromClipboard = watchValue(
108+
(DraftManager m) => m.addAttachmentFromClipboardCommand.isRunning,
109+
);
110+
107111
final isSending = watchValue((DraftManager m) => m.sendCommand.isRunning);
108112

109113
final sendingFile = draftFiles.isNotEmpty && isSending;
@@ -177,7 +181,7 @@ class _ChatInputState extends State<ChatInput> {
177181
maxLines: 10,
178182
focusNode: _sendNode,
179183
controller: _sendController,
180-
enabled: sendingFile
184+
enabled: sendingFile || isPastingFromClipboard
181185
? false
182186
: !archiveActive && !unAcceptedDirectChat,
183187
autofocus: true,
@@ -258,15 +262,21 @@ class _ChatInputState extends State<ChatInput> {
258262
suffixIcon: Row(
259263
mainAxisSize: MainAxisSize.min,
260264
children: [
261-
IconButton(
262-
tooltip: l10n.send,
263-
padding: EdgeInsets.zero,
264-
icon: transform,
265-
onPressed:
266-
attaching || archiveActive || unAcceptedDirectChat
267-
? null
268-
: () => send(),
269-
),
265+
if (isPastingFromClipboard ||
266+
attaching ||
267+
unAcceptedDirectChat)
268+
const SizedBox(
269+
width: 20,
270+
height: 20,
271+
child: CircularProgressIndicator(strokeWidth: 2),
272+
)
273+
else
274+
IconButton(
275+
tooltip: l10n.send,
276+
padding: EdgeInsets.zero,
277+
icon: transform,
278+
onPressed: () => send(),
279+
),
270280
],
271281
),
272282
),

lib/common/chat_manager.dart

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,14 +170,27 @@ class ChatManager extends SafeChangeNotifier {
170170

171171
bool _archiveActive = false;
172172
bool get archiveActive => _archiveActive;
173-
Future<void> toggleArchive() async {
173+
174+
late final Command<
175+
void,
176+
({bool archiveActive, List<ArchivedRoom> archivedRooms})
177+
>
178+
toggleArchiveCommand = Command.createAsyncNoParam(
179+
_toggleArchive,
180+
initialValue: (archiveActive: false, archivedRooms: _client.archivedRooms),
181+
);
182+
183+
Future<({bool archiveActive, List<ArchivedRoom> archivedRooms})>
184+
_toggleArchive() async {
174185
_archiveActive = !_archiveActive;
175186
if (_archiveActive) {
187+
setSelectedRoom(null);
176188
await _client.loadArchive();
177-
} else {
178-
await Future.value();
179189
}
180-
setSelectedRoom(null);
190+
return (
191+
archiveActive: _archiveActive,
192+
archivedRooms: _client.archivedRooms,
193+
);
181194
}
182195

183196
Stream<bool> getPendingDirectChatStream(Room room) => _client

0 commit comments

Comments
 (0)