Skip to content

Commit

Permalink
New menu icons for read receipts
Browse files Browse the repository at this point in the history
 krille-chan#38 Fluffy Chat: moved read receipts to a subfolder and added filter to filter users according to given or not given read receipts

 krille-chan#38 FluffyChat: hide user who has give read receipt in list of users and read receipts

 krille-chan#44 FluffyChat: remove required from param onReadReceipt in class Message

 krille-chan#34 FluffyChat: only admin is allowed to request read receipt

fix errors probably introduced by my rebase

chat list header: missed vrouter dependency
  • Loading branch information
Matthias committed Dec 20, 2022
1 parent 88f4ada commit 646168d
Show file tree
Hide file tree
Showing 15 changed files with 378 additions and 132 deletions.
2 changes: 1 addition & 1 deletion assets/l10n/intl_de.arb
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
"type": "text",
"placeholders": {}
},
"allChats": "Alle Chats",
"allChats": "Räume",
"@allChats": {
"type": "text",
"placeholders": {}
Expand Down
2 changes: 1 addition & 1 deletion assets/l10n/intl_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
"type": "text",
"placeholders": {}
},
"allChats": "All chats",
"allChats": "Rooms",
"@allChats": {
"type": "text",
"placeholders": {}
Expand Down
9 changes: 9 additions & 0 deletions lib/config/routes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import 'package:fluffychat/pages/login/login.dart';
import 'package:fluffychat/pages/new_group/new_group.dart';
import 'package:fluffychat/pages/new_private_chat/new_private_chat.dart';
import 'package:fluffychat/pages/new_space/new_space.dart';
import 'package:fluffychat/pages/read_receipt_overview/read_receipt_overview.dart';
import 'package:fluffychat/pages/settings/settings.dart';
import 'package:fluffychat/pages/settings_3pid/settings_3pid.dart';
import 'package:fluffychat/pages/settings_account/settings_account.dart';
Expand Down Expand Up @@ -57,6 +58,10 @@ class AppRoutes {
path: '/stories/create',
widget: const AddStoryPage(),
),
VWidget(
path: '/readreceipts',
widget: const ReadReceiptOverviewPage(),
),
VWidget(
path: '/stories/:roomid',
widget: const StoryPage(),
Expand Down Expand Up @@ -135,6 +140,10 @@ class AppRoutes {
buildTransition: _fadeTransition,
widget: const AddStoryPage(),
),
VWidget(
path: '/readreceipts',
widget: const ReadReceiptOverviewPage(),
),
VWidget(
path: '/stories/:roomid',
buildTransition: _fadeTransition,
Expand Down
42 changes: 33 additions & 9 deletions lib/pages/chat/chat.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import 'package:vrouter/vrouter.dart';
import 'package:fluffychat/config/edu_settings.dart';
import 'package:fluffychat/pages/chat/chat_view.dart';
import 'package:fluffychat/pages/chat/event_info_dialog.dart';
import 'package:fluffychat/pages/chat/read_receipt_list_dialog.dart';
import 'package:fluffychat/pages/chat/read_receipt/read_receipt_list_dialog.dart';
import 'package:fluffychat/pages/chat/recording_dialog.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions.dart/event_extension.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions.dart/ios_badge_client_extension.dart';
Expand All @@ -35,8 +35,6 @@ import 'send_file_dialog.dart';
import 'send_location_dialog.dart';
import 'sticker_picker_dialog.dart';

// edu imports

class Chat extends StatefulWidget {
final Widget? sideView;

Expand Down Expand Up @@ -66,7 +64,7 @@ class ChatController extends State<Chat> {
bool currentlyTyping = false;
bool dragging = false;

bool requirereadReceipt = false;
bool requireReadReceipt = false;
String? lastSentEventId;

void onDragEntered(_) => setState(() => dragging = true);
Expand Down Expand Up @@ -292,17 +290,22 @@ class ChatController extends State<Chat> {
}

Map<String, String>? readReceipt = null;
if (requirereadReceipt) {
if (requireReadReceipt) {
readReceipt = {EduSettings.eduNamespace: EduSettings.requireReadReceipt};
}

// ignore: unawaited_futures
await room!.sendTextEvent(sendController.text,
String? eventId = await room!.sendTextEvent(sendController.text,
inReplyTo: replyEvent,
editEventId: editEvent?.eventId,
parseCommands: parseCommands,
additionalContent: readReceipt);

if (requireReadReceipt && eventId != null) {
final client = Matrix.of(context).client;
await client.database?.addReadReceiptRequiredEvent(eventId, room!.id);
}

sendController.value = TextEditingValue(
text: pendingText,
selection: const TextSelection.collapsed(offset: 0),
Expand All @@ -313,7 +316,7 @@ class ChatController extends State<Chat> {
replyEvent = null;
editEvent = null;
pendingText = '';
requirereadReceipt = false;
requireReadReceipt = false;
});
}

Expand Down Expand Up @@ -492,10 +495,15 @@ class ChatController extends State<Chat> {

void toggleReadReceiptAction() {
setState(() {
requirereadReceipt = !requirereadReceipt;
requireReadReceipt = !requireReadReceipt;
});
}

bool showReadReceiptButton() {
// only admin is allowed to request read receipt
return room!.ownPowerLevel == 100;
}

void onReadReceipt(Event event) async {
final requiresReadReceipt =
event.content.keys.contains(EduSettings.eduNamespace) &&
Expand All @@ -519,7 +527,7 @@ class ChatController extends State<Chat> {
userId)
.toList();

if (userReadReceipt.length < 1) {
if (userReadReceipt.isEmpty) {
await room!.sendReadReceipt(event.eventId, userId);
}
}
Expand Down Expand Up @@ -637,6 +645,12 @@ class ChatController extends State<Chat> {
});
}

void showReadReceiptAction() {
if (selectedEvents.isNotEmpty) {
selectedEvents.first.showReadReceiptListDialog(context, room!, timeline!);
}
}

List<Client?> get currentRoomBundle {
final clients = matrix!.currentBundle!;
clients.removeWhere((c) => c!.getRoomById(roomId!) == null);
Expand All @@ -660,6 +674,16 @@ class ChatController extends State<Chat> {
.any((cl) => selectedEvents.first.senderId == cl!.userID);
}

bool get canViewReadReceiptsOfSelectedEvents {
if (selectedEvents.length == 1) {
return selectedEvents.first.content.keys
.contains(EduSettings.eduNamespace) &&
selectedEvents.first.content[EduSettings.eduNamespace] ==
EduSettings.requireReadReceipt;
}
return false;
}

void forwardEventsAction() async {
if (selectedEvents.length == 1) {
Matrix.of(context).shareContent =
Expand Down
33 changes: 17 additions & 16 deletions lib/pages/chat/chat_input_row.dart
Original file line number Diff line number Diff line change
Expand Up @@ -264,23 +264,24 @@ class ChatInputRow extends StatelessWidget {
alignment: Alignment.center,
child: Row(
children: [
controller.requirereadReceipt
? IconButton(
tooltip: L10n.of(context)!.readReceiptOff,
icon: const Icon(
Icons.mark_chat_read,
color: AppConfig.primaryColor,
if (controller.showReadReceiptButton())
controller.requireReadReceipt
? IconButton(
tooltip: L10n.of(context)!.readReceiptOff,
icon: const Icon(
Icons.mark_chat_read,
color: AppConfig.primaryColor,
),
onPressed: controller.toggleReadReceiptAction,
)
: IconButton(
tooltip: L10n.of(context)!.readReceiptOn,
icon: const Icon(
Icons.mark_chat_read_outlined,
color: Colors.grey,
),
onPressed: controller.toggleReadReceiptAction,
),
onPressed: controller.toggleReadReceiptAction,
)
: IconButton(
tooltip: L10n.of(context)!.readReceiptOn,
icon: const Icon(
Icons.mark_chat_read_outlined,
color: Colors.grey,
),
onPressed: controller.toggleReadReceiptAction,
),
IconButton(
icon: const Icon(Icons.send_outlined),
onPressed: controller.send,
Expand Down
6 changes: 6 additions & 0 deletions lib/pages/chat/chat_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ class ChatView extends StatelessWidget {
tooltip: L10n.of(context)!.redactMessage,
onPressed: controller.redactEventsAction,
),
if (controller.canViewReadReceiptsOfSelectedEvents)
IconButton(
icon: const Icon(Icons.mark_chat_read_outlined),
tooltip: L10n.of(context)!.readReceipts,
onPressed: controller.showReadReceiptAction,
),
IconButton(
icon: const Icon(Icons.push_pin_outlined),
onPressed: controller.pinEvent,
Expand Down
7 changes: 4 additions & 3 deletions lib/pages/chat/events/message.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class Message extends StatelessWidget {
final void Function(Event)? onInfoTab;
final void Function(String)? scrollToEventId;
final void Function(SwipeDirection) onSwipe;
final void Function(Event) onReadReceipt;
final void Function(Event)? onReadReceipt;
final bool longPressSelect;
final bool selected;
final Timeline timeline;
Expand All @@ -40,7 +40,7 @@ class Message extends StatelessWidget {
this.onAvatarTab,
this.scrollToEventId,
required this.onSwipe,
required this.onReadReceipt,
this.onReadReceipt,
this.selected = false,
required this.timeline,
Key? key})
Expand Down Expand Up @@ -329,7 +329,8 @@ class Message extends StatelessWidget {
Icons.mark_chat_read,
color: AppConfig.primaryColor,
),
onPressed: () => onReadReceipt(displayEvent),
onPressed: () =>
{if (onReadReceipt != null) onReadReceipt!(displayEvent)},
),
)
];
Expand Down
84 changes: 84 additions & 0 deletions lib/pages/chat/read_receipt/read_receipt_list.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import 'package:flutter/cupertino.dart';

import 'package:matrix/matrix.dart';

import 'package:fluffychat/pages/chat/read_receipt/read_receipt_list_view.dart';

class ReadReceiptList extends StatefulWidget {
final Event event;
final Room room;
final Timeline timeline;

const ReadReceiptList(
{required this.event,
required this.room,
required this.timeline,
Key? key})
: super(key: key);

@override
ReadReceiptListController createState() =>
ReadReceiptListController(event, room, timeline);
}

class ReadReceiptListController extends State<ReadReceiptList> {
Event? event;
Room? room;
Timeline? timeline;
List<User> members = [];
Set<Event>? readReceipts;
String filter = "all";

ReadReceiptListController(
Event this.event, Room this.room, Timeline this.timeline);

@override
void initState() {
members = room!.getParticipants();
readReceipts =
event!.aggregatedEvents(timeline!, RelationshipTypes.readReceipt);

super.initState();
}

bool userHasGivenReadReceipt(int index) {
bool found = false;
final userId = members[index].id;

for (final event in readReceipts!) {
if (event.senderId == userId) {
found = true;
}
}

return found;
}

bool userIsVisible(int index) {
// don't show user who has requested read receipt
if (event!.senderId == members[index].id) {
return false;
} else if (filter == "all") {
return true;
} else {
final hasReadReceipt = userHasGivenReadReceipt(index);
if (filter == "open" && !hasReadReceipt ||
filter == "given" && hasReadReceipt) {
return true;
} else {
return false;
}
}
}

void changeFilter(value) {
setState(() {
filter = value.toString();
});
}

@override
Widget build(BuildContext context) {
return ReadReceiptListView(this);
}
}
49 changes: 49 additions & 0 deletions lib/pages/chat/read_receipt/read_receipt_list_dialog.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import 'package:flutter/material.dart';

import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:matrix/matrix.dart';

import 'package:fluffychat/pages/chat/read_receipt/read_receipt_list.dart';

extension ReadReceiptListDialogExtension on Event {
void showReadReceiptListDialog(
BuildContext context, Room room, Timeline timeline) =>
showModalBottomSheet(
context: context,
builder: (context) => ReadReceiptListDialog(
l10n: L10n.of(context)!,
event: this,
room: room,
timeline: timeline,
),
);
}

class ReadReceiptListDialog extends StatelessWidget {
final Event event;
final L10n l10n;
final Room room;
final Timeline timeline;

const ReadReceiptListDialog({
required this.event,
required this.l10n,
required this.room,
required this.timeline,
Key? key,
}) : super(key: key);

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(L10n.of(context)!.readReceipts),
leading: IconButton(
icon: const Icon(Icons.arrow_downward),
onPressed: Navigator.of(context, rootNavigator: false).pop,
tooltip: L10n.of(context)!.close,
),
),
body: ReadReceiptList(event: event, room: room, timeline: timeline));
}
}
Loading

0 comments on commit 646168d

Please sign in to comment.