fixes for dht based providers

This commit is contained in:
Christien Rioux 2023-10-21 19:23:43 -04:00
parent 8ac551a5e0
commit 2a68172e0a
15 changed files with 97 additions and 101 deletions

View File

@ -6,7 +6,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_chat_types/flutter_chat_types.dart' as types; import 'package:flutter_chat_types/flutter_chat_types.dart' as types;
import 'package:flutter_chat_ui/flutter_chat_ui.dart'; import 'package:flutter_chat_ui/flutter_chat_ui.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:uuid/uuid.dart';
import '../proto/proto.dart' as proto; import '../proto/proto.dart' as proto;
import '../providers/account.dart'; import '../providers/account.dart';

View File

@ -1,6 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:typed_data'; import 'dart:typed_data';
import 'dart:ui';
import 'package:awesome_extensions/awesome_extensions.dart'; import 'package:awesome_extensions/awesome_extensions.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';

View File

@ -5,6 +5,7 @@ import 'package:go_router/go_router.dart';
import '../providers/connection_state.dart'; import '../providers/connection_state.dart';
import '../tools/tools.dart'; import '../tools/tools.dart';
import '../veilid_support/veilid_support.dart';
class SignalStrengthMeterWidget extends ConsumerWidget { class SignalStrengthMeterWidget extends ConsumerWidget {
const SignalStrengthMeterWidget({super.key}); const SignalStrengthMeterWidget({super.key});
@ -16,34 +17,34 @@ class SignalStrengthMeterWidget extends ConsumerWidget {
final scale = theme.extension<ScaleScheme>()!; final scale = theme.extension<ScaleScheme>()!;
const iconSize = 16.0; const iconSize = 16.0;
final connState = ref.watch(globalConnectionStateProvider); final connState = ref.watch(connectionStateProvider);
late final double value; late final double value;
late final Color color; late final Color color;
late final Color inactiveColor; late final Color inactiveColor;
switch (connState) { switch (connState.attachment.state) {
case GlobalConnectionState.detached: case AttachmentState.detached:
return Icon(Icons.signal_cellular_nodata, return Icon(Icons.signal_cellular_nodata,
size: iconSize, color: scale.grayScale.text); size: iconSize, color: scale.grayScale.text);
case GlobalConnectionState.detaching: case AttachmentState.detaching:
return Icon(Icons.signal_cellular_off, return Icon(Icons.signal_cellular_off,
size: iconSize, color: scale.grayScale.text); size: iconSize, color: scale.grayScale.text);
case GlobalConnectionState.attaching: case AttachmentState.attaching:
value = 0; value = 0;
color = scale.primaryScale.text; color = scale.primaryScale.text;
case GlobalConnectionState.attachedWeak: case AttachmentState.attachedWeak:
value = 1; value = 1;
color = scale.primaryScale.text; color = scale.primaryScale.text;
case GlobalConnectionState.attachedStrong: case AttachmentState.attachedStrong:
value = 2; value = 2;
color = scale.primaryScale.text; color = scale.primaryScale.text;
case GlobalConnectionState.attachedGood: case AttachmentState.attachedGood:
value = 3; value = 3;
color = scale.primaryScale.text; color = scale.primaryScale.text;
case GlobalConnectionState.fullyAttached: case AttachmentState.fullyAttached:
value = 4; value = 4;
color = scale.primaryScale.text; color = scale.primaryScale.text;
case GlobalConnectionState.overAttached: case AttachmentState.overAttached:
value = 4; value = 4;
color = scale.secondaryScale.subtleText; color = scale.secondaryScale.subtleText;
} }

View File

@ -30,9 +30,7 @@ class Processor {
// In case of hot restart shut down first // In case of hot restart shut down first
try { try {
await Veilid.instance.shutdownVeilidCore(); await Veilid.instance.shutdownVeilidCore();
} on Exception { } on Exception {}
//
}
final updateStream = final updateStream =
await Veilid.instance.startupVeilidCore(await getVeilidChatConfig()); await Veilid.instance.startupVeilidCore(await getVeilidChatConfig());
@ -60,57 +58,21 @@ class Processor {
VeilidUpdateAttachment updateAttachment) async { VeilidUpdateAttachment updateAttachment) async {
//loggy.info("Attachment: ${updateAttachment.json}"); //loggy.info("Attachment: ${updateAttachment.json}");
// Set connection meter and ui state for connection state // // Set connection meter and ui state for connection state
var cs = GlobalConnectionState.detached;
var checkPublicInternet = false;
switch (updateAttachment.state) {
case AttachmentState.detached:
cs = GlobalConnectionState.detached;
break;
case AttachmentState.detaching:
cs = GlobalConnectionState.detaching;
break;
case AttachmentState.attaching:
cs = GlobalConnectionState.attaching;
break;
case AttachmentState.attachedWeak:
checkPublicInternet = true;
cs = GlobalConnectionState.attachedWeak;
break;
case AttachmentState.attachedGood:
checkPublicInternet = true;
cs = GlobalConnectionState.attachedGood;
break;
case AttachmentState.attachedStrong:
checkPublicInternet = true;
cs = GlobalConnectionState.attachedStrong;
break;
case AttachmentState.fullyAttached:
checkPublicInternet = true;
cs = GlobalConnectionState.fullyAttached;
break;
case AttachmentState.overAttached:
checkPublicInternet = true;
cs = GlobalConnectionState.overAttached;
break;
}
if (checkPublicInternet) {
if (!updateAttachment.publicInternetReady) {
cs = GlobalConnectionState.attaching;
}
}
globalConnectionState.state = cs; connectionState.state = ConnectionState(
attachment: VeilidStateAttachment(
state: updateAttachment.state,
publicInternetReady: updateAttachment.publicInternetReady,
localNetworkReady: updateAttachment.localNetworkReady));
} }
Future<void> processUpdateConfig(VeilidUpdateConfig updateConfig) async { Future<void> processUpdateConfig(VeilidUpdateConfig updateConfig) async {
//loggy.info("Config: ${updateConfig.json}"); //loggy.info("Config: ${updateConfig.json}");
// xxx: store in flutterflow local state? do we need this for anything?
} }
Future<void> processUpdateNetwork(VeilidUpdateNetwork updateNetwork) async { Future<void> processUpdateNetwork(VeilidUpdateNetwork updateNetwork) async {
//loggy.info("Network: ${updateNetwork.json}"); //loggy.info("Network: ${updateNetwork.json}");
// xxx: store in flutterflow local state? do we need this for anything?
} }
Future<void> processUpdates() async { Future<void> processUpdates() async {

View File

@ -64,6 +64,7 @@ Future<AccountInfo> fetchAccount(FetchAccountRef ref,
.scope((accountRec) => accountRec.getProtobuf(proto.Account.fromBuffer)); .scope((accountRec) => accountRec.getProtobuf(proto.Account.fromBuffer));
if (account == null) { if (account == null) {
// Account could not be read or decrypted from DHT // Account could not be read or decrypted from DHT
ref.invalidateSelf();
return AccountInfo( return AccountInfo(
status: AccountInfoStatus.accountInvalid, active: active); status: AccountInfoStatus.accountInvalid, active: active);
} }
@ -119,7 +120,7 @@ Future<ActiveAccountInfo?> fetchActiveAccount(FetchActiveAccountRef ref) async {
parent: localAccount.identityMaster.identityRecordKey)) parent: localAccount.identityMaster.identityRecordKey))
.scope((accountRec) => accountRec.getProtobuf(proto.Account.fromBuffer)); .scope((accountRec) => accountRec.getProtobuf(proto.Account.fromBuffer));
if (account == null) { if (account == null) {
// Account could not be read or decrypted from DHT ref.invalidateSelf();
return null; return null;
} }

View File

@ -6,7 +6,7 @@ part of 'account.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
String _$fetchAccountHash() => r'88dadc0d005cef8b3df1d03088c8a5da728c333c'; String _$fetchAccountHash() => r'f3072fdd89611b53cd9821613acab450b3c08820';
/// Copied from Dart SDK /// Copied from Dart SDK
class _SystemHash { class _SystemHash {
@ -176,7 +176,7 @@ class _FetchAccountProviderElement
} }
String _$fetchActiveAccountHash() => String _$fetchActiveAccountHash() =>
r'd074ab2c160bab41ed3dd979b7054603b7d5b2b1'; r'197e5dd793563ff1d9927309a5ec9db1c9f67f07';
/// Get the active account info /// Get the active account info
/// ///

View File

@ -1,18 +1,29 @@
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
enum GlobalConnectionState { import '../veilid_support/veilid_support.dart';
detached,
detaching, part 'connection_state.freezed.dart';
attaching,
attachedWeak, @freezed
attachedGood, class ConnectionState with _$ConnectionState {
attachedStrong, const factory ConnectionState({
fullyAttached, required VeilidStateAttachment attachment,
overAttached, }) = _ConnectionState;
const ConnectionState._();
bool get isAttached => !(attachment.state == AttachmentState.detached ||
attachment.state == AttachmentState.detaching ||
attachment.state == AttachmentState.attaching);
bool get isPublicInternetReady => attachment.publicInternetReady;
} }
final globalConnectionState = final connectionState = StateController<ConnectionState>(const ConnectionState(
StateController<GlobalConnectionState>(GlobalConnectionState.detached); attachment: VeilidStateAttachment(
final globalConnectionStateProvider = StateNotifierProvider< state: AttachmentState.detached,
StateController<GlobalConnectionState>, publicInternetReady: false,
GlobalConnectionState>((ref) => globalConnectionState); localNetworkReady: false)));
final connectionStateProvider =
StateNotifierProvider<StateController<ConnectionState>, ConnectionState>(
(ref) => connectionState);

View File

@ -536,6 +536,8 @@ Future<IList<ContactInvitationRecord>?> fetchContactInvitationRecords(
// Decode the contact invitation list from the DHT // Decode the contact invitation list from the DHT
IList<ContactInvitationRecord> out = const IListConst([]); IList<ContactInvitationRecord> out = const IListConst([]);
try {
await (await DHTShortArray.openOwned( await (await DHTShortArray.openOwned(
proto.OwnedDHTRecordPointerProto.fromProto( proto.OwnedDHTRecordPointerProto.fromProto(
activeAccountInfo.account.contactInvitationRecords), activeAccountInfo.account.contactInvitationRecords),
@ -549,6 +551,15 @@ Future<IList<ContactInvitationRecord>?> fetchContactInvitationRecords(
out = out.add(ContactInvitationRecord.fromBuffer(cir)); out = out.add(ContactInvitationRecord.fromBuffer(cir));
} }
}); });
} on VeilidAPIExceptionTryAgain catch (_) {
// Try again later
ref.invalidateSelf();
return null;
} on Exception catch (_) {
// Try again later
ref.invalidateSelf();
rethrow;
}
return out; return out;
} }

View File

@ -7,7 +7,7 @@ part of 'contact_invite.dart';
// ************************************************************************** // **************************************************************************
String _$fetchContactInvitationRecordsHash() => String _$fetchContactInvitationRecordsHash() =>
r'2fe40d7aaf5fa856f00c6d2b4d9e28f4a08bed1b'; r'365d563c5e66f45679f597502ea9e4b8296ff8af';
/// Get the active account contact invitation list /// Get the active account contact invitation list
/// ///

View File

@ -17,7 +17,7 @@ enum OrientationCapability {
landscapeOnly, landscapeOnly,
} }
// Local account manager // Window Control
@riverpod @riverpod
class WindowControl extends _$WindowControl { class WindowControl extends _$WindowControl {
/// Change window control /// Change window control

View File

@ -9,6 +9,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'proto/proto.dart' as proto; import 'proto/proto.dart' as proto;
import 'providers/account.dart'; import 'providers/account.dart';
import 'providers/chat.dart'; import 'providers/chat.dart';
import 'providers/connection_state.dart';
import 'providers/contact.dart'; import 'providers/contact.dart';
import 'providers/contact_invite.dart'; import 'providers/contact_invite.dart';
import 'providers/conversation.dart'; import 'providers/conversation.dart';
@ -65,10 +66,13 @@ class BackgroundTickerState extends ConsumerState<BackgroundTicker> {
} }
Future<void> _onTick() async { Future<void> _onTick() async {
// Don't tick until veilid is started // Don't tick until veilid is started and attached
if (!eventualVeilid.isCompleted) { if (!eventualVeilid.isCompleted) {
return; return;
} }
if (!connectionState.state.isAttached) {
return;
}
_inTick = true; _inTick = true;
try { try {
@ -95,10 +99,16 @@ class BackgroundTickerState extends ConsumerState<BackgroundTicker> {
} }
Future<void> _doContactInvitationCheck() async { Future<void> _doContactInvitationCheck() async {
if (!connectionState.state.isPublicInternetReady) {
return;
}
final contactInvitationRecords = final contactInvitationRecords =
await ref.read(fetchContactInvitationRecordsProvider.future); await ref.read(fetchContactInvitationRecordsProvider.future);
if (contactInvitationRecords == null) {
return;
}
final activeAccountInfo = await ref.read(fetchActiveAccountProvider.future); final activeAccountInfo = await ref.read(fetchActiveAccountProvider.future);
if (contactInvitationRecords == null || activeAccountInfo == null) { if (activeAccountInfo == null) {
return; return;
} }
@ -135,6 +145,9 @@ class BackgroundTickerState extends ConsumerState<BackgroundTicker> {
} }
Future<void> _doNewMessageCheck() async { Future<void> _doNewMessageCheck() async {
if (!connectionState.state.isPublicInternetReady) {
return;
}
final activeChat = ref.read(activeChatStateProvider); final activeChat = ref.read(activeChatStateProvider);
if (activeChat == null) { if (activeChat == null) {
return; return;

View File

@ -117,7 +117,7 @@ class DHTShortArray {
parent: parent, routingContext: routingContext, crypto: crypto); parent: parent, routingContext: routingContext, crypto: crypto);
try { try {
final dhtShortArray = DHTShortArray._(headRecord: dhtRecord); final dhtShortArray = DHTShortArray._(headRecord: dhtRecord);
await dhtShortArray._refreshHead(forceRefresh: true); await dhtShortArray._refreshHead();
return dhtShortArray; return dhtShortArray;
} on Exception catch (_) { } on Exception catch (_) {
await dhtRecord.close(); await dhtRecord.close();
@ -137,7 +137,7 @@ class DHTShortArray {
parent: parent, routingContext: routingContext, crypto: crypto); parent: parent, routingContext: routingContext, crypto: crypto);
try { try {
final dhtShortArray = DHTShortArray._(headRecord: dhtRecord); final dhtShortArray = DHTShortArray._(headRecord: dhtRecord);
await dhtShortArray._refreshHead(forceRefresh: true); await dhtShortArray._refreshHead();
return dhtShortArray; return dhtShortArray;
} on Exception catch (_) { } on Exception catch (_) {
await dhtRecord.close(); await dhtRecord.close();

View File

@ -26,8 +26,7 @@
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
436AD2FE296F594700C56F41 /* libveilid_flutter.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 436AD2FD296F594700C56F41 /* libveilid_flutter.dylib */; settings = {ATTRIBUTES = (Weak, ); }; }; 4376861A2AE2BC81008CB542 /* libveilid_flutter.dylib in Bundle Framework */ = {isa = PBXBuildFile; fileRef = 437686192AE2BC81008CB542 /* libveilid_flutter.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
436AD2FF296F596F00C56F41 /* libveilid_flutter.dylib in Bundle Framework */ = {isa = PBXBuildFile; fileRef = 436AD2FD296F594700C56F41 /* libveilid_flutter.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
88D9990A2A4DDB76FC4A6A85 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 330475447B6E6E81B8D4BB24 /* Pods_Runner.framework */; }; 88D9990A2A4DDB76FC4A6A85 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 330475447B6E6E81B8D4BB24 /* Pods_Runner.framework */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
@ -44,11 +43,11 @@
/* Begin PBXCopyFilesBuildPhase section */ /* Begin PBXCopyFilesBuildPhase section */
33CC110E2044A8840003C045 /* Bundle Framework */ = { 33CC110E2044A8840003C045 /* Bundle Framework */ = {
isa = PBXCopyFilesBuildPhase; isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 12;
dstPath = ""; dstPath = "";
dstSubfolderSpec = 10; dstSubfolderSpec = 10;
files = ( files = (
436AD2FF296F596F00C56F41 /* libveilid_flutter.dylib in Bundle Framework */, 4376861A2AE2BC81008CB542 /* libveilid_flutter.dylib in Bundle Framework */,
); );
name = "Bundle Framework"; name = "Bundle Framework";
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@ -71,7 +70,7 @@
33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; }; 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; };
33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; }; 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; }; 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
436AD2FD296F594700C56F41 /* libveilid_flutter.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libveilid_flutter.dylib; path = "../../veilid/target/lipo-darwin/libveilid_flutter.dylib"; sourceTree = "<group>"; }; 437686192AE2BC81008CB542 /* libveilid_flutter.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libveilid_flutter.dylib; path = "../../veilid/target/lipo-darwin/libveilid_flutter.dylib"; sourceTree = "<group>"; };
52C7C81B1B7DA140873DBED2 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; }; 52C7C81B1B7DA140873DBED2 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
@ -84,7 +83,6 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
436AD2FE296F594700C56F41 /* libveilid_flutter.dylib in Frameworks */,
88D9990A2A4DDB76FC4A6A85 /* Pods_Runner.framework in Frameworks */, 88D9990A2A4DDB76FC4A6A85 /* Pods_Runner.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@ -106,6 +104,7 @@
33CC10E42044A3C60003C045 = { 33CC10E42044A3C60003C045 = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
437686192AE2BC81008CB542 /* libveilid_flutter.dylib */,
33FAB671232836740065AC1E /* Runner */, 33FAB671232836740065AC1E /* Runner */,
33CEB47122A05771004F2AC0 /* Flutter */, 33CEB47122A05771004F2AC0 /* Flutter */,
33CC10EE2044A3C60003C045 /* Products */, 33CC10EE2044A3C60003C045 /* Products */,
@ -170,7 +169,6 @@
D73912EC22F37F3D000D13A0 /* Frameworks */ = { D73912EC22F37F3D000D13A0 /* Frameworks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
436AD2FD296F594700C56F41 /* libveilid_flutter.dylib */,
330475447B6E6E81B8D4BB24 /* Pods_Runner.framework */, 330475447B6E6E81B8D4BB24 /* Pods_Runner.framework */,
); );
name = Frameworks; name = Frameworks;

View File

@ -487,7 +487,7 @@ packages:
source: hosted source: hosted
version: "3.3.1" version: "3.3.1"
flutter_chat_types: flutter_chat_types:
dependency: transitive dependency: "direct main"
description: description:
name: flutter_chat_types name: flutter_chat_types
sha256: e285b588f6d19d907feb1f6d912deaf22e223656769c34093b64e1c59b094fb9 sha256: e285b588f6d19d907feb1f6d912deaf22e223656769c34093b64e1c59b094fb9
@ -1552,7 +1552,7 @@ packages:
path: "../veilid/veilid-flutter" path: "../veilid/veilid-flutter"
relative: true relative: true
source: path source: path
version: "0.2.3" version: "0.2.4"
visibility_detector: visibility_detector:
dependency: transitive dependency: transitive
description: description:

View File

@ -27,6 +27,7 @@ dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
flutter_animate: ^4.2.0+1 flutter_animate: ^4.2.0+1
flutter_chat_types: ^3.6.2
flutter_chat_ui: ^1.6.9 flutter_chat_ui: ^1.6.9
flutter_form_builder: ^9.1.0 flutter_form_builder: ^9.1.0
flutter_hooks: ^0.20.1 flutter_hooks: ^0.20.1