parseMessage method

dynamic parseMessage(
  1. dynamic message
)

Implementation

types.Message parseMessage(RoomMessage message) {
  RoomVirtualItem? virtualItem = message.virtualItem();
  if (virtualItem != null) {
    switch (virtualItem.eventType()) {
      case 'ReadMarker':
        return const types.SystemMessage(
          metadata: {'type': '_read_marker'},
          id: 'read-marker',
          text: 'read-until-here',
        );
      // should not return null, before we can keep track of index in diff receiver
      default:
        return types.UnsupportedMessage(
          author: const types.User(id: 'virtual'),
          id: UniqueKey().toString(),
          metadata: {
            'itemType': 'virtual',
            'eventType': virtualItem.eventType(),
          },
        );
    }
  }

  // If not virtual item, it should be event item
  RoomEventItem eventItem = message.eventItem()!;
  EventSendState? eventState;
  if (eventItem.sendState() != null) {
    eventState = eventItem.sendState();
  }

  String eventType = eventItem.eventType();
  String sender = eventItem.sender();
  bool isEditable = eventItem.isEditable();
  bool wasEdited = eventItem.wasEdited();
  final author = types.User(
    id: sender,
    firstName: simplifyUserId(sender),
  );
  int createdAt = eventItem.originServerTs(); // in milliseconds
  String uniqueId = message.uniqueId();
  String? eventId = eventItem.eventId();

  String? inReplyTo = eventItem.inReplyTo();

  // user read receipts for timeline event item
  Map<String, int> receipts = {};
  for (var userId in eventItem.readUsers()) {
    String id = userId.toDartString();
    final ts = eventItem.receiptTs(id);
    if (ts != null) {
      receipts[id] = ts;
    }
  }

  // state event
  switch (eventType) {
    case 'm.policy.rule.room':
    case 'm.policy.rule.server':
    case 'm.policy.rule.user':
    case 'm.room.aliases':
    case 'm.room.avatar':
    case 'm.room.canonical_alias':
    case 'm.room.create':
    case 'm.room.encryption':
    case 'm.room.guest.access':
    case 'm.room.history_visibility':
    case 'm.room.join.rules':
    case 'm.room.name':
    case 'm.room.pinned_events':
    case 'm.room.power_levels':
    case 'm.room.server_acl':
    case 'm.room.third_party_invite':
    case 'm.room.tombstone':
    case 'm.room.topic':
    case 'm.space.child':
    case 'm.space.parent':
      return types.CustomMessage(
        author: author,
        createdAt: createdAt,
        id: uniqueId,
        remoteId: eventId,
        metadata: {
          'itemType': 'event',
          'eventType': eventType,
          'body': eventItem.msgContent()?.body(),
          'eventState': eventItem.sendState(),
          'receipts': receipts,
        },
      );
  }

  // message event
  switch (eventType) {
    case 'm.call.answer':
    case 'm.call.candidates':
    case 'm.call.hangup':
    case 'm.call.invite':
      break;
    case 'm.reaction':
    case 'm.room.encrypted':
      final metadata = {
        'itemType': 'event',
        'eventType': eventType,
        'eventState': eventState,
        'receipts': receipts,
      };
      if (inReplyTo != null) {
        metadata['repliedTo'] = inReplyTo;
      }
      return types.CustomMessage(
        remoteId: eventId,
        author: author,
        createdAt: createdAt,
        id: uniqueId,
        metadata: metadata,
      );
    case 'm.room.redaction':
      final metadata = {
        'itemType': 'event',
        'eventType': eventType,
        'eventState': eventState,
        'receipts': receipts,
      };
      if (inReplyTo != null) {
        metadata['repliedTo'] = inReplyTo;
      }
      return types.CustomMessage(
        remoteId: eventId,
        author: author,
        createdAt: createdAt,
        id: uniqueId,
        metadata: metadata,
      );
    case 'm.room.member':
      MsgContent? msgContent = eventItem.msgContent();
      if (msgContent != null) {
        String? formattedBody = msgContent.formattedBody();
        String body = msgContent.body(); // always exists
        return types.CustomMessage(
          author: author,
          createdAt: createdAt,
          id: uniqueId,
          remoteId: eventId,
          metadata: {
            'itemType': 'event',
            'eventType': eventType,
            'msgType': eventItem.msgType(),
            'body': formattedBody ?? body,
            'eventState': eventState,
            'receipts': receipts,
          },
        );
      }
      break;
    case 'm.room.message':
      Map<String, dynamic> reactions = {};
      for (var key in eventItem.reactionKeys()) {
        String k = key.toDartString();
        final records = eventItem.reactionRecords(k);
        if (records != null) {
          reactions[k] = records.toList();
        }
      }
      String? msgType = eventItem.msgType();
      switch (msgType) {
        case 'm.audio':
          MsgContent? msgContent = eventItem.msgContent();
          if (msgContent != null) {
            Map<String, dynamic> metadata = {
              'base64': '',
              'eventState': eventState,
              'receipts': receipts,
              'was_edited': wasEdited,
              'isEditable': isEditable,
            };
            if (inReplyTo != null) {
              metadata['repliedTo'] = inReplyTo;
            }
            if (reactions.isNotEmpty) {
              metadata['reactions'] = reactions;
            }
            return types.AudioMessage(
              author: author,
              createdAt: createdAt,
              remoteId: eventId,
              duration: Duration(seconds: msgContent.duration() ?? 0),
              id: uniqueId,
              metadata: metadata,
              mimeType: msgContent.mimetype(),
              name: msgContent.body(),
              size: msgContent.size() ?? 0,
              uri: msgContent.source()!.url(),
            );
          }
          break;
        case 'm.emote':
          MsgContent? msgContent = eventItem.msgContent();
          if (msgContent != null) {
            String? formattedBody = msgContent.formattedBody();
            String body = msgContent.body(); // always exists
            Map<String, dynamic> metadata = {
              'eventState': eventState,
              'receipts': receipts,
              'was_edited': wasEdited,
              'isEditable': isEditable,
              // check whether string only contains emoji(s).
              'enlargeEmoji': isOnlyEmojis(body),
            };
            if (inReplyTo != null) {
              metadata['repliedTo'] = inReplyTo;
            }
            if (reactions.isNotEmpty) {
              metadata['reactions'] = reactions;
            }
            return types.TextMessage(
              author: author,
              remoteId: eventId,
              createdAt: createdAt,
              id: uniqueId,
              metadata: metadata,
              text: formattedBody ?? body,
            );
          }
          break;
        case 'm.file':
          MsgContent? msgContent = eventItem.msgContent();
          if (msgContent != null) {
            Map<String, dynamic> metadata = {
              'eventState': eventState,
              'receipts': receipts,
              'was_edited': wasEdited,
              'isEditable': isEditable,
            };
            if (inReplyTo != null) {
              metadata['repliedTo'] = inReplyTo;
            }
            if (reactions.isNotEmpty) {
              metadata['reactions'] = reactions;
            }
            return types.FileMessage(
              author: author,
              remoteId: eventId,
              createdAt: createdAt,
              id: uniqueId,
              metadata: metadata,
              mimeType: msgContent.mimetype(),
              name: msgContent.body(),
              size: msgContent.size() ?? 0,
              uri: msgContent.source()!.url(),
            );
          }
          break;
        case 'm.image':
          MsgContent? msgContent = eventItem.msgContent();
          if (msgContent != null) {
            Map<String, dynamic> metadata = {
              'eventState': eventState,
              'receipts': receipts,
              'was_edited': wasEdited,
              'isEditable': isEditable,
            };
            if (inReplyTo != null) {
              metadata['repliedTo'] = inReplyTo;
            }
            if (reactions.isNotEmpty) {
              metadata['reactions'] = reactions;
            }
            return types.ImageMessage(
              author: author,
              remoteId: eventId,
              createdAt: createdAt,
              height: msgContent.height()?.toDouble(),
              id: uniqueId,
              metadata: metadata,
              name: msgContent.body(),
              size: msgContent.size() ?? 0,
              uri: msgContent.source()!.url(),
              width: msgContent.width()?.toDouble(),
            );
          }
          break;
        case 'm.location':
          MsgContent? msgContent = eventItem.msgContent();
          if (msgContent != null) {
            Map<String, dynamic> metadata = {
              'itemType': 'event',
              'eventType': eventType,
              'msgType': msgType,
              'body': msgContent.body(),
              'geoUri': msgContent.geoUri(),
              'eventState': eventState,
              'receipts': receipts,
              'was_edited': wasEdited,
              'isEditable': isEditable,
            };
            if (inReplyTo != null) {
              metadata['repliedTo'] = inReplyTo;
            }
            if (reactions.isNotEmpty) {
              metadata['reactions'] = reactions;
            }
            final thumbnailSource = msgContent.thumbnailSource();
            if (thumbnailSource != null) {
              metadata['thumbnailSource'] = thumbnailSource.url();
            }
            final thumbnailInfo = msgContent.thumbnailInfo();
            final mimetype = thumbnailInfo?.mimetype();
            final size = thumbnailInfo?.size();
            final width = thumbnailInfo?.width();
            final height = thumbnailInfo?.height();
            if (mimetype != null) {
              metadata['thumbnailMimetype'] = mimetype;
            }
            if (size != null) {
              metadata['thumbnailSize'] = size;
            }
            if (width != null) {
              metadata['thumbnailWidth'] = width;
            }
            if (height != null) {
              metadata['thumbnailHeight'] = height;
            }
            return types.CustomMessage(
              author: author,
              remoteId: eventId,
              createdAt: createdAt,
              id: uniqueId,
              metadata: metadata,
            );
          }
          break;
        case 'm.notice':
        case 'm.server_notice':
        case 'm.text':
          final body = prepareMsg(eventItem.msgContent());
          Map<String, dynamic> metadata = {
            'eventState': eventState,
            'receipts': receipts,
            'was_edited': wasEdited,
            'isEditable': isEditable,
            // check whether string only contains emoji(s).
            'enlargeEmoji': isOnlyEmojis(body),
          };
          if (inReplyTo != null) {
            metadata['repliedTo'] = inReplyTo;
          }
          if (reactions.isNotEmpty) {
            metadata['reactions'] = reactions;
          }
          return types.TextMessage(
            author: author,
            remoteId: eventId,
            createdAt: createdAt,
            id: uniqueId,
            metadata: metadata,
            text: body,
          );
        case 'm.video':
          MsgContent? msgContent = eventItem.msgContent();
          if (msgContent != null) {
            Map<String, dynamic> metadata = {
              'base64': '',
              'eventState': eventState,
              'receipts': receipts,
              'was_edited': wasEdited,
              'isEditable': isEditable,
            };
            if (inReplyTo != null) {
              metadata['repliedTo'] = inReplyTo;
            }
            if (reactions.isNotEmpty) {
              metadata['reactions'] = reactions;
            }
            return types.VideoMessage(
              author: author,
              remoteId: eventId,
              createdAt: createdAt,
              id: uniqueId,
              metadata: metadata,
              name: msgContent.body(),
              size: msgContent.size() ?? 0,
              uri: msgContent.source()!.url(),
            );
          }
          break;
        case 'm.key.verification.request':
          break;
      }
      break;
    case 'm.sticker':
      Map<String, dynamic> receipts = {};
      for (var userId in eventItem.readUsers()) {
        String id = userId.toDartString();
        final ts = eventItem.receiptTs(id);
        if (ts != null) {
          receipts[id] = ts;
        }
      }
      Map<String, dynamic> reactions = {};
      for (var key in eventItem.reactionKeys()) {
        String k = key.toDartString();
        final records = eventItem.reactionRecords(k);
        if (records != null) {
          reactions[k] = records.toList();
        }
      }
      MsgContent? msgContent = eventItem.msgContent();
      if (msgContent != null) {
        Map<String, dynamic> metadata = {
          'itemType': 'event',
          'eventType': eventType,
          'name': msgContent.body(),
          'size': msgContent.size() ?? 0,
          'width': msgContent.width()?.toDouble(),
          'height': msgContent.height()?.toDouble(),
          'base64': '',
          'eventState': eventState,
          'receipts': receipts,
          'was_edited': wasEdited,
          'isEditable': isEditable,
        };
        if (inReplyTo != null) {
          metadata['repliedTo'] = inReplyTo;
        }
        if (reactions.isNotEmpty) {
          metadata['reactions'] = reactions;
        }
        return types.CustomMessage(
          author: author,
          remoteId: eventId,
          createdAt: createdAt,
          id: uniqueId,
          metadata: metadata,
        );
      }
      break;
    case 'm.poll.start':
      MsgContent? msgContent = eventItem.msgContent();
      if (msgContent != null) {
        String body = msgContent.body();
        return types.CustomMessage(
          author: author,
          remoteId: eventId,
          createdAt: createdAt,
          id: uniqueId,
          metadata: {
            'itemType': 'event',
            'eventType': eventType,
            'msgType': eventItem.msgType(),
            'body': body,
            'was_edited': wasEdited,
            'isEditable': isEditable,
            'eventState': eventState,
            'receipts': receipts,
          },
        );
      }
      break;
  }
  return types.UnsupportedMessage(
    author: const types.User(id: 'virtual'),
    remoteId: eventId,
    id: UniqueKey().toString(),
    metadata: const {
      'itemType': 'virtual',
    },
  );
}