conversation cubit work

This commit is contained in:
Christien Rioux 2024-01-31 22:29:06 -05:00
parent 2e4deb2038
commit cd5d10ec1f
8 changed files with 515 additions and 168 deletions

View File

@ -7,7 +7,7 @@ import '../../proto/proto.dart' as proto;
class AccountRecordCubit extends DefaultDHTRecordCubit<proto.Account> {
AccountRecordCubit({
required super.record,
}) : super(decodeState: proto.Account.fromBuffer);
}) : super.value(decodeState: proto.Account.fromBuffer);
@override
Future<void> close() async {

View File

View File

@ -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<ChatComponent> {
IconButton(
icon: const Icon(Icons.close),
onPressed: () async {
ref.read(activeChatStateProvider.notifier).state =
null;
context.read<ActiveChatCubit>().setActiveChat(null);
}).paddingLTRB(16, 0, 16, 0)
]),
),

View File

@ -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<Object?> get props => [localConversation, remoteConversation];
}
class ConversationCubit extends Cubit<AsyncValue<ConversationState>> {
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<void> close() async {
await super.close();
}
// Open local converation key
Future<void> _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<ConversationState>.loading();
}
// state is complete, all required keys are open
return AsyncValue.data(_incrementalState);
},
loading: AsyncValue<ConversationState>.loading,
error: AsyncValue<ConversationState>.error,
);
emit(newState);
});
}
// Open remote converation key
Future<void> _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<ConversationState>.loading();
}
// state is complete, all required keys are open
return AsyncValue.data(_incrementalState);
},
loading: AsyncValue<ConversationState>.loading,
error: AsyncValue<ConversationState>.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<T> initLocalConversation<T>(
{required proto.Profile profile,
required FutureOr<T> 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<void> refresh() async {
if (_localConversationCubit != null) {
xxx use defaultdhtrecordcubit refresh mechanism
}
}
// Future<proto.Conversation?> 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<proto.Conversation?> 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<proto.Conversation?> 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<DHTRecordCrypto> 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<proto.Conversation>? _localConversationCubit;
DefaultDHTRecordCubit<proto.Conversation>? _remoteConversationCubit;
ConversationState _incrementalState;
//
DHTRecordCrypto? _conversationCrypto;
}

View File

@ -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);
}

View File

@ -7,33 +7,58 @@ import '../../veilid_support.dart';
class DHTRecordCubit<T> extends Cubit<AsyncValue<T>> {
DHTRecordCubit({
required Future<DHTRecord> Function() open,
required Future<T?> Function(DHTRecord) initialStateFunction,
required Future<T?> Function(DHTRecord, List<ValueSubkeyRange>, 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<T?> Function(DHTRecord) initialStateFunction,
required Future<T?> Function(DHTRecord, List<ValueSubkeyRange>, 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<void> _init(
Future<T?> Function(DHTRecord) initialStateFunction,
Future<T?> Function(DHTRecord, List<ValueSubkeyRange>, 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<T> extends Cubit<AsyncValue<T>> {
Future<void> close() async {
await _subscription?.cancel();
_subscription = null;
if (_wantsCloseRecord) {
await _record.close();
_wantsCloseRecord = false;
}
await super.close();
}
StreamSubscription<VeilidUpdateValueChange>? _subscription;
late DHTRecord _record;
bool _wantsCloseRecord;
}
// Cubit that watches the default subkey value of a dhtrecord
class DefaultDHTRecordCubit<T> extends DHTRecordCubit<T> {
DefaultDHTRecordCubit({
required super.record,
required super.open,
required T Function(List<int> 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<int> data) decodeState,
}) : super.value(
initialStateFunction: _makeInitialStateFunction(decodeState),
stateFunction: _makeStateFunction(decodeState),
);
static Future<T?> Function(DHTRecord) _makeInitialStateFunction<T>(
T Function(List<int> data) decodeState) =>
(record) async {
final initialData = await record.get();
if (initialData == null) {
return null;
}
return decodeState(initialData);
};
static Future<T?> Function(DHTRecord, List<ValueSubkeyRange>, ValueData)
_makeStateFunction<T>(T Function(List<int> data) decodeState) =>
(record, subkeys, valueData) async {
final defaultSubkey = record.subkeyOrDefault(-1);
if (subkeys.containsSubkey(defaultSubkey)) {
final Uint8List data;
@ -78,6 +125,8 @@ class DefaultDHTRecordCubit<T> extends DHTRecordCubit<T> {
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
}

View File

@ -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"

View File

@ -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