mirror of
https://gitlab.com/veilid/veilidchat.git
synced 2024-10-01 06:55:46 -04:00
xfer
This commit is contained in:
parent
08dab73757
commit
c08878b35a
98
assets/images/icon.svg
Normal file
98
assets/images/icon.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 38 KiB |
129
assets/images/splash.svg
Normal file
129
assets/images/splash.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 41 KiB |
41
assets/images/title.svg
Normal file
41
assets/images/title.svg
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg width="100%" height="100%" viewBox="0 0 1003 187" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||||
|
<g transform="matrix(1,0,0,0.352497,-60.1919,-339.48)">
|
||||||
|
<rect id="Artboard1" x="60.192" y="963.071" width="1002.92" height="528.331" style="fill:none;"/>
|
||||||
|
<g id="Artboard11" serif:id="Artboard1">
|
||||||
|
<g transform="matrix(12.4032,0,0,35.1866,98.2148,1359.83)">
|
||||||
|
<g transform="matrix(7.73995,0,0,7.73995,0,-8.88178e-16)">
|
||||||
|
<path d="M0.375,-0L0,-0.375L0,-1L0.25,-1L0.25,-0.5L0.5,-0.25L0.75,-0.5L0.75,-1L1,-1L1,-0.375L0.625,-0L0.375,-0Z" style="fill:rgb(242,89,201);fill-rule:nonzero;"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(7.73995,0,0,7.73995,8.51093,-8.88178e-16)">
|
||||||
|
<path d="M0,-0L0,-1L1,-1L1,-0.75L0.25,-0.75L0.25,-0.625L1,-0.625L1,-0.375L0.25,-0.375L0.25,-0.25L1,-0.25L1,-0L0,-0Z" style="fill:rgb(242,89,201);fill-rule:nonzero;"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(7.73995,0,0,7.73995,17.0219,-8.88178e-16)">
|
||||||
|
<rect x="0" y="-1" width="0.25" height="1" style="fill:rgb(242,89,201);fill-rule:nonzero;"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(7.73995,0,0,7.73995,19.7278,-8.88178e-16)">
|
||||||
|
<path d="M0,-0L0,-1L0.25,-1L0.25,-0.25L1,-0.25L1,-0L0,-0Z" style="fill:rgb(242,89,201);fill-rule:nonzero;"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(7.73995,0,0,7.73995,28.2387,-8.88178e-16)">
|
||||||
|
<rect x="0" y="-1" width="0.25" height="1" style="fill:rgb(242,89,201);fill-rule:nonzero;"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(7.73995,0,0,7.73995,30.9447,-8.88178e-16)">
|
||||||
|
<path d="M0.688,-0.25L0.75,-0.313L0.75,-0.688L0.688,-0.75L0.25,-0.75L0.25,-0.25L0.688,-0.25ZM0,-0L0,-1L0.875,-1L1,-0.875L1,-0.125L0.875,-0L0,-0Z" style="fill:rgb(242,89,201);fill-rule:nonzero;"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(7.73995,0,0,7.73995,39.4556,-8.88178e-16)">
|
||||||
|
<path d="M0,-0L0,-1L1,-1L1,-0.75L0.25,-0.75L0.25,-0.25L1,-0.25L1,-0L0,-0Z" style="fill:rgb(58,162,232);fill-rule:nonzero;"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(7.73995,0,0,7.73995,47.9665,-8.88178e-16)">
|
||||||
|
<path d="M0,-0L0,-1L0.25,-1L0.25,-0.625L0.75,-0.625L0.75,-1L1,-1L1,-0L0.75,-0L0.75,-0.375L0.25,-0.375L0.25,-0L0,-0Z" style="fill:rgb(58,162,232);fill-rule:nonzero;"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(7.73995,0,0,7.73995,56.4775,-8.88178e-16)">
|
||||||
|
<path d="M0.75,-0.625L0.75,-0.75L0.25,-0.75L0.25,-0.625L0.75,-0.625ZM0,-0L0,-1L1,-1L1,-0L0.75,-0L0.75,-0.375L0.25,-0.375L0.25,-0L0,-0Z" style="fill:rgb(58,162,232);fill-rule:nonzero;"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(7.73995,0,0,7.73995,64.9884,-8.88178e-16)">
|
||||||
|
<path d="M0.375,-0L0.375,-0.75L0,-0.75L0,-1L1,-1L1,-0.75L0.625,-0.75L0.625,-0L0.375,-0Z" style="fill:rgb(58,162,232);fill-rule:nonzero;"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.4 KiB |
BIN
assets/sources/Pointless.ttf
Normal file
BIN
assets/sources/Pointless.ttf
Normal file
Binary file not shown.
BIN
assets/sources/icon.afdesign
Normal file
BIN
assets/sources/icon.afdesign
Normal file
Binary file not shown.
BIN
assets/sources/splash.afdesign
Normal file
BIN
assets/sources/splash.afdesign
Normal file
Binary file not shown.
BIN
assets/sources/title.afdesign
Normal file
BIN
assets/sources/title.afdesign
Normal file
Binary file not shown.
@ -3,7 +3,7 @@
|
|||||||
archiveVersion = 1;
|
archiveVersion = 1;
|
||||||
classes = {
|
classes = {
|
||||||
};
|
};
|
||||||
objectVersion = 50;
|
objectVersion = 51;
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
@ -121,7 +121,6 @@
|
|||||||
66884EE8E4C818DD7F73E828 /* Pods-Runner.release.xcconfig */,
|
66884EE8E4C818DD7F73E828 /* Pods-Runner.release.xcconfig */,
|
||||||
DC6D2E60CBCA1AC9F82D654F /* Pods-Runner.profile.xcconfig */,
|
DC6D2E60CBCA1AC9F82D654F /* Pods-Runner.profile.xcconfig */,
|
||||||
);
|
);
|
||||||
name = Pods;
|
|
||||||
path = Pods;
|
path = Pods;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
@ -355,15 +354,16 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
DEVELOPMENT_TEAM = XP5LBLT7M7;
|
||||||
DEVELOPMENT_TEAM = ZJPQSFX5MW;
|
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = VeilidChat;
|
||||||
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.vekoni.veilidchat.veilidchat;
|
PRODUCT_BUNDLE_IDENTIFIER = com.veilid.veilidchat;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
@ -484,15 +484,16 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
DEVELOPMENT_TEAM = XP5LBLT7M7;
|
||||||
DEVELOPMENT_TEAM = ZJPQSFX5MW;
|
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = VeilidChat;
|
||||||
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.vekoni.veilidchat.veilidchat;
|
PRODUCT_BUNDLE_IDENTIFIER = com.veilid.veilidchat;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
@ -507,15 +508,16 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
DEVELOPMENT_TEAM = XP5LBLT7M7;
|
||||||
DEVELOPMENT_TEAM = ZJPQSFX5MW;
|
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = VeilidChat;
|
||||||
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.vekoni.veilidchat.veilidchat;
|
PRODUCT_BUNDLE_IDENTIFIER = com.veilid.veilidchat;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
|
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||||
|
<true/>
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
<key>CFBundleDisplayName</key>
|
<key>CFBundleDisplayName</key>
|
||||||
@ -24,6 +26,8 @@
|
|||||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||||
|
<true/>
|
||||||
<key>UILaunchStoryboardName</key>
|
<key>UILaunchStoryboardName</key>
|
||||||
<string>LaunchScreen</string>
|
<string>LaunchScreen</string>
|
||||||
<key>UIMainStoryboardFile</key>
|
<key>UIMainStoryboardFile</key>
|
||||||
@ -43,9 +47,5 @@
|
|||||||
</array>
|
</array>
|
||||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||||
<false/>
|
<false/>
|
||||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
|
||||||
<true/>
|
|
||||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
@ -25,6 +25,7 @@ class VeilidChatApp extends ConsumerWidget {
|
|||||||
return LocalizationProvider(
|
return LocalizationProvider(
|
||||||
state: LocalizationProvider.of(context).state,
|
state: LocalizationProvider.of(context).state,
|
||||||
child: MaterialApp.router(
|
child: MaterialApp.router(
|
||||||
|
debugShowCheckedModeBanner: false,
|
||||||
routerConfig: router,
|
routerConfig: router,
|
||||||
title: 'VeilidChat',
|
title: 'VeilidChat',
|
||||||
theme: theme,
|
theme: theme,
|
||||||
|
63
lib/components/account_bubble.dart
Normal file
63
lib/components/account_bubble.dart
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:window_manager/window_manager.dart';
|
||||||
|
import 'package:user_profile_avatar/user_profile_avatar.dart';
|
||||||
|
|
||||||
|
import '../providers/local_accounts.dart';
|
||||||
|
import '../providers/logins.dart';
|
||||||
|
|
||||||
|
class AccountBubble extends ConsumerWidget {
|
||||||
|
const AccountBubble({super.key});
|
||||||
|
|
||||||
|
void _onReorder(WidgetRef ref, int oldIndex, int newIndex) {
|
||||||
|
final accounts = ref.read(localAccountsProvider.notifier);
|
||||||
|
accounts.reorderAccount(oldIndex, newIndex);
|
||||||
|
// xxx fix this so we can await this properly, use FutureBuilder or whatever
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
windowManager.setTitleBarStyle(TitleBarStyle.normal);
|
||||||
|
final accounts = ref.watch(localAccountsProvider);
|
||||||
|
final logins = ref.watch(loginsProvider);
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
centerTitle: true,
|
||||||
|
title: const Text('Accounts'),
|
||||||
|
actions: <Widget>[
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Icons.settings),
|
||||||
|
tooltip: 'Accessibility',
|
||||||
|
onPressed: () {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
||||||
|
content:
|
||||||
|
Text('Accessibility and language options coming soon')));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
body: Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
const Spacer(),
|
||||||
|
accounts.when(
|
||||||
|
error: (obj, err) => Text("error loading accounts: $err"),
|
||||||
|
loading: () => CircularProgressIndicator(),
|
||||||
|
data: (accountList) => ReorderableGridView.extent(
|
||||||
|
maxCrossAxisExtent: 128,
|
||||||
|
onReorder: (oldIndex, newIndex) =>
|
||||||
|
_onReorder(ref, oldIndex, newIndex),
|
||||||
|
children: accountList.map((account) {
|
||||||
|
return AccountBubble(account);
|
||||||
|
}),
|
||||||
|
)),
|
||||||
|
const Spacer(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -12,9 +12,9 @@ part 'user_login.g.dart';
|
|||||||
class UserLogin with _$UserLogin {
|
class UserLogin with _$UserLogin {
|
||||||
const factory UserLogin({
|
const factory UserLogin({
|
||||||
// Master record key for the user used to index the local accounts table
|
// Master record key for the user used to index the local accounts table
|
||||||
required TypedKey accountMasterKey,
|
required TypedKey accountMasterRecordKey,
|
||||||
// The identity secret as unlocked from the local accounts table
|
// The identity secret as unlocked from the local accounts table
|
||||||
required TypedSecret secretKey,
|
required TypedSecret identitySecret,
|
||||||
// The time this login was most recently used
|
// The time this login was most recently used
|
||||||
required Timestamp lastActive,
|
required Timestamp lastActive,
|
||||||
}) = _UserLogin;
|
}) = _UserLogin;
|
||||||
|
@ -21,9 +21,9 @@ UserLogin _$UserLoginFromJson(Map<String, dynamic> json) {
|
|||||||
/// @nodoc
|
/// @nodoc
|
||||||
mixin _$UserLogin {
|
mixin _$UserLogin {
|
||||||
// Master record key for the user used to index the local accounts table
|
// Master record key for the user used to index the local accounts table
|
||||||
Typed<FixedEncodedString43> get accountMasterKey =>
|
Typed<FixedEncodedString43> get accountMasterRecordKey =>
|
||||||
throw _privateConstructorUsedError; // The identity secret as unlocked from the local accounts table
|
throw _privateConstructorUsedError; // The identity secret as unlocked from the local accounts table
|
||||||
Typed<FixedEncodedString43> get secretKey =>
|
Typed<FixedEncodedString43> get identitySecret =>
|
||||||
throw _privateConstructorUsedError; // The time this login was most recently used
|
throw _privateConstructorUsedError; // The time this login was most recently used
|
||||||
Timestamp get lastActive => throw _privateConstructorUsedError;
|
Timestamp get lastActive => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
@ -39,8 +39,8 @@ abstract class $UserLoginCopyWith<$Res> {
|
|||||||
_$UserLoginCopyWithImpl<$Res, UserLogin>;
|
_$UserLoginCopyWithImpl<$Res, UserLogin>;
|
||||||
@useResult
|
@useResult
|
||||||
$Res call(
|
$Res call(
|
||||||
{Typed<FixedEncodedString43> accountMasterKey,
|
{Typed<FixedEncodedString43> accountMasterRecordKey,
|
||||||
Typed<FixedEncodedString43> secretKey,
|
Typed<FixedEncodedString43> identitySecret,
|
||||||
Timestamp lastActive});
|
Timestamp lastActive});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,18 +57,18 @@ class _$UserLoginCopyWithImpl<$Res, $Val extends UserLogin>
|
|||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
Object? accountMasterKey = null,
|
Object? accountMasterRecordKey = null,
|
||||||
Object? secretKey = null,
|
Object? identitySecret = null,
|
||||||
Object? lastActive = null,
|
Object? lastActive = null,
|
||||||
}) {
|
}) {
|
||||||
return _then(_value.copyWith(
|
return _then(_value.copyWith(
|
||||||
accountMasterKey: null == accountMasterKey
|
accountMasterRecordKey: null == accountMasterRecordKey
|
||||||
? _value.accountMasterKey
|
? _value.accountMasterRecordKey
|
||||||
: accountMasterKey // ignore: cast_nullable_to_non_nullable
|
: accountMasterRecordKey // ignore: cast_nullable_to_non_nullable
|
||||||
as Typed<FixedEncodedString43>,
|
as Typed<FixedEncodedString43>,
|
||||||
secretKey: null == secretKey
|
identitySecret: null == identitySecret
|
||||||
? _value.secretKey
|
? _value.identitySecret
|
||||||
: secretKey // ignore: cast_nullable_to_non_nullable
|
: identitySecret // ignore: cast_nullable_to_non_nullable
|
||||||
as Typed<FixedEncodedString43>,
|
as Typed<FixedEncodedString43>,
|
||||||
lastActive: null == lastActive
|
lastActive: null == lastActive
|
||||||
? _value.lastActive
|
? _value.lastActive
|
||||||
@ -86,8 +86,8 @@ abstract class _$$_UserLoginCopyWith<$Res> implements $UserLoginCopyWith<$Res> {
|
|||||||
@override
|
@override
|
||||||
@useResult
|
@useResult
|
||||||
$Res call(
|
$Res call(
|
||||||
{Typed<FixedEncodedString43> accountMasterKey,
|
{Typed<FixedEncodedString43> accountMasterRecordKey,
|
||||||
Typed<FixedEncodedString43> secretKey,
|
Typed<FixedEncodedString43> identitySecret,
|
||||||
Timestamp lastActive});
|
Timestamp lastActive});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,18 +102,18 @@ class __$$_UserLoginCopyWithImpl<$Res>
|
|||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
Object? accountMasterKey = null,
|
Object? accountMasterRecordKey = null,
|
||||||
Object? secretKey = null,
|
Object? identitySecret = null,
|
||||||
Object? lastActive = null,
|
Object? lastActive = null,
|
||||||
}) {
|
}) {
|
||||||
return _then(_$_UserLogin(
|
return _then(_$_UserLogin(
|
||||||
accountMasterKey: null == accountMasterKey
|
accountMasterRecordKey: null == accountMasterRecordKey
|
||||||
? _value.accountMasterKey
|
? _value.accountMasterRecordKey
|
||||||
: accountMasterKey // ignore: cast_nullable_to_non_nullable
|
: accountMasterRecordKey // ignore: cast_nullable_to_non_nullable
|
||||||
as Typed<FixedEncodedString43>,
|
as Typed<FixedEncodedString43>,
|
||||||
secretKey: null == secretKey
|
identitySecret: null == identitySecret
|
||||||
? _value.secretKey
|
? _value.identitySecret
|
||||||
: secretKey // ignore: cast_nullable_to_non_nullable
|
: identitySecret // ignore: cast_nullable_to_non_nullable
|
||||||
as Typed<FixedEncodedString43>,
|
as Typed<FixedEncodedString43>,
|
||||||
lastActive: null == lastActive
|
lastActive: null == lastActive
|
||||||
? _value.lastActive
|
? _value.lastActive
|
||||||
@ -127,8 +127,8 @@ class __$$_UserLoginCopyWithImpl<$Res>
|
|||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
class _$_UserLogin implements _UserLogin {
|
class _$_UserLogin implements _UserLogin {
|
||||||
const _$_UserLogin(
|
const _$_UserLogin(
|
||||||
{required this.accountMasterKey,
|
{required this.accountMasterRecordKey,
|
||||||
required this.secretKey,
|
required this.identitySecret,
|
||||||
required this.lastActive});
|
required this.lastActive});
|
||||||
|
|
||||||
factory _$_UserLogin.fromJson(Map<String, dynamic> json) =>
|
factory _$_UserLogin.fromJson(Map<String, dynamic> json) =>
|
||||||
@ -136,17 +136,17 @@ class _$_UserLogin implements _UserLogin {
|
|||||||
|
|
||||||
// Master record key for the user used to index the local accounts table
|
// Master record key for the user used to index the local accounts table
|
||||||
@override
|
@override
|
||||||
final Typed<FixedEncodedString43> accountMasterKey;
|
final Typed<FixedEncodedString43> accountMasterRecordKey;
|
||||||
// The identity secret as unlocked from the local accounts table
|
// The identity secret as unlocked from the local accounts table
|
||||||
@override
|
@override
|
||||||
final Typed<FixedEncodedString43> secretKey;
|
final Typed<FixedEncodedString43> identitySecret;
|
||||||
// The time this login was most recently used
|
// The time this login was most recently used
|
||||||
@override
|
@override
|
||||||
final Timestamp lastActive;
|
final Timestamp lastActive;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'UserLogin(accountMasterKey: $accountMasterKey, secretKey: $secretKey, lastActive: $lastActive)';
|
return 'UserLogin(accountMasterRecordKey: $accountMasterRecordKey, identitySecret: $identitySecret, lastActive: $lastActive)';
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -154,18 +154,18 @@ class _$_UserLogin implements _UserLogin {
|
|||||||
return identical(this, other) ||
|
return identical(this, other) ||
|
||||||
(other.runtimeType == runtimeType &&
|
(other.runtimeType == runtimeType &&
|
||||||
other is _$_UserLogin &&
|
other is _$_UserLogin &&
|
||||||
(identical(other.accountMasterKey, accountMasterKey) ||
|
(identical(other.accountMasterRecordKey, accountMasterRecordKey) ||
|
||||||
other.accountMasterKey == accountMasterKey) &&
|
other.accountMasterRecordKey == accountMasterRecordKey) &&
|
||||||
(identical(other.secretKey, secretKey) ||
|
(identical(other.identitySecret, identitySecret) ||
|
||||||
other.secretKey == secretKey) &&
|
other.identitySecret == identitySecret) &&
|
||||||
(identical(other.lastActive, lastActive) ||
|
(identical(other.lastActive, lastActive) ||
|
||||||
other.lastActive == lastActive));
|
other.lastActive == lastActive));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
@override
|
@override
|
||||||
int get hashCode =>
|
int get hashCode => Object.hash(
|
||||||
Object.hash(runtimeType, accountMasterKey, secretKey, lastActive);
|
runtimeType, accountMasterRecordKey, identitySecret, lastActive);
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
@override
|
@override
|
||||||
@ -183,17 +183,17 @@ class _$_UserLogin implements _UserLogin {
|
|||||||
|
|
||||||
abstract class _UserLogin implements UserLogin {
|
abstract class _UserLogin implements UserLogin {
|
||||||
const factory _UserLogin(
|
const factory _UserLogin(
|
||||||
{required final Typed<FixedEncodedString43> accountMasterKey,
|
{required final Typed<FixedEncodedString43> accountMasterRecordKey,
|
||||||
required final Typed<FixedEncodedString43> secretKey,
|
required final Typed<FixedEncodedString43> identitySecret,
|
||||||
required final Timestamp lastActive}) = _$_UserLogin;
|
required final Timestamp lastActive}) = _$_UserLogin;
|
||||||
|
|
||||||
factory _UserLogin.fromJson(Map<String, dynamic> json) =
|
factory _UserLogin.fromJson(Map<String, dynamic> json) =
|
||||||
_$_UserLogin.fromJson;
|
_$_UserLogin.fromJson;
|
||||||
|
|
||||||
@override // Master record key for the user used to index the local accounts table
|
@override // Master record key for the user used to index the local accounts table
|
||||||
Typed<FixedEncodedString43> get accountMasterKey;
|
Typed<FixedEncodedString43> get accountMasterRecordKey;
|
||||||
@override // The identity secret as unlocked from the local accounts table
|
@override // The identity secret as unlocked from the local accounts table
|
||||||
Typed<FixedEncodedString43> get secretKey;
|
Typed<FixedEncodedString43> get identitySecret;
|
||||||
@override // The time this login was most recently used
|
@override // The time this login was most recently used
|
||||||
Timestamp get lastActive;
|
Timestamp get lastActive;
|
||||||
@override
|
@override
|
||||||
|
@ -7,16 +7,17 @@ part of 'user_login.dart';
|
|||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
_$_UserLogin _$$_UserLoginFromJson(Map<String, dynamic> json) => _$_UserLogin(
|
_$_UserLogin _$$_UserLoginFromJson(Map<String, dynamic> json) => _$_UserLogin(
|
||||||
accountMasterKey:
|
accountMasterRecordKey: Typed<FixedEncodedString43>.fromJson(
|
||||||
Typed<FixedEncodedString43>.fromJson(json['account_master_key']),
|
json['account_master_record_key']),
|
||||||
secretKey: Typed<FixedEncodedString43>.fromJson(json['secret_key']),
|
identitySecret:
|
||||||
|
Typed<FixedEncodedString43>.fromJson(json['identity_secret']),
|
||||||
lastActive: Timestamp.fromJson(json['last_active']),
|
lastActive: Timestamp.fromJson(json['last_active']),
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$$_UserLoginToJson(_$_UserLogin instance) =>
|
Map<String, dynamic> _$$_UserLoginToJson(_$_UserLogin instance) =>
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
'account_master_key': instance.accountMasterKey.toJson(),
|
'account_master_record_key': instance.accountMasterRecordKey.toJson(),
|
||||||
'secret_key': instance.secretKey.toJson(),
|
'identity_secret': instance.identitySecret.toJson(),
|
||||||
'last_active': instance.lastActive.toJson(),
|
'last_active': instance.lastActive.toJson(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3,12 +3,14 @@ import 'dart:async';
|
|||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:flutter_translate/flutter_translate.dart';
|
||||||
|
import 'package:window_manager/window_manager.dart';
|
||||||
|
|
||||||
import 'log/log.dart';
|
import 'log/log.dart';
|
||||||
import 'veilid_support/veilid_support.dart';
|
import 'veilid_support/veilid_support.dart';
|
||||||
import 'theming/theming.dart';
|
import 'theming/theming.dart';
|
||||||
import 'app.dart';
|
import 'app.dart';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:flutter_translate/flutter_translate.dart';
|
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
// Disable all debugprints in release mode
|
// Disable all debugprints in release mode
|
||||||
@ -29,13 +31,30 @@ void main() async {
|
|||||||
final themeService = await ThemeService.instance;
|
final themeService = await ThemeService.instance;
|
||||||
var initTheme = themeService.initial;
|
var initTheme = themeService.initial;
|
||||||
|
|
||||||
// Start up Veilid and Veilid processor in the background
|
// Manage window on desktop platforms
|
||||||
unawaited(initializeVeilid());
|
if (Platform.isWindows || Platform.isLinux || Platform.isMacOS) {
|
||||||
|
await windowManager.ensureInitialized();
|
||||||
|
|
||||||
|
const windowOptions = WindowOptions(
|
||||||
|
size: Size(768, 1024),
|
||||||
|
center: true,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
skipTaskbar: false,
|
||||||
|
titleBarStyle: TitleBarStyle.hidden,
|
||||||
|
);
|
||||||
|
windowManager.waitUntilReadyToShow(windowOptions, () async {
|
||||||
|
await windowManager.show();
|
||||||
|
await windowManager.focus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Make localization delegate
|
// Make localization delegate
|
||||||
var delegate = await LocalizationDelegate.create(
|
var delegate = await LocalizationDelegate.create(
|
||||||
fallbackLocale: 'en_US', supportedLocales: ['en_US']);
|
fallbackLocale: 'en_US', supportedLocales: ['en_US']);
|
||||||
|
|
||||||
|
// Start up Veilid and Veilid processor in the background
|
||||||
|
unawaited(initializeVeilid());
|
||||||
|
|
||||||
// Run the app
|
// Run the app
|
||||||
// Hot reloads will only restart this part, not Veilid
|
// Hot reloads will only restart this part, not Veilid
|
||||||
runApp(ProviderScope(
|
runApp(ProviderScope(
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:radix_colors/radix_colors.dart';
|
||||||
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:window_manager/window_manager.dart';
|
||||||
|
|
||||||
class IndexPage extends StatelessWidget {
|
class IndexPage extends StatelessWidget {
|
||||||
const IndexPage({super.key});
|
const IndexPage({super.key});
|
||||||
@ -6,8 +9,34 @@ class IndexPage extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return const Scaffold(
|
windowManager.setTitleBarStyle(TitleBarStyle.hidden);
|
||||||
body: Center(child: Text("Index Page")),
|
return Scaffold(
|
||||||
);
|
body: DecoratedBox(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: LinearGradient(
|
||||||
|
begin: Alignment.topCenter,
|
||||||
|
end: Alignment.bottomCenter,
|
||||||
|
colors: <Color>[
|
||||||
|
RadixColors.dark.plum.step4,
|
||||||
|
RadixColors.dark.plum.step2,
|
||||||
|
])),
|
||||||
|
child: Center(
|
||||||
|
child: ConstrainedBox(
|
||||||
|
constraints: const BoxConstraints(maxHeight: 300),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 2,
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
"assets/images/icon.svg",
|
||||||
|
)),
|
||||||
|
Expanded(
|
||||||
|
flex: 1,
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
"assets/images/title.svg",
|
||||||
|
))
|
||||||
|
]))),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,30 +1,61 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import '../state/active_logins_state.dart';
|
import 'package:window_manager/window_manager.dart';
|
||||||
|
import 'package:reorderable_grid/reorderable_grid.dart';
|
||||||
|
|
||||||
|
import '../providers/local_accounts.dart';
|
||||||
|
import '../providers/logins.dart';
|
||||||
|
|
||||||
class LoginPage extends ConsumerWidget {
|
class LoginPage extends ConsumerWidget {
|
||||||
const LoginPage({super.key});
|
const LoginPage({super.key});
|
||||||
static const path = '/login';
|
static const path = '/login';
|
||||||
|
|
||||||
|
void _onReorder(WidgetRef ref, int oldIndex, int newIndex) {
|
||||||
|
final accounts = ref.read(localAccountsProvider.notifier);
|
||||||
|
accounts.reorderAccount(oldIndex, newIndex);
|
||||||
|
// xxx fix this so we can await this properly, use FutureBuilder or whatever
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
windowManager.setTitleBarStyle(TitleBarStyle.normal);
|
||||||
|
final accounts = ref.watch(localAccountsProvider);
|
||||||
|
final logins = ref.watch(loginsProvider);
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: null,
|
appBar: AppBar(
|
||||||
|
centerTitle: true,
|
||||||
|
title: const Text('Accounts'),
|
||||||
|
actions: <Widget>[
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Icons.settings),
|
||||||
|
tooltip: 'Accessibility',
|
||||||
|
onPressed: () {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
||||||
|
content:
|
||||||
|
Text('Accessibility and language options coming soon')));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
body: Center(
|
body: Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
const Text("Login Page"),
|
const Spacer(),
|
||||||
ElevatedButton(
|
accounts.when(
|
||||||
onPressed: () async {
|
error: (obj, err) => Text("error loading accounts: $err"),
|
||||||
await ref.watch(authNotifierProvider.notifier).login(
|
loading: () => CircularProgressIndicator(),
|
||||||
"myEmail",
|
data: (accountList) => ReorderableGridView.extent(
|
||||||
"myPassword",
|
maxCrossAxisExtent: 128,
|
||||||
);
|
onReorder: (oldIndex, newIndex) =>
|
||||||
},
|
_onReorder(ref, oldIndex, newIndex),
|
||||||
child: const Text("Login"),
|
children: accountList.map((account) {
|
||||||
),
|
return AccountBubble(account);
|
||||||
|
}),
|
||||||
|
)),
|
||||||
|
const Spacer(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -10,6 +10,7 @@ import '../tools/tools.dart';
|
|||||||
import '../veilid_support/veilid_support.dart';
|
import '../veilid_support/veilid_support.dart';
|
||||||
import '../entities/entities.dart';
|
import '../entities/entities.dart';
|
||||||
import '../entities/proto.dart' as proto;
|
import '../entities/proto.dart' as proto;
|
||||||
|
import 'logins.dart';
|
||||||
|
|
||||||
part 'local_accounts.g.dart';
|
part 'local_accounts.g.dart';
|
||||||
|
|
||||||
@ -38,58 +39,15 @@ class LocalAccounts extends _$LocalAccounts
|
|||||||
//////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////
|
||||||
/// Mutators and Selectors
|
/// Mutators and Selectors
|
||||||
|
|
||||||
/// Creates a new master identity and returns it with its secrets
|
/// Reorder accounts
|
||||||
Future<IdentityMasterWithSecrets> newIdentityMaster() async {
|
Future<void> reorderAccount(int oldIndex, int newIndex) async {
|
||||||
final crypto = await Veilid.instance.bestCryptoSystem();
|
final localAccounts = state.requireValue;
|
||||||
final dhtctx = (await Veilid.instance.routingContext())
|
var removedItem = Output<LocalAccount>();
|
||||||
.withPrivacy()
|
final updated = localAccounts
|
||||||
.withSequencing(Sequencing.ensureOrdered);
|
.removeAt(oldIndex, removedItem)
|
||||||
|
.insert(newIndex, removedItem.value!);
|
||||||
// IdentityMaster DHT record is public/unencrypted
|
await store(updated);
|
||||||
return (await DHTRecord.create(dhtctx,
|
state = AsyncValue.data(updated);
|
||||||
crypto: const DHTRecordCryptoPublic()))
|
|
||||||
.deleteScope((masterRec) async {
|
|
||||||
// Identity record is private
|
|
||||||
return (await DHTRecord.create(dhtctx)).deleteScope((identityRec) async {
|
|
||||||
// Make IdentityMaster
|
|
||||||
final masterRecordKey = masterRec.key();
|
|
||||||
final masterOwner = masterRec.ownerKeyPair()!;
|
|
||||||
final masterSigBuf = masterRecordKey.decode()
|
|
||||||
..addAll(masterOwner.key.decode());
|
|
||||||
|
|
||||||
final identityRecordKey = identityRec.key();
|
|
||||||
final identityOwner = identityRec.ownerKeyPair()!;
|
|
||||||
final identitySigBuf = identityRecordKey.decode()
|
|
||||||
..addAll(identityOwner.key.decode());
|
|
||||||
|
|
||||||
final identitySignature =
|
|
||||||
await crypto.signWithKeyPair(masterOwner, identitySigBuf);
|
|
||||||
final masterSignature =
|
|
||||||
await crypto.signWithKeyPair(identityOwner, masterSigBuf);
|
|
||||||
|
|
||||||
final identityMaster = IdentityMaster(
|
|
||||||
identityRecordKey: identityRecordKey,
|
|
||||||
identityPublicKey: identityOwner.key,
|
|
||||||
masterRecordKey: masterRecordKey,
|
|
||||||
masterPublicKey: masterOwner.key,
|
|
||||||
identitySignature: identitySignature,
|
|
||||||
masterSignature: masterSignature);
|
|
||||||
|
|
||||||
// Write identity master to master dht key
|
|
||||||
await masterRec.eventualWriteJson(identityMaster);
|
|
||||||
|
|
||||||
// Make empty identity
|
|
||||||
const identity = Identity(accountRecords: IMapConst({}));
|
|
||||||
|
|
||||||
// Write empty identity to identity dht key
|
|
||||||
await identityRec.eventualWriteJson(identity);
|
|
||||||
|
|
||||||
return IdentityMasterWithSecrets(
|
|
||||||
identityMaster: identityMaster,
|
|
||||||
masterSecret: masterOwner.secret,
|
|
||||||
identitySecret: identityOwner.secret);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new account associated with master identity
|
/// Creates a new account associated with master identity
|
||||||
@ -99,6 +57,7 @@ class LocalAccounts extends _$LocalAccounts
|
|||||||
EncryptionKeyType encryptionKeyType,
|
EncryptionKeyType encryptionKeyType,
|
||||||
String encryptionKey,
|
String encryptionKey,
|
||||||
proto.Account account) async {
|
proto.Account account) async {
|
||||||
|
final veilid = await eventualVeilid.future;
|
||||||
final localAccounts = state.requireValue;
|
final localAccounts = state.requireValue;
|
||||||
|
|
||||||
// Encrypt identitySecret with key
|
// Encrypt identitySecret with key
|
||||||
@ -111,8 +70,8 @@ class LocalAccounts extends _$LocalAccounts
|
|||||||
identitySecretSaltBytes = Uint8List(0);
|
identitySecretSaltBytes = Uint8List(0);
|
||||||
case EncryptionKeyType.pin:
|
case EncryptionKeyType.pin:
|
||||||
case EncryptionKeyType.password:
|
case EncryptionKeyType.password:
|
||||||
final cs = await Veilid.instance
|
final cs =
|
||||||
.getCryptoSystem(identityMaster.identityRecordKey.kind);
|
await veilid.getCryptoSystem(identityMaster.identityRecordKey.kind);
|
||||||
final ekbytes = Uint8List.fromList(utf8.encode(encryptionKey));
|
final ekbytes = Uint8List.fromList(utf8.encode(encryptionKey));
|
||||||
final nonce = await cs.randomNonce();
|
final nonce = await cs.randomNonce();
|
||||||
identitySecretSaltBytes = nonce.decode();
|
identitySecretSaltBytes = nonce.decode();
|
||||||
@ -135,7 +94,7 @@ class LocalAccounts extends _$LocalAccounts
|
|||||||
/////// Add account with profile to DHT
|
/////// Add account with profile to DHT
|
||||||
|
|
||||||
// Create private routing context
|
// Create private routing context
|
||||||
final dhtctx = (await Veilid.instance.routingContext())
|
final dhtctx = (await veilid.routingContext())
|
||||||
.withPrivacy()
|
.withPrivacy()
|
||||||
.withSequencing(Sequencing.ensureOrdered);
|
.withSequencing(Sequencing.ensureOrdered);
|
||||||
|
|
||||||
@ -171,6 +130,22 @@ class LocalAccounts extends _$LocalAccounts
|
|||||||
return localAccount;
|
return localAccount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remove an account and wipe the messages for this account from this device
|
||||||
|
Future<bool> deleteAccount(TypedKey accountMasterRecordKey) async {
|
||||||
|
final logins = ref.read(loginsProvider.notifier);
|
||||||
|
await logins.logout(accountMasterRecordKey);
|
||||||
|
|
||||||
|
final localAccounts = state.requireValue;
|
||||||
|
final updated = localAccounts.removeWhere(
|
||||||
|
(la) => la.identityMaster.masterRecordKey == accountMasterRecordKey);
|
||||||
|
await store(updated);
|
||||||
|
state = AsyncValue.data(updated);
|
||||||
|
|
||||||
|
// xxx todo: wipe messages
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// Import an account from another VeilidChat instance
|
/// Import an account from another VeilidChat instance
|
||||||
|
|
||||||
/// Recover an account with the master identity secret
|
/// Recover an account with the master identity secret
|
||||||
|
@ -6,7 +6,7 @@ part of 'local_accounts.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$localAccountsHash() => r'41f70b78e71c8b3faa2cd1f2a96084fbb373324c';
|
String _$localAccountsHash() => r'694236fa91156c00b3f7d6985fbc55b8871646ab';
|
||||||
|
|
||||||
/// See also [LocalAccounts].
|
/// See also [LocalAccounts].
|
||||||
@ProviderFor(LocalAccounts)
|
@ProviderFor(LocalAccounts)
|
||||||
|
@ -4,10 +4,10 @@ import 'dart:typed_data';
|
|||||||
|
|
||||||
import 'package:veilid/veilid.dart';
|
import 'package:veilid/veilid.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:veilidchat/providers/repositories.dart';
|
|
||||||
|
|
||||||
import '../veilid_support/veilid_support.dart';
|
import '../veilid_support/veilid_support.dart';
|
||||||
import '../entities/entities.dart';
|
import '../entities/entities.dart';
|
||||||
|
import 'local_accounts.dart';
|
||||||
|
|
||||||
part 'logins.g.dart';
|
part 'logins.g.dart';
|
||||||
|
|
||||||
@ -34,19 +34,20 @@ class Logins extends _$Logins with AsyncTableDBBacked<ActiveLogins> {
|
|||||||
//////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////
|
||||||
/// Mutators and Selectors
|
/// Mutators and Selectors
|
||||||
|
|
||||||
Future<void> setActiveUserLogin(TypedKey accountMasterKey) async {
|
Future<void> switchToAccount(TypedKey? accountMasterRecordKey) async {
|
||||||
final current = state.requireValue;
|
final current = state.requireValue;
|
||||||
for (final userLogin in current.userLogins) {
|
if (accountMasterRecordKey != null) {
|
||||||
if (userLogin.accountMasterRecordKey == accountMasterKey) {
|
// Assert the specified record key can be found, will throw if not
|
||||||
state = AsyncValue.data(
|
final _ = current.userLogins.firstWhere(
|
||||||
current.copyWith(activeUserLogin: accountMasterKey));
|
(ul) => ul.accountMasterRecordKey == accountMasterRecordKey);
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
throw Exception("User not found");
|
final updated = current.copyWith(activeUserLogin: accountMasterRecordKey);
|
||||||
|
await store(updated);
|
||||||
|
state = AsyncValue.data(updated);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> loginWithNone(TypedKey accountMasterRecordKey) async {
|
Future<bool> loginWithNone(TypedKey accountMasterRecordKey) async {
|
||||||
|
final veilid = await eventualVeilid.future;
|
||||||
final localAccounts = ref.read(localAccountsProvider).requireValue;
|
final localAccounts = ref.read(localAccountsProvider).requireValue;
|
||||||
|
|
||||||
// Get account, throws if not found
|
// Get account, throws if not found
|
||||||
@ -64,7 +65,7 @@ class Logins extends _$Logins with AsyncTableDBBacked<ActiveLogins> {
|
|||||||
SecretKey.fromBytes(localAccount.identitySecretKeyBytes);
|
SecretKey.fromBytes(localAccount.identitySecretKeyBytes);
|
||||||
|
|
||||||
// Validate this secret with the identity public key
|
// Validate this secret with the identity public key
|
||||||
final cs = await Veilid.instance
|
final cs = await veilid
|
||||||
.getCryptoSystem(localAccount.identityMaster.identityRecordKey.kind);
|
.getCryptoSystem(localAccount.identityMaster.identityRecordKey.kind);
|
||||||
final keyOk = await cs.validateKeyPair(
|
final keyOk = await cs.validateKeyPair(
|
||||||
localAccount.identityMaster.identityPublicKey, identitySecret);
|
localAccount.identityMaster.identityPublicKey, identitySecret);
|
||||||
@ -74,15 +75,15 @@ class Logins extends _$Logins with AsyncTableDBBacked<ActiveLogins> {
|
|||||||
|
|
||||||
// Add to user logins and select it
|
// Add to user logins and select it
|
||||||
final current = state.requireValue;
|
final current = state.requireValue;
|
||||||
final now = Veilid.instance.now();
|
final now = veilid.now();
|
||||||
final updated = current.copyWith(
|
final updated = current.copyWith(
|
||||||
userLogins: current.userLogins.replaceFirstWhere(
|
userLogins: current.userLogins.replaceFirstWhere(
|
||||||
(ul) => ul.accountMasterRecordKey == accountMasterRecordKey,
|
(ul) => ul.accountMasterRecordKey == accountMasterRecordKey,
|
||||||
(ul) => ul != null
|
(ul) => ul != null
|
||||||
? ul.copyWith(lastActive: now)
|
? ul.copyWith(lastActive: now)
|
||||||
: UserLogin(
|
: UserLogin(
|
||||||
accountMasterKey: accountMasterRecordKey,
|
accountMasterRecordKey: accountMasterRecordKey,
|
||||||
secretKey:
|
identitySecret:
|
||||||
TypedSecret(kind: cs.kind(), value: identitySecret),
|
TypedSecret(kind: cs.kind(), value: identitySecret),
|
||||||
lastActive: now),
|
lastActive: now),
|
||||||
addIfNotFound: true),
|
addIfNotFound: true),
|
||||||
@ -95,6 +96,7 @@ class Logins extends _$Logins with AsyncTableDBBacked<ActiveLogins> {
|
|||||||
|
|
||||||
Future<bool> loginWithPasswordOrPin(
|
Future<bool> loginWithPasswordOrPin(
|
||||||
TypedKey accountMasterRecordKey, String encryptionKey) async {
|
TypedKey accountMasterRecordKey, String encryptionKey) async {
|
||||||
|
final veilid = await eventualVeilid.future;
|
||||||
final localAccounts = ref.read(localAccountsProvider).requireValue;
|
final localAccounts = ref.read(localAccountsProvider).requireValue;
|
||||||
|
|
||||||
// Get account, throws if not found
|
// Get account, throws if not found
|
||||||
@ -108,7 +110,7 @@ class Logins extends _$Logins with AsyncTableDBBacked<ActiveLogins> {
|
|||||||
localAccount.encryptionKeyType != EncryptionKeyType.pin) {
|
localAccount.encryptionKeyType != EncryptionKeyType.pin) {
|
||||||
throw Exception("Wrong authentication type");
|
throw Exception("Wrong authentication type");
|
||||||
}
|
}
|
||||||
final cs = await Veilid.instance
|
final cs = await veilid
|
||||||
.getCryptoSystem(localAccount.identityMaster.identityRecordKey.kind);
|
.getCryptoSystem(localAccount.identityMaster.identityRecordKey.kind);
|
||||||
final ekbytes = Uint8List.fromList(utf8.encode(encryptionKey));
|
final ekbytes = Uint8List.fromList(utf8.encode(encryptionKey));
|
||||||
final eksalt = localAccount.identitySecretSaltBytes;
|
final eksalt = localAccount.identitySecretSaltBytes;
|
||||||
@ -126,15 +128,15 @@ class Logins extends _$Logins with AsyncTableDBBacked<ActiveLogins> {
|
|||||||
|
|
||||||
// Add to user logins and select it
|
// Add to user logins and select it
|
||||||
final current = state.requireValue;
|
final current = state.requireValue;
|
||||||
final now = Veilid.instance.now();
|
final now = veilid.now();
|
||||||
final updated = current.copyWith(
|
final updated = current.copyWith(
|
||||||
userLogins: current.userLogins.replaceFirstWhere(
|
userLogins: current.userLogins.replaceFirstWhere(
|
||||||
(ul) => ul.accountMasterRecordKey == accountMasterRecordKey,
|
(ul) => ul.accountMasterRecordKey == accountMasterRecordKey,
|
||||||
(ul) => ul != null
|
(ul) => ul != null
|
||||||
? ul.copyWith(lastActive: now)
|
? ul.copyWith(lastActive: now)
|
||||||
: UserLogin(
|
: UserLogin(
|
||||||
accountMasterKey: accountMasterRecordKey,
|
accountMasterRecordKey: accountMasterRecordKey,
|
||||||
secretKey:
|
identitySecret:
|
||||||
TypedSecret(kind: cs.kind(), value: identitySecret),
|
TypedSecret(kind: cs.kind(), value: identitySecret),
|
||||||
lastActive: now),
|
lastActive: now),
|
||||||
addIfNotFound: true),
|
addIfNotFound: true),
|
||||||
@ -145,25 +147,18 @@ class Logins extends _$Logins with AsyncTableDBBacked<ActiveLogins> {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> logout() async {
|
Future<void> logout(TypedKey? accountMasterRecordKey) async {
|
||||||
final current = state.requireValue;
|
final current = state.requireValue;
|
||||||
if (current.activeUserLogin == null) {
|
final logoutUser = accountMasterRecordKey ?? current.activeUserLogin;
|
||||||
|
if (logoutUser == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final updated = current.copyWith(
|
final updated = current.copyWith(
|
||||||
activeUserLogin: null,
|
activeUserLogin: current.activeUserLogin == logoutUser
|
||||||
userLogins: current.userLogins.removeWhere(
|
? null
|
||||||
(ul) => ul.accountMasterRecordKey == current.activeUserLogin));
|
: current.activeUserLogin,
|
||||||
await store(updated);
|
userLogins: current.userLogins
|
||||||
state = AsyncValue.data(updated);
|
.removeWhere((ul) => ul.accountMasterRecordKey == logoutUser));
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> switchToAccount(TypedKey accountMasterRecordKey) async {
|
|
||||||
final current = state.requireValue;
|
|
||||||
final userLogin = current.userLogins.firstWhere(
|
|
||||||
(ul) => ul.accountMasterRecordKey == accountMasterRecordKey);
|
|
||||||
final updated =
|
|
||||||
current.copyWith(activeUserLogin: userLogin.accountMasterRecordKey);
|
|
||||||
await store(updated);
|
await store(updated);
|
||||||
state = AsyncValue.data(updated);
|
state = AsyncValue.data(updated);
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ part of 'logins.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$loginsHash() => r'379514b8b6623d59cb89b4f128be5953d5ea62a6';
|
String _$loginsHash() => r'cf7f1a2343340a4dc4ebfa4009e846d0a39c0167';
|
||||||
|
|
||||||
/// See also [Logins].
|
/// See also [Logins].
|
||||||
@ProviderFor(Logins)
|
@ProviderFor(Logins)
|
||||||
|
@ -3,56 +3,42 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
|
||||||
import '../pages/pages.dart';
|
import '../pages/pages.dart';
|
||||||
import '../state/active_logins_state.dart';
|
import '../providers/logins.dart';
|
||||||
|
|
||||||
/// This notifier is meant to implement the [Listenable] our [GoRouter] needs.
|
|
||||||
///
|
|
||||||
/// We aim to trigger redirects whenever's needed.
|
|
||||||
/// This is done by calling our (only) listener everytime we want to notify stuff.
|
|
||||||
/// This allows to centralize global redirecting logic in this class.
|
|
||||||
/// In this simple case, we just listen to auth changes.
|
|
||||||
///
|
|
||||||
/// SIDE NOTE.
|
|
||||||
/// This might look overcomplicated at a first glance;
|
|
||||||
/// Instead, this method aims to follow some good some good practices:
|
|
||||||
/// 1. It doesn't require us to pipe down any `ref` parameter
|
|
||||||
/// 2. It works as a complete replacement for [ChangeNotifier] (it's a [Listenable] implementation)
|
|
||||||
/// 3. It allows for listening to multiple providers if needed (we do have a [Ref] now!)
|
|
||||||
class RouterNotifier extends AutoDisposeAsyncNotifier<void>
|
class RouterNotifier extends AutoDisposeAsyncNotifier<void>
|
||||||
implements Listenable {
|
implements Listenable {
|
||||||
|
/// GoRouter listener
|
||||||
VoidCallback? routerListener;
|
VoidCallback? routerListener;
|
||||||
bool isAuth = false; // Useful for our global redirect function
|
|
||||||
|
|
||||||
|
/// Router state for redirect
|
||||||
|
bool hasActiveUserLogin = false;
|
||||||
|
|
||||||
|
/// AsyncNotifier build
|
||||||
@override
|
@override
|
||||||
Future<void> build() async {
|
Future<void> build() async {
|
||||||
// One could watch more providers and write logic accordingly
|
hasActiveUserLogin = await ref.watch(
|
||||||
|
loginsProvider.selectAsync((data) => data.activeUserLogin != null),
|
||||||
isAuth = await ref.watch(
|
|
||||||
authNotifierProvider.selectAsync((data) => data != null),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// When this notifier's state changes, inform GoRouter
|
||||||
ref.listenSelf((_, __) {
|
ref.listenSelf((_, __) {
|
||||||
// One could write more conditional logic for when to call redirection
|
|
||||||
if (state.isLoading) return;
|
if (state.isLoading) return;
|
||||||
routerListener?.call();
|
routerListener?.call();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Redirects the user when our authentication changes
|
/// Redirects when our state changes
|
||||||
String? redirect(BuildContext context, GoRouterState state) {
|
String? redirect(BuildContext context, GoRouterState state) {
|
||||||
if (this.state.isLoading || this.state.hasError) return null;
|
if (this.state.isLoading || this.state.hasError) return null;
|
||||||
|
|
||||||
final isIndex = state.location == IndexPage.path;
|
switch (state.location) {
|
||||||
if (isIndex) {
|
case IndexPage.path:
|
||||||
return isAuth ? HomePage.path : LoginPage.path;
|
return hasActiveUserLogin ? HomePage.path : LoginPage.path;
|
||||||
|
case LoginPage.path:
|
||||||
|
return hasActiveUserLogin ? HomePage.path : null;
|
||||||
|
default:
|
||||||
|
return hasActiveUserLogin ? null : LoginPage.path;
|
||||||
}
|
}
|
||||||
|
|
||||||
final isLoggingIn = state.location == LoginPage.path;
|
|
||||||
if (isLoggingIn) {
|
|
||||||
return isAuth ? HomePage.path : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return isAuth ? null : IndexPage.path;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Our application routes
|
/// Our application routes
|
||||||
@ -103,6 +89,9 @@ class RouterNotifier extends AutoDisposeAsyncNotifier<void>
|
|||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
/// Listenable
|
||||||
|
|
||||||
/// Adds [GoRouter]'s listener as specified by its [Listenable].
|
/// Adds [GoRouter]'s listener as specified by its [Listenable].
|
||||||
/// [GoRouteInformationProvider] uses this method on creation to handle its
|
/// [GoRouteInformationProvider] uses this method on creation to handle its
|
||||||
/// internal [ChangeNotifier].
|
/// internal [ChangeNotifier].
|
||||||
|
@ -24,7 +24,8 @@ class ThemeService {
|
|||||||
String? themeName = prefs.getString('previousThemeName');
|
String? themeName = prefs.getString('previousThemeName');
|
||||||
if (themeName == null) {
|
if (themeName == null) {
|
||||||
final isPlatformDark =
|
final isPlatformDark =
|
||||||
WidgetsBinding.instance.window.platformBrightness == Brightness.dark;
|
WidgetsBinding.instance.platformDispatcher.platformBrightness ==
|
||||||
|
Brightness.dark;
|
||||||
themeName = isPlatformDark ? 'light' : 'dark';
|
themeName = isPlatformDark ? 'light' : 'dark';
|
||||||
}
|
}
|
||||||
return themeName;
|
return themeName;
|
||||||
@ -34,7 +35,8 @@ class ThemeService {
|
|||||||
String? themeName = prefs.getString('theme');
|
String? themeName = prefs.getString('theme');
|
||||||
if (themeName == null) {
|
if (themeName == null) {
|
||||||
final isPlatformDark =
|
final isPlatformDark =
|
||||||
WidgetsBinding.instance.window.platformBrightness == Brightness.dark;
|
WidgetsBinding.instance.platformDispatcher.platformBrightness ==
|
||||||
|
Brightness.dark;
|
||||||
themeName = isPlatformDark ? 'dark' : 'light';
|
themeName = isPlatformDark ? 'dark' : 'light';
|
||||||
}
|
}
|
||||||
return allThemes[themeName];
|
return allThemes[themeName];
|
||||||
|
@ -3,6 +3,8 @@ import 'dart:async';
|
|||||||
import 'package:veilid/veilid.dart';
|
import 'package:veilid/veilid.dart';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'veilid_init.dart';
|
||||||
|
|
||||||
abstract class DHTRecordCrypto {
|
abstract class DHTRecordCrypto {
|
||||||
FutureOr<Uint8List> encrypt(Uint8List data, int subkey);
|
FutureOr<Uint8List> encrypt(Uint8List data, int subkey);
|
||||||
FutureOr<Uint8List> decrypt(Uint8List data, int subkey);
|
FutureOr<Uint8List> decrypt(Uint8List data, int subkey);
|
||||||
@ -21,15 +23,16 @@ class DHTRecordCryptoPrivate implements DHTRecordCrypto {
|
|||||||
|
|
||||||
static Future<DHTRecordCryptoPrivate> fromTypedKeyPair(
|
static Future<DHTRecordCryptoPrivate> fromTypedKeyPair(
|
||||||
TypedKeyPair typedKeyPair) async {
|
TypedKeyPair typedKeyPair) async {
|
||||||
final cryptoSystem =
|
final veilid = await eventualVeilid.future;
|
||||||
await Veilid.instance.getCryptoSystem(typedKeyPair.kind);
|
final cryptoSystem = await veilid.getCryptoSystem(typedKeyPair.kind);
|
||||||
final secretKey = typedKeyPair.secret;
|
final secretKey = typedKeyPair.secret;
|
||||||
return DHTRecordCryptoPrivate._(cryptoSystem, secretKey);
|
return DHTRecordCryptoPrivate._(cryptoSystem, secretKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<DHTRecordCryptoPrivate> fromSecret(
|
static Future<DHTRecordCryptoPrivate> fromSecret(
|
||||||
CryptoKind kind, SharedSecret secretKey) async {
|
CryptoKind kind, SharedSecret secretKey) async {
|
||||||
final cryptoSystem = await Veilid.instance.getCryptoSystem(kind);
|
final veilid = await eventualVeilid.future;
|
||||||
|
final cryptoSystem = await veilid.getCryptoSystem(kind);
|
||||||
return DHTRecordCryptoPrivate._(cryptoSystem, secretKey);
|
return DHTRecordCryptoPrivate._(cryptoSystem, secretKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,8 +6,9 @@ import 'veilid_support.dart';
|
|||||||
|
|
||||||
/// Creates a new master identity and returns it with its secrets
|
/// Creates a new master identity and returns it with its secrets
|
||||||
Future<IdentityMasterWithSecrets> newIdentityMaster() async {
|
Future<IdentityMasterWithSecrets> newIdentityMaster() async {
|
||||||
final crypto = await Veilid.instance.bestCryptoSystem();
|
final veilid = await eventualVeilid.future;
|
||||||
final dhtctx = (await Veilid.instance.routingContext())
|
final crypto = await veilid.bestCryptoSystem();
|
||||||
|
final dhtctx = (await veilid.routingContext())
|
||||||
.withPrivacy()
|
.withPrivacy()
|
||||||
.withSequencing(Sequencing.ensureOrdered);
|
.withSequencing(Sequencing.ensureOrdered);
|
||||||
|
|
||||||
|
@ -24,6 +24,8 @@ class Processor {
|
|||||||
_veilidVersion = 'Failed to get veilid version.';
|
_veilidVersion = 'Failed to get veilid version.';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.info("Veilid version: $_veilidVersion");
|
||||||
|
|
||||||
// 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();
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import 'package:veilid/veilid.dart';
|
import 'package:veilid/veilid.dart';
|
||||||
|
import 'veilid_init.dart';
|
||||||
|
|
||||||
Future<T> tableScope<T>(
|
Future<T> tableScope<T>(
|
||||||
String name, Future<T> Function(VeilidTableDB tdb) callback,
|
String name, Future<T> Function(VeilidTableDB tdb) callback,
|
||||||
{int columnCount = 1}) async {
|
{int columnCount = 1}) async {
|
||||||
VeilidTableDB tableDB = await Veilid.instance.openTableDB(name, columnCount);
|
final veilid = await eventualVeilid.future;
|
||||||
|
VeilidTableDB tableDB = await veilid.openTableDB(name, columnCount);
|
||||||
try {
|
try {
|
||||||
return await callback(tableDB);
|
return await callback(tableDB);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:veilid/veilid.dart';
|
import 'package:veilid/veilid.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'processor.dart';
|
import 'processor.dart';
|
||||||
import 'veilid_log.dart';
|
import 'veilid_log.dart';
|
||||||
|
|
||||||
|
part 'veilid_init.g.dart';
|
||||||
|
|
||||||
Future<String> getVeilidVersion() async {
|
Future<String> getVeilidVersion() async {
|
||||||
String veilidVersion;
|
String veilidVersion;
|
||||||
try {
|
try {
|
||||||
@ -45,11 +51,12 @@ void _initVeilid() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool initialized = false;
|
Completer<Veilid> eventualVeilid = Completer<Veilid>();
|
||||||
Processor processor = Processor();
|
Processor processor = Processor();
|
||||||
|
|
||||||
Future<void> initializeVeilid() async {
|
Future<void> initializeVeilid() async {
|
||||||
if (initialized) {
|
// Ensure this runs only once
|
||||||
|
if (eventualVeilid.isCompleted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,5 +69,12 @@ Future<void> initializeVeilid() async {
|
|||||||
// Startup Veilid
|
// Startup Veilid
|
||||||
await processor.startup();
|
await processor.startup();
|
||||||
|
|
||||||
initialized = true;
|
// Share the initialized veilid instance to the rest of the app
|
||||||
|
eventualVeilid.complete(Veilid.instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expose the Veilid instance as a FutureProvider
|
||||||
|
@riverpod
|
||||||
|
FutureOr<Veilid> veilidInstance(VeilidInstanceRef ref) async {
|
||||||
|
return await eventualVeilid.future;
|
||||||
}
|
}
|
24
lib/veilid_support/veilid_init.g.dart
Normal file
24
lib/veilid_support/veilid_init.g.dart
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'veilid_init.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
String _$veilidInstanceHash() => r'6086fc1e7a83e7af81ee05ee84954507d38cb748';
|
||||||
|
|
||||||
|
/// See also [veilidInstance].
|
||||||
|
@ProviderFor(veilidInstance)
|
||||||
|
final veilidInstanceProvider = AutoDisposeFutureProvider<Veilid>.internal(
|
||||||
|
veilidInstance,
|
||||||
|
name: r'veilidInstanceProvider',
|
||||||
|
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$veilidInstanceHash,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef VeilidInstanceRef = AutoDisposeFutureProviderRef<Veilid>;
|
||||||
|
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
|
@ -1,7 +1,7 @@
|
|||||||
export 'config.dart';
|
export 'config.dart';
|
||||||
export 'processor.dart';
|
export 'processor.dart';
|
||||||
export 'veilid_log.dart';
|
export 'veilid_log.dart';
|
||||||
export 'init.dart';
|
export 'veilid_init.dart';
|
||||||
export 'dht_record.dart';
|
export 'dht_record.dart';
|
||||||
export 'dht_record_crypto.dart';
|
export 'dht_record_crypto.dart';
|
||||||
export 'table_db.dart';
|
export 'table_db.dart';
|
||||||
|
@ -6,10 +6,18 @@
|
|||||||
|
|
||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
|
#include <screen_retriever/screen_retriever_plugin.h>
|
||||||
#include <veilid/veilid_plugin.h>
|
#include <veilid/veilid_plugin.h>
|
||||||
|
#include <window_manager/window_manager_plugin.h>
|
||||||
|
|
||||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||||
|
g_autoptr(FlPluginRegistrar) screen_retriever_registrar =
|
||||||
|
fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverPlugin");
|
||||||
|
screen_retriever_plugin_register_with_registrar(screen_retriever_registrar);
|
||||||
g_autoptr(FlPluginRegistrar) veilid_registrar =
|
g_autoptr(FlPluginRegistrar) veilid_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "VeilidPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "VeilidPlugin");
|
||||||
veilid_plugin_register_with_registrar(veilid_registrar);
|
veilid_plugin_register_with_registrar(veilid_registrar);
|
||||||
|
g_autoptr(FlPluginRegistrar) window_manager_registrar =
|
||||||
|
fl_plugin_registry_get_registrar_for_plugin(registry, "WindowManagerPlugin");
|
||||||
|
window_manager_plugin_register_with_registrar(window_manager_registrar);
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
|
screen_retriever
|
||||||
veilid
|
veilid
|
||||||
|
window_manager
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
@ -6,11 +6,15 @@ import FlutterMacOS
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
import path_provider_foundation
|
import path_provider_foundation
|
||||||
|
import screen_retriever
|
||||||
import shared_preferences_foundation
|
import shared_preferences_foundation
|
||||||
import veilid
|
import veilid
|
||||||
|
import window_manager
|
||||||
|
|
||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||||
|
ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin"))
|
||||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||||
VeilidPlugin.register(with: registry.registrar(forPlugin: "VeilidPlugin"))
|
VeilidPlugin.register(with: registry.registrar(forPlugin: "VeilidPlugin"))
|
||||||
|
WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin"))
|
||||||
}
|
}
|
||||||
|
@ -3,33 +3,45 @@ PODS:
|
|||||||
- path_provider_foundation (0.0.1):
|
- path_provider_foundation (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
|
- screen_retriever (0.0.1):
|
||||||
|
- FlutterMacOS
|
||||||
- shared_preferences_foundation (0.0.1):
|
- shared_preferences_foundation (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- veilid (0.0.1):
|
- veilid (0.0.1):
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
|
- window_manager (0.2.0):
|
||||||
|
- FlutterMacOS
|
||||||
|
|
||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
- FlutterMacOS (from `Flutter/ephemeral`)
|
- FlutterMacOS (from `Flutter/ephemeral`)
|
||||||
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
|
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
|
||||||
|
- screen_retriever (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos`)
|
||||||
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
|
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||||
- veilid (from `Flutter/ephemeral/.symlinks/plugins/veilid/macos`)
|
- veilid (from `Flutter/ephemeral/.symlinks/plugins/veilid/macos`)
|
||||||
|
- window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`)
|
||||||
|
|
||||||
EXTERNAL SOURCES:
|
EXTERNAL SOURCES:
|
||||||
FlutterMacOS:
|
FlutterMacOS:
|
||||||
:path: Flutter/ephemeral
|
:path: Flutter/ephemeral
|
||||||
path_provider_foundation:
|
path_provider_foundation:
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
|
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
|
||||||
|
screen_retriever:
|
||||||
|
:path: Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos
|
||||||
shared_preferences_foundation:
|
shared_preferences_foundation:
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
|
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
|
||||||
veilid:
|
veilid:
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/veilid/macos
|
:path: Flutter/ephemeral/.symlinks/plugins/veilid/macos
|
||||||
|
window_manager:
|
||||||
|
:path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
|
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
|
||||||
path_provider_foundation: eaf5b3e458fc0e5fbb9940fb09980e853fe058b8
|
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
|
||||||
|
screen_retriever: 59634572a57080243dd1bf715e55b6c54f241a38
|
||||||
shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
|
shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
|
||||||
veilid: a54f57b7bcf0e4e072fe99272d76ca126b2026d0
|
veilid: a54f57b7bcf0e4e072fe99272d76ca126b2026d0
|
||||||
|
window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8
|
||||||
|
|
||||||
PODFILE CHECKSUM: ff0a9a3ce75ee73f200ca7e2f47745698c917ef9
|
PODFILE CHECKSUM: ff0a9a3ce75ee73f200ca7e2f47745698c917ef9
|
||||||
|
|
||||||
|
@ -425,9 +425,13 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
|
DEVELOPMENT_TEAM = XP5LBLT7M7;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = VeilidChat;
|
||||||
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/../Frameworks",
|
"@executable_path/../Frameworks",
|
||||||
@ -438,6 +442,7 @@
|
|||||||
/usr/lib/swift,
|
/usr/lib/swift,
|
||||||
"../../veilid/target/lipo-darwin",
|
"../../veilid/target/lipo-darwin",
|
||||||
);
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.veilid.veilidchat;
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
};
|
};
|
||||||
@ -557,9 +562,13 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
|
DEVELOPMENT_TEAM = XP5LBLT7M7;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = VeilidChat;
|
||||||
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/../Frameworks",
|
"@executable_path/../Frameworks",
|
||||||
@ -570,6 +579,7 @@
|
|||||||
/usr/lib/swift,
|
/usr/lib/swift,
|
||||||
"../../veilid/target/lipo-darwin",
|
"../../veilid/target/lipo-darwin",
|
||||||
);
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.veilid.veilidchat;
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
@ -583,9 +593,13 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements;
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
|
DEVELOPMENT_TEAM = XP5LBLT7M7;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = VeilidChat;
|
||||||
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/../Frameworks",
|
"@executable_path/../Frameworks",
|
||||||
@ -596,6 +610,7 @@
|
|||||||
/usr/lib/swift,
|
/usr/lib/swift,
|
||||||
"../../veilid/target/lipo-darwin",
|
"../../veilid/target/lipo-darwin",
|
||||||
);
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.veilid.veilidchat;
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
};
|
};
|
||||||
|
82
pubspec.lock
82
pubspec.lock
@ -339,6 +339,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.6"
|
version: "2.3.6"
|
||||||
|
flutter_svg:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_svg
|
||||||
|
sha256: "8c5d68a82add3ca76d792f058b186a0599414f279f00ece4830b9b231b570338"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.7"
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
@ -549,6 +557,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.3"
|
version: "1.8.3"
|
||||||
|
path_parsing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_parsing
|
||||||
|
sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.1"
|
||||||
path_provider:
|
path_provider:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -597,6 +613,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.7"
|
version: "2.1.7"
|
||||||
|
petitparser:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: petitparser
|
||||||
|
sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.4.0"
|
||||||
platform:
|
platform:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -653,6 +677,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.4"
|
version: "1.0.4"
|
||||||
|
reorderable_grid:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: reorderable_grid
|
||||||
|
sha256: e482ecb05c0a8c45a383d19b39cdc5c3c02f16339c6699c81d5978e602409fff
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.7"
|
||||||
riverpod:
|
riverpod:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -693,6 +725,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.27.7"
|
version: "0.27.7"
|
||||||
|
screen_retriever:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: screen_retriever
|
||||||
|
sha256: "4931f226ca158123ccd765325e9fbf360bfed0af9b460a10f960f9bb13d58323"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.6"
|
||||||
shared_preferences:
|
shared_preferences:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -890,6 +930,30 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.7"
|
version: "3.0.7"
|
||||||
|
vector_graphics:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: vector_graphics
|
||||||
|
sha256: "670f6e07aca990b4a2bcdc08a784193c4ccdd1932620244c3a86bb72a0eac67f"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.7"
|
||||||
|
vector_graphics_codec:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: vector_graphics_codec
|
||||||
|
sha256: "7451721781d967db9933b63f5733b1c4533022c0ba373a01bdd79d1a5457f69f"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.7"
|
||||||
|
vector_graphics_compiler:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: vector_graphics_compiler
|
||||||
|
sha256: "80a13c613c8bde758b1464a1755a7b3a8f2b6cec61fbf0f5a53c94c30f03ba2e"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.7"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -904,7 +968,7 @@ packages:
|
|||||||
path: "../veilid/veilid-flutter"
|
path: "../veilid/veilid-flutter"
|
||||||
relative: true
|
relative: true
|
||||||
source: path
|
source: path
|
||||||
version: "0.1.4"
|
version: "0.1.6"
|
||||||
watcher:
|
watcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -929,6 +993,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.0.5"
|
version: "5.0.5"
|
||||||
|
window_manager:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: window_manager
|
||||||
|
sha256: "9eef00e393e7f9308309ce9a8b2398c9ee3ca78b50c96e8b4f9873945693ac88"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.5"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -937,6 +1009,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.1"
|
version: "1.0.1"
|
||||||
|
xml:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: xml
|
||||||
|
sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.3.0"
|
||||||
yaml:
|
yaml:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
17
pubspec.yaml
17
pubspec.yaml
@ -39,6 +39,10 @@ dependencies:
|
|||||||
fixnum: ^1.1.0
|
fixnum: ^1.1.0
|
||||||
protobuf: ^3.0.0
|
protobuf: ^3.0.0
|
||||||
charcode: ^1.3.1
|
charcode: ^1.3.1
|
||||||
|
window_manager: ^0.3.5
|
||||||
|
flutter_svg: ^2.0.7
|
||||||
|
reorderable_grid: ^1.0.7
|
||||||
|
user_profile_avatar: ^0.1.2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
@ -50,14 +54,13 @@ dev_dependencies:
|
|||||||
riverpod_generator: ^2.2.3
|
riverpod_generator: ^2.2.3
|
||||||
|
|
||||||
flutter:
|
flutter:
|
||||||
|
|
||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
|
assets:
|
||||||
# To add assets to your application, add an assets section, like this:
|
- assets/i18n/en.json
|
||||||
# assets:
|
- assets/images/splash.svg
|
||||||
# - images/a_dot_burr.jpeg
|
- assets/images/icon.svg
|
||||||
# - images/a_dot_ham.jpeg
|
- assets/images/title.svg
|
||||||
|
|
||||||
# An image asset can refer to one or more resolution-specific "variants", see
|
# An image asset can refer to one or more resolution-specific "variants", see
|
||||||
# https://flutter.dev/assets-and-images/#resolution-aware
|
# https://flutter.dev/assets-and-images/#resolution-aware
|
||||||
|
|
||||||
|
@ -6,9 +6,15 @@
|
|||||||
|
|
||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
|
#include <screen_retriever/screen_retriever_plugin.h>
|
||||||
#include <veilid/veilid_plugin.h>
|
#include <veilid/veilid_plugin.h>
|
||||||
|
#include <window_manager/window_manager_plugin.h>
|
||||||
|
|
||||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
|
ScreenRetrieverPluginRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("ScreenRetrieverPlugin"));
|
||||||
VeilidPluginRegisterWithRegistrar(
|
VeilidPluginRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("VeilidPlugin"));
|
registry->GetRegistrarForPlugin("VeilidPlugin"));
|
||||||
|
WindowManagerPluginRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("WindowManagerPlugin"));
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
|
screen_retriever
|
||||||
veilid
|
veilid
|
||||||
|
window_manager
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
Loading…
Reference in New Issue
Block a user