Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ build/.last_build_id
widgets/matrix_widget_api/build/.last_build_id
widgets/calendar/android/local.properties
.vscode/settings.json
.idea/
.idea/
/build
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'package:commet/client/client.dart' as commet;
import 'package:commet/client/matrix/components/emoticon/matrix_emoticon_component.dart';
import 'package:commet/client/matrix/matrix_mxc_image_provider.dart';
import 'package:commet/client/room.dart' show RoomVisibility;
import 'package:commet/client/room_preview.dart';
import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';
Expand Down Expand Up @@ -42,11 +41,12 @@ extension MatrixExtensions on Client {
};

var visibility = switch (joinRule) {
"public" => RoomVisibility.public,
"knock" => RoomVisibility.knock,
"invite" => RoomVisibility.invite,
"private" => RoomVisibility.private,
_ => RoomVisibility.private,
"public" => commet.RoomVisibilityPublic(),
"knock" => commet.RoomVisibilityPrivate(),
"invite" => commet.RoomVisibilityPrivate(),
"private" => commet.RoomVisibilityPrivate(),
"restricted" => commet.RoomVisibilityRestricted([]),
_ => commet.RoomVisibilityPrivate(),
};

if (name != null && id != null) {
Expand Down
38 changes: 34 additions & 4 deletions commet/lib/client/matrix/matrix_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -464,14 +464,44 @@ class MatrixClient extends Client {
];
}

var visibility = switch (args.visibility) {
final RoomVisibilityPrivate _ => matrix.Visibility.private,
final RoomVisibilityPublic _ => matrix.Visibility.public,
final RoomVisibilityRestricted _ => null,
_ => matrix.Visibility.private,
};

if (args.visibility case RoomVisibilityRestricted restricted) {
initialState ??= List.empty(growable: true);

initialState = [
...initialState,
for (var i in restricted.spaces)
matrix.StateEvent(
stateKey: i,
type: matrix.EventTypes.SpaceParent,
content: {
"canonical": true,
"via": [
if (self?.identifier.domain != null) self?.identifier.domain
]
}),
matrix.StateEvent(content: {
"join_rule": "restricted",
"allow": [
for (var i in restricted.spaces)
{"room_id": i, "type": "m.room_membership"},
]
}, type: matrix.EventTypes.RoomJoinRules)
];
}

var id = await _matrixClient.createRoom(
creationContent: creationContent,
name: args.name,
initialState: initialState,
topic: args.topic,
visibility: args.visibility == RoomVisibility.private
? matrix.Visibility.private
: matrix.Visibility.public,
visibility: visibility,
);

await _matrixClient.waitForRoomInSync(id);
Expand All @@ -492,7 +522,7 @@ class MatrixClient extends Client {
var id = await _matrixClient.createSpace(
name: args.name,
waitForSync: true,
visibility: args.visibility == RoomVisibility.private
visibility: args.visibility is RoomVisibilityPrivate
? matrix.Visibility.private
: matrix.Visibility.public,
);
Expand Down
52 changes: 51 additions & 1 deletion commet/lib/client/matrix/matrix_room.dart
Original file line number Diff line number Diff line change
Expand Up @@ -748,7 +748,7 @@ class MatrixRoom extends Room {

case matrix.JoinRules.restricted:
if (_client.spaces.any((e) =>
e.visibility == RoomVisibility.public &&
e.visibility is RoomVisibilityPublic &&
e.containsRoom(_matrixRoom.id))) {
// if any public space contains this room, consider the room public
// this is kind of flawed, because there could be public spaces we are not a member of
Expand Down Expand Up @@ -847,4 +847,54 @@ class MatrixRoom extends Room {

await tl.setReadMarker();
}

@override
RoomVisibility get visibility {
switch (_matrixRoom.joinRules) {
case matrix.JoinRules.public:
return RoomVisibilityPublic();
case matrix.JoinRules.knock:
return RoomVisibilityPrivate();
case matrix.JoinRules.invite:
return RoomVisibilityPrivate();
case matrix.JoinRules.private:
return RoomVisibilityPrivate();
case matrix.JoinRules.restricted:
return RoomVisibilityRestricted(matrixRoom
.getState(matrix.EventTypes.RoomJoinRules)
?.content
.tryGetList<Map<String, dynamic>>("allow")
?.map((i) => i.tryGet<String>("room_id"))
.nonNulls
.toList() ??
[]);
case matrix.JoinRules.knockRestricted:
return RoomVisibilityPrivate();
case null:
return RoomVisibilityPublic();
}
}

@override
Future<void> setVisibility(RoomVisibility visibility) async {
var state = switch (visibility) {
final RoomVisibilityPrivate _ => matrix.StateEvent(content: {
"join_rule": "invite",
}, type: matrix.EventTypes.RoomJoinRules),
final RoomVisibilityPublic _ => matrix.StateEvent(
content: {"join_rule": "public"},
type: matrix.EventTypes.RoomJoinRules),
final RoomVisibilityRestricted restricted => matrix.StateEvent(content: {
"join_rule": "restricted",
"allow": [
for (var i in restricted.spaces)
{"room_id": i, "type": "m.room_membership"},
]
}, type: matrix.EventTypes.RoomJoinRules),
RoomVisibility() => throw UnimplementedError(),
};

await _matrixRoom.client
.setRoomStateWithKey(_matrixRoom.id, state.type, "", state.content);
}
}
4 changes: 4 additions & 0 deletions commet/lib/client/matrix/matrix_room_permissions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,8 @@ class MatrixRoomPermissions extends Permissions {

@override
bool get canChangeRoles => room.canChangePowerLevel;

@override
bool get canChangeVisibility =>
room.canChangeStateEvent(matrix.EventTypes.RoomJoinRules);
}
26 changes: 20 additions & 6 deletions commet/lib/client/matrix/matrix_space.dart
Original file line number Diff line number Diff line change
Expand Up @@ -100,15 +100,19 @@ class MatrixSpace extends Space {
RoomVisibility get visibility {
switch (_matrixRoom.joinRules) {
case matrix.JoinRules.public:
return RoomVisibility.public;
return RoomVisibilityPublic();
case matrix.JoinRules.knock:
return RoomVisibility.knock;
return RoomVisibilityPrivate();
case matrix.JoinRules.invite:
return RoomVisibility.invite;
return RoomVisibilityPrivate();
case matrix.JoinRules.private:
return RoomVisibility.private;
default:
return RoomVisibility.private;
return RoomVisibilityPrivate();
case matrix.JoinRules.restricted:
return RoomVisibilityRestricted([]);
case matrix.JoinRules.knockRestricted:
return RoomVisibilityPrivate();
case null:
return RoomVisibilityPublic();
}
}

Expand Down Expand Up @@ -449,6 +453,16 @@ class MatrixSpace extends Space {
final update = event.rooms?.join;
if (update == null) return;

var thisRoom = update[_matrixRoom.id];
if (thisRoom != null) {
if (thisRoom.timeline?.events
?.any((i) => i.type == matrix.EventTypes.SpaceChild) ==
true) {
print("A child of this space has been modified!");
loadExtra();
}
}

for (var id in update.keys) {
if (roomsWithChildren.any((i) => i.identifier == id)) {
_updateTopLevelStatus();
Expand Down
10 changes: 10 additions & 0 deletions commet/lib/client/matrix_background/matrix_background_room.dart
Original file line number Diff line number Diff line change
Expand Up @@ -349,4 +349,14 @@ class MatrixBackgroundRoom implements Room {
// TODO: implement markAsRead
throw UnimplementedError();
}

@override
// TODO: implement visibility
RoomVisibility get visibility => throw UnimplementedError();

@override
Future<void> setVisibility(RoomVisibility visibility) {
// TODO: implement setVisibility
throw UnimplementedError();
}
}
2 changes: 2 additions & 0 deletions commet/lib/client/permissions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ abstract class Permissions {

bool get canEnableE2EE => false;

bool get canChangeVisibility => false;

bool get canEditRoomSecurity => canEnableE2EE;

bool get canChangeNotificationSettings => true;
Expand Down
50 changes: 49 additions & 1 deletion commet/lib/client/room.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'dart:async';
import 'dart:typed_data';
import 'package:collection/collection.dart';
import 'package:commet/client/client.dart';
import 'package:commet/client/components/calendar_room/calendar_room_component.dart';
import 'package:commet/client/components/direct_messages/direct_message_component.dart';
Expand All @@ -14,7 +15,50 @@ import 'package:flutter/material.dart';
import 'attachment.dart';
import 'permissions.dart';

enum RoomVisibility { public, private, invite, knock }
// enum RoomVisibility { public, private, invite, knock }

abstract class RoomVisibility {
static IconData icon(RoomVisibility? visibility) {
return switch (visibility) {
final RoomVisibilityPublic _ => Icons.public,
final RoomVisibilityPrivate _ => Icons.lock,
final RoomVisibilityRestricted _ => Icons.shield,
_ => Icons.question_mark,
};
}
}

class RoomVisibilityPrivate implements RoomVisibility {
@override
bool operator ==(Object other) {
if (other is RoomVisibilityPrivate) return true;
if (identical(this, other)) return true;
return false;
}
}

class RoomVisibilityPublic implements RoomVisibility {
@override
bool operator ==(Object other) {
if (other is RoomVisibilityPublic) return true;
if (identical(this, other)) return true;
return false;
}
}

class RoomVisibilityRestricted implements RoomVisibility {
final List<String> spaces;

@override
bool operator ==(Object other) {
if (other is! RoomVisibilityRestricted) return false;
if (identical(this, other)) return true;

return ListEquality().equals(this.spaces, other.spaces);
}

RoomVisibilityRestricted(this.spaces);
}

enum PushRule { notify, mentionsOnly, dontNotify }

Expand Down Expand Up @@ -104,6 +148,8 @@ abstract class Room {
int get displayHighlightedNotificationCount =>
pushRule != PushRule.dontNotify ? highlightedNotificationCount : 0;

RoomVisibility get visibility;

/// Send a message in this room
Future<TimelineEvent?> sendMessage({
String? message,
Expand Down Expand Up @@ -151,6 +197,8 @@ abstract class Room {
/// Set a notification push rule
Future<void> setPushRule(PushRule rule);

Future<void> setVisibility(RoomVisibility visibility);

/// Gets the color of a user based on their ID
Color getColorOfUser(String userId);

Expand Down
8 changes: 4 additions & 4 deletions commet/lib/ui/atoms/room_preview.dart
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ class RoomPreviewView extends StatelessWidget {
size: 15,
switch (previewData.visibility) {
null => Icons.lock,
RoomVisibility.public => Icons.public,
RoomVisibility.private => Icons.lock,
RoomVisibility.invite => Icons.lock,
RoomVisibility.knock => Icons.lock,
final RoomVisibilityPublic _ => Icons.public,
final RoomVisibilityPrivate _ => Icons.lock,
final RoomVisibilityRestricted _ => Icons.shield,
_ => Icons.question_mark,
})
],
),
Expand Down
45 changes: 30 additions & 15 deletions commet/lib/ui/atoms/space_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:commet/client/client.dart';
import 'package:commet/client/room_preview.dart';
import 'package:commet/client/space_child.dart';
import 'package:commet/main.dart';
import 'package:commet/ui/atoms/adaptive_context_menu.dart';
import 'package:commet/ui/atoms/room_preview_text_button.dart';
import 'package:commet/ui/atoms/room_text_button.dart';
import 'package:commet/ui/navigation/adaptive_dialog.dart';
Expand Down Expand Up @@ -166,22 +167,36 @@ class _SpaceListState extends State<SpaceList> {
Widget buildChild(SpaceChild child) {
if (child case SpaceChildSpace _) {
if (widget.currentDepth < widget.maxDepth) {
return tiamat.TextButtonExpander(child.child.displayName,
initiallyExpanded: true,
childrenPadding: const EdgeInsets.fromLTRB(2, 0, 0, 0),
iconColor: Theme.of(context).colorScheme.secondary,
textColor: Theme.of(context).colorScheme.secondary,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 0, 8),
child: SpaceList(
child.child,
isTopLevel: false,
currentDepth: widget.currentDepth + 1,
onRoomSelected: widget.onRoomSelected,
),
return AdaptiveContextMenu(
items: [
if (widget.space.permissions.canEditChildren)
tiamat.ContextMenuItem(
icon: Icons.remove_circle,
text: "Remove from ${widget.space.displayName}",
onPressed: () async {
if (await AdaptiveDialog.confirmation(context) == true) {
widget.space.removeChild(child);
}
},
)
]);
],
child: tiamat.TextButtonExpander(child.child.displayName,
initiallyExpanded: true,
childrenPadding: const EdgeInsets.fromLTRB(2, 0, 0, 0),
iconColor: Theme.of(context).colorScheme.secondary,
textColor: Theme.of(context).colorScheme.secondary,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 0, 8),
child: SpaceList(
child.child,
isTopLevel: false,
currentDepth: widget.currentDepth + 1,
onRoomSelected: widget.onRoomSelected,
),
)
]),
);
} else {
return tiamat.TextButton(widget.space.displayName);
}
Expand Down
Loading