diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index 1e7eb7723..40aab748d 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -3208,6 +3208,16 @@ } } }, + "sentVoiceMessage": "{sender}: \uD83C\uDF99\uFE0F {duration}", + "@sentVoiceMessage": { + "type": "String", + "placeholders": { + "rule": { + "sender": "String", + "duration": "String" + } + } + }, "deletePushRuleCanNotBeUndone": "If you delete this notification setting, this can not be undone.", "more": "More", "shareKeysWith": "Share keys with...", diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 27e9bef00..d99b43caa 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -308,10 +308,14 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", ); + inputPaths = ( + ); name = "[CP] Copy Pods Resources"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", ); + outputPaths = ( + ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; @@ -400,10 +404,14 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); + inputPaths = ( + ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); + outputPaths = ( + ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; @@ -525,6 +533,8 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 4NXF6Z997G; ENABLE_BITCODE = NO; @@ -544,6 +554,7 @@ MARKETING_VERSION = 0.32.1; PRODUCT_BUNDLE_IDENTIFIER = im.fluffychat.app; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; @@ -665,6 +676,8 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 4NXF6Z997G; ENABLE_BITCODE = NO; @@ -684,6 +697,7 @@ MARKETING_VERSION = 0.32.1; PRODUCT_BUNDLE_IDENTIFIER = im.fluffychat.app; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -699,6 +713,8 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 4NXF6Z997G; ENABLE_BITCODE = NO; @@ -718,6 +734,7 @@ MARKETING_VERSION = 0.32.1; PRODUCT_BUNDLE_IDENTIFIER = im.fluffychat.app; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; diff --git a/lib/pages/chat_members/chat_members_view.dart b/lib/pages/chat_members/chat_members_view.dart index e5ee2ad27..67bf67cd2 100644 --- a/lib/pages/chat_members/chat_members_view.dart +++ b/lib/pages/chat_members/chat_members_view.dart @@ -1,9 +1,10 @@ -import 'package:fluffychat/utils/localized_exception_extension.dart'; import 'package:flutter/material.dart'; + import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:go_router/go_router.dart'; import 'package:matrix/matrix.dart'; +import 'package:fluffychat/utils/localized_exception_extension.dart'; import '../../widgets/layouts/max_width_body.dart'; import '../../widgets/matrix.dart'; import '../chat_details/participant_list_item.dart'; diff --git a/lib/utils/client_manager.dart b/lib/utils/client_manager.dart index 34016065a..83cd5a738 100644 --- a/lib/utils/client_manager.dart +++ b/lib/utils/client_manager.dart @@ -18,7 +18,6 @@ import 'package:fluffychat/config/setting_keys.dart'; import 'package:fluffychat/utils/custom_http_client.dart'; import 'package:fluffychat/utils/custom_image_resizer.dart'; import 'package:fluffychat/utils/init_with_restore.dart'; -import 'package:fluffychat/utils/matrix_sdk_extensions/flutter_hive_collections_database.dart'; import 'package:fluffychat/utils/platform_infos.dart'; import 'matrix_sdk_extensions/flutter_matrix_dart_sdk_database/builder.dart'; @@ -119,7 +118,6 @@ abstract class ClientManager { }, logLevel: kReleaseMode ? Level.warning : Level.verbose, databaseBuilder: flutterMatrixSdkDatabaseBuilder, - legacyDatabaseBuilder: FlutterHiveCollectionsDatabase.databaseBuilder, supportedLoginTypes: { AuthenticationTypes.password, AuthenticationTypes.sso, diff --git a/lib/utils/matrix_sdk_extensions/flutter_hive_collections_database.dart b/lib/utils/matrix_sdk_extensions/flutter_hive_collections_database.dart deleted file mode 100644 index 9ad5ce5c0..000000000 --- a/lib/utils/matrix_sdk_extensions/flutter_hive_collections_database.dart +++ /dev/null @@ -1,149 +0,0 @@ -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'; -import 'package:universal_html/html.dart' as html; - -// ignore: deprecated_member_use -class FlutterHiveCollectionsDatabase extends HiveCollectionsDatabase { - FlutterHiveCollectionsDatabase( - super.name, - String super.path, { - super.key, - }); - - static const String _cipherStorageKey = 'hive_encryption_key'; - - static Future databaseBuilder( - Client client, - ) async { - Logs().d('Open Hive...'); - HiveAesCipher? hiverCipher; - try { - // Workaround for secure storage is calling Platform.operatingSystem on web - if (kIsWeb) { - // ignore: unawaited_futures - html.window.navigator.storage?.persist(); - 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 findDatabasePath(Client client) async { - var 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 * 1000 * 1000 : 0; - @override - bool get supportsFileStoring => !kIsWeb; - - Future _getFileStoreDirectory() async { - try { - try { - return (await getTemporaryDirectory()).path; - } catch (_) { - return (await getApplicationDocumentsDirectory()).path; - } - } catch (_) { - return (await getDownloadsDirectory())!.path; - } - } - - @override - Future 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; - } -} diff --git a/lib/utils/matrix_sdk_extensions/flutter_matrix_dart_sdk_database/builder.dart b/lib/utils/matrix_sdk_extensions/flutter_matrix_dart_sdk_database/builder.dart index 0919b607f..d0c0d931a 100644 --- a/lib/utils/matrix_sdk_extensions/flutter_matrix_dart_sdk_database/builder.dart +++ b/lib/utils/matrix_sdk_extensions/flutter_matrix_dart_sdk_database/builder.dart @@ -11,7 +11,6 @@ import 'package:universal_html/html.dart' as html; import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/utils/client_manager.dart'; -import 'package:fluffychat/utils/matrix_sdk_extensions/flutter_hive_collections_database.dart'; import 'package:fluffychat/utils/platform_infos.dart'; import 'cipher.dart'; @@ -55,7 +54,7 @@ Future flutterMatrixSdkDatabaseBuilder(Client client) async { Logs().e('Unable to send error notification', e, s); } - return FlutterHiveCollectionsDatabase.databaseBuilder(client); + rethrow; } } diff --git a/lib/utils/matrix_sdk_extensions/matrix_locals.dart b/lib/utils/matrix_sdk_extensions/matrix_locals.dart index 165130c0b..cd3aa3384 100644 --- a/lib/utils/matrix_sdk_extensions/matrix_locals.dart +++ b/lib/utils/matrix_sdk_extensions/matrix_locals.dart @@ -1,4 +1,5 @@ import 'package:flutter_gen/gen_l10n/l10n.dart'; +import 'package:intl/intl.dart'; import 'package:matrix/matrix.dart'; /// This is a temporary helper class until there is a proper solution to this with the new system @@ -350,4 +351,21 @@ class MatrixLocals extends MatrixLocalizations { @override String get cancelledSend => l10n.sendCanceled; + + @override + String voiceMessage(String senderName, Duration? duration) { + final dateTime = duration == null + ? null + : DateTime.fromMillisecondsSinceEpoch( + duration.inSeconds * 1000, + ); + final formattedDuration = dateTime == null + ? '' + : DateFormat( + DateFormat.MINUTE_SECOND, + l10n.localeName, + ).format(dateTime); + + return l10n.sentVoiceMessage(senderName, formattedDuration); + } } diff --git a/pubspec.lock b/pubspec.lock index 341b86188..333376f33 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1151,10 +1151,10 @@ packages: dependency: "direct main" description: name: matrix - sha256: c45e0b04053ce61f1c6d91d4fa7554cd6891ac40620282c911b71f5ae4b2ede8 + sha256: "7d15fdbc760be7e40c58bb65e03baa8241b1e31db2bc67dab61883aabc083a85" url: "https://pub.dev" source: hosted - version: "0.39.4" + version: "0.40.0" meta: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 78db9d603..c83a4d154 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -61,7 +61,7 @@ dependencies: just_audio: ^0.9.39 latlong2: ^0.9.1 linkify: ^5.0.0 - matrix: ^0.39.4 + matrix: ^0.40.0 mime: ^1.0.6 native_imaging: ^0.2.0 opus_caf_converter_dart: ^1.0.1 diff --git a/test/utils/test_client.dart b/test/utils/test_client.dart index 7cbe72f71..c27faa8f6 100644 --- a/test/utils/test_client.dart +++ b/test/utils/test_client.dart @@ -3,7 +3,7 @@ import 'package:matrix/encryption/utils/key_verification.dart'; import 'package:matrix/matrix.dart'; -import 'package:fluffychat/utils/matrix_sdk_extensions/flutter_hive_collections_database.dart'; +import 'package:fluffychat/utils/matrix_sdk_extensions/flutter_matrix_dart_sdk_database/builder.dart'; Future prepareTestClient({ bool loggedIn = false, @@ -22,7 +22,7 @@ Future prepareTestClient({ importantStateEvents: { 'im.ponies.room_emotes', // we want emotes to work properly }, - databaseBuilder: FlutterHiveCollectionsDatabase.databaseBuilder, + databaseBuilder: flutterMatrixSdkDatabaseBuilder, supportedLoginTypes: { AuthenticationTypes.password, AuthenticationTypes.sso,