accessiblity fixes
This commit is contained in:
parent
7775afdf38
commit
b594f5a1d1
11 changed files with 147 additions and 118 deletions
|
|
@ -4,23 +4,21 @@ import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||||
import "package:nexus/models/event.dart";
|
import "package:nexus/models/event.dart";
|
||||||
import "package:nexus/models/room.dart";
|
import "package:nexus/models/room.dart";
|
||||||
|
|
||||||
class MembersController extends AsyncNotifier<IList<Event>> {
|
class MembersController extends Notifier<IList<Event>> {
|
||||||
final Room room;
|
final Room room;
|
||||||
MembersController(this.room);
|
MembersController(this.room);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<IList<Event>> build() async =>
|
IList<Event> build() => (room.state["m.room.member"]?.values ?? [])
|
||||||
(room.state["m.room.member"]?.values ?? [])
|
|
||||||
.map(
|
.map(
|
||||||
(eventRowId) => room.events.firstWhereOrNull(
|
(eventRowId) =>
|
||||||
(event) => event.rowId == eventRowId,
|
room.events.firstWhereOrNull((event) => event.rowId == eventRowId),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.nonNulls
|
.nonNulls
|
||||||
.where((member) => member.content["membership"] == "join")
|
.where((member) => member.content["membership"] == "join")
|
||||||
.toIList();
|
.toIList();
|
||||||
|
|
||||||
static final provider = AsyncNotifierProvider.family
|
static final provider = NotifierProvider.family
|
||||||
.autoDispose<MembersController, IList<Event>, Room>(
|
.autoDispose<MembersController, IList<Event>, Room>(
|
||||||
MembersController.new,
|
MembersController.new,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -37,9 +37,7 @@ class MessageController extends AsyncNotifier<Message?> {
|
||||||
|
|
||||||
if (!ref.mounted) return null;
|
if (!ref.mounted) return null;
|
||||||
|
|
||||||
final members = await ref.watch(
|
final members = ref.watch(MembersController.provider(config.room));
|
||||||
MembersController.provider(config.room).future,
|
|
||||||
);
|
|
||||||
final author = members.firstWhereOrNull(
|
final author = members.firstWhereOrNull(
|
||||||
(member) => member.stateKey == event.authorId,
|
(member) => member.stateKey == event.authorId,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ class RoomChatController extends AsyncNotifier<ChatController> {
|
||||||
@override
|
@override
|
||||||
Future<ChatController> build() async {
|
Future<ChatController> build() async {
|
||||||
final client = ref.watch(ClientController.provider.notifier);
|
final client = ref.watch(ClientController.provider.notifier);
|
||||||
final room = ref.read(RoomsController.provider)[roomId];
|
var room = ref.read(RoomsController.provider)[roomId];
|
||||||
if (room == null) return InMemoryChatController();
|
if (room == null) return InMemoryChatController();
|
||||||
|
|
||||||
final state = await client.getRoomState(
|
final state = await client.getRoomState(
|
||||||
|
|
@ -59,13 +59,16 @@ class RoomChatController extends AsyncNotifier<ChatController> {
|
||||||
const ISet.empty(),
|
const ISet.empty(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
room = ref.read(RoomsController.provider)[roomId];
|
||||||
|
if (room == null) return InMemoryChatController();
|
||||||
|
|
||||||
final messages = await ref.watch(
|
final messages = await ref.watch(
|
||||||
MessagesController.provider(
|
MessagesController.provider(
|
||||||
MessagesConfig(
|
MessagesConfig(
|
||||||
room: room,
|
room: room,
|
||||||
events: room.timeline
|
events: room.timeline
|
||||||
.map(
|
.map(
|
||||||
(timelineRowTuple) => room.events.firstWhereOrNull(
|
(timelineRowTuple) => room!.events.firstWhereOrNull(
|
||||||
(event) => event.rowId == timelineRowTuple.eventRowId,
|
(event) => event.rowId == timelineRowTuple.eventRowId,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -91,7 +94,7 @@ class RoomChatController extends AsyncNotifier<ChatController> {
|
||||||
} else {
|
} else {
|
||||||
final message = await ref.watch(
|
final message = await ref.watch(
|
||||||
MessageController.provider(
|
MessageController.provider(
|
||||||
MessageConfig(event: event, room: room, includeEdits: true),
|
MessageConfig(event: event, room: room!, includeEdits: true),
|
||||||
).future,
|
).future,
|
||||||
);
|
);
|
||||||
if (event.relationType == "m.replace") {
|
if (event.relationType == "m.replace") {
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,7 @@ class LoginPage extends HookConsumerWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
IconButton.filled(
|
IconButton.filled(
|
||||||
|
tooltip: "Confirm homeserver choice",
|
||||||
onPressed: isLoading.value
|
onPressed: isLoading.value
|
||||||
? null
|
? null
|
||||||
: () => setHomeserver(Uri.tryParse(homeserverUrl.text)),
|
: () => setHomeserver(Uri.tryParse(homeserverUrl.text)),
|
||||||
|
|
@ -143,6 +144,7 @@ class LoginPage extends HookConsumerWidget {
|
||||||
? null
|
? null
|
||||||
: () => setHomeserver(homeserver.url),
|
: () => setHomeserver(homeserver.url),
|
||||||
trailing: IconButton(
|
trailing: IconButton(
|
||||||
|
tooltip: "Launch homeserver info page",
|
||||||
onPressed: () => launch(homeserver.url),
|
onPressed: () => launch(homeserver.url),
|
||||||
icon: Icon(Icons.info_outline),
|
icon: Icon(Icons.info_outline),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -49,10 +49,15 @@ class Appbar extends StatelessWidget implements PreferredSizeWidget {
|
||||||
if (!(Platform.isAndroid || Platform.isIOS)) ...[
|
if (!(Platform.isAndroid || Platform.isIOS)) ...[
|
||||||
if (!Platform.isLinux)
|
if (!Platform.isLinux)
|
||||||
IconButton(
|
IconButton(
|
||||||
|
tooltip: "Maximize window",
|
||||||
onPressed: maximize,
|
onPressed: maximize,
|
||||||
icon: const Icon(Icons.fullscreen),
|
icon: const Icon(Icons.fullscreen),
|
||||||
),
|
),
|
||||||
IconButton(onPressed: () => exit(0), icon: const Icon(Icons.close)),
|
IconButton(
|
||||||
|
tooltip: "Close window",
|
||||||
|
onPressed: () => exit(0),
|
||||||
|
icon: const Icon(Icons.close),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,27 @@ class ChatBox extends HookConsumerWidget {
|
||||||
spacing: 8,
|
spacing: 8,
|
||||||
children: [
|
children: [
|
||||||
PopupMenuButton(
|
PopupMenuButton(
|
||||||
itemBuilder: (context) => [],
|
tooltip: "Add media",
|
||||||
|
itemBuilder: (context) => [
|
||||||
|
PopupMenuItem(
|
||||||
|
child: ListTile(
|
||||||
|
title: Text("Camera"),
|
||||||
|
leading: Icon(Icons.add_a_photo),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
PopupMenuItem(
|
||||||
|
child: ListTile(
|
||||||
|
title: Text("Gallery"),
|
||||||
|
leading: Icon(Icons.add_photo_alternate),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
PopupMenuItem(
|
||||||
|
child: ListTile(
|
||||||
|
title: Text("Files"),
|
||||||
|
leading: Icon(Icons.add_photo_alternate),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
icon: Icon(Icons.add),
|
icon: Icon(Icons.add),
|
||||||
// enabled: room.canSendDefaultMessages, TODO: Permissions check
|
// enabled: room.canSendDefaultMessages, TODO: Permissions check
|
||||||
),
|
),
|
||||||
|
|
@ -138,6 +158,7 @@ class ChatBox extends HookConsumerWidget {
|
||||||
onPressed: send,
|
onPressed: send,
|
||||||
// onPressed: room.canSendDefaultMessages ? send : null,
|
// onPressed: room.canSendDefaultMessages ? send : null,
|
||||||
icon: Icon(Icons.send),
|
icon: Icon(Icons.send),
|
||||||
|
tooltip: "Send message",
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
import "package:hooks_riverpod/hooks_riverpod.dart";
|
import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||||
import "package:nexus/controllers/members_controller.dart";
|
import "package:nexus/controllers/members_controller.dart";
|
||||||
import "package:nexus/helpers/extensions/better_when.dart";
|
|
||||||
import "package:nexus/models/room.dart";
|
import "package:nexus/models/room.dart";
|
||||||
import "package:nexus/widgets/avatar_or_hash.dart";
|
import "package:nexus/widgets/avatar_or_hash.dart";
|
||||||
|
|
||||||
|
|
@ -10,12 +9,11 @@ class MemberList extends ConsumerWidget {
|
||||||
const MemberList(this.room, {super.key});
|
const MemberList(this.room, {super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) => Drawer(
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final members = ref.watch(MembersController.provider(room));
|
||||||
|
return Drawer(
|
||||||
shape: Border(),
|
shape: Border(),
|
||||||
child: ref
|
child: ListView(
|
||||||
.watch(MembersController.provider(room))
|
|
||||||
.betterWhen(
|
|
||||||
data: (members) => ListView(
|
|
||||||
children: [
|
children: [
|
||||||
AppBar(
|
AppBar(
|
||||||
scrolledUnderElevation: 0,
|
scrolledUnderElevation: 0,
|
||||||
|
|
@ -27,6 +25,7 @@ class MemberList extends ConsumerWidget {
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: Scaffold.of(context).closeEndDrawer,
|
onPressed: Scaffold.of(context).closeEndDrawer,
|
||||||
icon: Icon(Icons.close),
|
icon: Icon(Icons.close),
|
||||||
|
tooltip: "Close member list",
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
@ -53,6 +52,6 @@ class MemberList extends ConsumerWidget {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ import "package:flutter/material.dart";
|
||||||
import "package:hooks_riverpod/hooks_riverpod.dart";
|
import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||||
import "package:nexus/controllers/members_controller.dart";
|
import "package:nexus/controllers/members_controller.dart";
|
||||||
import "package:nexus/controllers/rooms_controller.dart";
|
import "package:nexus/controllers/rooms_controller.dart";
|
||||||
import "package:nexus/helpers/extensions/better_when.dart";
|
|
||||||
import "package:nexus/models/room.dart";
|
import "package:nexus/models/room.dart";
|
||||||
import "package:nexus/widgets/avatar_or_hash.dart";
|
import "package:nexus/widgets/avatar_or_hash.dart";
|
||||||
import "package:nexus/widgets/loading.dart";
|
import "package:nexus/widgets/loading.dart";
|
||||||
|
|
@ -32,28 +31,22 @@ class MentionOverlay extends ConsumerWidget {
|
||||||
color: Theme.of(context).colorScheme.surfaceContainerHigh,
|
color: Theme.of(context).colorScheme.surfaceContainerHigh,
|
||||||
padding: EdgeInsets.all(8),
|
padding: EdgeInsets.all(8),
|
||||||
child: switch (triggerCharacter) {
|
child: switch (triggerCharacter) {
|
||||||
"@" =>
|
"@" => Consumer(
|
||||||
ref
|
builder: (_, ref, _) {
|
||||||
.watch(MembersController.provider(room))
|
final members = ref.watch(MembersController.provider(room));
|
||||||
.betterWhen(
|
return ListView(
|
||||||
data: (members) => ListView(
|
|
||||||
children:
|
children:
|
||||||
(query.isEmpty
|
(query.isEmpty
|
||||||
? members
|
? members
|
||||||
: members.where(
|
: members.where(
|
||||||
(member) =>
|
(member) =>
|
||||||
member.stateKey
|
member.stateKey?.toLowerCase().contains(
|
||||||
?.toLowerCase()
|
|
||||||
.contains(
|
|
||||||
query.toLowerCase(),
|
query.toLowerCase(),
|
||||||
) ==
|
) ==
|
||||||
true ||
|
true ||
|
||||||
(member.content["displayname"]
|
(member.content["displayname"] as String?)
|
||||||
as String?)
|
|
||||||
?.toLowerCase()
|
?.toLowerCase()
|
||||||
.contains(
|
.contains(query.toLowerCase()) ==
|
||||||
query.toLowerCase(),
|
|
||||||
) ==
|
|
||||||
true,
|
true,
|
||||||
))
|
))
|
||||||
.map(
|
.map(
|
||||||
|
|
@ -84,7 +77,8 @@ class MentionOverlay extends ConsumerWidget {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
),
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
"#" => ListView(
|
"#" => ListView(
|
||||||
children:
|
children:
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,8 @@ class RelationPreview extends ConsumerWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
|
tooltip:
|
||||||
|
"Cancel ${relationType == RelationType.edit ? "edit" : "reply"}",
|
||||||
onPressed: onDismiss,
|
onPressed: onDismiss,
|
||||||
icon: Icon(Icons.close),
|
icon: Icon(Icons.close),
|
||||||
iconSize: 20,
|
iconSize: 20,
|
||||||
|
|
|
||||||
|
|
@ -52,9 +52,14 @@ class RoomAppbar extends StatelessWidget implements PreferredSizeWidget {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(onPressed: () {}, icon: Icon(Icons.push_pin)),
|
IconButton(
|
||||||
|
onPressed: null,
|
||||||
|
icon: Icon(Icons.push_pin),
|
||||||
|
tooltip: "Open pinned messages",
|
||||||
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () => onOpenMemberList(context),
|
onPressed: () => onOpenMemberList(context),
|
||||||
|
tooltip: "Open member list",
|
||||||
icon: Icon(Icons.people),
|
icon: Icon(Icons.people),
|
||||||
),
|
),
|
||||||
RoomMenu(room),
|
RoomMenu(room),
|
||||||
|
|
|
||||||
|
|
@ -155,6 +155,7 @@ class Sidebar extends HookConsumerWidget {
|
||||||
icon: Icon(Icons.add),
|
icon: Icon(Icons.add),
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
|
tooltip: "Explore other rooms",
|
||||||
onPressed: () => showDialog(
|
onPressed: () => showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => AlertDialog(title: Text("To-do")),
|
builder: (context) => AlertDialog(title: Text("To-do")),
|
||||||
|
|
@ -162,6 +163,7 @@ class Sidebar extends HookConsumerWidget {
|
||||||
icon: Icon(Icons.explore),
|
icon: Icon(Icons.explore),
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
|
tooltip: "Open settings",
|
||||||
onPressed: () => Navigator.of(
|
onPressed: () => Navigator.of(
|
||||||
context,
|
context,
|
||||||
).push(MaterialPageRoute(builder: (_) => SettingsPage())),
|
).push(MaterialPageRoute(builder: (_) => SettingsPage())),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue