diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index 9a15720fd..248188d25 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -349,13 +349,16 @@ class ChatController extends State } }); - _levelSubscription = pangeaController.getAnalytics.analyticsStream.stream - .where((update) => update.levelUp) + _levelSubscription = pangeaController.getAnalytics.stateStream + .where( + (update) => + update is Map && update['level_up'] != null, + ) .listen( (update) => Future.delayed( const Duration(milliseconds: 500), () => LevelUpUtil.showLevelUpDialog( - pangeaController.getAnalytics.constructListModel.level, + update['level_up'], context, ), ), diff --git a/lib/pages/user_bottom_sheet/user_bottom_sheet_view.dart b/lib/pages/user_bottom_sheet/user_bottom_sheet_view.dart index 0254c6b14..6d5677e6e 100644 --- a/lib/pages/user_bottom_sheet/user_bottom_sheet_view.dart +++ b/lib/pages/user_bottom_sheet/user_bottom_sheet_view.dart @@ -6,6 +6,7 @@ import 'package:matrix/matrix.dart'; import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pangea/bot/utils/bot_name.dart'; +import 'package:fluffychat/pangea/user/widgets/public_level_indicator.dart'; import 'package:fluffychat/utils/date_time_extension.dart'; import 'package:fluffychat/utils/fluffy_share.dart'; import 'package:fluffychat/utils/url_launcher.dart'; @@ -194,6 +195,9 @@ class UserBottomSheetView extends StatelessWidget { ); }, ), + // #Pangea + PublicLevelIndicator(userId: userId), + // Pangea# ], ), ), diff --git a/lib/pangea/analytics_misc/get_analytics_controller.dart b/lib/pangea/analytics_misc/get_analytics_controller.dart index 0fa711aa8..b143864e0 100644 --- a/lib/pangea/analytics_misc/get_analytics_controller.dart +++ b/lib/pangea/analytics_misc/get_analytics_controller.dart @@ -14,12 +14,13 @@ import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart'; import 'package:fluffychat/pangea/analytics_misc/message_analytics_controller.dart'; import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart'; import 'package:fluffychat/pangea/common/constants/local.key.dart'; +import 'package:fluffychat/pangea/common/controllers/base_controller.dart'; import 'package:fluffychat/pangea/common/controllers/pangea_controller.dart'; import 'package:fluffychat/pangea/common/utils/error_handler.dart'; import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart'; /// A minimized version of AnalyticsController that get the logged in user's analytics -class GetAnalyticsController { +class GetAnalyticsController extends BaseController { late PangeaController _pangeaController; late MessageAnalyticsController perMessage; @@ -31,6 +32,7 @@ class GetAnalyticsController { ConstructListModel constructListModel = ConstructListModel(uses: []); Completer initCompleter = Completer(); + bool _initializing = false; GetAnalyticsController(PangeaController pangeaController) { _pangeaController = pangeaController; @@ -69,7 +71,8 @@ class GetAnalyticsController { } Future initialize() async { - if (initCompleter.isCompleted) return; + if (_initializing || initCompleter.isCompleted) return; + _initializing = true; try { _client.updateAnalyticsRoomVisibility(); @@ -100,10 +103,12 @@ class GetAnalyticsController { } finally { _updateAnalyticsStream(); if (!initCompleter.isCompleted) initCompleter.complete(); + _initializing = false; } } /// Clear all cached analytics data. + @override void dispose() { constructListModel.dispose(); _analyticsUpdateSubscription?.cancel(); @@ -124,19 +129,21 @@ class GetAnalyticsController { if (analyticsUpdate.type == AnalyticsUpdateType.server) { await _getConstructs(forceUpdate: true); } - _updateAnalyticsStream( - origin: analyticsUpdate.origin, - levelUp: oldLevel < constructListModel.level, - ); + _updateAnalyticsStream(origin: analyticsUpdate.origin); + if (oldLevel < constructListModel.level) _onLevelUp(); } void _updateAnalyticsStream({ - bool levelUp = false, AnalyticsUpdateOrigin? origin, - }) { - analyticsStream.add( - AnalyticsStreamUpdate(origin: origin, levelUp: levelUp), + }) => + analyticsStream.add(AnalyticsStreamUpdate(origin: origin)); + + void _onLevelUp() { + _pangeaController.userController.updatePublicProfile( + level: constructListModel.level, ); + + setState({'level_up': constructListModel.level}); } /// A local cache of eventIds and construct uses for messages sent since the last update. @@ -209,7 +216,9 @@ class GetAnalyticsController { }) async { // if the user isn't logged in, return an empty list if (_client.userID == null) return []; - await _client.roomsLoading; + if (_client.prevBatch == null) { + await _client.onSync.stream.first; + } // don't try to get constructs until last updated time has been loaded await _pangeaController.putAnalytics.lastUpdatedCompleter.future; @@ -342,10 +351,8 @@ class AnalyticsCacheEntry { class AnalyticsStreamUpdate { final AnalyticsUpdateOrigin? origin; - final bool levelUp; AnalyticsStreamUpdate({ this.origin, - this.levelUp = false, }); } diff --git a/lib/pangea/analytics_misc/put_analytics_controller.dart b/lib/pangea/analytics_misc/put_analytics_controller.dart index d2f53cb42..1454e2fa9 100644 --- a/lib/pangea/analytics_misc/put_analytics_controller.dart +++ b/lib/pangea/analytics_misc/put_analytics_controller.dart @@ -151,7 +151,10 @@ class PutAnalyticsController extends BaseController { await sendLocalAnalyticsToAnalyticsRoom( l2Override: previousL2, ); - _pangeaController.resetAnalytics(); + _pangeaController.resetAnalytics().then((_) { + final level = _pangeaController.getAnalytics.constructListModel.level; + _pangeaController.userController.updatePublicProfile(level: level); + }); } void addDraftUses( @@ -361,6 +364,8 @@ class PutAnalyticsController extends BaseController { String? l2Override, }) async { if (_pangeaController.matrixState.client.userID == null) return; + if (_pangeaController.getAnalytics.messagesSinceUpdate.isEmpty) return; + if (!(_updateCompleter?.isCompleted ?? true)) { await _updateCompleter!.future; return; diff --git a/lib/pangea/chat_list/utils/app_version_util.dart b/lib/pangea/chat_list/utils/app_version_util.dart index af736339c..46359e655 100644 --- a/lib/pangea/chat_list/utils/app_version_util.dart +++ b/lib/pangea/chat_list/utils/app_version_util.dart @@ -16,6 +16,7 @@ import 'package:fluffychat/pangea/common/constants/local.key.dart'; import 'package:fluffychat/pangea/common/constants/model_keys.dart'; import 'package:fluffychat/pangea/common/network/requests.dart'; import 'package:fluffychat/pangea/common/network/urls.dart'; +import 'package:fluffychat/pangea/common/utils/error_handler.dart'; import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart'; import 'package:fluffychat/widgets/matrix.dart'; @@ -52,7 +53,14 @@ class AppVersionUtil { final currentBuildNumber = packageInfo.buildNumber; final accessToken = MatrixState.pangeaController.userController.accessToken; - final AppVersionResponse resp = await _getAppVersion(accessToken); + + AppVersionResponse? resp; + try { + resp = await _getAppVersion(accessToken); + } catch (err, s) { + ErrorHandler.logError(e: err, s: s, data: {}); + return; + } final remoteVersion = resp.latestVersion; final remoteBuildNumber = resp.latestBuildNumber; diff --git a/lib/pangea/common/constants/model_keys.dart b/lib/pangea/common/constants/model_keys.dart index 357b8c189..8052bfa60 100644 --- a/lib/pangea/common/constants/model_keys.dart +++ b/lib/pangea/common/constants/model_keys.dart @@ -152,4 +152,7 @@ class ModelKey { static const String latestBuildNumber = "latest_build_number"; static const String mandatoryUpdate = "mandatory_update"; static const String emoji = "emoji"; + + static const String analytics = "analytics"; + static const String level = "level"; } diff --git a/lib/pangea/common/controllers/pangea_controller.dart b/lib/pangea/common/controllers/pangea_controller.dart index fe272d5ab..84fe22854 100644 --- a/lib/pangea/common/controllers/pangea_controller.dart +++ b/lib/pangea/common/controllers/pangea_controller.dart @@ -158,14 +158,14 @@ class PangeaController { case LoginState.loggedOut: case LoginState.softLoggedOut: // Reset cached analytics data - MatrixState.pangeaController.putAnalytics.dispose(); - MatrixState.pangeaController.getAnalytics.dispose(); + putAnalytics.dispose(); + getAnalytics.dispose(); _languageStream?.cancel(); break; case LoginState.loggedIn: // Initialize analytics data - MatrixState.pangeaController.putAnalytics.initialize(); - MatrixState.pangeaController.getAnalytics.initialize(); + putAnalytics.initialize(); + getAnalytics.initialize(); break; } if (state != LoginState.loggedIn) { @@ -186,7 +186,7 @@ class PangeaController { putAnalytics.dispose(); getAnalytics.dispose(); putAnalytics.initialize(); - getAnalytics.initialize(); + await getAnalytics.initialize(); } void startChatWithBotIfNotPresent() { diff --git a/lib/pangea/events/constants/pangea_event_types.dart b/lib/pangea/events/constants/pangea_event_types.dart index 0f80c1653..e2840835a 100644 --- a/lib/pangea/events/constants/pangea_event_types.dart +++ b/lib/pangea/events/constants/pangea_event_types.dart @@ -36,4 +36,7 @@ class PangeaEventTypes { /// A record of completion of an activity. There /// can be one per user per activity. static const activityRecord = "pangea.activity_completion"; + + /// Profile information related to a user's analytics + static const profileAnalytics = "pangea.analytics_profile"; } diff --git a/lib/pangea/learning_settings/pages/settings_learning.dart b/lib/pangea/learning_settings/pages/settings_learning.dart index 2206851e3..62707da5e 100644 --- a/lib/pangea/learning_settings/pages/settings_learning.dart +++ b/lib/pangea/learning_settings/pages/settings_learning.dart @@ -46,6 +46,7 @@ class SettingsLearningController extends State { context: context, future: () async => pangeaController.userController.updateProfile( (_) => _profile, + waitForDataInSync: true, ), ); Navigator.of(context).pop(); diff --git a/lib/pangea/login/pages/signup.dart b/lib/pangea/login/pages/signup.dart index 21ffd8661..67e24340e 100644 --- a/lib/pangea/login/pages/signup.dart +++ b/lib/pangea/login/pages/signup.dart @@ -241,7 +241,10 @@ class SignupPageController extends State { data: {}, ); } - error = (e).toLocalizedString(context); + + if (mounted) { + error = (e).toLocalizedString(context); + } } finally { if (mounted) { setState(() => loadingSignup = false); diff --git a/lib/pangea/login/pages/user_settings.dart b/lib/pangea/login/pages/user_settings.dart index 9963dc984..fec3ed1b2 100644 --- a/lib/pangea/login/pages/user_settings.dart +++ b/lib/pangea/login/pages/user_settings.dart @@ -215,6 +215,10 @@ class UserSettingsState extends State { }, waitForDataInSync: true, ), + _pangeaController.userController.updatePublicProfile( + targetLanguage: selectedTargetLanguage, + level: 1, + ), ]; await Future.wait(updateFuture).timeout( const Duration(seconds: 30), diff --git a/lib/pangea/user/controllers/user_controller.dart b/lib/pangea/user/controllers/user_controller.dart index d2d4dbebd..3bff48bca 100644 --- a/lib/pangea/user/controllers/user_controller.dart +++ b/lib/pangea/user/controllers/user_controller.dart @@ -8,7 +8,10 @@ import 'package:fluffychat/pangea/common/constants/model_keys.dart'; import 'package:fluffychat/pangea/common/controllers/base_controller.dart'; import 'package:fluffychat/pangea/common/controllers/pangea_controller.dart'; import 'package:fluffychat/pangea/common/utils/error_handler.dart'; +import 'package:fluffychat/pangea/events/constants/pangea_event_types.dart'; import 'package:fluffychat/pangea/learning_settings/constants/language_constants.dart'; +import 'package:fluffychat/pangea/learning_settings/models/language_model.dart'; +import 'package:fluffychat/pangea/user/models/profile_model.dart'; import '../models/user_model.dart'; /// Controller that manages saving and reading of user/profile information @@ -18,23 +21,26 @@ class UserController extends BaseController { _pangeaController = pangeaController; } + matrix.Client get client => _pangeaController.matrixState.client; + /// Convenience function that returns the user ID currently stored in the client. - String? get userId => _pangeaController.matrixState.client.userID; + String? get userId => client.userID; /// Cached version of the user profile, so it doesn't have /// to be read in from client's account data each time it is accessed. Profile? _cachedProfile; + PublicProfileModel? publicProfile; + /// Listens for account updates and updates the cached profile StreamSubscription? _profileListener; /// Listen for updates to account data in syncs and update the cached profile void addProfileListener() { - _profileListener ??= _pangeaController.matrixState.client.onSync.stream + _profileListener ??= client.onSync.stream .where((sync) => sync.accountData != null) .listen((sync) { - final profileData = _pangeaController - .matrixState.client.accountData[ModelKey.userProfile]?.content; + final profileData = client.accountData[ModelKey.userProfile]?.content; final Profile? fromAccountData = Profile.fromAccountData(profileData); if (fromAccountData != null) { _cachedProfile = fromAccountData; @@ -50,14 +56,13 @@ class UserController extends BaseController { if (_cachedProfile != null) return _cachedProfile!; /// if account data is empty, return an empty profile - if (_pangeaController.matrixState.client.accountData.isEmpty) { + if (client.accountData.isEmpty) { return Profile.emptyProfile; } /// try to get the account data in the up-to-date format final Profile? fromAccountData = Profile.fromAccountData( - _pangeaController - .matrixState.client.accountData[ModelKey.userProfile]?.content, + client.accountData[ModelKey.userProfile]?.content, ); if (fromAccountData != null) { @@ -85,16 +90,6 @@ class UserController extends BaseController { } } - /// Creates a new profile for the user with the given date of birth. - Future createProfile({DateTime? dob}) async { - final userSettings = UserSettings( - dateOfBirth: dob, - createdAt: DateTime.now(), - ); - final newProfile = Profile(userSettings: userSettings); - await newProfile.saveProfileData(waitForDataInSync: true); - } - /// A completer for the profile model of a user. Completer? _profileCompleter; @@ -136,8 +131,31 @@ class UserController extends BaseController { Future _initialize() async { // wait for account data to load // as long as it's not null, then this we've already migrated the profile - if (_pangeaController.matrixState.client.prevBatch == null) { - await _pangeaController.matrixState.client.onSync.stream.first; + if (client.prevBatch == null) { + await client.onSync.stream.first; + } + + if (client.userID == null) return; + try { + final resp = await client.getUserProfile(client.userID!); + publicProfile = PublicProfileModel.fromJson(resp.additionalProperties); + } catch (e) { + // getting a 404 error for some users without pre-existing profile + // still want to set other properties, so catch this error + publicProfile = PublicProfileModel(); + } + + // Do not await. This function pulls level from analytics, + // so it waits for analytics to finish initializing. Analytics waits for user controller to + // finish initializing, so this would cause a deadlock. + if (publicProfile!.isEmpty) { + _pangeaController.getAnalytics.initCompleter.future + .timeout(const Duration(seconds: 10)) + .then((_) { + updatePublicProfile( + level: _pangeaController.getAnalytics.constructListModel.level, + ); + }); } } @@ -149,12 +167,36 @@ class UserController extends BaseController { await initialize(); } + Future updatePublicProfile({ + LanguageModel? targetLanguage, + int? level, + }) async { + targetLanguage ??= _pangeaController.languageController.userL2; + if (targetLanguage == null || publicProfile == null) return; + + if (publicProfile!.targetLanguage == targetLanguage && + publicProfile!.languageAnalytics?[targetLanguage]?.level == level) { + return; + } + + publicProfile!.targetLanguage = targetLanguage; + if (level != null) { + publicProfile!.setLevel(targetLanguage, level); + } + + await client.setUserProfile( + client.userID!, + PangeaEventTypes.profileAnalytics, + publicProfile!.toJson(), + ); + } + /// Returns a boolean value indicating whether a new JWT (JSON Web Token) is needed. bool needNewJWT(String token) => Jwt.isExpired(token); /// Retrieves matrix access token. String get accessToken { - final token = _pangeaController.matrixState.client.accessToken; + final token = client.accessToken; if (token == null) { throw ("Trying to get accessToken with null token. User is not logged in."); } @@ -251,11 +293,27 @@ class UserController extends BaseController { /// is found. Future get userEmail async { final List? identifiers = - await _pangeaController.matrixState.client.getAccount3PIDs(); + await client.getAccount3PIDs(); final matrix.ThirdPartyIdentifier? email = identifiers?.firstWhereOrNull( (identifier) => identifier.medium == matrix.ThirdPartyIdentifierMedium.email, ); return email?.address; } + + Future getPublicProfile(String userId) async { + try { + final resp = await client.getUserProfile(userId); + return PublicProfileModel.fromJson(resp.additionalProperties); + } catch (e, s) { + ErrorHandler.logError( + e: e, + s: s, + data: { + userId: userId, + }, + ); + return PublicProfileModel(); + } + } } diff --git a/lib/pangea/user/models/profile_model.dart b/lib/pangea/user/models/profile_model.dart new file mode 100644 index 000000000..02c46e673 --- /dev/null +++ b/lib/pangea/user/models/profile_model.dart @@ -0,0 +1,75 @@ +import 'package:fluffychat/pangea/common/constants/model_keys.dart'; +import 'package:fluffychat/pangea/events/constants/pangea_event_types.dart'; +import 'package:fluffychat/pangea/learning_settings/models/language_model.dart'; +import 'package:fluffychat/pangea/learning_settings/utils/language_list_util.dart'; + +class PublicProfileModel { + LanguageModel? targetLanguage; + Map? languageAnalytics; + + PublicProfileModel({this.targetLanguage, this.languageAnalytics}); + + factory PublicProfileModel.fromJson(Map json) { + if (!json.containsKey(PangeaEventTypes.profileAnalytics)) { + return PublicProfileModel(); + } + + final profileJson = json[PangeaEventTypes.profileAnalytics]; + + final targetLanguage = profileJson[ModelKey.userTargetLanguage] != null + ? PangeaLanguage.byLangCode(profileJson[ModelKey.userTargetLanguage]) + : null; + + final languageAnalytics = {}; + if (profileJson[ModelKey.analytics] != null && + profileJson[ModelKey.analytics]!.isNotEmpty) { + for (final entry in profileJson[ModelKey.analytics].entries) { + final lang = PangeaLanguage.byLangCode(entry.key); + if (lang == null) continue; + final level = entry.value[ModelKey.level]; + languageAnalytics[lang] = LanguageAnalyticsProfileEntry(level); + } + } + + final profile = PublicProfileModel( + targetLanguage: targetLanguage, + languageAnalytics: languageAnalytics, + ); + return profile; + } + + Map toJson() { + final json = {}; + if (targetLanguage != null) { + json[ModelKey.userTargetLanguage] = targetLanguage!.langCode; + } + + final analytics = {}; + if (languageAnalytics != null && languageAnalytics!.isNotEmpty) { + for (final entry in languageAnalytics!.entries) { + analytics[entry.key.langCode] = {ModelKey.level: entry.value.level}; + } + } + + json[ModelKey.analytics] = analytics; + return json; + } + + bool get isEmpty => + targetLanguage == null && + (languageAnalytics == null || languageAnalytics!.isEmpty); + + void setLevel(LanguageModel language, int level) { + languageAnalytics ??= {}; + languageAnalytics![language] ??= LanguageAnalyticsProfileEntry(0); + languageAnalytics![language]!.level = level; + } + + int? get level => languageAnalytics?[targetLanguage]?.level; +} + +class LanguageAnalyticsProfileEntry { + int level; + + LanguageAnalyticsProfileEntry(this.level); +} diff --git a/lib/pangea/user/widgets/public_level_indicator.dart b/lib/pangea/user/widgets/public_level_indicator.dart new file mode 100644 index 000000000..9efeb6907 --- /dev/null +++ b/lib/pangea/user/widgets/public_level_indicator.dart @@ -0,0 +1,150 @@ +import 'package:flutter/material.dart'; + +import 'package:flutter_gen/gen_l10n/l10n.dart'; + +import 'package:fluffychat/config/app_config.dart'; +import 'package:fluffychat/pangea/user/models/profile_model.dart'; +import 'package:fluffychat/widgets/matrix.dart'; + +class PublicLevelIndicator extends StatelessWidget { + final String userId; + const PublicLevelIndicator({ + required this.userId, + super.key, + }); + + @override + Widget build(BuildContext context) { + final profileFuture = + MatrixState.pangeaController.userController.getPublicProfile(userId); + + return FutureBuilder( + future: profileFuture, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const Padding( + padding: EdgeInsets.all(16), + child: LinearProgressIndicator(), + ); + } + + if (snapshot.hasError) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(15), + color: Theme.of(context).colorScheme.surfaceBright, + ), + padding: const EdgeInsets.symmetric( + horizontal: 6, + vertical: 2, + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + size: 14, + Icons.error_outline, + color: Theme.of(context).colorScheme.error, + weight: 1000, + ), + const SizedBox(width: 5), + Text( + L10n.of(context).oopsSomethingWentWrong, + style: const TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + ); + } + + if (snapshot.hasData && + snapshot.data!.targetLanguage == null && + snapshot.data!.level == null) { + return const SizedBox.shrink(); + } + + return Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (snapshot.data?.targetLanguage != null) + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(15), + color: Theme.of(context).colorScheme.surfaceBright, + ), + padding: const EdgeInsets.symmetric( + horizontal: 6, + vertical: 2, + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + size: 14, + Icons.language, + color: Theme.of(context).colorScheme.primary, + weight: 1000, + ), + const SizedBox(width: 5), + Text( + snapshot.data!.targetLanguage!.displayName, + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + color: Theme.of(context).colorScheme.primary, + ), + ), + ], + ), + ), + const SizedBox(width: 12), + if (snapshot.data?.level != null) + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(15), + color: Theme.of(context).colorScheme.surfaceBright, + ), + padding: const EdgeInsets.symmetric( + horizontal: 4, + vertical: 2, + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + CircleAvatar( + backgroundColor: AppConfig.gold, + radius: 8, + child: Icon( + size: 12, + Icons.star, + color: Theme.of(context).colorScheme.surfaceBright, + weight: 1000, + ), + ), + const SizedBox(width: 4), + Text( + L10n.of(context).levelShort(snapshot.data!.level!), + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + color: Theme.of(context).colorScheme.primary, + ), + ), + ], + ), + ), + ], + ), + ); + }, + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index c4386aaae..f675b46b7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -153,14 +153,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.4.0" - base58check: - dependency: transitive - description: - name: base58check - sha256: "6c300dfc33e598d2fe26319e13f6243fea81eaf8204cb4c6b69ef20a625319a5" - url: "https://pub.dev" - source: hosted - version: "2.0.0" blurhash_dart: dependency: "direct main" description: @@ -193,14 +185,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.3" - canonical_json: - dependency: transitive - description: - name: canonical_json - sha256: d6be1dd66b420c6ac9f42e3693e09edf4ff6edfee26cb4c28c1c019fdb8c0c15 - url: "https://pub.dev" - source: hosted - version: "1.1.2" characters: dependency: "direct main" description: @@ -433,14 +417,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.9.9" - enhanced_enum: - dependency: transitive - description: - name: enhanced_enum - sha256: "074c5a8b9664799ca91e1e8b68003b8694cb19998671cbafd9c7779c13fcdecf" - url: "https://pub.dev" - source: hosted - version: "0.2.4" equatable: dependency: transitive description: @@ -1119,14 +1095,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.15.4" - html_unescape: - dependency: transitive - description: - name: html_unescape - sha256: "15362d7a18f19d7b742ef8dcb811f5fd2a2df98db9f80ea393c075189e0b61e3" - url: "https://pub.dev" - source: hosted - version: "2.0.0" http: dependency: "direct main" description: @@ -1465,7 +1433,7 @@ packages: description: path: "." ref: main - resolved-ref: "03be44cc13cb15a1b6fa586589eb8c243979d381" + resolved-ref: e77d79ff2a9b91d5cd950a0742be2f74781cb19f url: "https://github.com/pangeachat/matrix-dart-sdk.git" source: git version: "0.37.0" @@ -1525,14 +1493,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.2" - olm: - dependency: transitive - description: - name: olm - sha256: "3306bf534ceb914fd148b3b4a3d603fb5e067b2e6da8304025b47c24cfdf6b46" - url: "https://pub.dev" - source: hosted - version: "2.0.4" open_file: dependency: "direct main" description: @@ -1885,14 +1845,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" - random_string: - dependency: transitive - description: - name: random_string - sha256: "03b52435aae8cbdd1056cf91bfc5bf845e9706724dd35ae2e99fa14a1ef79d02" - url: "https://pub.dev" - source: hosted - version: "2.3.1" receive_sharing_intent: dependency: "direct main" description: @@ -2005,14 +1957,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.1" - sdp_transform: - dependency: transitive - description: - name: sdp_transform - sha256: "73e412a5279a5c2de74001535208e20fff88f225c9a4571af0f7146202755e45" - url: "https://pub.dev" - source: hosted - version: "0.3.2" sentry: dependency: transitive description: @@ -2490,14 +2434,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.2" - unorm_dart: - dependency: transitive - description: - name: unorm_dart - sha256: "5b35bff83fce4d76467641438f9e867dc9bcfdb8c1694854f230579d68cd8f4b" - url: "https://pub.dev" - source: hosted - version: "0.2.0" url_launcher: dependency: "direct main" description: