refactor: null safety for all utils
This commit is contained in:
parent
687a6341f1
commit
a7818bbd0f
|
|
@ -864,7 +864,8 @@ class KeyManager {
|
||||||
}
|
}
|
||||||
} else if (event.type == EventTypes.ForwardedRoomKey) {
|
} else if (event.type == EventTypes.ForwardedRoomKey) {
|
||||||
// we *received* an incoming key request
|
// we *received* an incoming key request
|
||||||
if (event.encryptedContent == null) {
|
final encryptedContent = event.encryptedContent;
|
||||||
|
if (encryptedContent == null) {
|
||||||
return; // event wasn't encrypted, this is a security risk
|
return; // event wasn't encrypted, this is a security risk
|
||||||
}
|
}
|
||||||
final request = outgoingShareRequests.values.firstWhereOrNull((r) =>
|
final request = outgoingShareRequests.values.firstWhereOrNull((r) =>
|
||||||
|
|
@ -876,7 +877,7 @@ class KeyManager {
|
||||||
}
|
}
|
||||||
final device = request.devices.firstWhereOrNull((d) =>
|
final device = request.devices.firstWhereOrNull((d) =>
|
||||||
d.userId == event.sender &&
|
d.userId == event.sender &&
|
||||||
d.curve25519Key == event.encryptedContent['sender_key']);
|
d.curve25519Key == encryptedContent['sender_key']);
|
||||||
if (device == null) {
|
if (device == null) {
|
||||||
return; // someone we didn't send our request to replied....better ignore this
|
return; // someone we didn't send our request to replied....better ignore this
|
||||||
}
|
}
|
||||||
|
|
@ -885,7 +886,7 @@ class KeyManager {
|
||||||
event.content['forwarding_curve25519_key_chain'] = <String>[];
|
event.content['forwarding_curve25519_key_chain'] = <String>[];
|
||||||
}
|
}
|
||||||
event.content['forwarding_curve25519_key_chain']
|
event.content['forwarding_curve25519_key_chain']
|
||||||
.add(event.encryptedContent['sender_key']);
|
.add(encryptedContent['sender_key']);
|
||||||
// TODO: verify that the keys work to decrypt a message
|
// TODO: verify that the keys work to decrypt a message
|
||||||
// alright, all checks out, let's go ahead and store this session
|
// alright, all checks out, let's go ahead and store this session
|
||||||
setInboundGroupSession(
|
setInboundGroupSession(
|
||||||
|
|
@ -920,7 +921,8 @@ class KeyManager {
|
||||||
} else if (event.type == EventTypes.RoomKey) {
|
} else if (event.type == EventTypes.RoomKey) {
|
||||||
Logs().v(
|
Logs().v(
|
||||||
'[KeyManager] Received room key with session ${event.content['session_id']}');
|
'[KeyManager] Received room key with session ${event.content['session_id']}');
|
||||||
if (event.encryptedContent == null) {
|
final encryptedContent = event.encryptedContent;
|
||||||
|
if (encryptedContent == null) {
|
||||||
Logs().v('[KeyManager] not encrypted, ignoring...');
|
Logs().v('[KeyManager] not encrypted, ignoring...');
|
||||||
return; // the event wasn't encrypted, this is a security risk;
|
return; // the event wasn't encrypted, this is a security risk;
|
||||||
}
|
}
|
||||||
|
|
@ -932,8 +934,8 @@ class KeyManager {
|
||||||
event.content['sender_claimed_ed25519_key'] = sender_ed25519;
|
event.content['sender_claimed_ed25519_key'] = sender_ed25519;
|
||||||
}
|
}
|
||||||
Logs().v('[KeyManager] Keeping room key');
|
Logs().v('[KeyManager] Keeping room key');
|
||||||
setInboundGroupSession(roomId, sessionId,
|
setInboundGroupSession(
|
||||||
event.encryptedContent['sender_key'], event.content,
|
roomId, sessionId, encryptedContent['sender_key'], event.content,
|
||||||
forwarded: false);
|
forwarded: false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -972,11 +974,11 @@ class RoomKeyRequest extends ToDeviceEvent {
|
||||||
KeyManager keyManager;
|
KeyManager keyManager;
|
||||||
KeyManagerKeyShareRequest request;
|
KeyManagerKeyShareRequest request;
|
||||||
RoomKeyRequest.fromToDeviceEvent(
|
RoomKeyRequest.fromToDeviceEvent(
|
||||||
ToDeviceEvent toDeviceEvent, this.keyManager, this.request) {
|
ToDeviceEvent toDeviceEvent, this.keyManager, this.request)
|
||||||
sender = toDeviceEvent.sender;
|
: super(
|
||||||
content = toDeviceEvent.content;
|
sender: toDeviceEvent.sender,
|
||||||
type = toDeviceEvent.type;
|
content: toDeviceEvent.content,
|
||||||
}
|
type: toDeviceEvent.type);
|
||||||
|
|
||||||
Room get room => request.room;
|
Room get room => request.room;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -653,11 +653,12 @@ class OlmManager {
|
||||||
if (event.type == EventTypes.Dummy) {
|
if (event.type == EventTypes.Dummy) {
|
||||||
// We receive dan encrypted m.dummy. This means that the other end was not able to
|
// We receive dan encrypted m.dummy. This means that the other end was not able to
|
||||||
// decrypt our last message. So, we re-send it.
|
// decrypt our last message. So, we re-send it.
|
||||||
if (event.encryptedContent == null || client.database == null) {
|
final encryptedContent = event.encryptedContent;
|
||||||
|
if (encryptedContent == null || client.database == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final device = client.getUserDeviceKeysByCurve25519Key(
|
final device = client.getUserDeviceKeysByCurve25519Key(
|
||||||
event.encryptedContent.tryGet<String>('sender_key') ?? '');
|
encryptedContent.tryGet<String>('sender_key') ?? '');
|
||||||
if (device == null) {
|
if (device == null) {
|
||||||
return; // device not found
|
return; // device not found
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -509,9 +509,10 @@ class SSSS {
|
||||||
} else if (event.type == EventTypes.SecretSend) {
|
} else if (event.type == EventTypes.SecretSend) {
|
||||||
// receiving a secret we asked for
|
// receiving a secret we asked for
|
||||||
Logs().i('[SSSS] Received shared secret...');
|
Logs().i('[SSSS] Received shared secret...');
|
||||||
|
final encryptedContent = event.encryptedContent;
|
||||||
if (event.sender != client.userID ||
|
if (event.sender != client.userID ||
|
||||||
!pendingShareRequests.containsKey(event.content['request_id']) ||
|
!pendingShareRequests.containsKey(event.content['request_id']) ||
|
||||||
event.encryptedContent == null) {
|
encryptedContent == null) {
|
||||||
Logs().i('[SSSS] Not by us or unknown request');
|
Logs().i('[SSSS] Not by us or unknown request');
|
||||||
return; // we have no idea what we just received
|
return; // we have no idea what we just received
|
||||||
}
|
}
|
||||||
|
|
@ -519,7 +520,7 @@ class SSSS {
|
||||||
// alright, as we received a known request id, let's check if the sender is valid
|
// alright, as we received a known request id, let's check if the sender is valid
|
||||||
final device = request.devices.firstWhereOrNull((d) =>
|
final device = request.devices.firstWhereOrNull((d) =>
|
||||||
d.userId == event.sender &&
|
d.userId == event.sender &&
|
||||||
d.curve25519Key == event.encryptedContent['sender_key']);
|
d.curve25519Key == encryptedContent['sender_key']);
|
||||||
if (device == null) {
|
if (device == null) {
|
||||||
Logs().i('[SSSS] Someone else replied?');
|
Logs().i('[SSSS] Someone else replied?');
|
||||||
return; // someone replied whom we didn't send the share request to
|
return; // someone replied whom we didn't send the share request to
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
// @dart=2.9
|
|
||||||
/*
|
/*
|
||||||
* Famedly Matrix SDK
|
* Famedly Matrix SDK
|
||||||
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
|
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
// @dart=2.9
|
|
||||||
/*
|
/*
|
||||||
* Famedly Matrix SDK
|
* Famedly Matrix SDK
|
||||||
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
|
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
|
||||||
|
|
@ -17,6 +16,8 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
|
|
||||||
import '../../encryption.dart';
|
import '../../encryption.dart';
|
||||||
import '../../matrix.dart';
|
import '../../matrix.dart';
|
||||||
import '../event.dart';
|
import '../event.dart';
|
||||||
|
|
@ -77,7 +78,7 @@ abstract class EventLocalizations {
|
||||||
// This map holds how to localize event types, and thus which event types exist.
|
// This map holds how to localize event types, and thus which event types exist.
|
||||||
// If an event exists but it does not have a localized body, set its callback to null
|
// If an event exists but it does not have a localized body, set its callback to null
|
||||||
static final Map<String,
|
static final Map<String,
|
||||||
String Function(Event event, MatrixLocalizations i18n, String body)>
|
String Function(Event event, MatrixLocalizations i18n, String body)?>
|
||||||
localizationsMap = {
|
localizationsMap = {
|
||||||
EventTypes.Sticker: (event, i18n, body) =>
|
EventTypes.Sticker: (event, i18n, body) =>
|
||||||
i18n.sentASticker(event.sender.calcDisplayname()),
|
i18n.sentASticker(event.sender.calcDisplayname()),
|
||||||
|
|
@ -91,11 +92,9 @@ abstract class EventLocalizations {
|
||||||
i18n.createdTheChat(event.sender.calcDisplayname()),
|
i18n.createdTheChat(event.sender.calcDisplayname()),
|
||||||
EventTypes.RoomTombstone: (event, i18n, body) => i18n.roomHasBeenUpgraded,
|
EventTypes.RoomTombstone: (event, i18n, body) => i18n.roomHasBeenUpgraded,
|
||||||
EventTypes.RoomJoinRules: (event, i18n, body) {
|
EventTypes.RoomJoinRules: (event, i18n, body) {
|
||||||
final joinRules = JoinRules.values.firstWhere(
|
final joinRules = JoinRules.values.firstWhereOrNull((r) =>
|
||||||
(r) =>
|
r.toString().replaceAll('JoinRules.', '') ==
|
||||||
r.toString().replaceAll('JoinRules.', '') ==
|
event.content['join_rule']);
|
||||||
event.content['join_rule'],
|
|
||||||
orElse: () => null);
|
|
||||||
if (joinRules == null) {
|
if (joinRules == null) {
|
||||||
return i18n.changedTheJoinRules(event.sender.calcDisplayname());
|
return i18n.changedTheJoinRules(event.sender.calcDisplayname());
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -177,11 +176,9 @@ abstract class EventLocalizations {
|
||||||
EventTypes.RoomAvatar: (event, i18n, body) =>
|
EventTypes.RoomAvatar: (event, i18n, body) =>
|
||||||
i18n.changedTheChatAvatar(event.sender.calcDisplayname()),
|
i18n.changedTheChatAvatar(event.sender.calcDisplayname()),
|
||||||
EventTypes.GuestAccess: (event, i18n, body) {
|
EventTypes.GuestAccess: (event, i18n, body) {
|
||||||
final guestAccess = GuestAccess.values.firstWhere(
|
final guestAccess = GuestAccess.values.firstWhereOrNull((r) =>
|
||||||
(r) =>
|
r.toString().replaceAll('GuestAccess.', '') ==
|
||||||
r.toString().replaceAll('GuestAccess.', '') ==
|
event.content['guest_access']);
|
||||||
event.content['guest_access'],
|
|
||||||
orElse: () => null);
|
|
||||||
if (guestAccess == null) {
|
if (guestAccess == null) {
|
||||||
return i18n.changedTheGuestAccessRules(event.sender.calcDisplayname());
|
return i18n.changedTheGuestAccessRules(event.sender.calcDisplayname());
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -190,11 +187,9 @@ abstract class EventLocalizations {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
EventTypes.HistoryVisibility: (event, i18n, body) {
|
EventTypes.HistoryVisibility: (event, i18n, body) {
|
||||||
final historyVisibility = HistoryVisibility.values.firstWhere(
|
final historyVisibility = HistoryVisibility.values.firstWhereOrNull((r) =>
|
||||||
(r) =>
|
r.toString().replaceAll('HistoryVisibility.', '') ==
|
||||||
r.toString().replaceAll('HistoryVisibility.', '') ==
|
event.content['history_visibility']);
|
||||||
event.content['history_visibility'],
|
|
||||||
orElse: () => null);
|
|
||||||
if (historyVisibility == null) {
|
if (historyVisibility == null) {
|
||||||
return i18n.changedTheHistoryVisibility(event.sender.calcDisplayname());
|
return i18n.changedTheHistoryVisibility(event.sender.calcDisplayname());
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
// @dart=2.9
|
|
||||||
/*
|
/*
|
||||||
* Famedly Matrix SDK
|
* Famedly Matrix SDK
|
||||||
* Copyright (C) 2021 Famedly GmbH
|
* Copyright (C) 2021 Famedly GmbH
|
||||||
|
|
@ -17,6 +16,8 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
|
|
||||||
import 'package:html/parser.dart';
|
import 'package:html/parser.dart';
|
||||||
import 'package:html/dom.dart';
|
import 'package:html/dom.dart';
|
||||||
import 'package:html_unescape/html_unescape.dart';
|
import 'package:html_unescape/html_unescape.dart';
|
||||||
|
|
@ -71,9 +72,9 @@ class HtmlToText {
|
||||||
}
|
}
|
||||||
final language =
|
final language =
|
||||||
RegExp(r'language-(\w+)', multiLine: false, caseSensitive: false)
|
RegExp(r'language-(\w+)', multiLine: false, caseSensitive: false)
|
||||||
.firstMatch(match.group(1));
|
.firstMatch(match.group(1)!);
|
||||||
if (language != null) {
|
if (language != null) {
|
||||||
text = language.group(1) + text;
|
text = language.group(1)! + text;
|
||||||
}
|
}
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
@ -116,17 +117,16 @@ class HtmlToText {
|
||||||
opts.listDepth++;
|
opts.listDepth++;
|
||||||
final entries = _listChildNodes(opts, node, {'li'});
|
final entries = _listChildNodes(opts, node, {'li'});
|
||||||
opts.listDepth--;
|
opts.listDepth--;
|
||||||
var entry = 1;
|
final startStr = node.attributes['start'];
|
||||||
if (node.attributes['start'] is String &&
|
final start = (startStr is String &&
|
||||||
RegExp(r'^[0-9]+$', multiLine: false)
|
RegExp(r'^[0-9]+$', multiLine: false).hasMatch(startStr))
|
||||||
.hasMatch(node.attributes['start'])) {
|
? int.parse(startStr)
|
||||||
entry = int.parse(node.attributes['start']);
|
: 1;
|
||||||
}
|
|
||||||
|
|
||||||
return entries
|
return entries
|
||||||
.map((s) =>
|
.mapIndexed((index, s) =>
|
||||||
(' ' * opts.listDepth) +
|
(' ' * opts.listDepth) +
|
||||||
'${entry++}. ' +
|
'${start + index}. ' +
|
||||||
s.replaceAll('\n', '\n' + (' ' * opts.listDepth) + ' '))
|
s.replaceAll('\n', '\n' + (' ' * opts.listDepth) + ' '))
|
||||||
.join('\n');
|
.join('\n');
|
||||||
}
|
}
|
||||||
|
|
@ -134,14 +134,14 @@ class HtmlToText {
|
||||||
static const _listBulletPoints = <String>['●', '○', '■', '‣'];
|
static const _listBulletPoints = <String>['●', '○', '■', '‣'];
|
||||||
|
|
||||||
static List<String> _listChildNodes(_ConvertOpts opts, Element node,
|
static List<String> _listChildNodes(_ConvertOpts opts, Element node,
|
||||||
[Iterable<String> types]) {
|
[Iterable<String>? types]) {
|
||||||
final replies = <String>[];
|
final replies = <String>[];
|
||||||
for (final child in node.nodes) {
|
for (final child in node.nodes) {
|
||||||
if (types != null &&
|
if (types != null &&
|
||||||
types.isNotEmpty &&
|
types.isNotEmpty &&
|
||||||
((child is Text) ||
|
((child is Text) ||
|
||||||
((child is Element) &&
|
((child is Element) &&
|
||||||
!types.contains(child.localName.toLowerCase())))) {
|
!types.contains(child.localName!.toLowerCase())))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
replies.add(_walkNode(opts, child));
|
replies.add(_walkNode(opts, child));
|
||||||
|
|
@ -166,7 +166,7 @@ class HtmlToText {
|
||||||
var reply = '';
|
var reply = '';
|
||||||
var lastTag = '';
|
var lastTag = '';
|
||||||
for (final child in node.nodes) {
|
for (final child in node.nodes) {
|
||||||
final thisTag = child is Element ? child.localName.toLowerCase() : '';
|
final thisTag = child is Element ? child.localName!.toLowerCase() : '';
|
||||||
if (thisTag == 'p' && lastTag == 'p') {
|
if (thisTag == 'p' && lastTag == 'p') {
|
||||||
reply += '\n\n';
|
reply += '\n\n';
|
||||||
} else if (_blockTags.contains(thisTag) &&
|
} else if (_blockTags.contains(thisTag) &&
|
||||||
|
|
@ -187,7 +187,7 @@ class HtmlToText {
|
||||||
// ignore \n between single nodes
|
// ignore \n between single nodes
|
||||||
return node.text == '\n' ? '' : node.text;
|
return node.text == '\n' ? '' : node.text;
|
||||||
} else if (node is Element) {
|
} else if (node is Element) {
|
||||||
final tag = node.localName.toLowerCase();
|
final tag = node.localName!.toLowerCase();
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
case 'em':
|
case 'em':
|
||||||
case 'i':
|
case 'i':
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
// @dart=2.9
|
|
||||||
/*
|
/*
|
||||||
* Famedly Matrix SDK
|
* Famedly Matrix SDK
|
||||||
* Copyright (C) 2020, 2021 Famedly GmbH
|
* Copyright (C) 2020, 2021 Famedly GmbH
|
||||||
|
|
@ -24,10 +23,10 @@ import '../room.dart';
|
||||||
|
|
||||||
extension ImagePackRoomExtension on Room {
|
extension ImagePackRoomExtension on Room {
|
||||||
/// Get all the active image packs for the specified [usage], mapped by their slug
|
/// Get all the active image packs for the specified [usage], mapped by their slug
|
||||||
Map<String, ImagePackContent> getImagePacks([ImagePackUsage usage]) {
|
Map<String, ImagePackContent> getImagePacks([ImagePackUsage? usage]) {
|
||||||
final allMxcs = <Uri>{}; // used for easy deduplication
|
final allMxcs = <Uri>{}; // used for easy deduplication
|
||||||
final packs = <String, ImagePackContent>{};
|
final packs = <String, ImagePackContent>{};
|
||||||
final addImagePack = (BasicEvent event, {Room room, String slug}) {
|
final addImagePack = (BasicEvent? event, {Room? room, String? slug}) {
|
||||||
if (event == null) return;
|
if (event == null) return;
|
||||||
final imagePack = event.parsedImagePackContent;
|
final imagePack = event.parsedImagePackContent;
|
||||||
final finalSlug = slugify(slug ?? 'pack');
|
final finalSlug = slugify(slug ?? 'pack');
|
||||||
|
|
@ -42,17 +41,16 @@ extension ImagePackRoomExtension on Room {
|
||||||
!imageUsage.contains(usage)) {
|
!imageUsage.contains(usage)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!packs.containsKey(finalSlug)) {
|
packs
|
||||||
packs[finalSlug] = ImagePackContent.fromJson(<String, dynamic>{});
|
.putIfAbsent(
|
||||||
packs[finalSlug].pack.displayName = imagePack.pack.displayName ??
|
finalSlug,
|
||||||
room?.displayname ??
|
() => ImagePackContent.fromJson({})
|
||||||
finalSlug ??
|
..pack.displayName = imagePack.pack.displayName ??
|
||||||
'';
|
room?.displayname ??
|
||||||
packs[finalSlug].pack.avatarUrl =
|
finalSlug
|
||||||
imagePack.pack.avatarUrl ?? room?.avatar;
|
..pack.avatarUrl = imagePack.pack.avatarUrl ?? room?.avatar
|
||||||
packs[finalSlug].pack.attribution = imagePack.pack.attribution;
|
..pack.attribution = imagePack.pack.attribution)
|
||||||
}
|
.images[entry.key] = image;
|
||||||
packs[finalSlug].images[entry.key] = image;
|
|
||||||
allMxcs.add(image.url);
|
allMxcs.add(image.url);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -89,7 +87,7 @@ extension ImagePackRoomExtension on Room {
|
||||||
|
|
||||||
/// Get a flat view of all the image packs of a specified [usage], that is a map of all
|
/// Get a flat view of all the image packs of a specified [usage], that is a map of all
|
||||||
/// slugs to a map of the image code to their mxc url
|
/// slugs to a map of the image code to their mxc url
|
||||||
Map<String, Map<String, String>> getImagePacksFlat([ImagePackUsage usage]) =>
|
Map<String, Map<String, String>> getImagePacksFlat([ImagePackUsage? usage]) =>
|
||||||
getImagePacks(usage).map((k, v) =>
|
getImagePacks(usage).map((k, v) =>
|
||||||
MapEntry(k, v.images.map((k, v) => MapEntry(k, v.url.toString()))));
|
MapEntry(k, v.images.map((k, v) => MapEntry(k, v.url.toString()))));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
// @dart=2.9
|
|
||||||
/*
|
/*
|
||||||
* Famedly Matrix SDK
|
* Famedly Matrix SDK
|
||||||
* Copyright (C) 2020, 2021 Famedly GmbH
|
* Copyright (C) 2020, 2021 Famedly GmbH
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
// @dart=2.9
|
|
||||||
/*
|
/*
|
||||||
* Famedly Matrix SDK
|
* Famedly Matrix SDK
|
||||||
* Copyright (C) 2020, 2021 Famedly GmbH
|
* Copyright (C) 2020, 2021 Famedly GmbH
|
||||||
|
|
@ -37,7 +36,7 @@ class SpoilerSyntax extends TagSyntax {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Node close(InlineParser parser, Delimiter opener, Delimiter closer,
|
Node close(InlineParser parser, Delimiter opener, Delimiter closer,
|
||||||
{List<Node> Function() getChildren}) {
|
{required List<Node> Function() getChildren}) {
|
||||||
final children = getChildren();
|
final children = getChildren();
|
||||||
final newChildren = <Node>[];
|
final newChildren = <Node>[];
|
||||||
var searchingForReason = true;
|
var searchingForReason = true;
|
||||||
|
|
@ -72,16 +71,16 @@ class SpoilerSyntax extends TagSyntax {
|
||||||
}
|
}
|
||||||
|
|
||||||
class EmoteSyntax extends InlineSyntax {
|
class EmoteSyntax extends InlineSyntax {
|
||||||
final Map<String, Map<String, String>> Function() getEmotePacks;
|
final Map<String, Map<String, String>> Function()? getEmotePacks;
|
||||||
Map<String, Map<String, String>> emotePacks;
|
Map<String, Map<String, String>>? emotePacks;
|
||||||
EmoteSyntax(this.getEmotePacks) : super(r':(?:([-\w]+)~)?([-\w]+):');
|
EmoteSyntax(this.getEmotePacks) : super(r':(?:([-\w]+)~)?([-\w]+):');
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool onMatch(InlineParser parser, Match match) {
|
bool onMatch(InlineParser parser, Match match) {
|
||||||
emotePacks ??= getEmotePacks?.call() ?? <String, Map<String, String>>{};
|
final emotePacks = this.emotePacks ??= getEmotePacks?.call() ?? {};
|
||||||
final pack = match[1] ?? '';
|
final pack = match[1] ?? '';
|
||||||
final emote = match[2];
|
final emote = match[2];
|
||||||
String mxc;
|
String? mxc;
|
||||||
if (pack.isEmpty) {
|
if (pack.isEmpty) {
|
||||||
// search all packs
|
// search all packs
|
||||||
for (final emotePack in emotePacks.values) {
|
for (final emotePack in emotePacks.values) {
|
||||||
|
|
@ -91,11 +90,11 @@ class EmoteSyntax extends InlineSyntax {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mxc = emotePacks[pack] != null ? emotePacks[pack][emote] : null;
|
mxc = emotePacks[pack]?[emote];
|
||||||
}
|
}
|
||||||
if (mxc == null) {
|
if (mxc == null) {
|
||||||
// emote not found. Insert the whole thing as plain text
|
// emote not found. Insert the whole thing as plain text
|
||||||
parser.addNode(Text(match[0]));
|
parser.addNode(Text(match[0]!));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
final element = Element.empty('img');
|
final element = Element.empty('img');
|
||||||
|
|
@ -116,8 +115,8 @@ class InlineLatexSyntax extends TagSyntax {
|
||||||
@override
|
@override
|
||||||
bool onMatch(InlineParser parser, Match match) {
|
bool onMatch(InlineParser parser, Match match) {
|
||||||
final element =
|
final element =
|
||||||
Element('span', [Element.text('code', htmlEscape.convert(match[1]))]);
|
Element('span', [Element.text('code', htmlEscape.convert(match[1]!))]);
|
||||||
element.attributes['data-mx-maths'] = htmlAttrEscape.convert(match[1]);
|
element.attributes['data-mx-maths'] = htmlAttrEscape.convert(match[1]!);
|
||||||
parser.addNode(element);
|
parser.addNode(element);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -136,11 +135,11 @@ class BlockLatexSyntax extends BlockSyntax {
|
||||||
var first = true;
|
var first = true;
|
||||||
while (!parser.isDone) {
|
while (!parser.isDone) {
|
||||||
final match = endPattern.firstMatch(parser.current);
|
final match = endPattern.firstMatch(parser.current);
|
||||||
if (match == null || (first && match.group(1).trim().isEmpty)) {
|
if (match == null || (first && match[1]!.trim().isEmpty)) {
|
||||||
childLines.add(parser.current);
|
childLines.add(parser.current);
|
||||||
parser.advance();
|
parser.advance();
|
||||||
} else {
|
} else {
|
||||||
childLines.add(match.group(1));
|
childLines.add(match[1]!);
|
||||||
parser.advance();
|
parser.advance();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -171,10 +170,10 @@ class PillSyntax extends InlineSyntax {
|
||||||
bool onMatch(InlineParser parser, Match match) {
|
bool onMatch(InlineParser parser, Match match) {
|
||||||
if (match.start > 0 &&
|
if (match.start > 0 &&
|
||||||
!RegExp(r'[\s.!?:;\(]').hasMatch(match.input[match.start - 1])) {
|
!RegExp(r'[\s.!?:;\(]').hasMatch(match.input[match.start - 1])) {
|
||||||
parser.addNode(Text(match[0]));
|
parser.addNode(Text(match[0]!));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
final identifier = match[1];
|
final identifier = match[1]!;
|
||||||
final element = Element.text('a', htmlEscape.convert(identifier));
|
final element = Element.text('a', htmlEscape.convert(identifier));
|
||||||
element.attributes['href'] =
|
element.attributes['href'] =
|
||||||
htmlAttrEscape.convert('https://matrix.to/#/$identifier');
|
htmlAttrEscape.convert('https://matrix.to/#/$identifier');
|
||||||
|
|
@ -184,19 +183,19 @@ class PillSyntax extends InlineSyntax {
|
||||||
}
|
}
|
||||||
|
|
||||||
class MentionSyntax extends InlineSyntax {
|
class MentionSyntax extends InlineSyntax {
|
||||||
final String Function(String) getMention;
|
final String Function(String)? getMention;
|
||||||
MentionSyntax(this.getMention) : super(r'(@(?:\[[^\]:]+\]|\w+)(?:#\w+)?)');
|
MentionSyntax(this.getMention) : super(r'(@(?:\[[^\]:]+\]|\w+)(?:#\w+)?)');
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool onMatch(InlineParser parser, Match match) {
|
bool onMatch(InlineParser parser, Match match) {
|
||||||
final mention = getMention?.call(match[1]);
|
final mention = getMention?.call(match[1]!);
|
||||||
if ((match.start > 0 &&
|
if ((match.start > 0 &&
|
||||||
!RegExp(r'[\s.!?:;\(]').hasMatch(match.input[match.start - 1])) ||
|
!RegExp(r'[\s.!?:;\(]').hasMatch(match.input[match.start - 1])) ||
|
||||||
mention == null) {
|
mention == null) {
|
||||||
parser.addNode(Text(match[0]));
|
parser.addNode(Text(match[0]!));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
final element = Element.text('a', htmlEscape.convert(match[1]));
|
final element = Element.text('a', htmlEscape.convert(match[1]!));
|
||||||
element.attributes['href'] =
|
element.attributes['href'] =
|
||||||
htmlAttrEscape.convert('https://matrix.to/#/$mention');
|
htmlAttrEscape.convert('https://matrix.to/#/$mention');
|
||||||
parser.addNode(element);
|
parser.addNode(element);
|
||||||
|
|
@ -206,8 +205,8 @@ class MentionSyntax extends InlineSyntax {
|
||||||
|
|
||||||
String markdown(
|
String markdown(
|
||||||
String text, {
|
String text, {
|
||||||
Map<String, Map<String, String>> Function() getEmotePacks,
|
Map<String, Map<String, String>> Function()? getEmotePacks,
|
||||||
String Function(String) getMention,
|
String Function(String)? getMention,
|
||||||
}) {
|
}) {
|
||||||
var ret = markdownToHtml(
|
var ret = markdownToHtml(
|
||||||
text,
|
text,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
// @dart=2.9
|
|
||||||
/*
|
/*
|
||||||
* Famedly Matrix SDK
|
* Famedly Matrix SDK
|
||||||
* Copyright (C) 2020, 2021 Famedly GmbH
|
* Copyright (C) 2020, 2021 Famedly GmbH
|
||||||
|
|
@ -20,36 +19,31 @@
|
||||||
import '../../matrix.dart';
|
import '../../matrix.dart';
|
||||||
|
|
||||||
class ToDeviceEvent extends BasicEventWithSender {
|
class ToDeviceEvent extends BasicEventWithSender {
|
||||||
Map<String, dynamic> encryptedContent;
|
Map<String, dynamic>? encryptedContent;
|
||||||
|
|
||||||
String get sender => senderId;
|
String get sender => senderId;
|
||||||
set sender(String sender) => senderId = sender;
|
set sender(String sender) => senderId = sender;
|
||||||
|
|
||||||
ToDeviceEvent({
|
ToDeviceEvent({
|
||||||
String sender,
|
required String sender,
|
||||||
String type,
|
required String type,
|
||||||
Map<String, dynamic> content,
|
required Map<String, dynamic> content,
|
||||||
this.encryptedContent,
|
this.encryptedContent,
|
||||||
}) {
|
}) : super(senderId: sender, type: type, content: content);
|
||||||
senderId = sender;
|
|
||||||
this.type = type;
|
|
||||||
this.content = content;
|
|
||||||
}
|
|
||||||
|
|
||||||
ToDeviceEvent.fromJson(Map<String, dynamic> json) {
|
factory ToDeviceEvent.fromJson(Map<String, dynamic> json) {
|
||||||
final event = BasicEventWithSender.fromJson(json);
|
final event = BasicEventWithSender.fromJson(json);
|
||||||
senderId = event.senderId;
|
return ToDeviceEvent(
|
||||||
type = event.type;
|
sender: event.senderId, type: event.type, content: event.content);
|
||||||
content = event.content;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ToDeviceEventDecryptionError extends ToDeviceEvent {
|
class ToDeviceEventDecryptionError extends ToDeviceEvent {
|
||||||
Exception exception;
|
Exception exception;
|
||||||
StackTrace stackTrace;
|
StackTrace? stackTrace;
|
||||||
ToDeviceEventDecryptionError({
|
ToDeviceEventDecryptionError({
|
||||||
ToDeviceEvent toDeviceEvent,
|
required ToDeviceEvent toDeviceEvent,
|
||||||
this.exception,
|
required this.exception,
|
||||||
this.stackTrace,
|
this.stackTrace,
|
||||||
}) : super(
|
}) : super(
|
||||||
sender: toDeviceEvent.senderId,
|
sender: toDeviceEvent.senderId,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue