Skip to content

Commit e2e4a9c

Browse files
committed
feat: create space, disallow svgs for now, improve timeline model, add direct chat dialog, add location fallback bubble for now
1 parent 660b407 commit e2e4a9c

25 files changed

+488
-182
lines changed

lib/chat/chat_model.dart

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class ChatModel extends SafeChangeNotifier {
1515
// The matrix dart SDK client
1616
final Client _client;
1717
String? get myUserId => _client.userID;
18+
String? get homeServerId => _client.homeserver?.host;
1819
bool isUserEvent(Event event) => myUserId == event.senderId;
1920
bool get isLogged => _client.isLogged();
2021
bool get encryptionEnabled => _client.encryptionEnabled;
@@ -129,11 +130,10 @@ class ChatModel extends SafeChangeNotifier {
129130
return timeline.events.where((e) => !e.showAsBadge).toList();
130131
}
131132

132-
Stream<List<Room>> get spacesStream => joinedUpdateStream
133-
.map((e) => rooms.where((e) => !e.isArchived && e.isSpace).toList());
133+
Stream<List<Room>> get spacesStream =>
134+
syncStream.map((e) => rooms.where((e) => e.isSpace).toList());
134135

135-
List<Room> get notArchivedSpaces =>
136-
rooms.where((e) => !e.isArchived && e.isSpace).toList();
136+
List<Room> get spaces => rooms.where((e) => e.isSpace).toList();
137137

138138
RoomsFilter? _roomsFilter;
139139
RoomsFilter? get roomsFilter => _roomsFilter;
@@ -277,6 +277,47 @@ class ChatModel extends SafeChangeNotifier {
277277
}
278278
}
279279

280+
Future<String?> createSpace({
281+
required String name,
282+
Visibility visibility = Visibility.public,
283+
List<String>? invite,
284+
List<Invite3pid>? invite3pid,
285+
String? roomVersion,
286+
String? topic,
287+
bool waitForSync = true,
288+
String? spaceAliasName,
289+
required Function(String error) onFail,
290+
required Function() onSuccess,
291+
}) async {
292+
_setProcessingJoinOrLeave(true);
293+
String? spaceRoomId;
294+
try {
295+
printMessageInDebugMode('Creating space...');
296+
spaceRoomId = await _client.createSpace(
297+
name: name,
298+
visibility: visibility,
299+
invite: invite,
300+
invite3pid: invite3pid,
301+
roomVersion: roomVersion,
302+
topic: topic,
303+
waitForSync: waitForSync,
304+
spaceAliasName: spaceAliasName,
305+
);
306+
} on Exception catch (e, s) {
307+
printMessageInDebugMode(e, s);
308+
onFail(e.toString());
309+
}
310+
if (spaceRoomId != null) {
311+
final space = _client.getRoomById(spaceRoomId);
312+
if (space != null) {
313+
onSuccess();
314+
setSelectedRoom(space);
315+
}
316+
}
317+
_setProcessingJoinOrLeave(false);
318+
return spaceRoomId;
319+
}
320+
280321
Future<void> joinDirectChat(
281322
String userId, {
282323
required Function(String error) onFail,

lib/chat/draft_model.dart

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -172,10 +172,14 @@ class DraftModel extends SafeChangeNotifier {
172172
}
173173

174174
final Map<MatrixFile, XFile> _matrixFilesToXFile = {};
175-
Future<void> addAttachment(String roomId) async {
175+
Future<void> addAttachment(
176+
String roomId, {
177+
required Function(String error) onFail,
178+
}) async {
176179
setAttaching(true);
177180

178181
List<XFile>? xFiles;
182+
179183
if (Platform.isLinux) {
180184
xFiles = await openFiles();
181185
} else {
@@ -198,7 +202,8 @@ class DraftModel extends SafeChangeNotifier {
198202
return;
199203
}
200204

201-
for (var xFile in xFiles!) {
205+
// TODO(Feichtmeier): add svg send support
206+
for (var xFile in xFiles!.where((e) => !e.path.contains('.svg'))) {
202207
final mime = xFile.mimeType;
203208
final bytes = await xFile.readAsBytes();
204209
MatrixFile matrixFile;
@@ -207,7 +212,7 @@ class DraftModel extends SafeChangeNotifier {
207212
bytes: bytes,
208213
name: xFile.name,
209214
mimeType: mime,
210-
maxDimension: 1000,
215+
maxDimension: 2500,
211216
nativeImplementations: _client.nativeImplementations,
212217
);
213218
} else if (mime?.startsWith('video') == true) {
@@ -307,7 +312,7 @@ class DraftModel extends SafeChangeNotifier {
307312
} else {
308313
final result = await FilePicker.platform.pickFiles(
309314
allowMultiple: false,
310-
type: FileType.any,
315+
type: FileType.image,
311316
);
312317
xFile = result?.files
313318
.map(
@@ -328,7 +333,7 @@ class DraftModel extends SafeChangeNotifier {
328333
final mime = xFile.mimeType;
329334
final bytes = await xFile.readAsBytes();
330335

331-
if (mime?.startsWith('image') == true) {
336+
if (mime?.startsWith('image') == true && mime?.endsWith('svg') != true) {
332337
_avatarDraftFile = await MatrixImageFile.shrink(
333338
bytes: bytes,
334339
name: xFile.name,

lib/chat/event_x.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'package:matrix/matrix.dart';
22

33
extension EventX on Event {
44
bool get isImage => messageType == MessageTypes.Image;
5+
bool get isSvgImage => attachmentMimetype == 'image/svg+xml';
56

67
bool get showAsBadge =>
78
messageType == MessageTypes.Emote ||

lib/chat/matrix_file_x.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import 'package:matrix/matrix.dart';
22

33
extension MatrixFileX on MatrixFile {
4-
bool get isImage => mimeType.startsWith('image');
4+
bool get isRegularImage => mimeType.startsWith('image') && !isSvgImage;
5+
bool get isSvgImage => mimeType == 'image/svg+xml';
56
bool get isVideo => mimeType.startsWith('video');
67
bool get isAudio => mimeType.startsWith('audio');
78
}

lib/chat/settings/settings_dialog.dart

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'package:yaru/yaru.dart';
44

55
import '../../common/date_time_x.dart';
66
import '../../common/view/build_context_x.dart';
7+
import '../../common/view/common_widgets.dart';
78
import '../../common/view/snackbars.dart';
89
import '../../common/view/ui_constants.dart';
910
import '../../l10n/l10n.dart';
@@ -124,30 +125,38 @@ class _SettingsDialogState extends State<SettingsDialog> {
124125
),
125126
YaruSection(
126127
headline: Text(l10n.devices),
127-
child: Column(
128-
children: devices
129-
.map(
130-
(d) => YaruTile(
131-
trailing: d.deviceId != settingsModel.myDeviceId
132-
? IconButton(
133-
onPressed: () =>
134-
settingsModel.deleteDevice(d.deviceId),
135-
icon: Icon(
136-
YaruIcons.trash,
137-
color: context.colorScheme.error,
138-
),
139-
)
140-
: null,
141-
subtitle: Text(
142-
DateTime.fromMillisecondsSinceEpoch(
143-
d.lastSeenTs ?? 0,
144-
).formatAndLocalize(l10n, simple: true),
145-
),
146-
title: SelectableText(d.displayName ?? d.deviceId),
128+
child: devices == null
129+
? const Center(
130+
child: Padding(
131+
padding: EdgeInsets.all(kBigPadding),
132+
child: Progress(),
147133
),
148134
)
149-
.toList(),
150-
),
135+
: Column(
136+
children: devices
137+
.map(
138+
(d) => YaruTile(
139+
trailing: d.deviceId != settingsModel.myDeviceId
140+
? IconButton(
141+
onPressed: () => settingsModel
142+
.deleteDevice(d.deviceId),
143+
icon: Icon(
144+
YaruIcons.trash,
145+
color: context.colorScheme.error,
146+
),
147+
)
148+
: null,
149+
subtitle: Text(
150+
DateTime.fromMillisecondsSinceEpoch(
151+
d.lastSeenTs ?? 0,
152+
).formatAndLocalize(l10n, simple: true),
153+
),
154+
title:
155+
SelectableText(d.displayName ?? d.deviceId),
156+
),
157+
)
158+
.toList(),
159+
),
151160
),
152161
],
153162
),

lib/chat/settings/settings_model.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ class SettingsModel extends SafeChangeNotifier {
3131
}
3232

3333
String? get myDeviceId => _client.deviceID;
34-
List<Device> _devices = [];
35-
List<Device> get devices => _devices;
34+
List<Device>? _devices;
35+
List<Device>? get devices => _devices;
3636
Future<void> getDevices() async {
3737
_devices = await _client.getDevices() ?? [];
3838
notifyListeners();

lib/chat/timeline_model.dart

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@ import 'package:matrix/matrix.dart';
22
import 'package:safe_change_notifier/safe_change_notifier.dart';
33

44
class TimelineModel extends SafeChangeNotifier {
5-
// TIMELINES
6-
7-
bool _updatingTimeline = false;
8-
bool get updatingTimeline => _updatingTimeline;
9-
void setUpdatingTimeline(bool value) {
10-
if (value == _updatingTimeline) return;
11-
_updatingTimeline = value;
5+
final Map<String, bool> _updatingTimeline = {};
6+
bool getUpdatingTimeline(String roomId) => _updatingTimeline[roomId] == true;
7+
void setUpdatingTimeline({
8+
required String roomId,
9+
required bool value,
10+
}) {
11+
if (_updatingTimeline[roomId] == value) return;
12+
_updatingTimeline[roomId] = value;
1213
notifyListeners();
1314
}
1415

@@ -19,17 +20,19 @@ class TimelineModel extends SafeChangeNotifier {
1920
bool notify = true,
2021
}) async {
2122
if (notify) {
22-
setUpdatingTimeline(true);
23+
setUpdatingTimeline(roomId: timeline.room.id, value: true);
2324
}
2425
if (timeline.isRequestingHistory) {
25-
setUpdatingTimeline(false);
26+
setUpdatingTimeline(roomId: timeline.room.id, value: false);
2627
return;
2728
}
2829
await timeline.requestHistory(filter: filter, historyCount: historyCount);
2930
if (notify) {
30-
setUpdatingTimeline(false);
31+
setUpdatingTimeline(roomId: timeline.room.id, value: false);
32+
}
33+
if (!timeline.room.isArchived) {
34+
await timeline.setReadMarker();
3135
}
32-
await timeline.setReadMarker();
3336
}
3437

3538
bool _timelineSearchActive = false;

lib/chat/view/chat_image.dart

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
import 'dart:typed_data';
2+
13
import 'package:flutter/material.dart';
24
import 'package:matrix/matrix.dart';
35
import 'package:watch_it/watch_it.dart';
46
import 'package:yaru/yaru.dart';
57

6-
import '../../common/view/common_widgets.dart';
78
import '../../common/view/image_shimmer.dart';
89
import '../../common/view/ui_constants.dart';
910
import '../chat_download_model.dart';
@@ -174,38 +175,35 @@ class ChatImageFuture extends StatefulWidget {
174175
this.height,
175176
required this.width,
176177
this.fit,
177-
this.fromCache = true,
178+
this.getThumbnail = true,
178179
});
179180

180181
final Event event;
181182
final double? height;
182183
final double width;
183184
final BoxFit? fit;
184-
final bool fromCache;
185+
final bool getThumbnail;
185186

186187
@override
187188
State<ChatImageFuture> createState() => _ChatImageFutureState();
188189
}
189190

190191
class _ChatImageFutureState extends State<ChatImageFuture> {
191-
late final Future<dynamic> _future;
192+
late final Future<Uint8List?> _future;
192193

193194
@override
194195
void initState() {
195196
super.initState();
196-
_future = widget.fromCache
197-
? di<LocalImageModel>().downloadImage(event: widget.event)
198-
: widget.event.downloadAndDecryptAttachment(getThumbnail: true);
197+
_future = di<LocalImageModel>()
198+
.downloadImage(event: widget.event, getThumbnail: widget.getThumbnail);
199199
}
200200

201201
@override
202202
Widget build(BuildContext context) => FutureBuilder(
203203
future: _future,
204204
builder: (context, snapshot) {
205205
if (snapshot.hasData) {
206-
final data = widget.fromCache
207-
? snapshot.data
208-
: (snapshot.data as MatrixFile).bytes;
206+
final data = snapshot.data;
209207
return Image.memory(
210208
data!,
211209
fit: widget.fit,
@@ -214,11 +212,7 @@ class _ChatImageFutureState extends State<ChatImageFuture> {
214212
);
215213
}
216214

217-
return widget.fromCache
218-
? const ImageShimmer()
219-
: const Center(
220-
child: Progress(),
221-
);
215+
return const ImageShimmer();
222216
},
223217
);
224218
}

0 commit comments

Comments
 (0)