Add powerlevel checks
This commit is contained in:
parent
63535fb462
commit
f38715c8ef
6 changed files with 119 additions and 22 deletions
48
lib/controllers/power_level_controller.dart
Normal file
48
lib/controllers/power_level_controller.dart
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
import "package:collection/collection.dart";
|
||||||
|
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||||
|
import "package:nexus/controllers/client_state_controller.dart";
|
||||||
|
import "package:nexus/controllers/selected_room_controller.dart";
|
||||||
|
import "package:nexus/models/configs/power_level_config.dart";
|
||||||
|
import "package:nexus/models/requests/membership_action.dart";
|
||||||
|
|
||||||
|
class PowerLevelController extends Notifier<bool> {
|
||||||
|
final PowerLevelConfig config;
|
||||||
|
PowerLevelController(this.config);
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool build() {
|
||||||
|
final room = ref.watch(SelectedRoomController.provider);
|
||||||
|
final event = room?.events.firstWhereOrNull(
|
||||||
|
(event) => event.rowId == room.state["m.room.power_levels"]?[""],
|
||||||
|
);
|
||||||
|
final user = ref.watch(ClientStateController.provider)?.userId;
|
||||||
|
if (event == null || user == null) return false;
|
||||||
|
|
||||||
|
final users = (event.content["users"] as Map<String, dynamic>? ?? {});
|
||||||
|
final events = (event.content["events"] as Map<String, dynamic>? ?? {});
|
||||||
|
|
||||||
|
final userLevel = users.containsKey(user)
|
||||||
|
? (users[user] as int)
|
||||||
|
: (event.content["users_default"] as int? ?? 0);
|
||||||
|
|
||||||
|
final requiredLevel = switch (config.action) {
|
||||||
|
MembershipAction.ban ||
|
||||||
|
MembershipAction.unban => (event.content["ban"] as int? ?? 50),
|
||||||
|
MembershipAction.kick => (event.content["kick"] as int? ?? 50),
|
||||||
|
MembershipAction.invite => (event.content["invite"] as int? ?? 0),
|
||||||
|
null =>
|
||||||
|
events.containsKey(config.eventType)
|
||||||
|
? (events[config.eventType] as int)
|
||||||
|
: (config.isStateEvent
|
||||||
|
? (event.content["state_default"] as int? ?? 50)
|
||||||
|
: (event.content["events_default"] as int? ?? 0)),
|
||||||
|
};
|
||||||
|
|
||||||
|
return userLevel >= requiredLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final provider = NotifierProvider.autoDispose
|
||||||
|
.family<PowerLevelController, bool, PowerLevelConfig>(
|
||||||
|
PowerLevelController.new,
|
||||||
|
);
|
||||||
|
}
|
||||||
16
lib/models/configs/power_level_config.dart
Normal file
16
lib/models/configs/power_level_config.dart
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
import "package:freezed_annotation/freezed_annotation.dart";
|
||||||
|
import "package:nexus/models/requests/membership_action.dart";
|
||||||
|
part "power_level_config.freezed.dart";
|
||||||
|
part "power_level_config.g.dart";
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class PowerLevelConfig with _$PowerLevelConfig {
|
||||||
|
const factory PowerLevelConfig({
|
||||||
|
@Default(false) bool isStateEvent,
|
||||||
|
required String eventType,
|
||||||
|
MembershipAction? action,
|
||||||
|
}) = _PowerLevelConfig;
|
||||||
|
|
||||||
|
factory PowerLevelConfig.fromJson(Map<String, Object?> json) =>
|
||||||
|
_$PowerLevelConfigFromJson(json);
|
||||||
|
}
|
||||||
4
lib/models/requests/membership_action.dart
Normal file
4
lib/models/requests/membership_action.dart
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
import "package:freezed_annotation/freezed_annotation.dart";
|
||||||
|
|
||||||
|
@JsonEnum()
|
||||||
|
enum MembershipAction { ban, kick, unban, invite }
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import "package:freezed_annotation/freezed_annotation.dart";
|
import "package:freezed_annotation/freezed_annotation.dart";
|
||||||
|
import "package:nexus/models/requests/membership_action.dart";
|
||||||
part "set_membership_request.freezed.dart";
|
part "set_membership_request.freezed.dart";
|
||||||
part "set_membership_request.g.dart";
|
part "set_membership_request.g.dart";
|
||||||
|
|
||||||
|
|
@ -16,6 +17,3 @@ abstract class SetMembershipRequest with _$SetMembershipRequest {
|
||||||
factory SetMembershipRequest.fromJson(Map<String, Object?> json) =>
|
factory SetMembershipRequest.fromJson(Map<String, Object?> json) =>
|
||||||
_$SetMembershipRequestFromJson(json);
|
_$SetMembershipRequestFromJson(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonEnum()
|
|
||||||
enum MembershipAction { ban, kick, unban, invite }
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ import "package:flutter_chat_core/flutter_chat_core.dart";
|
||||||
import "package:flutter_hooks/flutter_hooks.dart";
|
import "package:flutter_hooks/flutter_hooks.dart";
|
||||||
import "package:fluttertagger/fluttertagger.dart";
|
import "package:fluttertagger/fluttertagger.dart";
|
||||||
import "package:hooks_riverpod/hooks_riverpod.dart";
|
import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||||
|
import "package:nexus/controllers/power_level_controller.dart";
|
||||||
|
import "package:nexus/models/configs/power_level_config.dart";
|
||||||
import "package:nexus/models/relation_type.dart";
|
import "package:nexus/models/relation_type.dart";
|
||||||
import "package:nexus/widgets/chat_page/composer/mention_overlay.dart";
|
import "package:nexus/widgets/chat_page/composer/mention_overlay.dart";
|
||||||
import "package:nexus/widgets/chat_page/composer/relation_preview.dart";
|
import "package:nexus/widgets/chat_page/composer/relation_preview.dart";
|
||||||
|
|
@ -42,6 +44,7 @@ class ChatBox extends HookConsumerWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
void send() {
|
void send() {
|
||||||
|
if (controller.value.text.isEmpty) return;
|
||||||
onSend(
|
onSend(
|
||||||
controller.value.formattedText,
|
controller.value.formattedText,
|
||||||
shouldMention: shouldMention.value,
|
shouldMention: shouldMention.value,
|
||||||
|
|
@ -69,6 +72,12 @@ class ChatBox extends HookConsumerWidget {
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final canSendMessages = ref.watch(
|
||||||
|
PowerLevelController.provider(
|
||||||
|
PowerLevelConfig(eventType: "m.room.message"),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
return Positioned(
|
return Positioned(
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
|
|
@ -95,6 +104,7 @@ class ChatBox extends HookConsumerWidget {
|
||||||
children: [
|
children: [
|
||||||
PopupMenuButton(
|
PopupMenuButton(
|
||||||
tooltip: "Add media",
|
tooltip: "Add media",
|
||||||
|
enabled: canSendMessages,
|
||||||
itemBuilder: (context) => [
|
itemBuilder: (context) => [
|
||||||
PopupMenuItem(
|
PopupMenuItem(
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
|
|
@ -136,12 +146,11 @@ class ChatBox extends HookConsumerWidget {
|
||||||
},
|
},
|
||||||
triggerCharacterAndStyles: {"@": style, "#": style},
|
triggerCharacterAndStyles: {"@": style, "#": style},
|
||||||
builder: (context, key) => TextFormField(
|
builder: (context, key) => TextFormField(
|
||||||
// enabled: room.canSendDefaultMessages,
|
enabled: canSendMessages,
|
||||||
maxLines: 12,
|
maxLines: 12,
|
||||||
minLines: 1,
|
minLines: 1,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText:
|
hintText: canSendMessages
|
||||||
true // TODO: room.canSendDefaultMessages
|
|
||||||
? "Your message here..."
|
? "Your message here..."
|
||||||
: "You don't have permission to send messages in this room...",
|
: "You don't have permission to send messages in this room...",
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
|
|
@ -156,7 +165,7 @@ class ChatBox extends HookConsumerWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: send,
|
onPressed: !canSendMessages ? null : send,
|
||||||
// onPressed: room.canSendDefaultMessages ? send : null,
|
// onPressed: room.canSendDefaultMessages ? send : null,
|
||||||
icon: Icon(Icons.send),
|
icon: Icon(Icons.send),
|
||||||
tooltip: "Send message",
|
tooltip: "Send message",
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,14 @@ import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||||
import "package:intl/intl.dart";
|
import "package:intl/intl.dart";
|
||||||
import "package:nexus/controllers/client_controller.dart";
|
import "package:nexus/controllers/client_controller.dart";
|
||||||
import "package:nexus/controllers/client_state_controller.dart";
|
import "package:nexus/controllers/client_state_controller.dart";
|
||||||
|
import "package:nexus/controllers/power_level_controller.dart";
|
||||||
import "package:nexus/controllers/profile_controller.dart";
|
import "package:nexus/controllers/profile_controller.dart";
|
||||||
import "package:nexus/controllers/selected_room_controller.dart";
|
import "package:nexus/controllers/selected_room_controller.dart";
|
||||||
import "package:nexus/helpers/extensions/better_when.dart";
|
import "package:nexus/helpers/extensions/better_when.dart";
|
||||||
|
import "package:nexus/models/configs/power_level_config.dart";
|
||||||
import "package:nexus/models/membership.dart";
|
import "package:nexus/models/membership.dart";
|
||||||
import "package:nexus/models/membership_status.dart";
|
import "package:nexus/models/membership_status.dart";
|
||||||
|
import "package:nexus/models/requests/membership_action.dart";
|
||||||
import "package:nexus/models/requests/set_membership_request.dart";
|
import "package:nexus/models/requests/set_membership_request.dart";
|
||||||
import "package:nexus/widgets/avatar_or_hash.dart";
|
import "package:nexus/widgets/avatar_or_hash.dart";
|
||||||
import "package:nexus/main.dart";
|
import "package:nexus/main.dart";
|
||||||
|
|
@ -150,7 +153,17 @@ class UserPopover extends ConsumerWidget {
|
||||||
runSpacing: 8,
|
runSpacing: 8,
|
||||||
children: [
|
children: [
|
||||||
FilledButton.icon(onPressed: null, label: Text("Message")),
|
FilledButton.icon(onPressed: null, label: Text("Message")),
|
||||||
if (member.status == MembershipStatus.join ||
|
|
||||||
|
if (ref.watch(
|
||||||
|
PowerLevelController.provider(
|
||||||
|
PowerLevelConfig(
|
||||||
|
eventType: "m.room.member",
|
||||||
|
action: MembershipAction.kick,
|
||||||
|
isStateEvent: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
) &&
|
||||||
|
member.status == MembershipStatus.join ||
|
||||||
member.status == MembershipStatus.invite)
|
member.status == MembershipStatus.invite)
|
||||||
FilledButton.icon(
|
FilledButton.icon(
|
||||||
onPressed: () => showMembershipDialog(MembershipAction.kick),
|
onPressed: () => showMembershipDialog(MembershipAction.kick),
|
||||||
|
|
@ -164,24 +177,33 @@ class UserPopover extends ConsumerWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
ElevatedButton.icon(
|
if (ref.watch(
|
||||||
onPressed: () => showMembershipDialog(
|
PowerLevelController.provider(
|
||||||
member.status == MembershipStatus.ban
|
PowerLevelConfig(
|
||||||
? MembershipAction.unban
|
eventType: "m.room.member",
|
||||||
: MembershipAction.ban,
|
action: MembershipAction.ban,
|
||||||
),
|
isStateEvent: true,
|
||||||
label: Text(
|
),
|
||||||
member.status == MembershipStatus.ban ? "Unban" : "Ban",
|
),
|
||||||
),
|
))
|
||||||
style: ButtonStyle(
|
ElevatedButton.icon(
|
||||||
backgroundColor: WidgetStatePropertyAll(
|
onPressed: () => showMembershipDialog(
|
||||||
theme.colorScheme.errorContainer,
|
member.status == MembershipStatus.ban
|
||||||
),
|
? MembershipAction.unban
|
||||||
foregroundColor: WidgetStatePropertyAll(
|
: MembershipAction.ban,
|
||||||
theme.colorScheme.onErrorContainer,
|
),
|
||||||
|
label: Text(
|
||||||
|
member.status == MembershipStatus.ban ? "Unban" : "Ban",
|
||||||
|
),
|
||||||
|
style: ButtonStyle(
|
||||||
|
backgroundColor: WidgetStatePropertyAll(
|
||||||
|
theme.colorScheme.errorContainer,
|
||||||
|
),
|
||||||
|
foregroundColor: WidgetStatePropertyAll(
|
||||||
|
theme.colorScheme.onErrorContainer,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue