chore: make Client.accountData read-only
- for external access, Client.accountData should be read only - added corresponding getter and private Map Signed-off-by: Lanna Michalke <l.michalke@famedly.com>
This commit is contained in:
parent
9b384efd24
commit
ac16724841
|
|
@ -49,3 +49,6 @@ export 'src/utils/to_device_event.dart';
|
||||||
export 'src/utils/uia_request.dart';
|
export 'src/utils/uia_request.dart';
|
||||||
export 'src/utils/uri_extension.dart';
|
export 'src/utils/uri_extension.dart';
|
||||||
export 'src/voip_content.dart';
|
export 'src/voip_content.dart';
|
||||||
|
|
||||||
|
export 'msc_extensions/extension_recent_emoji/recent_emoji.dart';
|
||||||
|
export 'msc_extensions/msc_1236_widgets/msc_1236_widgets.dart';
|
||||||
|
|
|
||||||
|
|
@ -224,6 +224,7 @@ class Client extends MatrixApi {
|
||||||
/// Returns the current login state.
|
/// Returns the current login state.
|
||||||
LoginState get loginState => __loginState;
|
LoginState get loginState => __loginState;
|
||||||
LoginState __loginState;
|
LoginState __loginState;
|
||||||
|
|
||||||
set _loginState(LoginState state) {
|
set _loginState(LoginState state) {
|
||||||
__loginState = state;
|
__loginState = state;
|
||||||
onLoginStateChanged.add(state);
|
onLoginStateChanged.add(state);
|
||||||
|
|
@ -256,7 +257,9 @@ class Client extends MatrixApi {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Key/Value store of account data.
|
/// Key/Value store of account data.
|
||||||
Map<String, BasicEvent> accountData = {};
|
Map<String, BasicEvent> _accountData = {};
|
||||||
|
|
||||||
|
Map<String, BasicEvent> get accountData => _accountData;
|
||||||
|
|
||||||
/// Presences of users by a given matrix ID
|
/// Presences of users by a given matrix ID
|
||||||
Map<String, Presence> presences = {};
|
Map<String, Presence> presences = {};
|
||||||
|
|
@ -287,12 +290,12 @@ class Client extends MatrixApi {
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> get directChats =>
|
Map<String, dynamic> get directChats =>
|
||||||
accountData['m.direct']?.content ?? {};
|
_accountData['m.direct']?.content ?? {};
|
||||||
|
|
||||||
/// Returns the (first) room ID from the store which is a private chat with the user [userId].
|
/// Returns the (first) room ID from the store which is a private chat with the user [userId].
|
||||||
/// Returns null if there is none.
|
/// Returns null if there is none.
|
||||||
String? getDirectChatFromUserId(String userId) {
|
String? getDirectChatFromUserId(String userId) {
|
||||||
final directChats = accountData['m.direct']?.content[userId];
|
final directChats = _accountData['m.direct']?.content[userId];
|
||||||
if (directChats is List<dynamic> && directChats.isNotEmpty) {
|
if (directChats is List<dynamic> && directChats.isNotEmpty) {
|
||||||
final potentialRooms = directChats
|
final potentialRooms = directChats
|
||||||
.cast<String>()
|
.cast<String>()
|
||||||
|
|
@ -834,13 +837,13 @@ class Client extends MatrixApi {
|
||||||
|
|
||||||
/// Returns the global push rules for the logged in user.
|
/// Returns the global push rules for the logged in user.
|
||||||
PushRuleSet? get globalPushRules {
|
PushRuleSet? get globalPushRules {
|
||||||
final pushrules = accountData['m.push_rules']?.content['global'];
|
final pushrules = _accountData['m.push_rules']?.content['global'];
|
||||||
return pushrules != null ? PushRuleSet.fromJson(pushrules) : null;
|
return pushrules != null ? PushRuleSet.fromJson(pushrules) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the device push rules for the logged in user.
|
/// Returns the device push rules for the logged in user.
|
||||||
PushRuleSet? get devicePushRules {
|
PushRuleSet? get devicePushRules {
|
||||||
final pushrules = accountData['m.push_rules']?.content['device'];
|
final pushrules = _accountData['m.push_rules']?.content['device'];
|
||||||
return pushrules != null ? PushRuleSet.fromJson(pushrules) : null;
|
return pushrules != null ? PushRuleSet.fromJson(pushrules) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1104,7 +1107,7 @@ class Client extends MatrixApi {
|
||||||
/// get them from the database.
|
/// get them from the database.
|
||||||
///
|
///
|
||||||
/// Set [waitForFirstSync] and [waitUntilLoadCompletedLoaded] to false to speed this
|
/// Set [waitForFirstSync] and [waitUntilLoadCompletedLoaded] to false to speed this
|
||||||
/// up. You can then wait for `roomsLoading`, `accountDataLoading` and
|
/// up. You can then wait for `roomsLoading`, `_accountDataLoading` and
|
||||||
/// `userDeviceKeysLoading` where it is necessary.
|
/// `userDeviceKeysLoading` where it is necessary.
|
||||||
Future<void> init({
|
Future<void> init({
|
||||||
String? newToken,
|
String? newToken,
|
||||||
|
|
@ -1232,13 +1235,13 @@ class Client extends MatrixApi {
|
||||||
_rooms = rooms;
|
_rooms = rooms;
|
||||||
_sortRooms();
|
_sortRooms();
|
||||||
});
|
});
|
||||||
accountDataLoading =
|
_accountDataLoading =
|
||||||
database.getAccountData().then((data) => accountData = data);
|
database.getAccountData().then((data) => _accountData = data);
|
||||||
presences.clear();
|
presences.clear();
|
||||||
if (waitUntilLoadCompletedLoaded) {
|
if (waitUntilLoadCompletedLoaded) {
|
||||||
await userDeviceKeysLoading;
|
await userDeviceKeysLoading;
|
||||||
await roomsLoading;
|
await roomsLoading;
|
||||||
await accountDataLoading;
|
await _accountDataLoading;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_initLock = false;
|
_initLock = false;
|
||||||
|
|
@ -1379,7 +1382,7 @@ class Client extends MatrixApi {
|
||||||
if (database != null) {
|
if (database != null) {
|
||||||
await userDeviceKeysLoading;
|
await userDeviceKeysLoading;
|
||||||
await roomsLoading;
|
await roomsLoading;
|
||||||
await accountDataLoading;
|
await _accountDataLoading;
|
||||||
_currentTransaction = database.transaction(() async {
|
_currentTransaction = database.transaction(() async {
|
||||||
await _handleSync(syncResp);
|
await _handleSync(syncResp);
|
||||||
if (prevBatch != syncResp.nextBatch) {
|
if (prevBatch != syncResp.nextBatch) {
|
||||||
|
|
@ -1888,7 +1891,9 @@ class Client extends MatrixApi {
|
||||||
|
|
||||||
Future? userDeviceKeysLoading;
|
Future? userDeviceKeysLoading;
|
||||||
Future? roomsLoading;
|
Future? roomsLoading;
|
||||||
Future? accountDataLoading;
|
Future? _accountDataLoading;
|
||||||
|
|
||||||
|
Future? get accountDataLoading => _accountDataLoading;
|
||||||
|
|
||||||
/// A map of known device keys per user.
|
/// A map of known device keys per user.
|
||||||
Map<String, DeviceKeysList> get userDeviceKeys => _userDeviceKeys;
|
Map<String, DeviceKeysList> get userDeviceKeys => _userDeviceKeys;
|
||||||
|
|
@ -2338,7 +2343,7 @@ class Client extends MatrixApi {
|
||||||
/// rule of the push rules: https://matrix.org/docs/spec/client_server/r0.6.0#m-rule-master
|
/// rule of the push rules: https://matrix.org/docs/spec/client_server/r0.6.0#m-rule-master
|
||||||
bool get allPushNotificationsMuted {
|
bool get allPushNotificationsMuted {
|
||||||
final Map<String, dynamic>? globalPushRules =
|
final Map<String, dynamic>? globalPushRules =
|
||||||
accountData['m.push_rules']?.content['global'];
|
_accountData['m.push_rules']?.content['global'];
|
||||||
if (globalPushRules == null) return false;
|
if (globalPushRules == null) return false;
|
||||||
|
|
||||||
if (globalPushRules['override'] is List) {
|
if (globalPushRules['override'] is List) {
|
||||||
|
|
@ -2418,11 +2423,11 @@ class Client extends MatrixApi {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A list of mxids of users who are ignored.
|
/// A list of mxids of users who are ignored.
|
||||||
List<String> get ignoredUsers => (accountData
|
List<String> get ignoredUsers => (_accountData
|
||||||
.containsKey('m.ignored_user_list') &&
|
.containsKey('m.ignored_user_list') &&
|
||||||
accountData['m.ignored_user_list']?.content['ignored_users'] is Map)
|
_accountData['m.ignored_user_list']?.content['ignored_users'] is Map)
|
||||||
? List<String>.from(
|
? List<String>.from(
|
||||||
accountData['m.ignored_user_list']?.content['ignored_users'].keys)
|
_accountData['m.ignored_user_list']?.content['ignored_users'].keys)
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
/// Ignore another user. This will clear the local cached messages to
|
/// Ignore another user. This will clear the local cached messages to
|
||||||
|
|
@ -2630,6 +2635,7 @@ class SyncStatusUpdate {
|
||||||
final SyncStatus status;
|
final SyncStatus status;
|
||||||
final SdkError? error;
|
final SdkError? error;
|
||||||
final double? progress;
|
final double? progress;
|
||||||
|
|
||||||
const SyncStatusUpdate(this.status, {this.error, this.progress});
|
const SyncStatusUpdate(this.status, {this.error, this.progress});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2643,6 +2649,7 @@ enum SyncStatus {
|
||||||
|
|
||||||
class BadServerVersionsException implements Exception {
|
class BadServerVersionsException implements Exception {
|
||||||
final Set<String> serverVersions, supportedVersions;
|
final Set<String> serverVersions, supportedVersions;
|
||||||
|
|
||||||
BadServerVersionsException(this.serverVersions, this.supportedVersions);
|
BadServerVersionsException(this.serverVersions, this.supportedVersions);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -2652,6 +2659,7 @@ class BadServerVersionsException implements Exception {
|
||||||
|
|
||||||
class BadServerLoginTypesException implements Exception {
|
class BadServerLoginTypesException implements Exception {
|
||||||
final Set<String> serverLoginTypes, supportedLoginTypes;
|
final Set<String> serverLoginTypes, supportedLoginTypes;
|
||||||
|
|
||||||
BadServerLoginTypesException(this.serverLoginTypes, this.supportedLoginTypes);
|
BadServerLoginTypesException(this.serverLoginTypes, this.supportedLoginTypes);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@ import 'package:html_unescape/html_unescape.dart';
|
||||||
import 'package:matrix/src/utils/crypto/crypto.dart';
|
import 'package:matrix/src/utils/crypto/crypto.dart';
|
||||||
import 'package:matrix/src/utils/file_send_request_credentials.dart';
|
import 'package:matrix/src/utils/file_send_request_credentials.dart';
|
||||||
import 'package:matrix/src/utils/space_child.dart';
|
import 'package:matrix/src/utils/space_child.dart';
|
||||||
import 'package:matrix/widget.dart';
|
|
||||||
|
|
||||||
import '../matrix.dart';
|
import '../matrix.dart';
|
||||||
import 'utils/markdown.dart';
|
import 'utils/markdown.dart';
|
||||||
|
|
@ -357,42 +356,6 @@ class Room {
|
||||||
: [];
|
: [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns all present Widgets in the room.
|
|
||||||
List<MatrixWidget> get widgets => {
|
|
||||||
...states['m.widget'] ?? states['im.vector.modular.widgets'] ?? {},
|
|
||||||
}.values.expand((e) {
|
|
||||||
try {
|
|
||||||
return [MatrixWidget.fromJson(e.content, this)];
|
|
||||||
} catch (_) {
|
|
||||||
return <MatrixWidget>[];
|
|
||||||
}
|
|
||||||
}).toList();
|
|
||||||
|
|
||||||
Future<String> addWidget(MatrixWidget widget) {
|
|
||||||
final user = client.userID;
|
|
||||||
final widgetId =
|
|
||||||
widget.name!.toLowerCase().replaceAll(RegExp(r'\W'), '_') + '_' + user!;
|
|
||||||
|
|
||||||
final json = widget.toJson();
|
|
||||||
json['creatorUserId'] = user;
|
|
||||||
json['id'] = widgetId;
|
|
||||||
return client.setRoomStateWithKey(
|
|
||||||
id,
|
|
||||||
'im.vector.modular.widgets',
|
|
||||||
widgetId,
|
|
||||||
json,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<String> deleteWidget(String widgetId) {
|
|
||||||
return client.setRoomStateWithKey(
|
|
||||||
id,
|
|
||||||
'im.vector.modular.widgets',
|
|
||||||
widgetId,
|
|
||||||
{},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Your current client instance.
|
/// Your current client instance.
|
||||||
final Client client;
|
final Client client;
|
||||||
|
|
||||||
|
|
|
||||||
128
lib/widget.dart
128
lib/widget.dart
|
|
@ -1,128 +0,0 @@
|
||||||
import 'package:matrix/src/room.dart';
|
|
||||||
|
|
||||||
class MatrixWidget {
|
|
||||||
final Room room;
|
|
||||||
final String? creatorUserId;
|
|
||||||
final Map<String, dynamic>? data;
|
|
||||||
final String? id;
|
|
||||||
final String? name;
|
|
||||||
final String type;
|
|
||||||
|
|
||||||
/// use [buildWidgetUrl] instead
|
|
||||||
final String url;
|
|
||||||
final bool waitForIframeLoad;
|
|
||||||
|
|
||||||
MatrixWidget({
|
|
||||||
required this.room,
|
|
||||||
this.creatorUserId,
|
|
||||||
this.data = const {},
|
|
||||||
this.id,
|
|
||||||
required this.name,
|
|
||||||
required this.type,
|
|
||||||
required this.url,
|
|
||||||
this.waitForIframeLoad = false,
|
|
||||||
});
|
|
||||||
|
|
||||||
factory MatrixWidget.fromJson(Map<String, dynamic> json, Room room) =>
|
|
||||||
MatrixWidget(
|
|
||||||
room: room,
|
|
||||||
creatorUserId:
|
|
||||||
json.containsKey('creatorUserId') ? json['creatorUserId'] : null,
|
|
||||||
data: json.containsKey('data') ? json['data'] : {},
|
|
||||||
id: json.containsKey('id') ? json['id'] : null,
|
|
||||||
name: json['name'],
|
|
||||||
type: json['type'],
|
|
||||||
url: json['url'],
|
|
||||||
waitForIframeLoad: json.containsKey('waitForIframeLoad')
|
|
||||||
? json['waitForIframeLoad']
|
|
||||||
: false,
|
|
||||||
);
|
|
||||||
|
|
||||||
/// creates an `m.etherpad` [MatrixWidget]
|
|
||||||
factory MatrixWidget.etherpad(Room room, String name, Uri url) =>
|
|
||||||
MatrixWidget(
|
|
||||||
room: room,
|
|
||||||
name: name,
|
|
||||||
type: 'm.etherpad',
|
|
||||||
url: url.toString(),
|
|
||||||
data: {
|
|
||||||
'url': url.toString(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
/// creates an `m.jitsi` [MatrixWidget]
|
|
||||||
factory MatrixWidget.jitsi(Room room, String name, Uri url,
|
|
||||||
{bool isAudioOnly = false}) =>
|
|
||||||
MatrixWidget(
|
|
||||||
room: room,
|
|
||||||
name: name,
|
|
||||||
type: 'm.jitsi',
|
|
||||||
url: url.toString(),
|
|
||||||
data: {
|
|
||||||
'domain': url.host,
|
|
||||||
'conferenceId': url.pathSegments.last,
|
|
||||||
'isAudioOnly': isAudioOnly,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
/// creates an `m.video` [MatrixWidget]
|
|
||||||
factory MatrixWidget.video(Room room, String name, Uri url) => MatrixWidget(
|
|
||||||
room: room,
|
|
||||||
name: name,
|
|
||||||
type: 'm.video',
|
|
||||||
url: url.toString(),
|
|
||||||
data: {
|
|
||||||
'url': url.toString(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
/// creates an `m.custom` [MatrixWidget]
|
|
||||||
factory MatrixWidget.custom(Room room, String name, Uri url) => MatrixWidget(
|
|
||||||
room: room,
|
|
||||||
name: name,
|
|
||||||
type: 'm.custom',
|
|
||||||
url: url.toString(),
|
|
||||||
data: {
|
|
||||||
'url': url.toString(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
Future<Uri> buildWidgetUrl() async {
|
|
||||||
// See https://github.com/matrix-org/matrix-doc/issues/1236 for a
|
|
||||||
// description, specifically the section
|
|
||||||
// `What does the other stuff in content mean?`
|
|
||||||
final userProfile = await room.client.ownProfile;
|
|
||||||
var parsedUri = url;
|
|
||||||
|
|
||||||
// a key-value map with the strings to be replaced
|
|
||||||
final replaceMap = {
|
|
||||||
r'$matrix_user_id': userProfile.userId,
|
|
||||||
r'$matrix_room_id': room.id,
|
|
||||||
r'$matrix_display_name': userProfile.displayName ?? '',
|
|
||||||
r'$matrix_avatar_url': userProfile.avatarUrl?.toString() ?? '',
|
|
||||||
// removing potentially dangerous keys containing anything but
|
|
||||||
// `[a-zA-Z0-9_-]` as well as non string values
|
|
||||||
if (data != null)
|
|
||||||
...Map.from(data!)
|
|
||||||
..removeWhere((key, value) =>
|
|
||||||
!RegExp(r'^[\w-]+$').hasMatch(key) || !value is String)
|
|
||||||
..map((key, value) => MapEntry('\$key', value)),
|
|
||||||
};
|
|
||||||
|
|
||||||
replaceMap.forEach((key, value) {
|
|
||||||
parsedUri = parsedUri.replaceAll(key, Uri.encodeComponent(value));
|
|
||||||
});
|
|
||||||
|
|
||||||
return Uri.parse(parsedUri);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
|
||||||
'creatorUserId': creatorUserId,
|
|
||||||
'data': data,
|
|
||||||
'id': id,
|
|
||||||
'name': name,
|
|
||||||
'type': type,
|
|
||||||
'url': url,
|
|
||||||
'waitForIframeLoad': waitForIframeLoad,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue