refactor: Remove dart from folder name
This commit is contained in:
parent
d29c6d60a3
commit
5cf18aabbf
40 changed files with 37 additions and 37 deletions
|
|
@ -0,0 +1,98 @@
|
|||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
import 'package:adaptive_dialog/adaptive_dialog.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
extension ClientStoriesExtension on Client {
|
||||
static const String storiesRoomType = 'msc3588.stories.stories-room';
|
||||
static const String storiesBlockListType = 'msc3588.stories.block-list';
|
||||
|
||||
static const int lifeTimeInHours = 24;
|
||||
static const int maxPostsPerStory = 20;
|
||||
|
||||
List<User> get contacts => rooms
|
||||
.where((room) => room.isDirectChat)
|
||||
.map((room) =>
|
||||
room.unsafeGetUserFromMemoryOrFallback(room.directChatMatrixID!))
|
||||
.toList();
|
||||
|
||||
List<Room> get storiesRooms =>
|
||||
rooms.where((room) => room.isStoryRoom).toList();
|
||||
|
||||
Future<List<User>> getUndecidedContactsForStories(Room? storiesRoom) async {
|
||||
if (storiesRoom == null) return contacts;
|
||||
final invitedContacts =
|
||||
(await storiesRoom.requestParticipants()).map((user) => user.id);
|
||||
final decidedContacts = storiesBlockList.toSet()..addAll(invitedContacts);
|
||||
return contacts
|
||||
.where((contact) => !decidedContacts.contains(contact.id))
|
||||
.toList();
|
||||
}
|
||||
|
||||
List<String> get storiesBlockList =>
|
||||
accountData[storiesBlockListType]?.content.tryGetList<String>('users') ??
|
||||
[];
|
||||
|
||||
Future<void> setStoriesBlockList(List<String> users) => setAccountData(
|
||||
userID!,
|
||||
storiesBlockListType,
|
||||
{'users': users},
|
||||
);
|
||||
|
||||
Future<Room> createStoriesRoom([List<String>? invite]) async {
|
||||
final roomId = await createRoom(
|
||||
creationContent: {"type": "msc3588.stories.stories-room"},
|
||||
preset: CreateRoomPreset.privateChat,
|
||||
powerLevelContentOverride: {"events_default": 100},
|
||||
name: 'Stories from ${userID!.localpart}',
|
||||
topic:
|
||||
'This is a room for stories sharing, not unlike the similarly named features in other messaging networks. For best experience please use FluffyChat or minesTrix. Feature development can be followed on: https://github.com/matrix-org/matrix-doc/pull/3588',
|
||||
initialState: [
|
||||
StateEvent(
|
||||
type: EventTypes.Encryption,
|
||||
stateKey: '',
|
||||
content: {
|
||||
'algorithm': 'm.megolm.v1.aes-sha2',
|
||||
},
|
||||
),
|
||||
StateEvent(
|
||||
type: 'm.room.retention',
|
||||
stateKey: '',
|
||||
content: {
|
||||
'min_lifetime': 86400000,
|
||||
'max_lifetime': 86400000,
|
||||
},
|
||||
),
|
||||
],
|
||||
invite: invite,
|
||||
);
|
||||
if (getRoomById(roomId) == null) {
|
||||
// Wait for room actually appears in sync
|
||||
await onSync.stream
|
||||
.firstWhere((sync) => sync.rooms?.join?.containsKey(roomId) ?? false);
|
||||
}
|
||||
return getRoomById(roomId)!;
|
||||
}
|
||||
|
||||
Future<Room?> getStoriesRoom(BuildContext context) async {
|
||||
final candidates = rooms.where((room) =>
|
||||
room.getState(EventTypes.RoomCreate)?.content.tryGet<String>('type') ==
|
||||
storiesRoomType &&
|
||||
room.ownPowerLevel >= 100);
|
||||
if (candidates.isEmpty) return null;
|
||||
if (candidates.length == 1) return candidates.single;
|
||||
return await showModalActionSheet<Room>(
|
||||
context: context,
|
||||
actions: candidates
|
||||
.map(
|
||||
(room) => SheetAction(label: room.displayname, key: room),
|
||||
)
|
||||
.toList());
|
||||
}
|
||||
}
|
||||
|
||||
extension StoryRoom on Room {
|
||||
bool get isStoryRoom =>
|
||||
getState(EventTypes.RoomCreate)?.content.tryGet<String>('type') ==
|
||||
ClientStoriesExtension.storiesRoomType;
|
||||
}
|
||||
45
lib/utils/matrix_sdk_extensions/device_extension.dart
Normal file
45
lib/utils/matrix_sdk_extensions/device_extension.dart
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
IconData _getIconFromName(String displayname) {
|
||||
final name = displayname.toLowerCase();
|
||||
if ({'android'}.any((s) => name.contains(s))) {
|
||||
return Icons.phone_android_outlined;
|
||||
}
|
||||
if ({'ios', 'ipad', 'iphone', 'ipod'}.any((s) => name.contains(s))) {
|
||||
return Icons.phone_iphone_outlined;
|
||||
}
|
||||
if ({
|
||||
'web',
|
||||
'http://',
|
||||
'https://',
|
||||
'firefox',
|
||||
'chrome',
|
||||
'/_matrix',
|
||||
'safari',
|
||||
'opera',
|
||||
}.any((s) => name.contains(s))) {
|
||||
return Icons.web_outlined;
|
||||
}
|
||||
if ({'desktop', 'windows', 'macos', 'linux', 'ubuntu'}
|
||||
.any((s) => name.contains(s))) {
|
||||
return Icons.desktop_mac_outlined;
|
||||
}
|
||||
return Icons.device_unknown_outlined;
|
||||
}
|
||||
|
||||
extension DeviceExtension on Device {
|
||||
String get displayname =>
|
||||
(displayName?.isNotEmpty ?? false) ? displayName! : 'Unknown device';
|
||||
|
||||
IconData get icon => _getIconFromName(displayname);
|
||||
}
|
||||
|
||||
extension DeviceKeysExtension on DeviceKeys {
|
||||
String get displayname => (deviceDisplayName?.isNotEmpty ?? false)
|
||||
? deviceDisplayName!
|
||||
: 'Unknown device';
|
||||
|
||||
IconData get icon => _getIconFromName(displayname);
|
||||
}
|
||||
49
lib/utils/matrix_sdk_extensions/event_extension.dart
Normal file
49
lib/utils/matrix_sdk_extensions/event_extension.dart
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:future_loading_dialog/future_loading_dialog.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/utils/size_string.dart';
|
||||
import 'matrix_file_extension.dart';
|
||||
|
||||
extension LocalizedBody on Event {
|
||||
Future<LoadingDialogResult<MatrixFile?>> _getFile(BuildContext context) =>
|
||||
showFutureLoadingDialog(
|
||||
context: context,
|
||||
future: downloadAndDecryptAttachment,
|
||||
);
|
||||
|
||||
void saveFile(BuildContext context) async {
|
||||
final matrixFile = await _getFile(context);
|
||||
|
||||
matrixFile.result?.save(context);
|
||||
}
|
||||
|
||||
void shareFile(BuildContext context) async {
|
||||
final matrixFile = await _getFile(context);
|
||||
|
||||
matrixFile.result?.share(context);
|
||||
}
|
||||
|
||||
bool get isAttachmentSmallEnough =>
|
||||
infoMap['size'] is int &&
|
||||
infoMap['size'] < room.client.database!.maxFileSize;
|
||||
|
||||
bool get isThumbnailSmallEnough =>
|
||||
thumbnailInfoMap['size'] is int &&
|
||||
thumbnailInfoMap['size'] < room.client.database!.maxFileSize;
|
||||
|
||||
bool get showThumbnail =>
|
||||
[MessageTypes.Image, MessageTypes.Sticker, MessageTypes.Video]
|
||||
.contains(messageType) &&
|
||||
(kIsWeb ||
|
||||
isAttachmentSmallEnough ||
|
||||
isThumbnailSmallEnough ||
|
||||
(content['url'] is String));
|
||||
|
||||
String? get sizeString => content
|
||||
.tryGetMap<String, dynamic>('info')
|
||||
?.tryGet<int>('size')
|
||||
?.sizeString;
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import '../../config/app_config.dart';
|
||||
|
||||
extension IsStateExtension on Event {
|
||||
bool get isVisibleInGui =>
|
||||
// always filter out edit and reaction relationships
|
||||
!{RelationshipTypes.edit, RelationshipTypes.reaction}
|
||||
.contains(relationshipType) &&
|
||||
// always filter out m.key.* events
|
||||
!type.startsWith('m.key.verification.') &&
|
||||
// event types to hide: redaction and reaction events
|
||||
// if a reaction has been redacted we also want it to be hidden in the timeline
|
||||
!{EventTypes.Reaction, EventTypes.Redaction}.contains(type) &&
|
||||
// if we enabled to hide all redacted events, don't show those
|
||||
(!AppConfig.hideRedactedEvents || !redacted) &&
|
||||
// if we enabled to hide all unknown events, don't show those
|
||||
(!AppConfig.hideUnknownEvents || isEventTypeKnown) &&
|
||||
// remove state events that we don't want to render
|
||||
(isState || !AppConfig.hideAllStateEvents) &&
|
||||
// hide unimportant state events
|
||||
(!AppConfig.hideUnimportantStateEvents ||
|
||||
!isState ||
|
||||
importantStateEvents.contains(type)) &&
|
||||
// hide simple join/leave member events in public rooms
|
||||
(!AppConfig.hideUnimportantStateEvents ||
|
||||
type != EventTypes.RoomMember ||
|
||||
room.joinRules != JoinRules.public ||
|
||||
content.tryGet<String>('membership') == 'ban' ||
|
||||
stateKey != senderId);
|
||||
|
||||
static const Set<String> importantStateEvents = {
|
||||
EventTypes.Encryption,
|
||||
EventTypes.RoomCreate,
|
||||
EventTypes.RoomMember,
|
||||
EventTypes.RoomTombstone,
|
||||
EventTypes.CallInvite,
|
||||
};
|
||||
|
||||
bool get isState => !{
|
||||
EventTypes.Message,
|
||||
EventTypes.Sticker,
|
||||
EventTypes.Encrypted
|
||||
}.contains(type);
|
||||
}
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart' hide Key;
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
||||
class FlutterHiveCollectionsDatabase extends HiveCollectionsDatabase {
|
||||
FlutterHiveCollectionsDatabase(
|
||||
String name,
|
||||
String path, {
|
||||
HiveCipher? key,
|
||||
}) : super(
|
||||
name,
|
||||
path,
|
||||
key: key,
|
||||
);
|
||||
|
||||
static const String _cipherStorageKey = 'hive_encryption_key';
|
||||
|
||||
static Future<FlutterHiveCollectionsDatabase> databaseBuilder(
|
||||
Client client) async {
|
||||
Logs().d('Open Hive...');
|
||||
HiveAesCipher? hiverCipher;
|
||||
try {
|
||||
// Workaround for secure storage is calling Platform.operatingSystem on web
|
||||
if (kIsWeb) throw MissingPluginException();
|
||||
|
||||
const secureStorage = FlutterSecureStorage();
|
||||
final containsEncryptionKey =
|
||||
await secureStorage.read(key: _cipherStorageKey) != null;
|
||||
if (!containsEncryptionKey) {
|
||||
// do not try to create a buggy secure storage for new Linux users
|
||||
if (Platform.isLinux) throw MissingPluginException();
|
||||
final key = Hive.generateSecureKey();
|
||||
await secureStorage.write(
|
||||
key: _cipherStorageKey,
|
||||
value: base64UrlEncode(key),
|
||||
);
|
||||
}
|
||||
|
||||
// workaround for if we just wrote to the key and it still doesn't exist
|
||||
final rawEncryptionKey = await secureStorage.read(key: _cipherStorageKey);
|
||||
if (rawEncryptionKey == null) throw MissingPluginException();
|
||||
|
||||
hiverCipher = HiveAesCipher(base64Url.decode(rawEncryptionKey));
|
||||
} on MissingPluginException catch (_) {
|
||||
const FlutterSecureStorage()
|
||||
.delete(key: _cipherStorageKey)
|
||||
.catchError((_) {});
|
||||
Logs().i('Hive encryption is not supported on this platform');
|
||||
} catch (e, s) {
|
||||
const FlutterSecureStorage()
|
||||
.delete(key: _cipherStorageKey)
|
||||
.catchError((_) {});
|
||||
Logs().w('Unable to init Hive encryption', e, s);
|
||||
}
|
||||
|
||||
final db = FlutterHiveCollectionsDatabase(
|
||||
'hive_collections_${client.clientName.replaceAll(' ', '_').toLowerCase()}',
|
||||
await _findDatabasePath(client),
|
||||
key: hiverCipher,
|
||||
);
|
||||
try {
|
||||
await db.open();
|
||||
} catch (e, s) {
|
||||
Logs().w('Unable to open Hive. Delete database and storage key...', e, s);
|
||||
const FlutterSecureStorage().delete(key: _cipherStorageKey);
|
||||
await db.clear().catchError((_) {});
|
||||
await Hive.deleteFromDisk();
|
||||
rethrow;
|
||||
}
|
||||
Logs().d('Hive is ready');
|
||||
return db;
|
||||
}
|
||||
|
||||
static Future<String> _findDatabasePath(Client client) async {
|
||||
String path = client.clientName;
|
||||
if (!kIsWeb) {
|
||||
Directory directory;
|
||||
try {
|
||||
if (Platform.isLinux) {
|
||||
directory = await getApplicationSupportDirectory();
|
||||
} else {
|
||||
directory = await getApplicationDocumentsDirectory();
|
||||
}
|
||||
} catch (_) {
|
||||
try {
|
||||
directory = await getLibraryDirectory();
|
||||
} catch (_) {
|
||||
directory = Directory.current;
|
||||
}
|
||||
}
|
||||
// do not destroy your stable FluffyChat in debug mode
|
||||
directory = Directory(directory.uri
|
||||
.resolve(kDebugMode ? 'hive_debug' : 'hive')
|
||||
.toFilePath());
|
||||
directory.create(recursive: true);
|
||||
path = directory.path;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
@override
|
||||
int get maxFileSize => supportsFileStoring ? 100 * 1024 * 1024 : 0;
|
||||
@override
|
||||
bool get supportsFileStoring => !kIsWeb;
|
||||
|
||||
Future<String> _getFileStoreDirectory() async {
|
||||
try {
|
||||
try {
|
||||
return (await getApplicationSupportDirectory()).path;
|
||||
} catch (_) {
|
||||
return (await getApplicationDocumentsDirectory()).path;
|
||||
}
|
||||
} catch (_) {
|
||||
return (await getDownloadsDirectory())!.path;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Uint8List?> getFile(Uri mxcUri) async {
|
||||
if (!supportsFileStoring) return null;
|
||||
final tempDirectory = await _getFileStoreDirectory();
|
||||
final file =
|
||||
File('$tempDirectory/${Uri.encodeComponent(mxcUri.toString())}');
|
||||
if (await file.exists() == false) return null;
|
||||
final bytes = await file.readAsBytes();
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@override
|
||||
Future storeFile(Uri mxcUri, Uint8List bytes, int time) async {
|
||||
if (!supportsFileStoring) return null;
|
||||
final tempDirectory = await _getFileStoreDirectory();
|
||||
final file =
|
||||
File('$tempDirectory/${Uri.encodeComponent(mxcUri.toString())}');
|
||||
if (await file.exists()) return;
|
||||
await file.writeAsBytes(bytes);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import 'package:flutter_app_badger/flutter_app_badger.dart';
|
||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/utils/platform_infos.dart';
|
||||
|
||||
extension IosBadgeClientExtension on Client {
|
||||
void updateIosBadge() {
|
||||
if (PlatformInfos.isIOS) {
|
||||
// Workaround for iOS not clearing notifications with fcm_shared_isolate
|
||||
if (!rooms.any((r) =>
|
||||
r.membership == Membership.invite || (r.notificationCount > 0))) {
|
||||
// ignore: unawaited_futures
|
||||
FlutterLocalNotificationsPlugin().cancelAll();
|
||||
FlutterAppBadger.removeBadge();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
56
lib/utils/matrix_sdk_extensions/matrix_file_extension.dart
Normal file
56
lib/utils/matrix_sdk_extensions/matrix_file_extension.dart
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:file_picker_cross/file_picker_cross.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
|
||||
import 'package:fluffychat/utils/platform_infos.dart';
|
||||
import 'package:fluffychat/utils/size_string.dart';
|
||||
|
||||
extension MatrixFileExtension on MatrixFile {
|
||||
void save(BuildContext context) async {
|
||||
if (PlatformInfos.isIOS) {
|
||||
return share(context);
|
||||
}
|
||||
final fileName = name.split('/').last;
|
||||
|
||||
final file = FilePickerCross(bytes);
|
||||
await file.exportToStorage(fileName: fileName, share: false);
|
||||
}
|
||||
|
||||
void share(BuildContext context) async {
|
||||
final fileName = name.split('/').last;
|
||||
final tmpDirectory = await getTemporaryDirectory();
|
||||
final path = '${tmpDirectory.path}$fileName';
|
||||
await File(path).writeAsBytes(bytes);
|
||||
|
||||
// Workaround for iPad from
|
||||
// https://github.com/fluttercommunity/plus_plugins/tree/main/packages/share_plus/share_plus#ipad
|
||||
final box = context.findRenderObject() as RenderBox?;
|
||||
|
||||
await Share.shareFiles(
|
||||
[path],
|
||||
sharePositionOrigin:
|
||||
box == null ? null : box.localToGlobal(Offset.zero) & box.size,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
MatrixFile get detectFileType {
|
||||
if (msgType == MessageTypes.Image) {
|
||||
return MatrixImageFile(bytes: bytes, name: name);
|
||||
}
|
||||
if (msgType == MessageTypes.Video) {
|
||||
return MatrixVideoFile(bytes: bytes, name: name);
|
||||
}
|
||||
if (msgType == MessageTypes.Audio) {
|
||||
return MatrixAudioFile(bytes: bytes, name: name);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
String get sizeString => size.sizeString;
|
||||
}
|
||||
307
lib/utils/matrix_sdk_extensions/matrix_locals.dart
Normal file
307
lib/utils/matrix_sdk_extensions/matrix_locals.dart
Normal file
|
|
@ -0,0 +1,307 @@
|
|||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
/// This is a temporary helper class until there is a proper solution to this with the new system
|
||||
class MatrixLocals extends MatrixLocalizations {
|
||||
final L10n l10n;
|
||||
|
||||
MatrixLocals(this.l10n);
|
||||
|
||||
@override
|
||||
String acceptedTheInvitation(String targetName) {
|
||||
return l10n.acceptedTheInvitation(targetName);
|
||||
}
|
||||
|
||||
@override
|
||||
String activatedEndToEndEncryption(String senderName) {
|
||||
return l10n.activatedEndToEndEncryption(senderName);
|
||||
}
|
||||
|
||||
@override
|
||||
String answeredTheCall(String senderName) {
|
||||
return l10n.answeredTheCall(senderName);
|
||||
}
|
||||
|
||||
@override
|
||||
String get anyoneCanJoin => l10n.anyoneCanJoin;
|
||||
|
||||
@override
|
||||
String bannedUser(String senderName, String targetName) {
|
||||
return l10n.bannedUser(senderName, targetName);
|
||||
}
|
||||
|
||||
@override
|
||||
String changedTheChatAvatar(String senderName) {
|
||||
return l10n.changedTheChatAvatar(senderName);
|
||||
}
|
||||
|
||||
@override
|
||||
String changedTheChatDescriptionTo(String senderName, String content) {
|
||||
return l10n.changedTheChatDescriptionTo(senderName, content);
|
||||
}
|
||||
|
||||
@override
|
||||
String changedTheChatNameTo(String senderName, String content) {
|
||||
return l10n.changedTheChatNameTo(senderName, content);
|
||||
}
|
||||
|
||||
@override
|
||||
String changedTheChatPermissions(String senderName) {
|
||||
return l10n.changedTheChatPermissions(senderName);
|
||||
}
|
||||
|
||||
@override
|
||||
String changedTheDisplaynameTo(String targetName, String newDisplayname) {
|
||||
return l10n.changedTheDisplaynameTo(targetName, newDisplayname);
|
||||
}
|
||||
|
||||
@override
|
||||
String changedTheGuestAccessRules(String senderName) {
|
||||
return l10n.changedTheGuestAccessRules(senderName);
|
||||
}
|
||||
|
||||
@override
|
||||
String changedTheGuestAccessRulesTo(
|
||||
String senderName, String localizedString) {
|
||||
return l10n.changedTheGuestAccessRulesTo(senderName, localizedString);
|
||||
}
|
||||
|
||||
@override
|
||||
String changedTheHistoryVisibility(String senderName) {
|
||||
return l10n.changedTheHistoryVisibility(senderName);
|
||||
}
|
||||
|
||||
@override
|
||||
String changedTheHistoryVisibilityTo(
|
||||
String senderName, String localizedString) {
|
||||
return l10n.changedTheHistoryVisibilityTo(senderName, localizedString);
|
||||
}
|
||||
|
||||
@override
|
||||
String changedTheJoinRules(String senderName) {
|
||||
return l10n.changedTheJoinRules(senderName);
|
||||
}
|
||||
|
||||
@override
|
||||
String changedTheJoinRulesTo(String senderName, String localizedString) {
|
||||
return l10n.changedTheJoinRulesTo(senderName, localizedString);
|
||||
}
|
||||
|
||||
@override
|
||||
String changedTheProfileAvatar(String targetName) {
|
||||
return l10n.changedTheProfileAvatar(targetName);
|
||||
}
|
||||
|
||||
@override
|
||||
String changedTheRoomAliases(String senderName) {
|
||||
return l10n.changedTheRoomAliases(senderName);
|
||||
}
|
||||
|
||||
@override
|
||||
String changedTheRoomInvitationLink(String senderName) {
|
||||
return l10n.changedTheRoomInvitationLink(senderName);
|
||||
}
|
||||
|
||||
@override
|
||||
String get channelCorruptedDecryptError => l10n.channelCorruptedDecryptError;
|
||||
|
||||
@override
|
||||
String couldNotDecryptMessage(String errorText) {
|
||||
return l10n.couldNotDecryptMessage(errorText);
|
||||
}
|
||||
|
||||
@override
|
||||
String createdTheChat(String senderName) {
|
||||
return l10n.createdTheChat(senderName);
|
||||
}
|
||||
|
||||
@override
|
||||
String get emptyChat => l10n.emptyChat;
|
||||
|
||||
@override
|
||||
String get encryptionNotEnabled => l10n.encryptionNotEnabled;
|
||||
|
||||
@override
|
||||
String endedTheCall(String senderName) {
|
||||
return l10n.endedTheCall(senderName);
|
||||
}
|
||||
|
||||
@override
|
||||
String get fromJoining => l10n.fromJoining;
|
||||
|
||||
@override
|
||||
String get fromTheInvitation => l10n.fromTheInvitation;
|
||||
|
||||
@override
|
||||
String groupWith(String displayname) {
|
||||
return l10n.groupWith(displayname);
|
||||
}
|
||||
|
||||
@override
|
||||
String get guestsAreForbidden => l10n.guestsAreForbidden;
|
||||
|
||||
@override
|
||||
String get guestsCanJoin => l10n.guestsCanJoin;
|
||||
|
||||
@override
|
||||
String hasWithdrawnTheInvitationFor(String senderName, String targetName) {
|
||||
return l10n.hasWithdrawnTheInvitationFor(senderName, targetName);
|
||||
}
|
||||
|
||||
@override
|
||||
String invitedUser(String senderName, String targetName) {
|
||||
return l10n.invitedUser(senderName, targetName);
|
||||
}
|
||||
|
||||
@override
|
||||
String get invitedUsersOnly => l10n.invitedUsersOnly;
|
||||
|
||||
@override
|
||||
String joinedTheChat(String targetName) {
|
||||
return l10n.joinedTheChat(targetName);
|
||||
}
|
||||
|
||||
@override
|
||||
String kicked(String senderName, String targetName) {
|
||||
return l10n.kicked(senderName, targetName);
|
||||
}
|
||||
|
||||
@override
|
||||
String kickedAndBanned(String senderName, String targetName) {
|
||||
return l10n.kickedAndBanned(senderName, targetName);
|
||||
}
|
||||
|
||||
@override
|
||||
String get needPantalaimonWarning => l10n.needPantalaimonWarning;
|
||||
|
||||
@override
|
||||
String get noPermission => l10n.noKeyForThisMessage;
|
||||
|
||||
@override
|
||||
String redactedAnEvent(String senderName) {
|
||||
return l10n.redactedAnEvent(senderName);
|
||||
}
|
||||
|
||||
@override
|
||||
String rejectedTheInvitation(String targetName) {
|
||||
return l10n.rejectedTheInvitation(targetName);
|
||||
}
|
||||
|
||||
@override
|
||||
String removedBy(String calcDisplayname) {
|
||||
return l10n.removedBy(calcDisplayname);
|
||||
}
|
||||
|
||||
@override
|
||||
String get roomHasBeenUpgraded => l10n.roomHasBeenUpgraded;
|
||||
|
||||
@override
|
||||
String sentAFile(String senderName) {
|
||||
return l10n.sentAFile(senderName);
|
||||
}
|
||||
|
||||
@override
|
||||
String sentAPicture(String senderName) {
|
||||
return l10n.sentAPicture(senderName);
|
||||
}
|
||||
|
||||
@override
|
||||
String sentASticker(String senderName) {
|
||||
return l10n.sentASticker(senderName);
|
||||
}
|
||||
|
||||
@override
|
||||
String sentAVideo(String senderName) {
|
||||
return l10n.sentAVideo(senderName);
|
||||
}
|
||||
|
||||
@override
|
||||
String sentAnAudio(String senderName) {
|
||||
return l10n.sentAnAudio(senderName);
|
||||
}
|
||||
|
||||
@override
|
||||
String sentCallInformations(String senderName) {
|
||||
return l10n.sentCallInformations(senderName);
|
||||
}
|
||||
|
||||
@override
|
||||
String sharedTheLocation(String senderName) {
|
||||
return l10n.sharedTheLocation(senderName);
|
||||
}
|
||||
|
||||
@override
|
||||
String startedACall(String senderName) {
|
||||
return l10n.startedACall(senderName);
|
||||
}
|
||||
|
||||
@override
|
||||
String unbannedUser(String senderName, String targetName) {
|
||||
return l10n.unbannedUser(senderName, targetName);
|
||||
}
|
||||
|
||||
@override
|
||||
String get unknownEncryptionAlgorithm => l10n.unknownEncryptionAlgorithm;
|
||||
|
||||
@override
|
||||
String unknownEvent(String typeKey) {
|
||||
return l10n.unknownEvent(typeKey);
|
||||
}
|
||||
|
||||
@override
|
||||
String userLeftTheChat(String targetName) {
|
||||
return l10n.userLeftTheChat(targetName);
|
||||
}
|
||||
|
||||
@override
|
||||
String get visibleForAllParticipants => l10n.visibleForAllParticipants;
|
||||
|
||||
@override
|
||||
String get visibleForEveryone => l10n.visibleForEveryone;
|
||||
|
||||
@override
|
||||
String get you => l10n.you;
|
||||
|
||||
@override
|
||||
String sentReaction(String senderName, String reactionKey) =>
|
||||
l10n.reactedWith(senderName, reactionKey);
|
||||
|
||||
@override
|
||||
// TODO: implement youAcceptedTheInvitation
|
||||
String get youAcceptedTheInvitation => l10n.youAcceptedTheInvitation;
|
||||
|
||||
@override
|
||||
String youBannedUser(String targetName) => l10n.youBannedUser(targetName);
|
||||
|
||||
@override
|
||||
String youHaveWithdrawnTheInvitationFor(String targetName) =>
|
||||
l10n.youHaveWithdrawnTheInvitationFor(targetName);
|
||||
|
||||
@override
|
||||
String youInvitedBy(String senderName) => l10n.youInvitedBy(senderName);
|
||||
|
||||
@override
|
||||
String youInvitedUser(String targetName) => l10n.youInvitedUser(targetName);
|
||||
|
||||
@override
|
||||
// TODO: implement youJoinedTheChat
|
||||
String get youJoinedTheChat => l10n.youJoinedTheChat;
|
||||
|
||||
@override
|
||||
String youKicked(String targetName) => l10n.youKicked(targetName);
|
||||
|
||||
@override
|
||||
String youKickedAndBanned(String targetName) =>
|
||||
l10n.youKickedAndBanned(targetName);
|
||||
|
||||
@override
|
||||
// TODO: implement youRejectedTheInvitation
|
||||
String get youRejectedTheInvitation => l10n.youRejectedTheInvitation;
|
||||
|
||||
@override
|
||||
String youUnbannedUser(String targetName) => l10n.youUnbannedUser(targetName);
|
||||
|
||||
@override
|
||||
String wasDirectChatDisplayName(String oldDisplayName) =>
|
||||
l10n.wasDirectChatDisplayName(oldDisplayName);
|
||||
}
|
||||
40
lib/utils/matrix_sdk_extensions/presence_extension.dart
Normal file
40
lib/utils/matrix_sdk_extensions/presence_extension.dart
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import '../date_time_extension.dart';
|
||||
|
||||
extension PresenceExtension on CachedPresence {
|
||||
String getLocalizedLastActiveAgo(BuildContext context) {
|
||||
final lastActiveTimestamp = this.lastActiveTimestamp;
|
||||
if (lastActiveTimestamp != null) {
|
||||
return L10n.of(context)!
|
||||
.lastActiveAgo(lastActiveTimestamp.localizedTimeShort(context));
|
||||
}
|
||||
return L10n.of(context)!.lastSeenLongTimeAgo;
|
||||
}
|
||||
|
||||
String getLocalizedStatusMessage(BuildContext context) {
|
||||
final statusMsg = this.statusMsg;
|
||||
if (statusMsg != null && statusMsg.isNotEmpty) {
|
||||
return statusMsg;
|
||||
}
|
||||
if (currentlyActive ?? false) {
|
||||
return L10n.of(context)!.currentlyActive;
|
||||
}
|
||||
return getLocalizedLastActiveAgo(context);
|
||||
}
|
||||
|
||||
Color get color {
|
||||
switch (presence) {
|
||||
case PresenceType.online:
|
||||
return Colors.green;
|
||||
case PresenceType.offline:
|
||||
return Colors.grey;
|
||||
case PresenceType.unavailable:
|
||||
default:
|
||||
return Colors.red;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue