diff --git a/lib/account_manager/cubit/account_record_cubit.dart b/lib/account_manager/cubit/account_record_cubit.dart index 65306dd..b62d37a 100644 --- a/lib/account_manager/cubit/account_record_cubit.dart +++ b/lib/account_manager/cubit/account_record_cubit.dart @@ -7,7 +7,7 @@ import '../../proto/proto.dart' as proto; class AccountRecordCubit extends DefaultDHTRecordCubit { AccountRecordCubit({ required super.record, - }) : super(decodeState: proto.Account.fromBuffer); + }) : super.value(decodeState: proto.Account.fromBuffer); @override Future close() async { diff --git a/lib/chat/cubits/messages_cubit.dart b/lib/chat/cubits/messages_cubit.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/chat/views/chat_component.dart b/lib/chat/views/chat_component.dart index 270847d..dcfc8a1 100644 --- a/lib/chat/views/chat_component.dart +++ b/lib/chat/views/chat_component.dart @@ -2,9 +2,13 @@ import 'dart:async'; import 'package:awesome_extensions/awesome_extensions.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_chat_types/flutter_chat_types.dart' as types; import 'package:flutter_chat_ui/flutter_chat_ui.dart'; +import '../../theme/theme.dart'; +import '../chat.dart'; + class ChatComponent extends StatefulWidget { const ChatComponent({super.key}); @@ -144,8 +148,7 @@ class ChatComponentState extends State { IconButton( icon: const Icon(Icons.close), onPressed: () async { - ref.read(activeChatStateProvider.notifier).state = - null; + context.read().setActiveChat(null); }).paddingLTRB(16, 0, 16, 0) ]), ), diff --git a/lib/contacts/cubits/conversation_cubit.dart b/lib/contacts/cubits/conversation_cubit.dart new file mode 100644 index 0000000..973cf95 --- /dev/null +++ b/lib/contacts/cubits/conversation_cubit.dart @@ -0,0 +1,295 @@ +// A Conversation is a type of Chat that is 1:1 between two Contacts only +// Each Contact in the ContactList has at most one Conversation between the +// remote contact and the local account + +import 'dart:async'; +import 'dart:convert'; + +import 'package:equatable/equatable.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:meta/meta.dart'; +import 'package:veilid_support/veilid_support.dart'; + +import '../../account_manager/account_manager.dart'; +import '../../proto/proto.dart' as proto; + +@immutable +class ConversationState extends Equatable { + const ConversationState( + {required this.localConversation, required this.remoteConversation}); + + final proto.Conversation? localConversation; + final proto.Conversation? remoteConversation; + + @override + List get props => [localConversation, remoteConversation]; +} + +class ConversationCubit extends Cubit> { + ConversationCubit( + {required ActiveAccountInfo activeAccountInfo, + required TypedKey remoteIdentityPublicKey, + TypedKey? localConversationRecordKey, + TypedKey? remoteConversationRecordKey}) + : _activeAccountInfo = activeAccountInfo, + _localConversationRecordKey = localConversationRecordKey, + _remoteIdentityPublicKey = remoteIdentityPublicKey, + _remoteConversationRecordKey = remoteConversationRecordKey, + _incrementalState = const ConversationState( + localConversation: null, remoteConversation: null), + super(const AsyncValue.loading()) { + if (_localConversationRecordKey != null) { + Future.delayed(Duration.zero, () async { + final accountRecordKey = _activeAccountInfo + .userLogin.accountRecordInfo.accountRecord.recordKey; + + // Open local record key if it is specified + final pool = DHTRecordPool.instance; + final crypto = await getConversationCrypto(); + final writer = _activeAccountInfo.conversationWriter; + final record = await pool.openWrite( + _localConversationRecordKey!, writer, + parent: accountRecordKey, crypto: crypto); + await _setLocalConversation(record); + }); + } + + if (_remoteConversationRecordKey != null) { + Future.delayed(Duration.zero, () async { + final accountRecordKey = _activeAccountInfo + .userLogin.accountRecordInfo.accountRecord.recordKey; + + // Open remote record key if it is specified + final pool = DHTRecordPool.instance; + final crypto = await getConversationCrypto(); + final record = await pool.openRead(_remoteConversationRecordKey!, + parent: accountRecordKey, crypto: crypto); + await _setRemoteConversation(record); + }); + } + } + + @override + Future close() async { + await super.close(); + } + + // Open local converation key + Future _setLocalConversation(DHTRecord localConversationRecord) async { + _localConversationCubit = DefaultDHTRecordCubit.value( + record: localConversationRecord, + decodeState: proto.Conversation.fromBuffer); + _localConversationCubit!.stream.listen((avconv) { + final newState = avconv.when( + data: (conv) { + _incrementalState = ConversationState( + localConversation: conv, + remoteConversation: _incrementalState.remoteConversation); + // return loading still if state isn't complete + if ((_localConversationRecordKey != null && + _incrementalState.localConversation == null) || + (_remoteConversationRecordKey != null && + _incrementalState.remoteConversation == null)) { + return const AsyncValue.loading(); + } + // state is complete, all required keys are open + return AsyncValue.data(_incrementalState); + }, + loading: AsyncValue.loading, + error: AsyncValue.error, + ); + emit(newState); + }); + } + + // Open remote converation key + Future _setRemoteConversation( + DHTRecord remoteConversationRecord) async { + _remoteConversationCubit = DefaultDHTRecordCubit.value( + record: remoteConversationRecord, + decodeState: proto.Conversation.fromBuffer); + _remoteConversationCubit!.stream.listen((avconv) { + final newState = avconv.when( + data: (conv) { + _incrementalState = ConversationState( + localConversation: _incrementalState.localConversation, + remoteConversation: conv); + // return loading still if state isn't complete + if ((_localConversationRecordKey != null && + _incrementalState.localConversation == null) || + (_remoteConversationRecordKey != null && + _incrementalState.remoteConversation == null)) { + return const AsyncValue.loading(); + } + // state is complete, all required keys are open + return AsyncValue.data(_incrementalState); + }, + loading: AsyncValue.loading, + error: AsyncValue.error, + ); + emit(newState); + }); + } + + // Initialize a local conversation + // If we were the initiator of the conversation there may be an + // incomplete 'existingConversationRecord' that we need to fill + // in now that we have the remote identity key + // The ConversationCubit must not already have a local conversation + Future initLocalConversation( + {required proto.Profile profile, + required FutureOr Function(DHTRecord) callback, + TypedKey? existingConversationRecordKey}) async { + assert(_localConversationRecordKey == null, + 'must not have a local conversation yet'); + + final pool = DHTRecordPool.instance; + final accountRecordKey = + _activeAccountInfo.userLogin.accountRecordInfo.accountRecord.recordKey; + + final crypto = await getConversationCrypto(); + final writer = _activeAccountInfo.conversationWriter; + + // Open with SMPL scheme for identity writer + late final DHTRecord localConversationRecord; + if (existingConversationRecordKey != null) { + localConversationRecord = await pool.openWrite( + existingConversationRecordKey, writer, + parent: accountRecordKey, crypto: crypto); + } else { + final localConversationRecordCreate = await pool.create( + parent: accountRecordKey, + crypto: crypto, + schema: DHTSchema.smpl( + oCnt: 0, members: [DHTSchemaMember(mKey: writer.key, mCnt: 1)])); + await localConversationRecordCreate.close(); + localConversationRecord = await pool.openWrite( + localConversationRecordCreate.key, writer, + parent: accountRecordKey, crypto: crypto); + } + final out = localConversationRecord + // ignore: prefer_expression_function_bodies + .deleteScope((localConversation) async { + // Make messages log + return (await DHTShortArray.create( + parent: localConversation.key, + crypto: crypto, + smplWriter: writer)) + .deleteScope((messages) async { + // Write local conversation key + final conversation = proto.Conversation() + ..profile = profile + ..identityMasterJson = jsonEncode( + _activeAccountInfo.localAccount.identityMaster.toJson()) + ..messages = messages.record.key.toProto(); + + // + final update = await localConversation.tryWriteProtobuf( + proto.Conversation.fromBuffer, conversation); + if (update != null) { + throw Exception('Failed to write local conversation'); + } + return await callback(localConversation); + }); + }); + + // If success, save the new local conversation record key in this object + _localConversationRecordKey = localConversationRecord.key; + await _setLocalConversation(localConversationRecord); + + return out; + } + + // Force refresh of conversation keys + Future refresh() async { + if (_localConversationCubit != null) { + xxx use defaultdhtrecordcubit refresh mechanism + } + } + + // Future readRemoteConversation() async { + // final accountRecordKey = + // _activeAccountInfo.userLogin.accountRecordInfo.accountRecord.recordKey; + // final pool = DHTRecordPool.instance; + + // final crypto = await getConversationCrypto(); + // return (await pool.openRead(_remoteConversationRecordKey!, + // parent: accountRecordKey, crypto: crypto)) + // .scope((remoteConversation) async { + // // + // final conversation = + // await remoteConversation.getProtobuf(proto.Conversation.fromBuffer); + // return conversation; + // }); + // } + + // Future readLocalConversation() async { + // final accountRecordKey = + // _activeAccountInfo.userLogin.accountRecordInfo.accountRecord.recordKey; + // final pool = DHTRecordPool.instance; + + // final crypto = await getConversationCrypto(); + // return (await pool.openRead(_localConversationRecordKey!, + // parent: accountRecordKey, crypto: crypto)) + // .scope((localConversation) async { + // // + // final update = + // await localConversation.getProtobuf(proto.Conversation.fromBuffer); + // if (update != null) { + // return update; + // } + // return null; + // }); + // } + + // Future writeLocalConversation({ + // required proto.Conversation conversation, + // }) async { + // final accountRecordKey = + // _activeAccountInfo.userLogin.accountRecordInfo.accountRecord.recordKey; + // final pool = DHTRecordPool.instance; + + // final crypto = await getConversationCrypto(); + // final writer = _activeAccountInfo.conversationWriter; + + // return (await pool.openWrite(_localConversationRecordKey!, writer, + // parent: accountRecordKey, crypto: crypto)) + // .scope((localConversation) async { + // // + // final update = await localConversation.tryWriteProtobuf( + // proto.Conversation.fromBuffer, conversation); + // if (update != null) { + // return update; + // } + // return null; + // }); + // } + + // + + Future getConversationCrypto() async { + var conversationCrypto = _conversationCrypto; + if (conversationCrypto != null) { + return conversationCrypto; + } + final identitySecret = _activeAccountInfo.userLogin.identitySecret; + final cs = await Veilid.instance.getCryptoSystem(identitySecret.kind); + final sharedSecret = + await cs.cachedDH(_remoteIdentityPublicKey.value, identitySecret.value); + + conversationCrypto = await DHTRecordCryptoPrivate.fromSecret( + identitySecret.kind, sharedSecret); + _conversationCrypto = conversationCrypto; + return conversationCrypto; + } + + final ActiveAccountInfo _activeAccountInfo; + final TypedKey _remoteIdentityPublicKey; + TypedKey? _localConversationRecordKey; + TypedKey? _remoteConversationRecordKey; + DefaultDHTRecordCubit? _localConversationCubit; + DefaultDHTRecordCubit? _remoteConversationCubit; + ConversationState _incrementalState; + // + DHTRecordCrypto? _conversationCrypto; +} diff --git a/lib/tools/stack_trace.dart b/lib/tools/stack_trace.dart index ec21f24..6cd7f55 100644 --- a/lib/tools/stack_trace.dart +++ b/lib/tools/stack_trace.dart @@ -6,7 +6,7 @@ Never throwErrorWithCombinedStackTrace(Object error, StackTrace stackTrace) { final chain = Chain([ Trace.current(), ...Chain.forTrace(stackTrace).traces, - ]); // .foldFrames((frame) => frame.package == 'riverpod'); + ]); // .foldFrames((frame) => frame.package == 'xxx'); Error.throwWithStackTrace(error, chain.toTrace().vmTrace); } diff --git a/packages/veilid_support/lib/dht_support/src/dht_record_cubit.dart b/packages/veilid_support/lib/dht_support/src/dht_record_cubit.dart index 00db3fd..78e6eb6 100644 --- a/packages/veilid_support/lib/dht_support/src/dht_record_cubit.dart +++ b/packages/veilid_support/lib/dht_support/src/dht_record_cubit.dart @@ -7,33 +7,58 @@ import '../../veilid_support.dart'; class DHTRecordCubit extends Cubit> { DHTRecordCubit({ + required Future Function() open, + required Future Function(DHTRecord) initialStateFunction, + required Future Function(DHTRecord, List, ValueData) + stateFunction, + }) : _wantsCloseRecord = false, + super(const AsyncValue.loading()) { + Future.delayed(Duration.zero, () async { + // Do record open/create + _record = await open(); + _wantsCloseRecord = true; + await _init(initialStateFunction, stateFunction); + }); + } + + DHTRecordCubit.value({ required DHTRecord record, required Future Function(DHTRecord) initialStateFunction, required Future Function(DHTRecord, List, ValueData) stateFunction, - }) : super(const AsyncValue.loading()) { + }) : _record = record, + _wantsCloseRecord = false, + super(const AsyncValue.loading()) { Future.delayed(Duration.zero, () async { - // Make initial state update + await _init(initialStateFunction, stateFunction); + }); + } + + Future _init( + Future Function(DHTRecord) initialStateFunction, + Future Function(DHTRecord, List, ValueData) + stateFunction, + ) async { + // Make initial state update + try { + final initialState = await initialStateFunction(_record); + if (initialState != null) { + emit(AsyncValue.data(initialState)); + } + } on Exception catch (e) { + emit(AsyncValue.error(e)); + } + + _subscription = await _record.listen((update) async { try { - final initialState = await initialStateFunction(record); - if (initialState != null) { - emit(AsyncValue.data(initialState)); + final newState = + await stateFunction(_record, update.subkeys, update.valueData); + if (newState != null) { + emit(AsyncValue.data(newState)); } } on Exception catch (e) { emit(AsyncValue.error(e)); } - - _subscription = await record.listen((update) async { - try { - final newState = - await stateFunction(record, update.subkeys, update.valueData); - if (newState != null) { - emit(AsyncValue.data(newState)); - } - } on Exception catch (e) { - emit(AsyncValue.error(e)); - } - }); }); } @@ -41,26 +66,48 @@ class DHTRecordCubit extends Cubit> { Future close() async { await _subscription?.cancel(); _subscription = null; + if (_wantsCloseRecord) { + await _record.close(); + _wantsCloseRecord = false; + } await super.close(); } StreamSubscription? _subscription; + late DHTRecord _record; + bool _wantsCloseRecord; } // Cubit that watches the default subkey value of a dhtrecord class DefaultDHTRecordCubit extends DHTRecordCubit { DefaultDHTRecordCubit({ - required super.record, + required super.open, required T Function(List data) decodeState, }) : super( - initialStateFunction: (record) async { - final initialData = await record.get(); - if (initialData == null) { - return null; - } - return decodeState(initialData); - }, - stateFunction: (record, subkeys, valueData) async { + initialStateFunction: _makeInitialStateFunction(decodeState), + stateFunction: _makeStateFunction(decodeState)); + + DefaultDHTRecordCubit.value({ + required super.record, + required T Function(List data) decodeState, + }) : super.value( + initialStateFunction: _makeInitialStateFunction(decodeState), + stateFunction: _makeStateFunction(decodeState), + ); + + static Future Function(DHTRecord) _makeInitialStateFunction( + T Function(List data) decodeState) => + (record) async { + final initialData = await record.get(); + if (initialData == null) { + return null; + } + return decodeState(initialData); + }; + + static Future Function(DHTRecord, List, ValueData) + _makeStateFunction(T Function(List data) decodeState) => + (record, subkeys, valueData) async { final defaultSubkey = record.subkeyOrDefault(-1); if (subkeys.containsSubkey(defaultSubkey)) { final Uint8List data; @@ -78,6 +125,8 @@ class DefaultDHTRecordCubit extends DHTRecordCubit { return newState; } return null; - }, - ); + }; + + xxx add refresh/get mechanism to DHTRecordCubit and here too, then propagage to conversation_cubit + xxx should just be a 'get' like in dht_short_array_cubit } diff --git a/pubspec.lock b/pubspec.lock index ee6c0fa..648e896 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -37,10 +37,10 @@ packages: dependency: "direct main" description: name: archive - sha256: "7b875fd4a20b165a3084bd2d210439b22ebc653f21cea4842729c0c30c82596b" + sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d" url: "https://pub.dev" source: hosted - version: "3.4.9" + version: "3.4.10" args: dependency: transitive description: @@ -61,10 +61,10 @@ packages: dependency: "direct main" description: name: awesome_extensions - sha256: a8b68d567119b9be85bc62d8dc2ab6712d74c0130bdc31a52c53d1058c4fe33a + sha256: cde9c8c155c1a1cafc5286807e16124e97f0cff739a47ec17aa9d26c3c37abcf url: "https://pub.dev" source: hosted - version: "2.0.11" + version: "2.0.12" badges: dependency: "direct main" description: @@ -141,18 +141,18 @@ packages: dependency: "direct dev" description: name: build_runner - sha256: "67d591d602906ef9201caf93452495ad1812bea2074f04e25dbd7c133785821b" + sha256: "581bacf68f89ec8792f5e5a0b2c4decd1c948e97ce659dc783688c8a88fbec21" url: "https://pub.dev" source: hosted - version: "2.4.7" + version: "2.4.8" build_runner_core: dependency: transitive description: name: build_runner_core - sha256: c9e32d21dd6626b5c163d48b037ce906bbe428bc23ab77bcd77bb21e593b6185 + sha256: "4ae8ffe5ac758da294ecf1802f2aff01558d8b1b00616aa7538ea9a8a5d50799" url: "https://pub.dev" source: hosted - version: "7.2.11" + version: "7.3.0" built_collection: dependency: transitive description: @@ -165,74 +165,74 @@ packages: dependency: transitive description: name: built_value - sha256: c9aabae0718ec394e5bc3c7272e6bb0dc0b32201a08fe185ec1d8401d3e39309 + sha256: a3ec2e0f967bc47f69f95009bb93db936288d61d5343b9436e378b28a2f830c6 url: "https://pub.dev" source: hosted - version: "8.8.1" + version: "8.9.0" cached_network_image: dependency: transitive description: name: cached_network_image - sha256: f98972704692ba679db144261172a8e20feb145636c617af0eb4022132a6797f + sha256: "28ea9690a8207179c319965c13cd8df184d5ee721ae2ce60f398ced1219cea1f" url: "https://pub.dev" source: hosted - version: "3.3.0" + version: "3.3.1" cached_network_image_platform_interface: dependency: transitive description: name: cached_network_image_platform_interface - sha256: "56aa42a7a01e3c9db8456d9f3f999931f1e05535b5a424271e9a38cabf066613" + sha256: "9e90e78ae72caa874a323d78fa6301b3fb8fa7ea76a8f96dc5b5bf79f283bf2f" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "4.0.0" cached_network_image_web: dependency: transitive description: name: cached_network_image_web - sha256: "759b9a9f8f6ccbb66c185df805fac107f05730b1dab9c64626d1008cca532257" + sha256: "42a835caa27c220d1294311ac409a43361088625a4f23c820b006dd9bffb3316" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" camera: dependency: transitive description: name: camera - sha256: "7fa53bb1c2059e58bf86b7ab506e3b2a78e42f82d365b44b013239b975a166ef" + sha256: "9499cbc2e51d8eb0beadc158b288380037618ce4e30c9acbc4fae1ac3ecb5797" url: "https://pub.dev" source: hosted - version: "0.10.5+7" + version: "0.10.5+9" camera_android: dependency: transitive description: name: camera_android - sha256: "7215e38fa0be58cc3203a6e48de3636fb9b1bf93d6eeedf667f882d51b3a4bf3" + sha256: "351429510121d179b9aac5a2e8cb525c3cd6c39f4d709c5f72dfb21726e52371" url: "https://pub.dev" source: hosted - version: "0.10.8+15" + version: "0.10.8+16" camera_avfoundation: dependency: transitive description: name: camera_avfoundation - sha256: "3c8dd395f18722f01b5f325ddd7f5256e9bcdce538fb9243b378ba759df3283c" + sha256: "7d0763dfcbf060f56aa254a68c103210280bee9e97bbe4fdef23e257a4f70ab9" url: "https://pub.dev" source: hosted - version: "0.9.13+8" + version: "0.9.14" camera_platform_interface: dependency: transitive description: name: camera_platform_interface - sha256: b6a568984254cadaca41a6b896d87d3b2e79a2e5791afa036f8d524c6783b93a + sha256: e971ebca970f7cfee396f76ef02070b5e441b4aa04942da9c108d725f57bbd32 url: "https://pub.dev" source: hosted - version: "2.7.0" + version: "2.7.2" camera_web: dependency: transitive description: name: camera_web - sha256: d4c2c571c7af04f8b10702ca16bb9ed2a26e64534171e8f75c9349b2c004d8f1 + sha256: f18ccfb33b2a7c49a52ad5aa3f07330b7422faaecbdfd9b9fe8e51182f6ad67d url: "https://pub.dev" source: hosted - version: "0.3.2+3" + version: "0.3.2+4" change_case: dependency: "direct main" description: @@ -301,10 +301,10 @@ packages: dependency: transitive description: name: code_builder - sha256: feee43a5c05e7b3199bb375a86430b8ada1b04104f2923d0e03cc01ca87b6d84 + sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37 url: "https://pub.dev" source: hosted - version: "4.9.0" + version: "4.10.0" collection: dependency: transitive description: @@ -397,10 +397,10 @@ packages: dependency: "direct main" description: name: fast_immutable_collections - sha256: "3eb1d7495c70598964add20e10666003fad6e855b108fe684ebcbf8ad0c8e120" + sha256: b910ccdc99bb38a2abbce07c5afb8f81d4e222a892e4d095a548b99814837b0c url: "https://pub.dev" source: hosted - version: "9.2.0" + version: "9.2.1" ffi: dependency: transitive description: @@ -442,10 +442,10 @@ packages: dependency: "direct main" description: name: flutter_animate - sha256: "1dbc1aabfb8ec1e9d9feed2b675c21fb6b0a11f99be53ec3bc0f1901af6a8eb7" + sha256: cabe33af6201144be052352d53572a1b8a4f5782b46080be7520d95abe763715 url: "https://pub.dev" source: hosted - version: "4.3.0" + version: "4.4.1" flutter_bloc: dependency: "direct main" description: @@ -482,18 +482,18 @@ packages: dependency: "direct main" description: name: flutter_form_builder - sha256: "8973beed34b6d951d36bf688b52e9e3040b47b763c35c320bd6f4c2f6b13f3a2" + sha256: e8702c52dc45b43ed42e2b5d9b35f2970096d9cf1a58015cd3a76fad62a8f183 url: "https://pub.dev" source: hosted - version: "9.1.1" + version: "9.2.0" flutter_hooks: dependency: "direct main" description: name: flutter_hooks - sha256: "7c8db779c2d1010aa7f9ea3fbefe8f86524fcb87b69e8b0af31e1a4b55422dec" + sha256: "09f64db63fee3b2ab8b9038a1346be7d8986977fae3fec601275bf32455ccfc0" url: "https://pub.dev" source: hosted - version: "0.20.3" + version: "0.20.4" flutter_link_previewer: dependency: transitive description: @@ -519,10 +519,10 @@ packages: dependency: "direct main" description: name: flutter_native_splash - sha256: "141b20f15a2c4fe6e33c49257ca1bc114fc5c500b04fcbc8d75016bb86af672f" + sha256: "558f10070f03ee71f850a78f7136ab239a67636a294a44a06b6b7345178edb1e" url: "https://pub.dev" source: hosted - version: "2.3.8" + version: "2.3.10" flutter_parsed_text: dependency: transitive description: @@ -665,10 +665,10 @@ packages: dependency: transitive description: name: http - sha256: d4872660c46d929f6b8a9ef4e7a7eff7e49bbf0c4ec3f385ee32df5119175139 + sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.2.0" http_multi_server: dependency: transitive description: @@ -697,18 +697,18 @@ packages: dependency: "direct dev" description: name: icons_launcher - sha256: "3ed4560181f238e69ca5d55589d6946ef31e6a321c934251a26ce1d9e9867305" + sha256: "9b514ffed6ed69b232fd2bf34c44878c8526be71fc74129a658f35c04c9d4a9d" url: "https://pub.dev" source: hosted - version: "2.1.6" + version: "2.1.7" image: dependency: "direct main" description: name: image - sha256: "028f61960d56f26414eb616b48b04eb37d700cbe477b7fb09bf1d7ce57fd9271" + sha256: "004a2e90ce080f8627b5a04aecb4cdfac87d2c3f3b520aa291260be5a32c033d" url: "https://pub.dev" source: hosted - version: "4.1.3" + version: "4.1.4" intl: dependency: "direct main" description: @@ -809,26 +809,26 @@ packages: dependency: transitive description: name: mime - sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.0.5" mobile_scanner: dependency: "direct main" description: name: mobile_scanner - sha256: c3e5bba1cb626b6ab4fc46610f72a136803f6854267967e19f4a4a6a31ff9b74 + sha256: "1b60b8f9d4ce0cb0e7d7bc223c955d083a0737bee66fa1fcfe5de48225e0d5b3" url: "https://pub.dev" source: hosted - version: "3.5.5" + version: "3.5.7" motion_toast: dependency: "direct main" description: name: motion_toast - sha256: "1bdd11696de9151804644d3dadcbcfaa55749db0353aeca150389ecdeb2eaaac" + sha256: e423584213b459d021fbdfcd8e02b22e3480ff0b3cef05dc4cde040595ebf084 url: "https://pub.dev" source: hosted - version: "2.7.10" + version: "2.8.0" mutex: dependency: "direct main" description: @@ -889,10 +889,10 @@ packages: dependency: "direct main" description: name: path_provider - sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa + sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" path_provider_android: dependency: transitive description: @@ -905,10 +905,10 @@ packages: dependency: transitive description: name: path_provider_foundation - sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d" + sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" path_provider_linux: dependency: transitive description: @@ -921,10 +921,10 @@ packages: dependency: transitive description: name: path_provider_platform_interface - sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c" + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" path_provider_windows: dependency: transitive description: @@ -961,10 +961,10 @@ packages: dependency: transitive description: name: platform - sha256: "0a279f0707af40c890e80b1e9df8bb761694c074ba7e1d4ab1bc4b728e200b59" + sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" url: "https://pub.dev" source: hosted - version: "3.1.3" + version: "3.1.4" platform_info: dependency: transitive description: @@ -977,18 +977,18 @@ packages: dependency: transitive description: name: plugin_platform_interface - sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8 + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" url: "https://pub.dev" source: hosted - version: "2.1.7" + version: "2.1.8" pointycastle: dependency: transitive description: name: pointycastle - sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" + sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29" url: "https://pub.dev" source: hosted - version: "3.7.3" + version: "3.7.4" pool: dependency: transitive description: @@ -1121,18 +1121,18 @@ packages: dependency: "direct main" description: name: searchable_listview - sha256: "492bb75e133d1be902d2c1e8aa362f21127260106557492993432a4f5489494a" + sha256: fad781a412d1fec251c7a66e4aca49e49ab8b7104bda733b476d4b5c81891bea url: "https://pub.dev" source: hosted - version: "2.9.1" + version: "2.10.1" share_plus: dependency: "direct main" description: name: share_plus - sha256: f74fc3f1cbd99f39760182e176802f693fa0ec9625c045561cfad54681ea93dd + sha256: "3ef39599b00059db0990ca2e30fca0a29d8b37aae924d60063f8e0184cf20900" url: "https://pub.dev" source: hosted - version: "7.2.1" + version: "7.2.2" share_plus_platform_interface: dependency: transitive description: @@ -1161,10 +1161,10 @@ packages: dependency: transitive description: name: shared_preferences_foundation - sha256: "7bf53a9f2d007329ee6f3df7268fd498f8373602f943c975598bbb34649b62a7" + sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c" url: "https://pub.dev" source: hosted - version: "2.3.4" + version: "2.3.5" shared_preferences_linux: dependency: transitive description: @@ -1177,10 +1177,10 @@ packages: dependency: transitive description: name: shared_preferences_platform_interface - sha256: d4ec5fc9ebb2f2e056c617112aa75dcf92fc2e4faaf2ae999caa297473f75d8a + sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" shared_preferences_web: dependency: transitive description: @@ -1270,18 +1270,18 @@ packages: dependency: transitive description: name: sqflite - sha256: "591f1602816e9c31377d5f008c2d9ef7b8aca8941c3f89cc5fd9d84da0c38a9a" + sha256: a9016f495c927cb90557c909ff26a6d92d9bd54fc42ba92e19d4e79d61e798c6 url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.3.2" sqflite_common: dependency: transitive description: name: sqflite_common - sha256: bb4738f15b23352822f4c42a531677e5c6f522e079461fd240ead29d8d8a54a6 + sha256: "28d8c66baee4968519fb8bd6cdbedad982d6e53359091f0b74544a9f32ec72d5" url: "https://pub.dev" source: hosted - version: "2.5.0+2" + version: "2.5.3" stack_trace: dependency: "direct main" description: @@ -1398,26 +1398,26 @@ packages: dependency: transitive description: name: url_launcher - sha256: e9aa5ea75c84cf46b3db4eea212523591211c3cf2e13099ee4ec147f54201c86 + sha256: c512655380d241a337521703af62d2c122bf7b77a46ff7dd750092aa9433499c url: "https://pub.dev" source: hosted - version: "6.2.2" + version: "6.2.4" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: "31222ffb0063171b526d3e569079cf1f8b294075ba323443fdc690842bfd4def" + sha256: "507dc655b1d9cb5ebc756032eb785f114e415f91557b73bf60b7e201dfedeb2f" url: "https://pub.dev" source: hosted - version: "6.2.0" + version: "6.2.2" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: bba3373219b7abb6b5e0d071b0fe66dfbe005d07517a68e38d4fc3638f35c6d3 + sha256: "75bb6fe3f60070407704282a2d295630cab232991eb52542b18347a8a941df03" url: "https://pub.dev" source: hosted - version: "6.2.1" + version: "6.2.4" url_launcher_linux: dependency: transitive description: @@ -1438,18 +1438,18 @@ packages: dependency: transitive description: name: url_launcher_platform_interface - sha256: "980e8d9af422f477be6948bdfb68df8433be71f5743a188968b0c1b887807e50" + sha256: a932c3a8082e118f80a475ce692fde89dc20fddb24c57360b96bc56f7035de1f url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.3.1" url_launcher_web: dependency: transitive description: name: url_launcher_web - sha256: "7286aec002c8feecc338cc33269e96b73955ab227456e9fb2a91f7fab8a358e9" + sha256: fff0932192afeedf63cdd50ecbb1bc825d31aed259f02bb8dba0f3b729a5e88b url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.2.3" url_launcher_windows: dependency: transitive description: @@ -1470,26 +1470,26 @@ packages: dependency: transitive description: name: vector_graphics - sha256: "0f0c746dd2d6254a0057218ff980fc7f5670fd0fcf5e4db38a490d31eed4ad43" + sha256: "18f6690295af52d081f6808f2f7c69f0eed6d7e23a71539d75f4aeb8f0062172" url: "https://pub.dev" source: hosted - version: "1.1.9+1" + version: "1.1.9+2" vector_graphics_codec: dependency: transitive description: name: vector_graphics_codec - sha256: "0edf6d630d1bfd5589114138ed8fada3234deacc37966bec033d3047c29248b7" + sha256: "531d20465c10dfac7f5cd90b60bbe4dd9921f1ec4ca54c83ebb176dbacb7bb2d" url: "https://pub.dev" source: hosted - version: "1.1.9+1" + version: "1.1.9+2" vector_graphics_compiler: dependency: transitive description: name: vector_graphics_compiler - sha256: d24333727332d9bd20990f1483af4e09abdb9b1fc7c3db940b56ab5c42790c26 + sha256: "03012b0a33775c5530576b70240308080e1d5050f0faf000118c20e6463bc0ad" url: "https://pub.dev" source: hosted - version: "1.1.9+1" + version: "1.1.9+2" vector_math: dependency: transitive description: @@ -1548,26 +1548,26 @@ packages: dependency: transitive description: name: win32 - sha256: b0f37db61ba2f2e9b7a78a1caece0052564d1bc70668156cf3a29d676fe4e574 + sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8" url: "https://pub.dev" source: hosted - version: "5.1.1" + version: "5.2.0" window_manager: dependency: "direct main" description: name: window_manager - sha256: dcc865277f26a7dad263a47d0e405d77e21f12cb71f30333a52710a408690bd7 + sha256: b3c895bdf936c77b83c5254bec2e6b3f066710c1f89c38b20b8acc382b525494 url: "https://pub.dev" source: hosted - version: "0.3.7" + version: "0.3.8" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2" + sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "1.0.4" xml: dependency: transitive description: @@ -1609,5 +1609,5 @@ packages: source: hosted version: "0.9.0" sdks: - dart: ">=3.2.0 <4.0.0" - flutter: ">=3.16.0" + dart: ">=3.2.3 <4.0.0" + flutter: ">=3.16.6" diff --git a/pubspec.yaml b/pubspec.yaml index f91527d..a5f22bc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -8,65 +8,65 @@ environment: flutter: ">=3.10.0" dependencies: - animated_theme_switcher: ^2.0.7 - ansicolor: ^2.0.1 - archive: ^3.3.7 - awesome_extensions: ^2.0.9 - badges: ^3.1.1 - basic_utils: ^5.6.1 + animated_theme_switcher: ^2.0.10 + ansicolor: ^2.0.2 + archive: ^3.4.10 + awesome_extensions: ^2.0.12 + badges: ^3.1.2 + basic_utils: ^5.7.0 bloc: ^8.1.2 - blurry_modal_progress_hud: ^1.1.0 + blurry_modal_progress_hud: ^1.1.1 change_case: ^1.1.0 charcode: ^1.3.1 circular_profile_avatar: ^2.0.5 circular_reveal_animation: ^2.0.1 cool_dropdown: ^2.1.0 - cupertino_icons: ^1.0.2 + cupertino_icons: ^1.0.6 equatable: ^2.0.5 - fast_immutable_collections: ^9.1.5 + fast_immutable_collections: ^9.2.1 fixnum: ^1.1.0 flutter: sdk: flutter - flutter_animate: ^4.2.0+1 + flutter_animate: ^4.4.1 flutter_bloc: ^8.1.3 flutter_chat_types: ^3.6.2 - flutter_chat_ui: ^1.6.9 - flutter_form_builder: ^9.1.0 - flutter_hooks: ^0.20.1 + flutter_chat_ui: ^1.6.10 + flutter_form_builder: ^9.2.0 + flutter_hooks: ^0.20.4 flutter_localizations: sdk: flutter - flutter_native_splash: ^2.3.2 - flutter_slidable: ^3.0.0 + flutter_native_splash: ^2.3.10 + flutter_slidable: ^3.0.1 flutter_spinkit: ^5.2.0 - flutter_svg: ^2.0.7 + flutter_svg: ^2.0.9 flutter_translate: ^4.0.4 - form_builder_validators: ^9.0.0 - freezed_annotation: ^2.2.0 - go_router: ^11.0.0 + form_builder_validators: ^9.1.0 + freezed_annotation: ^2.4.1 + go_router: ^11.1.4 hydrated_bloc: ^9.1.3 - image: ^4.1.3 - intl: ^0.18.0 + image: ^4.1.4 + intl: ^0.18.1 json_annotation: ^4.8.1 loggy: ^2.0.3 meta: ^1.10.0 - mobile_scanner: ^3.5.1 - motion_toast: ^2.7.8 - mutex: ^3.0.1 + mobile_scanner: ^3.5.7 + motion_toast: ^2.8.0 + mutex: ^3.1.0 pasteboard: ^0.2.0 - path: ^1.8.2 - path_provider: ^2.0.11 + path: ^1.8.3 + path_provider: ^2.1.2 pinput: ^3.0.1 preload_page_view: ^0.2.0 - protobuf: ^3.0.0 + protobuf: ^3.1.0 provider: ^6.1.1 - qr_code_dart_scan: ^0.7.2 + qr_code_dart_scan: ^0.7.3 qr_flutter: ^4.1.0 - quickalert: ^1.0.1 + quickalert: ^1.0.2 radix_colors: ^1.0.4 - reorderable_grid: ^1.0.7 - searchable_listview: ^2.7.0 - share_plus: ^7.0.2 - shared_preferences: ^2.0.15 + reorderable_grid: ^1.0.10 + searchable_listview: ^2.10.1 + share_plus: ^7.2.2 + shared_preferences: ^2.2.2 signal_strength_indicator: ^0.4.1 split_view: ^3.2.1 stack_trace: ^1.11.1 @@ -78,16 +78,16 @@ dependencies: path: ../veilid/veilid-flutter veilid_support: path: packages/veilid_support - window_manager: ^0.3.5 + window_manager: ^0.3.8 xterm: ^3.5.0 - zxing2: ^0.2.0 + zxing2: ^0.2.1 dev_dependencies: - build_runner: ^2.4.6 + build_runner: ^2.4.8 flutter_test: sdk: flutter - freezed: ^2.3.5 - icons_launcher: ^2.1.3 + freezed: ^2.4.6 + icons_launcher: ^2.1.7 json_serializable: ^6.7.1 lint_hard: ^4.0.0