Skip to content

Commit

Permalink
feat: create space, disallow svgs for now, improve timeline model, ad…
Browse files Browse the repository at this point in the history
…d direct chat dialog, add location fallback bubble for now
  • Loading branch information
Feichtmeier committed Jan 13, 2025
1 parent 660b407 commit e2e4a9c
Show file tree
Hide file tree
Showing 25 changed files with 488 additions and 182 deletions.
49 changes: 45 additions & 4 deletions lib/chat/chat_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class ChatModel extends SafeChangeNotifier {
// The matrix dart SDK client
final Client _client;
String? get myUserId => _client.userID;
String? get homeServerId => _client.homeserver?.host;
bool isUserEvent(Event event) => myUserId == event.senderId;
bool get isLogged => _client.isLogged();
bool get encryptionEnabled => _client.encryptionEnabled;
Expand Down Expand Up @@ -129,11 +130,10 @@ class ChatModel extends SafeChangeNotifier {
return timeline.events.where((e) => !e.showAsBadge).toList();
}

Stream<List<Room>> get spacesStream => joinedUpdateStream
.map((e) => rooms.where((e) => !e.isArchived && e.isSpace).toList());
Stream<List<Room>> get spacesStream =>
syncStream.map((e) => rooms.where((e) => e.isSpace).toList());

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

RoomsFilter? _roomsFilter;
RoomsFilter? get roomsFilter => _roomsFilter;
Expand Down Expand Up @@ -277,6 +277,47 @@ class ChatModel extends SafeChangeNotifier {
}
}

Future<String?> createSpace({
required String name,
Visibility visibility = Visibility.public,
List<String>? invite,
List<Invite3pid>? invite3pid,
String? roomVersion,
String? topic,
bool waitForSync = true,
String? spaceAliasName,
required Function(String error) onFail,
required Function() onSuccess,
}) async {
_setProcessingJoinOrLeave(true);
String? spaceRoomId;
try {
printMessageInDebugMode('Creating space...');
spaceRoomId = await _client.createSpace(
name: name,
visibility: visibility,
invite: invite,
invite3pid: invite3pid,
roomVersion: roomVersion,
topic: topic,
waitForSync: waitForSync,
spaceAliasName: spaceAliasName,
);
} on Exception catch (e, s) {
printMessageInDebugMode(e, s);
onFail(e.toString());
}
if (spaceRoomId != null) {
final space = _client.getRoomById(spaceRoomId);
if (space != null) {
onSuccess();
setSelectedRoom(space);
}
}
_setProcessingJoinOrLeave(false);
return spaceRoomId;
}

Future<void> joinDirectChat(
String userId, {
required Function(String error) onFail,
Expand Down
15 changes: 10 additions & 5 deletions lib/chat/draft_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,14 @@ class DraftModel extends SafeChangeNotifier {
}

final Map<MatrixFile, XFile> _matrixFilesToXFile = {};
Future<void> addAttachment(String roomId) async {
Future<void> addAttachment(
String roomId, {
required Function(String error) onFail,
}) async {
setAttaching(true);

List<XFile>? xFiles;

if (Platform.isLinux) {
xFiles = await openFiles();
} else {
Expand All @@ -198,7 +202,8 @@ class DraftModel extends SafeChangeNotifier {
return;
}

for (var xFile in xFiles!) {
// TODO(Feichtmeier): add svg send support
for (var xFile in xFiles!.where((e) => !e.path.contains('.svg'))) {
final mime = xFile.mimeType;
final bytes = await xFile.readAsBytes();
MatrixFile matrixFile;
Expand All @@ -207,7 +212,7 @@ class DraftModel extends SafeChangeNotifier {
bytes: bytes,
name: xFile.name,
mimeType: mime,
maxDimension: 1000,
maxDimension: 2500,
nativeImplementations: _client.nativeImplementations,
);
} else if (mime?.startsWith('video') == true) {
Expand Down Expand Up @@ -307,7 +312,7 @@ class DraftModel extends SafeChangeNotifier {
} else {
final result = await FilePicker.platform.pickFiles(
allowMultiple: false,
type: FileType.any,
type: FileType.image,
);
xFile = result?.files
.map(
Expand All @@ -328,7 +333,7 @@ class DraftModel extends SafeChangeNotifier {
final mime = xFile.mimeType;
final bytes = await xFile.readAsBytes();

if (mime?.startsWith('image') == true) {
if (mime?.startsWith('image') == true && mime?.endsWith('svg') != true) {
_avatarDraftFile = await MatrixImageFile.shrink(
bytes: bytes,
name: xFile.name,
Expand Down
1 change: 1 addition & 0 deletions lib/chat/event_x.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:matrix/matrix.dart';

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

bool get showAsBadge =>
messageType == MessageTypes.Emote ||
Expand Down
3 changes: 2 additions & 1 deletion lib/chat/matrix_file_x.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import 'package:matrix/matrix.dart';

extension MatrixFileX on MatrixFile {
bool get isImage => mimeType.startsWith('image');
bool get isRegularImage => mimeType.startsWith('image') && !isSvgImage;
bool get isSvgImage => mimeType == 'image/svg+xml';
bool get isVideo => mimeType.startsWith('video');
bool get isAudio => mimeType.startsWith('audio');
}
53 changes: 31 additions & 22 deletions lib/chat/settings/settings_dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:yaru/yaru.dart';

import '../../common/date_time_x.dart';
import '../../common/view/build_context_x.dart';
import '../../common/view/common_widgets.dart';
import '../../common/view/snackbars.dart';
import '../../common/view/ui_constants.dart';
import '../../l10n/l10n.dart';
Expand Down Expand Up @@ -124,30 +125,38 @@ class _SettingsDialogState extends State<SettingsDialog> {
),
YaruSection(
headline: Text(l10n.devices),
child: Column(
children: devices
.map(
(d) => YaruTile(
trailing: d.deviceId != settingsModel.myDeviceId
? IconButton(
onPressed: () =>
settingsModel.deleteDevice(d.deviceId),
icon: Icon(
YaruIcons.trash,
color: context.colorScheme.error,
),
)
: null,
subtitle: Text(
DateTime.fromMillisecondsSinceEpoch(
d.lastSeenTs ?? 0,
).formatAndLocalize(l10n, simple: true),
),
title: SelectableText(d.displayName ?? d.deviceId),
child: devices == null
? const Center(
child: Padding(
padding: EdgeInsets.all(kBigPadding),
child: Progress(),
),
)
.toList(),
),
: Column(
children: devices
.map(
(d) => YaruTile(
trailing: d.deviceId != settingsModel.myDeviceId
? IconButton(
onPressed: () => settingsModel
.deleteDevice(d.deviceId),
icon: Icon(
YaruIcons.trash,
color: context.colorScheme.error,
),
)
: null,
subtitle: Text(
DateTime.fromMillisecondsSinceEpoch(
d.lastSeenTs ?? 0,
).formatAndLocalize(l10n, simple: true),
),
title:
SelectableText(d.displayName ?? d.deviceId),
),
)
.toList(),
),
),
],
),
Expand Down
4 changes: 2 additions & 2 deletions lib/chat/settings/settings_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ class SettingsModel extends SafeChangeNotifier {
}

String? get myDeviceId => _client.deviceID;
List<Device> _devices = [];
List<Device> get devices => _devices;
List<Device>? _devices;
List<Device>? get devices => _devices;
Future<void> getDevices() async {
_devices = await _client.getDevices() ?? [];
notifyListeners();
Expand Down
25 changes: 14 additions & 11 deletions lib/chat/timeline_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import 'package:matrix/matrix.dart';
import 'package:safe_change_notifier/safe_change_notifier.dart';

class TimelineModel extends SafeChangeNotifier {
// TIMELINES

bool _updatingTimeline = false;
bool get updatingTimeline => _updatingTimeline;
void setUpdatingTimeline(bool value) {
if (value == _updatingTimeline) return;
_updatingTimeline = value;
final Map<String, bool> _updatingTimeline = {};
bool getUpdatingTimeline(String roomId) => _updatingTimeline[roomId] == true;
void setUpdatingTimeline({
required String roomId,
required bool value,
}) {
if (_updatingTimeline[roomId] == value) return;
_updatingTimeline[roomId] = value;
notifyListeners();
}

Expand All @@ -19,17 +20,19 @@ class TimelineModel extends SafeChangeNotifier {
bool notify = true,
}) async {
if (notify) {
setUpdatingTimeline(true);
setUpdatingTimeline(roomId: timeline.room.id, value: true);
}
if (timeline.isRequestingHistory) {
setUpdatingTimeline(false);
setUpdatingTimeline(roomId: timeline.room.id, value: false);
return;
}
await timeline.requestHistory(filter: filter, historyCount: historyCount);
if (notify) {
setUpdatingTimeline(false);
setUpdatingTimeline(roomId: timeline.room.id, value: false);
}
if (!timeline.room.isArchived) {
await timeline.setReadMarker();
}
await timeline.setReadMarker();
}

bool _timelineSearchActive = false;
Expand Down
24 changes: 9 additions & 15 deletions lib/chat/view/chat_image.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';
import 'package:watch_it/watch_it.dart';
import 'package:yaru/yaru.dart';

import '../../common/view/common_widgets.dart';
import '../../common/view/image_shimmer.dart';
import '../../common/view/ui_constants.dart';
import '../chat_download_model.dart';
Expand Down Expand Up @@ -174,38 +175,35 @@ class ChatImageFuture extends StatefulWidget {
this.height,
required this.width,
this.fit,
this.fromCache = true,
this.getThumbnail = true,
});

final Event event;
final double? height;
final double width;
final BoxFit? fit;
final bool fromCache;
final bool getThumbnail;

@override
State<ChatImageFuture> createState() => _ChatImageFutureState();
}

class _ChatImageFutureState extends State<ChatImageFuture> {
late final Future<dynamic> _future;
late final Future<Uint8List?> _future;

@override
void initState() {
super.initState();
_future = widget.fromCache
? di<LocalImageModel>().downloadImage(event: widget.event)
: widget.event.downloadAndDecryptAttachment(getThumbnail: true);
_future = di<LocalImageModel>()
.downloadImage(event: widget.event, getThumbnail: widget.getThumbnail);
}

@override
Widget build(BuildContext context) => FutureBuilder(
future: _future,
builder: (context, snapshot) {
if (snapshot.hasData) {
final data = widget.fromCache
? snapshot.data
: (snapshot.data as MatrixFile).bytes;
final data = snapshot.data;
return Image.memory(
data!,
fit: widget.fit,
Expand All @@ -214,11 +212,7 @@ class _ChatImageFutureState extends State<ChatImageFuture> {
);
}

return widget.fromCache
? const ImageShimmer()
: const Center(
child: Progress(),
);
return const ImageShimmer();
},
);
}
Loading

0 comments on commit e2e4a9c

Please sign in to comment.