Skip to content

Commit

Permalink
krille-chan#81 FluffyChat: progress indicatior if read receipt is given
Browse files Browse the repository at this point in the history
  • Loading branch information
carowebtec authored and Caroline committed Mar 29, 2023
1 parent de95407 commit 1a57469
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 73 deletions.
100 changes: 54 additions & 46 deletions lib/pages/chat/events/message.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import 'package:fluffychat/utils/string_color.dart';
import 'package:fluffychat/widgets/avatar.dart';
import 'package:fluffychat/widgets/matrix.dart';
import '../../../config/app_config.dart';
import '../../read_receipt_overview/read_receipt_overview.dart';
import 'message_content.dart';
import 'message_reactions.dart';
import 'reply_content.dart';
Expand All @@ -31,22 +32,23 @@ class Message extends StatelessWidget {
final bool selected;
final Timeline timeline;
final String? searchTerm;
final ReadReceiptOverviewController? readReceiptOverviewController;

const Message(
this.event, {
this.nextEvent,
this.longPressSelect = false,
this.onSelect,
this.onInfoTab,
this.onAvatarTab,
this.scrollToEventId,
required this.onSwipe,
this.onReadReceipt,
this.selected = false,
required this.timeline,
this.searchTerm,
Key? key,
}) : super(key: key);
const Message(this.event,
{this.nextEvent,
this.longPressSelect = false,
this.onSelect,
this.onInfoTab,
this.onAvatarTab,
this.scrollToEventId,
required this.onSwipe,
this.onReadReceipt,
this.selected = false,
required this.timeline,
this.searchTerm,
this.readReceiptOverviewController,
Key? key})
: super(key: key);

/// Indicates wheither the user may use a mouse instead
/// of touchscreen.
Expand Down Expand Up @@ -129,40 +131,47 @@ class Message extends StatelessWidget {

final readReceiptGiven = event
.aggregatedEvents(timeline, RelationshipTypes.readReceipt)
.where(
(e) =>
e.content
.tryGetMap<String, dynamic>('m.relates_to')
?.tryGet<String>('user_id') ==
client.userID,
)
.where((e) =>
e.content
.tryGetMap<String, dynamic>('m.relates_to')
?.tryGet<String>('user_id') ==
client.userID)
.toList()
.isNotEmpty;

final rowChildren = <Widget>[
if (requiresReadReceipt && !ownMessage)
Padding(
padding: EdgeInsets.all(
8.0 * AppConfig.bubbleSizeFactor,
),
child: readReceiptGiven
? Tooltip(
message: L10n.of(context)!.readReceiptGiven,
child: const Icon(
Icons.mark_chat_read,
color: AppConfig.primaryColor,
),
)
: IconButton(
tooltip: L10n.of(context)!.readReceiptGive,
padding: const EdgeInsets.all(0),
icon: const Icon(
Icons.mark_chat_read_outlined,
color: AppConfig.primaryColor,
),
onPressed: () => onReadReceipt?.call(displayEvent),
),
),
padding: EdgeInsets.all(
8.0 * AppConfig.bubbleSizeFactor,
),
child: readReceiptGiven
? Tooltip(
message: L10n.of(context)!.readReceiptGiven,
child: const Icon(
Icons.mark_chat_read,
color: AppConfig.primaryColor,
),
)
: (readReceiptOverviewController != null &&
readReceiptOverviewController!
.readReceiptInProgress(event))
? const SizedBox(
width: 22,
height: 22,
child: CircularProgressIndicator.adaptive(
strokeWidth: 2,
),
)
: IconButton(
tooltip: L10n.of(context)!.readReceiptGive,
padding: const EdgeInsets.all(0),
icon: const Icon(
Icons.mark_chat_read_outlined,
color: AppConfig.primaryColor,
),
onPressed: () => onReadReceipt?.call(displayEvent),
)),
sameSender || ownMessage
? SizedBox(
width: Avatar.defaultSize,
Expand Down Expand Up @@ -286,9 +295,8 @@ class Message extends StatelessWidget {
child: AbsorbPointer(
child: Container(
margin: EdgeInsets.symmetric(
vertical:
4.0 * AppConfig.bubbleSizeFactor,
),
vertical: 4.0 *
AppConfig.bubbleSizeFactor),
child: ReplyContent(
replyEvent,
ownMessage: ownMessage,
Expand Down
84 changes: 63 additions & 21 deletions lib/pages/read_receipt_overview/read_receipt_overview.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class ReadReceiptOverviewPage extends StatefulWidget {

class ExpansionPanelItem {
List<Event> readReceiptRequests = [];
List<Event> messages = [];
List<MessageItem> messageItems = [];
bool messagesLoaded = false;
Timeline? timeline;
Room? room;
Expand All @@ -29,9 +29,16 @@ class ExpansionPanelItem {
ExpansionPanelItem(Room this.room);
}

class MessageItem {
final Event message;
bool readReceiptInProgress = false;

MessageItem(this.message);
}

class ReadReceiptOverviewController extends State<ReadReceiptOverviewPage> {
Map<String, ExpansionPanelItem> panelItems = {};
Map<String, Map<String, Event>> _localStorageEvents = {};
final Map<String, Map<String, Event>> _localStorageEvents = {};
bool roomsLoaded = false;
Client? _client;

Expand Down Expand Up @@ -177,7 +184,9 @@ class ReadReceiptOverviewController extends State<ReadReceiptOverviewPage> {
}

Future<bool> _addParentToMessages(
MatrixEvent mEvent, ExpansionPanelItem panelItem) async {
MatrixEvent mEvent,
ExpansionPanelItem panelItem,
) async {
final String? parentId = mEvent.content
.tryGetMap<String, dynamic>('m.relates_to')
?.tryGet<String>("event_id");
Expand All @@ -190,7 +199,11 @@ class ReadReceiptOverviewController extends State<ReadReceiptOverviewPage> {
if (parentEvent != null) {
// add related events as aggregated events to timeline
await _addAggregatedEventsToTimeline(
parentEvent, mEvent, panelItem.timeline!, room);
parentEvent,
mEvent,
panelItem.timeline!,
room,
);

// events from sync are sorted chronologically up
// but we need latest event first -> therefore insert(0, ...
Expand All @@ -202,8 +215,12 @@ class ReadReceiptOverviewController extends State<ReadReceiptOverviewPage> {
return false;
}

Future<void> _addAggregatedEventsToTimeline(Event parentEvent,
MatrixEvent aggregatedEvent, Timeline timeline, Room room) async {
Future<void> _addAggregatedEventsToTimeline(
Event parentEvent,
MatrixEvent aggregatedEvent,
Timeline timeline,
Room room,
) async {
final relations = await parentEvent.getRelations();

for (final relation in relations) {
Expand Down Expand Up @@ -263,28 +280,53 @@ class ReadReceiptOverviewController extends State<ReadReceiptOverviewPage> {
return parentEvent;
}

void onReadReceiptClick(Event event, ExpansionPanelItem panelItem) async {
final String? readReceiptEventId =
await event.onReadReceiptIconClick(event, panelItem.timeline!, context);
void onReadReceiptClick(Event event, ExpansionPanelItem panelItem,
MessageItem messageItem) async {
if (!messageItem.readReceiptInProgress) {
setState(() {
messageItem.readReceiptInProgress = true;
});

final String? readReceiptEventId = await event.onReadReceiptIconClick(
event, panelItem.timeline!, context);

// if readReceiptEventId is !null, then the user has given a new read receipt
if (readReceiptEventId != null) {
final MatrixEvent readReceiptEvent = await panelItem.room!.client
.getOneRoomEvent(panelItem.room!.id, readReceiptEventId);
// if readReceiptEventId is !null, then the user has given a new read receipt
if (readReceiptEventId != null) {
final MatrixEvent readReceiptEvent = await panelItem.room!.client
.getOneRoomEvent(panelItem.room!.id, readReceiptEventId);

_addAggregatedEventsToTimeline(
event, readReceiptEvent, panelItem.timeline!, panelItem.room!);
_addAggregatedEventsToTimeline(
event,
readReceiptEvent,
panelItem.timeline!,
panelItem.room!,
);

await _client!.updateOpenReadReceipts(panelItem.room!.id);
_updateOpenReadReceipt(panelItem);
_sortPanelItems();
await _client!.updateOpenReadReceipts(panelItem.room!.id);
_updateOpenReadReceipt(panelItem);
_sortPanelItems();

setState(() {
panelItems;
});
messageItem.readReceiptInProgress = false;
setState(() {
messageItem;
});
}
}
}

// returns true if process of giving read receipt for current user is in progress
bool readReceiptInProgress(Event event) {
for (final panelItem in panelItems.values) {
for (final messageItem in panelItem.messageItems) {
if (messageItem.message.eventId == event.eventId) {
return messageItem.readReceiptInProgress;
}
}
}

return false;
}

void expansionCallback(panelIndex, isExpanded) {
if (panelItems.length > panelIndex) {
final panelItem = panelItems.values.elementAt(panelIndex);
Expand Down
15 changes: 9 additions & 6 deletions lib/pages/read_receipt_overview/read_receipt_overview_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -98,28 +98,31 @@ class ReadReceiptOverviewView extends StatelessWidget {
child: item.messagesLoaded == true
? Column(
children: [
if (item.messages.isEmpty)
if (item.messageItems.isEmpty)
Text(
L10n.of(context)!
.noReadReceiptRequestsFound,
)
else
for (var message in item.messages)
for (var messageItem
in item.messageItems)
Padding(
padding: const EdgeInsets.only(
right: 25,
),
child: Message(
message,
messageItem.message,
onSwipe: (swipeDirection) {},
onReadReceipt: (event) =>
controller
.onReadReceiptClick(
event,
item,
),
event,
item,
messageItem),
onSelect: (event) {},
timeline: item.timeline!,
readReceiptOverviewController:
controller,
),
),
],
Expand Down

0 comments on commit 1a57469

Please sign in to comment.