refactor: Structure files in more directories
This commit is contained in:
parent
d3a5966f19
commit
988a691eeb
35 changed files with 55 additions and 55 deletions
|
|
@ -0,0 +1,29 @@
|
|||
import 'package:famedlysdk/famedlysdk.dart';
|
||||
|
||||
extension ClientPresenceExtension on Client {
|
||||
List<Presence> get contactList {
|
||||
final directChatsMxid = rooms
|
||||
.where((r) => r.isDirectChat)
|
||||
.map((r) => r.directChatMatrixID)
|
||||
.toSet();
|
||||
final contactList = directChatsMxid
|
||||
.map(
|
||||
(mxid) =>
|
||||
presences[mxid] ??
|
||||
Presence.fromJson(
|
||||
{
|
||||
'sender': mxid,
|
||||
'type': 'm.presence',
|
||||
'content': {'presence': 'offline'},
|
||||
},
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
|
||||
contactList.sort((a, b) => a.senderId.compareTo(b.senderId));
|
||||
contactList.sort((a, b) => (a.presence.lastActiveAgo?.toDouble() ??
|
||||
double.infinity)
|
||||
.compareTo((b.presence.lastActiveAgo?.toDouble() ?? double.infinity)));
|
||||
return contactList;
|
||||
}
|
||||
}
|
||||
33
lib/utils/matrix_sdk_extensions.dart/device_extension.dart
Normal file
33
lib/utils/matrix_sdk_extensions.dart/device_extension.dart
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import 'package:famedlysdk/famedlysdk.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
extension DeviceExtension on Device {
|
||||
String get displayname =>
|
||||
(displayName?.isNotEmpty ?? false) ? displayName : 'Unknown device';
|
||||
|
||||
IconData get icon => displayname.toLowerCase().contains('android')
|
||||
? Icons.phone_android_outlined
|
||||
: displayname.toLowerCase().contains('ios')
|
||||
? Icons.phone_iphone_outlined
|
||||
: displayname.toLowerCase().contains('web')
|
||||
? Icons.web_outlined
|
||||
: displayname.toLowerCase().contains('desktop')
|
||||
? Icons.desktop_mac_outlined
|
||||
: Icons.device_unknown_outlined;
|
||||
}
|
||||
|
||||
extension DeviceKeysExtension on DeviceKeys {
|
||||
String get displayname => (deviceDisplayName?.isNotEmpty ?? false)
|
||||
? deviceDisplayName
|
||||
: 'Unknown device';
|
||||
|
||||
IconData get icon => displayname.toLowerCase().contains('android')
|
||||
? Icons.phone_android_outlined
|
||||
: displayname.toLowerCase().contains('ios')
|
||||
? Icons.phone_iphone_outlined
|
||||
: displayname.toLowerCase().contains('web')
|
||||
? Icons.web_outlined
|
||||
: displayname.toLowerCase().contains('desktop')
|
||||
? Icons.desktop_mac_outlined
|
||||
: Icons.device_unknown_outlined;
|
||||
}
|
||||
107
lib/utils/matrix_sdk_extensions.dart/event_extension.dart
Normal file
107
lib/utils/matrix_sdk_extensions.dart/event_extension.dart
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
import 'package:famedlysdk/famedlysdk.dart';
|
||||
import 'package:future_loading_dialog/future_loading_dialog.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
||||
import 'matrix_file_extension.dart';
|
||||
import '../../pages/image_viewer.dart';
|
||||
|
||||
extension LocalizedBody on Event {
|
||||
void openFile(BuildContext context, {bool downloadOnly = false}) async {
|
||||
if (!downloadOnly &&
|
||||
[MessageTypes.Image, MessageTypes.Sticker].contains(messageType)) {
|
||||
await Navigator.of(context, rootNavigator: false).push(
|
||||
MaterialPageRoute(builder: (_) => ImageViewer(this)),
|
||||
);
|
||||
return;
|
||||
}
|
||||
final matrixFile = await showFutureLoadingDialog(
|
||||
context: context,
|
||||
future: () => downloadAndDecryptAttachmentCached(),
|
||||
);
|
||||
matrixFile.result?.open();
|
||||
}
|
||||
|
||||
IconData get statusIcon {
|
||||
switch (status) {
|
||||
case -1:
|
||||
return Icons.error_outline;
|
||||
case 0:
|
||||
return Icons.timer_outlined;
|
||||
case 1:
|
||||
return Icons.done_outlined;
|
||||
case 2:
|
||||
return Icons.done_all_outlined;
|
||||
default:
|
||||
return Icons.done_outlined;
|
||||
}
|
||||
}
|
||||
|
||||
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].contains(messageType) &&
|
||||
(kIsWeb ||
|
||||
isAttachmentSmallEnough ||
|
||||
isThumbnailSmallEnough ||
|
||||
(content['url'] is String));
|
||||
|
||||
String get sizeString {
|
||||
if (content['info'] is Map<String, dynamic> &&
|
||||
content['info'].containsKey('size')) {
|
||||
num size = content['info']['size'];
|
||||
if (size < 1000000) {
|
||||
size = size / 1000;
|
||||
size = (size * 10).round() / 10;
|
||||
return '${size.toString()} KB';
|
||||
} else if (size < 1000000000) {
|
||||
size = size / 1000000;
|
||||
size = (size * 10).round() / 10;
|
||||
return '${size.toString()} MB';
|
||||
} else {
|
||||
size = size / 1000000000;
|
||||
size = (size * 10).round() / 10;
|
||||
return '${size.toString()} GB';
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static final _downloadAndDecryptFutures = <String, Future<MatrixFile>>{};
|
||||
|
||||
Future<bool> isAttachmentCached({bool getThumbnail = false}) async {
|
||||
final mxcUrl = attachmentOrThumbnailMxcUrl(getThumbnail: getThumbnail);
|
||||
// check if we have it in-memory
|
||||
if (_downloadAndDecryptFutures.containsKey(mxcUrl)) {
|
||||
return true;
|
||||
}
|
||||
// check if it is stored
|
||||
if (await isAttachmentInLocalStore(getThumbnail: getThumbnail)) {
|
||||
return true;
|
||||
}
|
||||
// check if the url is cached
|
||||
final url = Uri.parse(mxcUrl).getDownloadLink(room.client);
|
||||
final file = await DefaultCacheManager().getFileFromCache(url.toString());
|
||||
return file != null;
|
||||
}
|
||||
|
||||
Future<MatrixFile> downloadAndDecryptAttachmentCached(
|
||||
{bool getThumbnail = false}) async {
|
||||
final mxcUrl = attachmentOrThumbnailMxcUrl(getThumbnail: getThumbnail);
|
||||
_downloadAndDecryptFutures[mxcUrl] ??= downloadAndDecryptAttachment(
|
||||
getThumbnail: getThumbnail,
|
||||
downloadCallback: (Uri url) async {
|
||||
final file = await DefaultCacheManager().getSingleFile(url.toString());
|
||||
return await file.readAsBytes();
|
||||
},
|
||||
);
|
||||
final res = await _downloadAndDecryptFutures[mxcUrl];
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
import 'package:famedlysdk/famedlysdk.dart';
|
||||
|
||||
import '../../config/app_config.dart';
|
||||
|
||||
extension FilteredTimelineExtension on Timeline {
|
||||
List<Event> getFilteredEvents({Set<String> unfolded = const {}}) {
|
||||
final filteredEvents = events
|
||||
.where((e) =>
|
||||
// always filter out edit and reaction relationships
|
||||
!{RelationshipTypes.edit, RelationshipTypes.reaction}
|
||||
.contains(e.relationshipType) &&
|
||||
// always filter out m.key.* events
|
||||
!e.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(e.type) &&
|
||||
// if we enabled to hide all redacted events, don't show those
|
||||
(!AppConfig.hideRedactedEvents || !e.redacted) &&
|
||||
// if we enabled to hide all unknown events, don't show those
|
||||
(!AppConfig.hideUnknownEvents || e.isEventTypeKnown) &&
|
||||
// remove state events that we don't want to render
|
||||
(e.isState || !AppConfig.hideAllStateEvents))
|
||||
.toList();
|
||||
|
||||
// Fold state events
|
||||
var counter = 0;
|
||||
for (var i = filteredEvents.length - 1; i >= 0; i--) {
|
||||
if (!filteredEvents[i].isState) continue;
|
||||
if (i > 0 &&
|
||||
filteredEvents[i - 1].isState &&
|
||||
!unfolded.contains(filteredEvents[i - 1].eventId)) {
|
||||
counter++;
|
||||
filteredEvents[i].unsigned['im.fluffychat.collapsed_state_event'] =
|
||||
true;
|
||||
} else {
|
||||
filteredEvents[i].unsigned['im.fluffychat.collapsed_state_event'] =
|
||||
false;
|
||||
filteredEvents[i]
|
||||
.unsigned['im.fluffychat.collapsed_state_event_count'] = counter;
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
return filteredEvents;
|
||||
}
|
||||
}
|
||||
|
||||
extension IsStateExtension on Event {
|
||||
bool get isState => !{
|
||||
EventTypes.Message,
|
||||
EventTypes.Sticker,
|
||||
EventTypes.Encrypted
|
||||
}.contains(type);
|
||||
}
|
||||
38
lib/utils/matrix_sdk_extensions.dart/fluffy_client.dart
Normal file
38
lib/utils/matrix_sdk_extensions.dart/fluffy_client.dart
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import 'package:famedlysdk/famedlysdk.dart';
|
||||
import 'package:famedlysdk/encryption.dart';
|
||||
import 'package:matrix_api_lite/fake_matrix_api.dart';
|
||||
import '../platform_infos.dart';
|
||||
import '../famedlysdk_store.dart';
|
||||
|
||||
class FluffyClient extends Client {
|
||||
static FluffyClient _instance;
|
||||
|
||||
/// The ID of the currently active room, if there is one. May be null or emtpy
|
||||
String activeRoomId;
|
||||
|
||||
factory FluffyClient({testMode = false}) {
|
||||
_instance ??= FluffyClient._internal(testMode: testMode);
|
||||
return _instance;
|
||||
}
|
||||
|
||||
FluffyClient._internal({testMode = false})
|
||||
: super(
|
||||
testMode ? 'FluffyChat Widget Tests' : PlatformInfos.clientName,
|
||||
httpClient: testMode ? FakeMatrixApi() : null,
|
||||
enableE2eeRecovery: true,
|
||||
verificationMethods: {
|
||||
KeyVerificationMethod.numbers,
|
||||
if (PlatformInfos.isMobile || PlatformInfos.isLinux)
|
||||
KeyVerificationMethod.emoji,
|
||||
},
|
||||
importantStateEvents: <String>{
|
||||
'im.ponies.room_emotes', // we want emotes to work properly
|
||||
},
|
||||
databaseBuilder: testMode ? null : getDatabase,
|
||||
supportedLoginTypes: {
|
||||
AuthenticationTypes.password,
|
||||
if (PlatformInfos.isMobile || PlatformInfos.isWeb)
|
||||
AuthenticationTypes.sso
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:android_path_provider/android_path_provider.dart';
|
||||
import 'package:famedlysdk/famedlysdk.dart';
|
||||
import 'package:fluffychat/utils/platform_infos.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:open_file/open_file.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:universal_html/html.dart' as html;
|
||||
import 'package:mime_type/mime_type.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
|
||||
extension MatrixFileExtension on MatrixFile {
|
||||
void open() async {
|
||||
if (kIsWeb) {
|
||||
final fileName = name.split('/').last;
|
||||
final mimeType = mime(fileName);
|
||||
final element = html.document.createElement('a');
|
||||
element.setAttribute(
|
||||
'href', html.Url.createObjectUrlFromBlob(html.Blob([bytes])));
|
||||
element.setAttribute('target', '_blank');
|
||||
element.setAttribute('rel', 'noopener');
|
||||
element.setAttribute('download', fileName);
|
||||
element.setAttribute('type', mimeType);
|
||||
element.style.display = 'none';
|
||||
html.document.body.append(element);
|
||||
element.click();
|
||||
element.remove();
|
||||
} else {
|
||||
if (PlatformInfos.isMobile &&
|
||||
!(await Permission.storage.request()).isGranted) return;
|
||||
final downloadsDir = PlatformInfos.isDesktop
|
||||
? (await getDownloadsDirectory()).path
|
||||
: Platform.isAndroid
|
||||
? (await AndroidPathProvider.downloadsPath)
|
||||
: (await getApplicationDocumentsDirectory()).path;
|
||||
|
||||
final file = File(downloadsDir + '/' + name.split('/').last);
|
||||
file.writeAsBytesSync(bytes);
|
||||
await OpenFile.open(file.path);
|
||||
}
|
||||
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 {
|
||||
var size = this.size.toDouble();
|
||||
if (size < 1000000) {
|
||||
size = size / 1000;
|
||||
size = (size * 10).round() / 10;
|
||||
return '${size.toString()} KB';
|
||||
} else if (size < 1000000000) {
|
||||
size = size / 1000000;
|
||||
size = (size * 10).round() / 10;
|
||||
return '${size.toString()} MB';
|
||||
} else {
|
||||
size = size / 1000000000;
|
||||
size = (size * 10).round() / 10;
|
||||
return '${size.toString()} GB';
|
||||
}
|
||||
}
|
||||
}
|
||||
264
lib/utils/matrix_sdk_extensions.dart/matrix_locals.dart
Normal file
264
lib/utils/matrix_sdk_extensions.dart/matrix_locals.dart
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
import 'package:famedlysdk/famedlysdk.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.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.noPermission;
|
||||
|
||||
@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;
|
||||
}
|
||||
38
lib/utils/matrix_sdk_extensions.dart/presence_extension.dart
Normal file
38
lib/utils/matrix_sdk_extensions.dart/presence_extension.dart
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import 'package:famedlysdk/famedlysdk.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
import '../date_time_extension.dart';
|
||||
|
||||
extension PresenceExtension on Presence {
|
||||
String getLocalizedLastActiveAgo(BuildContext context) {
|
||||
if (presence.lastActiveAgo != null && presence.lastActiveAgo != 0) {
|
||||
return L10n.of(context).lastActiveAgo(DateTime.fromMillisecondsSinceEpoch(
|
||||
DateTime.now().millisecondsSinceEpoch - presence.lastActiveAgo)
|
||||
.localizedTimeShort(context));
|
||||
}
|
||||
return L10n.of(context).lastSeenLongTimeAgo;
|
||||
}
|
||||
|
||||
String getLocalizedStatusMessage(BuildContext context) {
|
||||
if (presence.statusMsg?.isNotEmpty ?? false) {
|
||||
return presence.statusMsg;
|
||||
}
|
||||
if (presence.currentlyActive ?? false) {
|
||||
return L10n.of(context).currentlyActive;
|
||||
}
|
||||
return getLocalizedLastActiveAgo(context);
|
||||
}
|
||||
|
||||
Color get color {
|
||||
switch (presence?.presence ?? PresenceType.offline) {
|
||||
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