mirror of
https://gitlab.com/veilid/veilidchat.git
synced 2025-05-14 04:02:17 -04:00
home layout
This commit is contained in:
parent
f754f7d5ed
commit
ca6b00e021
45 changed files with 2168 additions and 561 deletions
|
@ -5,6 +5,11 @@
|
||||||
"app_bar": {
|
"app_bar": {
|
||||||
"settings_tooltip": "Settings"
|
"settings_tooltip": "Settings"
|
||||||
},
|
},
|
||||||
|
"pager": {
|
||||||
|
"account": "Account",
|
||||||
|
"chats": "Chats",
|
||||||
|
"contacts": "Contacts"
|
||||||
|
},
|
||||||
"account": {
|
"account": {
|
||||||
"form_name": "Name",
|
"form_name": "Name",
|
||||||
"form_title": "Title (optional)",
|
"form_title": "Title (optional)",
|
||||||
|
@ -22,25 +27,26 @@
|
||||||
},
|
},
|
||||||
"button": {
|
"button": {
|
||||||
"ok": "Ok",
|
"ok": "Ok",
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel"
|
||||||
"change_language": "Change Language"
|
|
||||||
},
|
},
|
||||||
"language": {
|
"language": {
|
||||||
"name": {
|
"name": {
|
||||||
"en": "English"
|
"en": "English"
|
||||||
},
|
},
|
||||||
|
"change_language": "Change Language",
|
||||||
"selected_message": "Currently selected language is {language}",
|
"selected_message": "Currently selected language is {language}",
|
||||||
"selection": {
|
"selection": {
|
||||||
"message": "Please select a language from the list",
|
"message": "Please select a language from the list",
|
||||||
"title": "Language Selection"
|
"title": "Language Selection"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"plural": {
|
"account_page": {
|
||||||
"demo": {
|
"missing_account_title": "Missing Account",
|
||||||
"zero": "Please start pushing the 'plus' button.",
|
"missing_account_text": "Account is missing, removing from list",
|
||||||
"one": "You have pushed the button one time.",
|
"invalid_account_title": "Missing Account",
|
||||||
"two": "You have pushed the button two times.",
|
"invalid_account_text": "Account is missing, removing from list"
|
||||||
"other": "You have pushed the button {{value}} times."
|
},
|
||||||
}
|
"themes": {
|
||||||
|
"vapor": "Vapor"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,21 +5,45 @@ class Chat extends ConsumerWidget {
|
||||||
const Chat({super.key});
|
const Chat({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) => Scaffold(
|
// ignore: prefer_expression_function_bodies
|
||||||
appBar: AppBar(title: const Text('Chat')),
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
body: const Center(
|
//
|
||||||
child: Column(
|
return Align(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
alignment: AlignmentDirectional.centerEnd,
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context).scaffoldBackgroundColor,
|
||||||
|
),
|
||||||
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
Text('Home Page'),
|
Column(
|
||||||
// ElevatedButton(
|
children: [
|
||||||
// onPressed: () {
|
Container(
|
||||||
// ref.watch(authNotifierProvider.notifier).logout();
|
height: 48,
|
||||||
// },
|
decoration: BoxDecoration(
|
||||||
// child: const Text("Logout"),
|
color: Theme.of(context).primaryColor,
|
||||||
// ),
|
),
|
||||||
|
child: Align(
|
||||||
|
alignment: AlignmentDirectional.centerStart,
|
||||||
|
child: Padding(
|
||||||
|
padding:
|
||||||
|
const EdgeInsetsDirectional.fromSTEB(16, 0, 16, 0),
|
||||||
|
child: Text("current contact",
|
||||||
|
textAlign: TextAlign.start,
|
||||||
|
style: Theme.of(context).textTheme.titleMedium),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
decoration: const BoxDecoration(),
|
||||||
|
child: Text("Chat"),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
25
lib/components/chat_list.dart
Normal file
25
lib/components/chat_list.dart
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
|
class ChatList extends ConsumerWidget {
|
||||||
|
const ChatList({super.key});
|
||||||
|
//final LocalAccount account;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
//final logins = ref.watch(loginsProvider);
|
||||||
|
|
||||||
|
return ConstrainedBox(
|
||||||
|
constraints: const BoxConstraints(maxHeight: 300),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [const Expanded(child: Text('Chat List'))]));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||||
|
super.debugFillProperties(properties);
|
||||||
|
//properties.add(DiagnosticsProperty<LocalAccount>('account', account));
|
||||||
|
}
|
||||||
|
}
|
36
lib/components/empty_chat_component_widget.dart
Normal file
36
lib/components/empty_chat_component_widget.dart
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
|
class EmptyChatComponentWidget extends ConsumerWidget {
|
||||||
|
const EmptyChatComponentWidget({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
// ignore: prefer_expression_function_bodies
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
//
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: double.infinity,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context).scaffoldBackgroundColor,
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.chat,
|
||||||
|
color: Theme.of(context).disabledColor,
|
||||||
|
size: 48,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'Say Something',
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||||
|
color: Theme.of(context).disabledColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
35
lib/components/empty_contact_list_component_widget.dart
Normal file
35
lib/components/empty_contact_list_component_widget.dart
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
|
class EmptyContactListComponentWidget extends ConsumerWidget {
|
||||||
|
const EmptyContactListComponentWidget({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
// ignore: prefer_expression_function_bodies
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
//
|
||||||
|
return Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: double.infinity,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context).scaffoldBackgroundColor,
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.group_add,
|
||||||
|
color: Theme.of(context).disabledColor,
|
||||||
|
size: 48,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'Start A Conversation',
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||||
|
color: Theme.of(context).disabledColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
36
lib/components/no_conversation_component_widget.dart
Normal file
36
lib/components/no_conversation_component_widget.dart
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
|
class NoContactComponentWidget extends ConsumerWidget {
|
||||||
|
const NoContactComponentWidget({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
// ignore: prefer_expression_function_bodies
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
//
|
||||||
|
return Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: double.infinity,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context).primaryColor,
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.emoji_people_outlined,
|
||||||
|
color: Theme.of(context).disabledColor,
|
||||||
|
size: 48,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'Choose A Conversation To Chat',
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||||
|
color: Theme.of(context).disabledColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
37
lib/components/profile.dart
Normal file
37
lib/components/profile.dart
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
|
class ProfileWidget extends ConsumerWidget {
|
||||||
|
const ProfileWidget({
|
||||||
|
required this.name,
|
||||||
|
this.title,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String name;
|
||||||
|
final String? title;
|
||||||
|
|
||||||
|
@override
|
||||||
|
// ignore: prefer_expression_function_bodies
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
// final logins = ref.watch(loginsProvider);
|
||||||
|
|
||||||
|
return ConstrainedBox(
|
||||||
|
constraints: const BoxConstraints(maxHeight: 300),
|
||||||
|
child: Column(children: [
|
||||||
|
Text('Profile', style: Theme.of(context).textTheme.headlineMedium),
|
||||||
|
Text(name, style: Theme.of(context).textTheme.bodyMedium),
|
||||||
|
if (title != null && title!.isNotEmpty)
|
||||||
|
Text(title!, style: Theme.of(context).textTheme.bodySmall),
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||||
|
super.debugFillProperties(properties);
|
||||||
|
properties
|
||||||
|
..add(StringProperty('name', name))
|
||||||
|
..add(StringProperty('title', title));
|
||||||
|
}
|
||||||
|
}
|
|
@ -48,6 +48,8 @@ class LocalAccount with _$LocalAccount {
|
||||||
// Keep account hidden unless account password is entered
|
// Keep account hidden unless account password is entered
|
||||||
// (tries all hidden accounts with auth method (no biometrics))
|
// (tries all hidden accounts with auth method (no biometrics))
|
||||||
required bool hiddenAccount,
|
required bool hiddenAccount,
|
||||||
|
// Display name for account until it is unlocked
|
||||||
|
required String name,
|
||||||
}) = _LocalAccount;
|
}) = _LocalAccount;
|
||||||
|
|
||||||
factory LocalAccount.fromJson(dynamic json) =>
|
factory LocalAccount.fromJson(dynamic json) =>
|
||||||
|
|
|
@ -34,7 +34,9 @@ mixin _$LocalAccount {
|
||||||
bool get biometricsEnabled =>
|
bool get biometricsEnabled =>
|
||||||
throw _privateConstructorUsedError; // Keep account hidden unless account password is entered
|
throw _privateConstructorUsedError; // Keep account hidden unless account password is entered
|
||||||
// (tries all hidden accounts with auth method (no biometrics))
|
// (tries all hidden accounts with auth method (no biometrics))
|
||||||
bool get hiddenAccount => throw _privateConstructorUsedError;
|
bool get hiddenAccount =>
|
||||||
|
throw _privateConstructorUsedError; // Display name for account until it is unlocked
|
||||||
|
String get name => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
|
@ -54,7 +56,8 @@ abstract class $LocalAccountCopyWith<$Res> {
|
||||||
@Uint8ListJsonConverter() Uint8List identitySecretSaltBytes,
|
@Uint8ListJsonConverter() Uint8List identitySecretSaltBytes,
|
||||||
EncryptionKeyType encryptionKeyType,
|
EncryptionKeyType encryptionKeyType,
|
||||||
bool biometricsEnabled,
|
bool biometricsEnabled,
|
||||||
bool hiddenAccount});
|
bool hiddenAccount,
|
||||||
|
String name});
|
||||||
|
|
||||||
$IdentityMasterCopyWith<$Res> get identityMaster;
|
$IdentityMasterCopyWith<$Res> get identityMaster;
|
||||||
}
|
}
|
||||||
|
@ -78,6 +81,7 @@ class _$LocalAccountCopyWithImpl<$Res, $Val extends LocalAccount>
|
||||||
Object? encryptionKeyType = null,
|
Object? encryptionKeyType = null,
|
||||||
Object? biometricsEnabled = null,
|
Object? biometricsEnabled = null,
|
||||||
Object? hiddenAccount = null,
|
Object? hiddenAccount = null,
|
||||||
|
Object? name = null,
|
||||||
}) {
|
}) {
|
||||||
return _then(_value.copyWith(
|
return _then(_value.copyWith(
|
||||||
identityMaster: null == identityMaster
|
identityMaster: null == identityMaster
|
||||||
|
@ -104,6 +108,10 @@ class _$LocalAccountCopyWithImpl<$Res, $Val extends LocalAccount>
|
||||||
? _value.hiddenAccount
|
? _value.hiddenAccount
|
||||||
: hiddenAccount // ignore: cast_nullable_to_non_nullable
|
: hiddenAccount // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,
|
as bool,
|
||||||
|
name: null == name
|
||||||
|
? _value.name
|
||||||
|
: name // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
) as $Val);
|
) as $Val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +138,8 @@ abstract class _$$_LocalAccountCopyWith<$Res>
|
||||||
@Uint8ListJsonConverter() Uint8List identitySecretSaltBytes,
|
@Uint8ListJsonConverter() Uint8List identitySecretSaltBytes,
|
||||||
EncryptionKeyType encryptionKeyType,
|
EncryptionKeyType encryptionKeyType,
|
||||||
bool biometricsEnabled,
|
bool biometricsEnabled,
|
||||||
bool hiddenAccount});
|
bool hiddenAccount,
|
||||||
|
String name});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
$IdentityMasterCopyWith<$Res> get identityMaster;
|
$IdentityMasterCopyWith<$Res> get identityMaster;
|
||||||
|
@ -153,6 +162,7 @@ class __$$_LocalAccountCopyWithImpl<$Res>
|
||||||
Object? encryptionKeyType = null,
|
Object? encryptionKeyType = null,
|
||||||
Object? biometricsEnabled = null,
|
Object? biometricsEnabled = null,
|
||||||
Object? hiddenAccount = null,
|
Object? hiddenAccount = null,
|
||||||
|
Object? name = null,
|
||||||
}) {
|
}) {
|
||||||
return _then(_$_LocalAccount(
|
return _then(_$_LocalAccount(
|
||||||
identityMaster: null == identityMaster
|
identityMaster: null == identityMaster
|
||||||
|
@ -179,6 +189,10 @@ class __$$_LocalAccountCopyWithImpl<$Res>
|
||||||
? _value.hiddenAccount
|
? _value.hiddenAccount
|
||||||
: hiddenAccount // ignore: cast_nullable_to_non_nullable
|
: hiddenAccount // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,
|
as bool,
|
||||||
|
name: null == name
|
||||||
|
? _value.name
|
||||||
|
: name // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -192,7 +206,8 @@ class _$_LocalAccount implements _LocalAccount {
|
||||||
@Uint8ListJsonConverter() required this.identitySecretSaltBytes,
|
@Uint8ListJsonConverter() required this.identitySecretSaltBytes,
|
||||||
required this.encryptionKeyType,
|
required this.encryptionKeyType,
|
||||||
required this.biometricsEnabled,
|
required this.biometricsEnabled,
|
||||||
required this.hiddenAccount});
|
required this.hiddenAccount,
|
||||||
|
required this.name});
|
||||||
|
|
||||||
factory _$_LocalAccount.fromJson(Map<String, dynamic> json) =>
|
factory _$_LocalAccount.fromJson(Map<String, dynamic> json) =>
|
||||||
_$$_LocalAccountFromJson(json);
|
_$$_LocalAccountFromJson(json);
|
||||||
|
@ -218,10 +233,13 @@ class _$_LocalAccount implements _LocalAccount {
|
||||||
// (tries all hidden accounts with auth method (no biometrics))
|
// (tries all hidden accounts with auth method (no biometrics))
|
||||||
@override
|
@override
|
||||||
final bool hiddenAccount;
|
final bool hiddenAccount;
|
||||||
|
// Display name for account until it is unlocked
|
||||||
|
@override
|
||||||
|
final String name;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'LocalAccount(identityMaster: $identityMaster, identitySecretKeyBytes: $identitySecretKeyBytes, identitySecretSaltBytes: $identitySecretSaltBytes, encryptionKeyType: $encryptionKeyType, biometricsEnabled: $biometricsEnabled, hiddenAccount: $hiddenAccount)';
|
return 'LocalAccount(identityMaster: $identityMaster, identitySecretKeyBytes: $identitySecretKeyBytes, identitySecretSaltBytes: $identitySecretSaltBytes, encryptionKeyType: $encryptionKeyType, biometricsEnabled: $biometricsEnabled, hiddenAccount: $hiddenAccount, name: $name)';
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -240,7 +258,8 @@ class _$_LocalAccount implements _LocalAccount {
|
||||||
(identical(other.biometricsEnabled, biometricsEnabled) ||
|
(identical(other.biometricsEnabled, biometricsEnabled) ||
|
||||||
other.biometricsEnabled == biometricsEnabled) &&
|
other.biometricsEnabled == biometricsEnabled) &&
|
||||||
(identical(other.hiddenAccount, hiddenAccount) ||
|
(identical(other.hiddenAccount, hiddenAccount) ||
|
||||||
other.hiddenAccount == hiddenAccount));
|
other.hiddenAccount == hiddenAccount) &&
|
||||||
|
(identical(other.name, name) || other.name == name));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
|
@ -252,7 +271,8 @@ class _$_LocalAccount implements _LocalAccount {
|
||||||
const DeepCollectionEquality().hash(identitySecretSaltBytes),
|
const DeepCollectionEquality().hash(identitySecretSaltBytes),
|
||||||
encryptionKeyType,
|
encryptionKeyType,
|
||||||
biometricsEnabled,
|
biometricsEnabled,
|
||||||
hiddenAccount);
|
hiddenAccount,
|
||||||
|
name);
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
@override
|
@override
|
||||||
|
@ -276,7 +296,8 @@ abstract class _LocalAccount implements LocalAccount {
|
||||||
required final Uint8List identitySecretSaltBytes,
|
required final Uint8List identitySecretSaltBytes,
|
||||||
required final EncryptionKeyType encryptionKeyType,
|
required final EncryptionKeyType encryptionKeyType,
|
||||||
required final bool biometricsEnabled,
|
required final bool biometricsEnabled,
|
||||||
required final bool hiddenAccount}) = _$_LocalAccount;
|
required final bool hiddenAccount,
|
||||||
|
required final String name}) = _$_LocalAccount;
|
||||||
|
|
||||||
factory _LocalAccount.fromJson(Map<String, dynamic> json) =
|
factory _LocalAccount.fromJson(Map<String, dynamic> json) =
|
||||||
_$_LocalAccount.fromJson;
|
_$_LocalAccount.fromJson;
|
||||||
|
@ -296,6 +317,8 @@ abstract class _LocalAccount implements LocalAccount {
|
||||||
@override // Keep account hidden unless account password is entered
|
@override // Keep account hidden unless account password is entered
|
||||||
// (tries all hidden accounts with auth method (no biometrics))
|
// (tries all hidden accounts with auth method (no biometrics))
|
||||||
bool get hiddenAccount;
|
bool get hiddenAccount;
|
||||||
|
@override // Display name for account until it is unlocked
|
||||||
|
String get name;
|
||||||
@override
|
@override
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
_$$_LocalAccountCopyWith<_$_LocalAccount> get copyWith =>
|
_$$_LocalAccountCopyWith<_$_LocalAccount> get copyWith =>
|
||||||
|
|
|
@ -17,6 +17,7 @@ _$_LocalAccount _$$_LocalAccountFromJson(Map<String, dynamic> json) =>
|
||||||
EncryptionKeyType.fromJson(json['encryption_key_type']),
|
EncryptionKeyType.fromJson(json['encryption_key_type']),
|
||||||
biometricsEnabled: json['biometrics_enabled'] as bool,
|
biometricsEnabled: json['biometrics_enabled'] as bool,
|
||||||
hiddenAccount: json['hidden_account'] as bool,
|
hiddenAccount: json['hidden_account'] as bool,
|
||||||
|
name: json['name'] as String,
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$$_LocalAccountToJson(_$_LocalAccount instance) =>
|
Map<String, dynamic> _$$_LocalAccountToJson(_$_LocalAccount instance) =>
|
||||||
|
@ -29,4 +30,5 @@ Map<String, dynamic> _$$_LocalAccountToJson(_$_LocalAccount instance) =>
|
||||||
'encryption_key_type': instance.encryptionKeyType.toJson(),
|
'encryption_key_type': instance.encryptionKeyType.toJson(),
|
||||||
'biometrics_enabled': instance.biometricsEnabled,
|
'biometrics_enabled': instance.biometricsEnabled,
|
||||||
'hidden_account': instance.hiddenAccount,
|
'hidden_account': instance.hiddenAccount,
|
||||||
|
'name': instance.name,
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,13 +6,13 @@ part 'preferences.g.dart';
|
||||||
|
|
||||||
// Theme supports light and dark mode, optionally selected by the
|
// Theme supports light and dark mode, optionally selected by the
|
||||||
// operating system
|
// operating system
|
||||||
enum DarkModePreference {
|
enum BrightnessPreference {
|
||||||
system,
|
system,
|
||||||
light,
|
light,
|
||||||
dark;
|
dark;
|
||||||
|
|
||||||
factory DarkModePreference.fromJson(dynamic j) =>
|
factory BrightnessPreference.fromJson(dynamic j) =>
|
||||||
DarkModePreference.values.byName((j as String).toCamelCase());
|
BrightnessPreference.values.byName((j as String).toCamelCase());
|
||||||
|
|
||||||
String toJson() => name.toPascalCase();
|
String toJson() => name.toPascalCase();
|
||||||
}
|
}
|
||||||
|
@ -33,34 +33,20 @@ class LockPreference with _$LockPreference {
|
||||||
|
|
||||||
// Theme supports multiple color variants based on 'Radix'
|
// Theme supports multiple color variants based on 'Radix'
|
||||||
enum ColorPreference {
|
enum ColorPreference {
|
||||||
amber,
|
// Radix Colors
|
||||||
blue,
|
scarlet,
|
||||||
bronze,
|
babydoll,
|
||||||
brown,
|
vapor,
|
||||||
crimson,
|
|
||||||
cyan,
|
|
||||||
gold,
|
gold,
|
||||||
grass,
|
garden,
|
||||||
gray,
|
forest,
|
||||||
green,
|
arctic,
|
||||||
indigo,
|
lapis,
|
||||||
|
eggplant,
|
||||||
lime,
|
lime,
|
||||||
mauve,
|
grim,
|
||||||
mint,
|
// Accessible Colors
|
||||||
olive,
|
contrast;
|
||||||
orange,
|
|
||||||
pink,
|
|
||||||
plum,
|
|
||||||
purple,
|
|
||||||
red,
|
|
||||||
sage,
|
|
||||||
sand,
|
|
||||||
sky,
|
|
||||||
slate,
|
|
||||||
teal,
|
|
||||||
tomato,
|
|
||||||
violet,
|
|
||||||
yellow;
|
|
||||||
|
|
||||||
factory ColorPreference.fromJson(dynamic j) =>
|
factory ColorPreference.fromJson(dynamic j) =>
|
||||||
ColorPreference.values.byName((j as String).toCamelCase());
|
ColorPreference.values.byName((j as String).toCamelCase());
|
||||||
|
@ -76,15 +62,25 @@ enum LanguagePreference {
|
||||||
String toJson() => name.toPascalCase();
|
String toJson() => name.toPascalCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
class ThemePreferences with _$ThemePreferences {
|
||||||
|
const factory ThemePreferences({
|
||||||
|
required BrightnessPreference brightnessPreference,
|
||||||
|
required ColorPreference colorPreference,
|
||||||
|
required double displayScale,
|
||||||
|
}) = _ThemePreferences;
|
||||||
|
|
||||||
|
factory ThemePreferences.fromJson(dynamic json) =>
|
||||||
|
_$ThemePreferencesFromJson(json as Map<String, dynamic>);
|
||||||
|
}
|
||||||
|
|
||||||
// Preferences are stored in a table locally and globally affect all
|
// Preferences are stored in a table locally and globally affect all
|
||||||
// accounts imported/added and the app in general
|
// accounts imported/added and the app in general
|
||||||
@freezed
|
@freezed
|
||||||
class Preferences with _$Preferences {
|
class Preferences with _$Preferences {
|
||||||
const factory Preferences({
|
const factory Preferences({
|
||||||
required DarkModePreference darkMode,
|
required ThemePreferences themePreferences,
|
||||||
required ColorPreference themeColor,
|
|
||||||
required LanguagePreference language,
|
required LanguagePreference language,
|
||||||
required int displayScale,
|
|
||||||
required LockPreference locking,
|
required LockPreference locking,
|
||||||
}) = _Preferences;
|
}) = _Preferences;
|
||||||
|
|
||||||
|
|
|
@ -198,16 +198,199 @@ abstract class _LockPreference implements LockPreference {
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ThemePreferences _$ThemePreferencesFromJson(Map<String, dynamic> json) {
|
||||||
|
return _ThemePreferences.fromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$ThemePreferences {
|
||||||
|
BrightnessPreference get brightnessPreference =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
ColorPreference get colorPreference => throw _privateConstructorUsedError;
|
||||||
|
double get displayScale => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
$ThemePreferencesCopyWith<ThemePreferences> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class $ThemePreferencesCopyWith<$Res> {
|
||||||
|
factory $ThemePreferencesCopyWith(
|
||||||
|
ThemePreferences value, $Res Function(ThemePreferences) then) =
|
||||||
|
_$ThemePreferencesCopyWithImpl<$Res, ThemePreferences>;
|
||||||
|
@useResult
|
||||||
|
$Res call(
|
||||||
|
{BrightnessPreference brightnessPreference,
|
||||||
|
ColorPreference colorPreference,
|
||||||
|
double displayScale});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class _$ThemePreferencesCopyWithImpl<$Res, $Val extends ThemePreferences>
|
||||||
|
implements $ThemePreferencesCopyWith<$Res> {
|
||||||
|
_$ThemePreferencesCopyWithImpl(this._value, this._then);
|
||||||
|
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Val _value;
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? brightnessPreference = null,
|
||||||
|
Object? colorPreference = null,
|
||||||
|
Object? displayScale = null,
|
||||||
|
}) {
|
||||||
|
return _then(_value.copyWith(
|
||||||
|
brightnessPreference: null == brightnessPreference
|
||||||
|
? _value.brightnessPreference
|
||||||
|
: brightnessPreference // ignore: cast_nullable_to_non_nullable
|
||||||
|
as BrightnessPreference,
|
||||||
|
colorPreference: null == colorPreference
|
||||||
|
? _value.colorPreference
|
||||||
|
: colorPreference // ignore: cast_nullable_to_non_nullable
|
||||||
|
as ColorPreference,
|
||||||
|
displayScale: null == displayScale
|
||||||
|
? _value.displayScale
|
||||||
|
: displayScale // ignore: cast_nullable_to_non_nullable
|
||||||
|
as double,
|
||||||
|
) as $Val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class _$$_ThemePreferencesCopyWith<$Res>
|
||||||
|
implements $ThemePreferencesCopyWith<$Res> {
|
||||||
|
factory _$$_ThemePreferencesCopyWith(
|
||||||
|
_$_ThemePreferences value, $Res Function(_$_ThemePreferences) then) =
|
||||||
|
__$$_ThemePreferencesCopyWithImpl<$Res>;
|
||||||
|
@override
|
||||||
|
@useResult
|
||||||
|
$Res call(
|
||||||
|
{BrightnessPreference brightnessPreference,
|
||||||
|
ColorPreference colorPreference,
|
||||||
|
double displayScale});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class __$$_ThemePreferencesCopyWithImpl<$Res>
|
||||||
|
extends _$ThemePreferencesCopyWithImpl<$Res, _$_ThemePreferences>
|
||||||
|
implements _$$_ThemePreferencesCopyWith<$Res> {
|
||||||
|
__$$_ThemePreferencesCopyWithImpl(
|
||||||
|
_$_ThemePreferences _value, $Res Function(_$_ThemePreferences) _then)
|
||||||
|
: super(_value, _then);
|
||||||
|
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? brightnessPreference = null,
|
||||||
|
Object? colorPreference = null,
|
||||||
|
Object? displayScale = null,
|
||||||
|
}) {
|
||||||
|
return _then(_$_ThemePreferences(
|
||||||
|
brightnessPreference: null == brightnessPreference
|
||||||
|
? _value.brightnessPreference
|
||||||
|
: brightnessPreference // ignore: cast_nullable_to_non_nullable
|
||||||
|
as BrightnessPreference,
|
||||||
|
colorPreference: null == colorPreference
|
||||||
|
? _value.colorPreference
|
||||||
|
: colorPreference // ignore: cast_nullable_to_non_nullable
|
||||||
|
as ColorPreference,
|
||||||
|
displayScale: null == displayScale
|
||||||
|
? _value.displayScale
|
||||||
|
: displayScale // ignore: cast_nullable_to_non_nullable
|
||||||
|
as double,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
@JsonSerializable()
|
||||||
|
class _$_ThemePreferences implements _ThemePreferences {
|
||||||
|
const _$_ThemePreferences(
|
||||||
|
{required this.brightnessPreference,
|
||||||
|
required this.colorPreference,
|
||||||
|
required this.displayScale});
|
||||||
|
|
||||||
|
factory _$_ThemePreferences.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$$_ThemePreferencesFromJson(json);
|
||||||
|
|
||||||
|
@override
|
||||||
|
final BrightnessPreference brightnessPreference;
|
||||||
|
@override
|
||||||
|
final ColorPreference colorPreference;
|
||||||
|
@override
|
||||||
|
final double displayScale;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'ThemePreferences(brightnessPreference: $brightnessPreference, colorPreference: $colorPreference, displayScale: $displayScale)';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(dynamic other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is _$_ThemePreferences &&
|
||||||
|
(identical(other.brightnessPreference, brightnessPreference) ||
|
||||||
|
other.brightnessPreference == brightnessPreference) &&
|
||||||
|
(identical(other.colorPreference, colorPreference) ||
|
||||||
|
other.colorPreference == colorPreference) &&
|
||||||
|
(identical(other.displayScale, displayScale) ||
|
||||||
|
other.displayScale == displayScale));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(
|
||||||
|
runtimeType, brightnessPreference, colorPreference, displayScale);
|
||||||
|
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$$_ThemePreferencesCopyWith<_$_ThemePreferences> get copyWith =>
|
||||||
|
__$$_ThemePreferencesCopyWithImpl<_$_ThemePreferences>(this, _$identity);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return _$$_ThemePreferencesToJson(
|
||||||
|
this,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class _ThemePreferences implements ThemePreferences {
|
||||||
|
const factory _ThemePreferences(
|
||||||
|
{required final BrightnessPreference brightnessPreference,
|
||||||
|
required final ColorPreference colorPreference,
|
||||||
|
required final double displayScale}) = _$_ThemePreferences;
|
||||||
|
|
||||||
|
factory _ThemePreferences.fromJson(Map<String, dynamic> json) =
|
||||||
|
_$_ThemePreferences.fromJson;
|
||||||
|
|
||||||
|
@override
|
||||||
|
BrightnessPreference get brightnessPreference;
|
||||||
|
@override
|
||||||
|
ColorPreference get colorPreference;
|
||||||
|
@override
|
||||||
|
double get displayScale;
|
||||||
|
@override
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
_$$_ThemePreferencesCopyWith<_$_ThemePreferences> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
||||||
|
|
||||||
Preferences _$PreferencesFromJson(Map<String, dynamic> json) {
|
Preferences _$PreferencesFromJson(Map<String, dynamic> json) {
|
||||||
return _Preferences.fromJson(json);
|
return _Preferences.fromJson(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
mixin _$Preferences {
|
mixin _$Preferences {
|
||||||
DarkModePreference get darkMode => throw _privateConstructorUsedError;
|
ThemePreferences get themePreferences => throw _privateConstructorUsedError;
|
||||||
ColorPreference get themeColor => throw _privateConstructorUsedError;
|
|
||||||
LanguagePreference get language => throw _privateConstructorUsedError;
|
LanguagePreference get language => throw _privateConstructorUsedError;
|
||||||
int get displayScale => throw _privateConstructorUsedError;
|
|
||||||
LockPreference get locking => throw _privateConstructorUsedError;
|
LockPreference get locking => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
|
@ -223,12 +406,11 @@ abstract class $PreferencesCopyWith<$Res> {
|
||||||
_$PreferencesCopyWithImpl<$Res, Preferences>;
|
_$PreferencesCopyWithImpl<$Res, Preferences>;
|
||||||
@useResult
|
@useResult
|
||||||
$Res call(
|
$Res call(
|
||||||
{DarkModePreference darkMode,
|
{ThemePreferences themePreferences,
|
||||||
ColorPreference themeColor,
|
|
||||||
LanguagePreference language,
|
LanguagePreference language,
|
||||||
int displayScale,
|
|
||||||
LockPreference locking});
|
LockPreference locking});
|
||||||
|
|
||||||
|
$ThemePreferencesCopyWith<$Res> get themePreferences;
|
||||||
$LockPreferenceCopyWith<$Res> get locking;
|
$LockPreferenceCopyWith<$Res> get locking;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,29 +427,19 @@ class _$PreferencesCopyWithImpl<$Res, $Val extends Preferences>
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
Object? darkMode = null,
|
Object? themePreferences = null,
|
||||||
Object? themeColor = null,
|
|
||||||
Object? language = null,
|
Object? language = null,
|
||||||
Object? displayScale = null,
|
|
||||||
Object? locking = null,
|
Object? locking = null,
|
||||||
}) {
|
}) {
|
||||||
return _then(_value.copyWith(
|
return _then(_value.copyWith(
|
||||||
darkMode: null == darkMode
|
themePreferences: null == themePreferences
|
||||||
? _value.darkMode
|
? _value.themePreferences
|
||||||
: darkMode // ignore: cast_nullable_to_non_nullable
|
: themePreferences // ignore: cast_nullable_to_non_nullable
|
||||||
as DarkModePreference,
|
as ThemePreferences,
|
||||||
themeColor: null == themeColor
|
|
||||||
? _value.themeColor
|
|
||||||
: themeColor // ignore: cast_nullable_to_non_nullable
|
|
||||||
as ColorPreference,
|
|
||||||
language: null == language
|
language: null == language
|
||||||
? _value.language
|
? _value.language
|
||||||
: language // ignore: cast_nullable_to_non_nullable
|
: language // ignore: cast_nullable_to_non_nullable
|
||||||
as LanguagePreference,
|
as LanguagePreference,
|
||||||
displayScale: null == displayScale
|
|
||||||
? _value.displayScale
|
|
||||||
: displayScale // ignore: cast_nullable_to_non_nullable
|
|
||||||
as int,
|
|
||||||
locking: null == locking
|
locking: null == locking
|
||||||
? _value.locking
|
? _value.locking
|
||||||
: locking // ignore: cast_nullable_to_non_nullable
|
: locking // ignore: cast_nullable_to_non_nullable
|
||||||
|
@ -275,6 +447,14 @@ class _$PreferencesCopyWithImpl<$Res, $Val extends Preferences>
|
||||||
) as $Val);
|
) as $Val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$ThemePreferencesCopyWith<$Res> get themePreferences {
|
||||||
|
return $ThemePreferencesCopyWith<$Res>(_value.themePreferences, (value) {
|
||||||
|
return _then(_value.copyWith(themePreferences: value) as $Val);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
$LockPreferenceCopyWith<$Res> get locking {
|
$LockPreferenceCopyWith<$Res> get locking {
|
||||||
|
@ -293,12 +473,12 @@ abstract class _$$_PreferencesCopyWith<$Res>
|
||||||
@override
|
@override
|
||||||
@useResult
|
@useResult
|
||||||
$Res call(
|
$Res call(
|
||||||
{DarkModePreference darkMode,
|
{ThemePreferences themePreferences,
|
||||||
ColorPreference themeColor,
|
|
||||||
LanguagePreference language,
|
LanguagePreference language,
|
||||||
int displayScale,
|
|
||||||
LockPreference locking});
|
LockPreference locking});
|
||||||
|
|
||||||
|
@override
|
||||||
|
$ThemePreferencesCopyWith<$Res> get themePreferences;
|
||||||
@override
|
@override
|
||||||
$LockPreferenceCopyWith<$Res> get locking;
|
$LockPreferenceCopyWith<$Res> get locking;
|
||||||
}
|
}
|
||||||
|
@ -314,29 +494,19 @@ class __$$_PreferencesCopyWithImpl<$Res>
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
Object? darkMode = null,
|
Object? themePreferences = null,
|
||||||
Object? themeColor = null,
|
|
||||||
Object? language = null,
|
Object? language = null,
|
||||||
Object? displayScale = null,
|
|
||||||
Object? locking = null,
|
Object? locking = null,
|
||||||
}) {
|
}) {
|
||||||
return _then(_$_Preferences(
|
return _then(_$_Preferences(
|
||||||
darkMode: null == darkMode
|
themePreferences: null == themePreferences
|
||||||
? _value.darkMode
|
? _value.themePreferences
|
||||||
: darkMode // ignore: cast_nullable_to_non_nullable
|
: themePreferences // ignore: cast_nullable_to_non_nullable
|
||||||
as DarkModePreference,
|
as ThemePreferences,
|
||||||
themeColor: null == themeColor
|
|
||||||
? _value.themeColor
|
|
||||||
: themeColor // ignore: cast_nullable_to_non_nullable
|
|
||||||
as ColorPreference,
|
|
||||||
language: null == language
|
language: null == language
|
||||||
? _value.language
|
? _value.language
|
||||||
: language // ignore: cast_nullable_to_non_nullable
|
: language // ignore: cast_nullable_to_non_nullable
|
||||||
as LanguagePreference,
|
as LanguagePreference,
|
||||||
displayScale: null == displayScale
|
|
||||||
? _value.displayScale
|
|
||||||
: displayScale // ignore: cast_nullable_to_non_nullable
|
|
||||||
as int,
|
|
||||||
locking: null == locking
|
locking: null == locking
|
||||||
? _value.locking
|
? _value.locking
|
||||||
: locking // ignore: cast_nullable_to_non_nullable
|
: locking // ignore: cast_nullable_to_non_nullable
|
||||||
|
@ -349,29 +519,23 @@ class __$$_PreferencesCopyWithImpl<$Res>
|
||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
class _$_Preferences implements _Preferences {
|
class _$_Preferences implements _Preferences {
|
||||||
const _$_Preferences(
|
const _$_Preferences(
|
||||||
{required this.darkMode,
|
{required this.themePreferences,
|
||||||
required this.themeColor,
|
|
||||||
required this.language,
|
required this.language,
|
||||||
required this.displayScale,
|
|
||||||
required this.locking});
|
required this.locking});
|
||||||
|
|
||||||
factory _$_Preferences.fromJson(Map<String, dynamic> json) =>
|
factory _$_Preferences.fromJson(Map<String, dynamic> json) =>
|
||||||
_$$_PreferencesFromJson(json);
|
_$$_PreferencesFromJson(json);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final DarkModePreference darkMode;
|
final ThemePreferences themePreferences;
|
||||||
@override
|
|
||||||
final ColorPreference themeColor;
|
|
||||||
@override
|
@override
|
||||||
final LanguagePreference language;
|
final LanguagePreference language;
|
||||||
@override
|
@override
|
||||||
final int displayScale;
|
|
||||||
@override
|
|
||||||
final LockPreference locking;
|
final LockPreference locking;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'Preferences(darkMode: $darkMode, themeColor: $themeColor, language: $language, displayScale: $displayScale, locking: $locking)';
|
return 'Preferences(themePreferences: $themePreferences, language: $language, locking: $locking)';
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -379,21 +543,17 @@ class _$_Preferences implements _Preferences {
|
||||||
return identical(this, other) ||
|
return identical(this, other) ||
|
||||||
(other.runtimeType == runtimeType &&
|
(other.runtimeType == runtimeType &&
|
||||||
other is _$_Preferences &&
|
other is _$_Preferences &&
|
||||||
(identical(other.darkMode, darkMode) ||
|
(identical(other.themePreferences, themePreferences) ||
|
||||||
other.darkMode == darkMode) &&
|
other.themePreferences == themePreferences) &&
|
||||||
(identical(other.themeColor, themeColor) ||
|
|
||||||
other.themeColor == themeColor) &&
|
|
||||||
(identical(other.language, language) ||
|
(identical(other.language, language) ||
|
||||||
other.language == language) &&
|
other.language == language) &&
|
||||||
(identical(other.displayScale, displayScale) ||
|
|
||||||
other.displayScale == displayScale) &&
|
|
||||||
(identical(other.locking, locking) || other.locking == locking));
|
(identical(other.locking, locking) || other.locking == locking));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(
|
int get hashCode =>
|
||||||
runtimeType, darkMode, themeColor, language, displayScale, locking);
|
Object.hash(runtimeType, themePreferences, language, locking);
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
@override
|
@override
|
||||||
|
@ -411,24 +571,18 @@ class _$_Preferences implements _Preferences {
|
||||||
|
|
||||||
abstract class _Preferences implements Preferences {
|
abstract class _Preferences implements Preferences {
|
||||||
const factory _Preferences(
|
const factory _Preferences(
|
||||||
{required final DarkModePreference darkMode,
|
{required final ThemePreferences themePreferences,
|
||||||
required final ColorPreference themeColor,
|
|
||||||
required final LanguagePreference language,
|
required final LanguagePreference language,
|
||||||
required final int displayScale,
|
|
||||||
required final LockPreference locking}) = _$_Preferences;
|
required final LockPreference locking}) = _$_Preferences;
|
||||||
|
|
||||||
factory _Preferences.fromJson(Map<String, dynamic> json) =
|
factory _Preferences.fromJson(Map<String, dynamic> json) =
|
||||||
_$_Preferences.fromJson;
|
_$_Preferences.fromJson;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
DarkModePreference get darkMode;
|
ThemePreferences get themePreferences;
|
||||||
@override
|
|
||||||
ColorPreference get themeColor;
|
|
||||||
@override
|
@override
|
||||||
LanguagePreference get language;
|
LanguagePreference get language;
|
||||||
@override
|
@override
|
||||||
int get displayScale;
|
|
||||||
@override
|
|
||||||
LockPreference get locking;
|
LockPreference get locking;
|
||||||
@override
|
@override
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
|
|
|
@ -20,20 +20,31 @@ Map<String, dynamic> _$$_LockPreferenceToJson(_$_LockPreference instance) =>
|
||||||
'lock_with_system_lock': instance.lockWithSystemLock,
|
'lock_with_system_lock': instance.lockWithSystemLock,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_$_ThemePreferences _$$_ThemePreferencesFromJson(Map<String, dynamic> json) =>
|
||||||
|
_$_ThemePreferences(
|
||||||
|
brightnessPreference:
|
||||||
|
BrightnessPreference.fromJson(json['brightness_preference']),
|
||||||
|
colorPreference: ColorPreference.fromJson(json['color_preference']),
|
||||||
|
displayScale: (json['display_scale'] as num).toDouble(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$$_ThemePreferencesToJson(_$_ThemePreferences instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'brightness_preference': instance.brightnessPreference.toJson(),
|
||||||
|
'color_preference': instance.colorPreference.toJson(),
|
||||||
|
'display_scale': instance.displayScale,
|
||||||
|
};
|
||||||
|
|
||||||
_$_Preferences _$$_PreferencesFromJson(Map<String, dynamic> json) =>
|
_$_Preferences _$$_PreferencesFromJson(Map<String, dynamic> json) =>
|
||||||
_$_Preferences(
|
_$_Preferences(
|
||||||
darkMode: DarkModePreference.fromJson(json['dark_mode']),
|
themePreferences: ThemePreferences.fromJson(json['theme_preferences']),
|
||||||
themeColor: ColorPreference.fromJson(json['theme_color']),
|
|
||||||
language: LanguagePreference.fromJson(json['language']),
|
language: LanguagePreference.fromJson(json['language']),
|
||||||
displayScale: json['display_scale'] as int,
|
|
||||||
locking: LockPreference.fromJson(json['locking']),
|
locking: LockPreference.fromJson(json['locking']),
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$$_PreferencesToJson(_$_Preferences instance) =>
|
Map<String, dynamic> _$$_PreferencesToJson(_$_Preferences instance) =>
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
'dark_mode': instance.darkMode.toJson(),
|
'theme_preferences': instance.themePreferences.toJson(),
|
||||||
'theme_color': instance.themeColor.toJson(),
|
|
||||||
'language': instance.language.toJson(),
|
'language': instance.language.toJson(),
|
||||||
'display_scale': instance.displayScale,
|
|
||||||
'locking': instance.locking.toJson(),
|
'locking': instance.locking.toJson(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,10 +6,10 @@ 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:flutter_translate/flutter_translate.dart';
|
||||||
|
|
||||||
import '../tools/desktop_control.dart';
|
|
||||||
import 'app.dart';
|
import 'app.dart';
|
||||||
import 'log/log.dart';
|
import 'log/log.dart';
|
||||||
import 'theming/theming.dart';
|
import 'providers/window_control.dart';
|
||||||
|
import 'tools/theme_service.dart';
|
||||||
import 'veilid_support/veilid_support.dart';
|
import 'veilid_support/veilid_support.dart';
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
|
@ -32,7 +32,7 @@ void main() async {
|
||||||
final initTheme = themeService.initial;
|
final initTheme = themeService.initial;
|
||||||
|
|
||||||
// Manage window on desktop platforms
|
// Manage window on desktop platforms
|
||||||
await setupDesktopWindow();
|
await WindowControl.initialize();
|
||||||
|
|
||||||
// Make localization delegate
|
// Make localization delegate
|
||||||
final delegate = await LocalizationDelegate.create(
|
final delegate = await LocalizationDelegate.create(
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/scheduler.dart';
|
|
||||||
import 'package:flutter_animate/flutter_animate.dart';
|
import 'package:flutter_animate/flutter_animate.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:multi_split_view/multi_split_view.dart';
|
||||||
import 'package:signal_strength_indicator/signal_strength_indicator.dart';
|
import 'package:signal_strength_indicator/signal_strength_indicator.dart';
|
||||||
|
|
||||||
|
import '../components/chat.dart';
|
||||||
|
import '../components/chat_list.dart';
|
||||||
|
import '../providers/window_control.dart';
|
||||||
import '../tools/tools.dart';
|
import '../tools/tools.dart';
|
||||||
|
import 'main_pager/main_pager.dart';
|
||||||
|
|
||||||
class HomePage extends ConsumerStatefulWidget {
|
class HomePage extends ConsumerStatefulWidget {
|
||||||
const HomePage({super.key});
|
const HomePage({super.key});
|
||||||
|
@ -17,6 +21,9 @@ class HomePage extends ConsumerStatefulWidget {
|
||||||
class HomePageState extends ConsumerState<HomePage>
|
class HomePageState extends ConsumerState<HomePage>
|
||||||
with TickerProviderStateMixin {
|
with TickerProviderStateMixin {
|
||||||
final _unfocusNode = FocusNode();
|
final _unfocusNode = FocusNode();
|
||||||
|
|
||||||
|
final MultiSplitViewController _splitController = MultiSplitViewController(
|
||||||
|
areas: [Area(minimalSize: 300, weight: 0.25), Area(minimalSize: 300)]);
|
||||||
final scaffoldKey = GlobalKey<ScaffoldState>();
|
final scaffoldKey = GlobalKey<ScaffoldState>();
|
||||||
bool hasContainerTriggered = false;
|
bool hasContainerTriggered = false;
|
||||||
final animationsMap = {
|
final animationsMap = {
|
||||||
|
@ -38,12 +45,6 @@ class HomePageState extends ConsumerState<HomePage>
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
// // On page load action.
|
|
||||||
// SchedulerBinding.instance.addPostFrameCallback((_) async {
|
|
||||||
// await actions.initialize(
|
|
||||||
// context,
|
|
||||||
// );
|
|
||||||
// });
|
|
||||||
|
|
||||||
setupAnimations(
|
setupAnimations(
|
||||||
animationsMap.values.where((anim) =>
|
animationsMap.values.where((anim) =>
|
||||||
|
@ -52,7 +53,11 @@ class HomePageState extends ConsumerState<HomePage>
|
||||||
this,
|
this,
|
||||||
);
|
);
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) => setState(() {}));
|
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||||
|
setState(() {});
|
||||||
|
await ref.read(windowControlProvider.notifier).changeWindowSetup(
|
||||||
|
TitleBarStyle.normal, OrientationCapability.normal);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -61,250 +66,66 @@ class HomePageState extends ConsumerState<HomePage>
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ignore: prefer_expression_function_bodies
|
||||||
|
Widget buildPhone(BuildContext context) {
|
||||||
|
//
|
||||||
|
return Material(
|
||||||
|
color: Colors.transparent, elevation: 4, child: MainPager());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ignore: prefer_expression_function_bodies
|
||||||
|
Widget buildTabletLeftPane(BuildContext context) {
|
||||||
|
//
|
||||||
|
return Material(
|
||||||
|
color: Colors.transparent, elevation: 4, child: MainPager());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ignore: prefer_expression_function_bodies
|
||||||
|
Widget buildTabletRightPane(BuildContext context) {
|
||||||
|
//
|
||||||
|
return Chat();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ignore: prefer_expression_function_bodies
|
||||||
|
Widget buildTablet(BuildContext context) {
|
||||||
|
final children = [
|
||||||
|
buildTabletLeftPane(context),
|
||||||
|
buildTabletRightPane(context),
|
||||||
|
];
|
||||||
|
|
||||||
|
final multiSplitView = MultiSplitView(
|
||||||
|
// onWeightChange: _onWeightChange,
|
||||||
|
// onDividerTap: _onDividerTap,
|
||||||
|
// onDividerDoubleTap: _onDividerDoubleTap,
|
||||||
|
controller: _splitController,
|
||||||
|
children: children);
|
||||||
|
|
||||||
|
final theme = MultiSplitViewTheme(
|
||||||
|
data: isDesktop
|
||||||
|
? MultiSplitViewThemeData(
|
||||||
|
dividerThickness: 1,
|
||||||
|
dividerPainter: DividerPainters.grooved2(thickness: 1))
|
||||||
|
: MultiSplitViewThemeData(
|
||||||
|
dividerThickness: 3,
|
||||||
|
dividerPainter: DividerPainters.grooved2(thickness: 1)),
|
||||||
|
child: multiSplitView);
|
||||||
|
|
||||||
|
return theme;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => Scaffold(
|
Widget build(BuildContext context) {
|
||||||
key: scaffoldKey,
|
ref.watch(windowControlProvider);
|
||||||
appBar: AppBar(title: const Text('VeilidChat')),
|
|
||||||
body: SafeArea(
|
return SafeArea(
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () => FocusScope.of(context).requestFocus(_unfocusNode),
|
onTap: () => FocusScope.of(context).requestFocus(_unfocusNode),
|
||||||
child: Stack(
|
child: responsiveVisibility(
|
||||||
children: [
|
|
||||||
if (responsiveVisibility(
|
|
||||||
context: context,
|
context: context,
|
||||||
phone: false,
|
phone: false,
|
||||||
))
|
|
||||||
Align(
|
|
||||||
alignment: AlignmentDirectional.centerEnd,
|
|
||||||
child: Container(
|
|
||||||
width: MediaQuery.of(context).size.width * 0.66,
|
|
||||||
height: double.infinity,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Theme.of(context).scaffoldBackgroundColor,
|
|
||||||
),
|
|
||||||
child: Stack(
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
width: double.infinity,
|
|
||||||
height: double.infinity,
|
|
||||||
decoration: const BoxDecoration(),
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.max,
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
width: double.infinity,
|
|
||||||
height: 56,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Theme.of(context).primaryColor,
|
|
||||||
borderRadius: BorderRadius.circular(0),
|
|
||||||
),
|
|
||||||
child: Align(
|
|
||||||
alignment: AlignmentDirectional.centerStart,
|
|
||||||
child: Padding(
|
|
||||||
padding:
|
|
||||||
const EdgeInsetsDirectional.fromSTEB(
|
|
||||||
16, 0, 16, 0),
|
|
||||||
child: Text(
|
|
||||||
"current contact",
|
|
||||||
// getJsonField(
|
|
||||||
// FFAppState().CurrentContact,
|
|
||||||
// r'''$.name''',
|
|
||||||
// ).toString(),
|
|
||||||
textAlign: TextAlign.start,
|
|
||||||
// style: Theme.of(context)
|
|
||||||
// .textTheme....
|
|
||||||
// .override(
|
|
||||||
// fontFamily: 'Noto Sans',
|
|
||||||
// color: FlutterFlowTheme.of(context)
|
|
||||||
// .header,
|
|
||||||
// ),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Container(
|
|
||||||
width: double.infinity,
|
|
||||||
height: 100,
|
|
||||||
decoration: const BoxDecoration(),
|
|
||||||
child: ChatComponentWidget(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// if (FFAppState().CurrentContact == null)
|
|
||||||
// Container(
|
|
||||||
// width: double.infinity,
|
|
||||||
// height: double.infinity,
|
|
||||||
// decoration: const BoxDecoration(),
|
|
||||||
// child: NoContactComponentWidget(),
|
|
||||||
// ),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
).animateOnActionTrigger(
|
|
||||||
animationsMap['containerOnActionTriggerAnimation']!,
|
|
||||||
hasBeenTriggered: hasContainerTriggered),
|
|
||||||
),
|
|
||||||
if (responsiveVisibility(
|
|
||||||
context: context,
|
|
||||||
phone: false,
|
|
||||||
))
|
|
||||||
Material(
|
|
||||||
color: Colors.transparent,
|
|
||||||
elevation: 4,
|
|
||||||
child: Container(
|
|
||||||
width: MediaQuery.of(context).size.width * 0.34,
|
|
||||||
height: double.infinity,
|
|
||||||
constraints: BoxConstraints(
|
|
||||||
maxWidth: MediaQuery.of(context).size.width * 0.34,
|
|
||||||
),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Theme.of(context).scaffoldBackgroundColor,
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
width: double.infinity,
|
|
||||||
height: 56,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Theme.of(context).secondaryHeaderColor,
|
|
||||||
borderRadius: BorderRadius.circular(0),
|
|
||||||
),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsetsDirectional.fromSTEB(
|
|
||||||
16, 8, 16, 8),
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Align(
|
|
||||||
alignment: AlignmentDirectional.centerStart,
|
|
||||||
child: Text(
|
|
||||||
'Contacts',
|
|
||||||
textAlign: TextAlign.start,
|
|
||||||
// style: Theme.of(context).dialogTheme.titleTextStyle
|
|
||||||
// .title2
|
|
||||||
// .override(
|
|
||||||
// fontFamily: 'Noto Sans',
|
|
||||||
// color: FlutterFlowTheme.of(context)
|
|
||||||
// .header,
|
|
||||||
// ),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SignalStrengthIndicator.bars(
|
|
||||||
value: .5, //_signalStrength,
|
|
||||||
size: 50,
|
|
||||||
barCount: 5,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Container(
|
|
||||||
width: double.infinity,
|
|
||||||
height: double.infinity,
|
|
||||||
decoration: const BoxDecoration(
|
|
||||||
boxShadow: [
|
|
||||||
BoxShadow(
|
|
||||||
blurRadius: 0,
|
|
||||||
color: Color(0x33000000),
|
|
||||||
offset: Offset(0, 0),
|
|
||||||
)
|
)
|
||||||
],
|
? buildTablet(context)
|
||||||
),
|
: buildPhone(context),
|
||||||
child: ContactListComponentWidget(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (responsiveVisibility(
|
|
||||||
context: context,
|
|
||||||
tablet: false,
|
|
||||||
tabletLandscape: false,
|
|
||||||
desktop: false,
|
|
||||||
))
|
|
||||||
Material(
|
|
||||||
color: Colors.transparent,
|
|
||||||
elevation: 4,
|
|
||||||
child: Container(
|
|
||||||
width: double.infinity,
|
|
||||||
height: double.infinity,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Theme.of(context).scaffoldBackgroundColor,
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.max,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
width: double.infinity,
|
|
||||||
height: 56,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
//color: Theme.of(context).secondaryColor,
|
|
||||||
borderRadius: BorderRadius.circular(0),
|
|
||||||
),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsetsDirectional.fromSTEB(
|
|
||||||
16, 8, 16, 8),
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.max,
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Align(
|
|
||||||
alignment:
|
|
||||||
const AlignmentDirectional(-1, 0),
|
|
||||||
child: Text(
|
|
||||||
'Contacts',
|
|
||||||
textAlign: TextAlign.start,
|
|
||||||
// style: FlutterFlowTheme.of(context)
|
|
||||||
// .title2
|
|
||||||
// .override(
|
|
||||||
// fontFamily: 'Noto Sans',
|
|
||||||
// color: FlutterFlowTheme.of(context)
|
|
||||||
// .header,
|
|
||||||
// ),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SignalStrengthIndicator.bars(
|
|
||||||
value: .5, //_signalStrength,
|
|
||||||
size: 50,
|
|
||||||
barCount: 5,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Container(
|
|
||||||
width: double.infinity,
|
|
||||||
height: double.infinity,
|
|
||||||
decoration: const BoxDecoration(
|
|
||||||
boxShadow: [
|
|
||||||
BoxShadow(
|
|
||||||
blurRadius: 0,
|
|
||||||
color: Color(0x33000000),
|
|
||||||
offset: Offset(0, 0),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
child: ContactListComponentWidget(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:radix_colors/radix_colors.dart';
|
import 'package:radix_colors/radix_colors.dart';
|
||||||
|
|
||||||
import '../tools/desktop_control.dart';
|
import '../providers/window_control.dart';
|
||||||
|
|
||||||
class IndexPage extends StatelessWidget {
|
class IndexPage extends ConsumerWidget {
|
||||||
const IndexPage({super.key});
|
const IndexPage({super.key});
|
||||||
static const path = '/';
|
static const path = '/';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
enableTitleBar(false);
|
ref.watch(windowControlProvider);
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: DecoratedBox(
|
body: DecoratedBox(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
|
|
126
lib/pages/main_pager/account_page.dart
Normal file
126
lib/pages/main_pager/account_page.dart
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_animate/flutter_animate.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:flutter_translate/flutter_translate.dart';
|
||||||
|
import 'package:veilid/veilid.dart';
|
||||||
|
|
||||||
|
import '../../components/profile.dart';
|
||||||
|
import '../../entities/local_account.dart';
|
||||||
|
import '../../entities/proto.dart' as proto;
|
||||||
|
import '../../providers/account.dart';
|
||||||
|
import '../../providers/local_accounts.dart';
|
||||||
|
import '../../providers/logins.dart';
|
||||||
|
import '../../tools/tools.dart';
|
||||||
|
|
||||||
|
class AccountPage extends ConsumerStatefulWidget {
|
||||||
|
const AccountPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
AccountPageState createState() => AccountPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class AccountPageState extends ConsumerState<AccountPage> {
|
||||||
|
final _unfocusNode = FocusNode();
|
||||||
|
TypedKey? _selectedAccount;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_selectedAccount = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_unfocusNode.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
// ignore: prefer_expression_function_bodies
|
||||||
|
Widget buildAccountList(BuildContext context) {
|
||||||
|
return Center(child: Text("account list"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget buildUnlockAccount(
|
||||||
|
BuildContext context,
|
||||||
|
IList<LocalAccount> localAccounts,
|
||||||
|
// ignore: prefer_expression_function_bodies
|
||||||
|
) {
|
||||||
|
return Center(child: Text("unlock account"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget buildUserAccount(
|
||||||
|
BuildContext context,
|
||||||
|
IList<LocalAccount> localAccounts,
|
||||||
|
TypedKey activeUserLogin,
|
||||||
|
proto.Account account,
|
||||||
|
// ignore: prefer_expression_function_bodies
|
||||||
|
) {
|
||||||
|
return ProfileWidget(
|
||||||
|
name: account.profile.name, title: account.profile.title);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
// ignore: prefer_expression_function_bodies
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final localAccountsV = ref.watch(localAccountsProvider);
|
||||||
|
final loginsV = ref.watch(loginsProvider);
|
||||||
|
|
||||||
|
if (!localAccountsV.hasValue || !loginsV.hasValue) {
|
||||||
|
return waitingPage(context);
|
||||||
|
}
|
||||||
|
final localAccounts = localAccountsV.requireValue;
|
||||||
|
final logins = loginsV.requireValue;
|
||||||
|
|
||||||
|
final activeUserLogin = logins.activeUserLogin;
|
||||||
|
if (activeUserLogin == null) {
|
||||||
|
// If no logged in user is active, show the list of account
|
||||||
|
return buildAccountList(context);
|
||||||
|
}
|
||||||
|
final accountV = ref
|
||||||
|
.watch(fetchAccountProvider(accountMasterRecordKey: activeUserLogin));
|
||||||
|
if (!accountV.hasValue) {
|
||||||
|
return waitingPage(context);
|
||||||
|
}
|
||||||
|
final account = accountV.requireValue;
|
||||||
|
switch (account.status) {
|
||||||
|
case AccountInfoStatus.noAccount:
|
||||||
|
Future.delayed(0.ms, () async {
|
||||||
|
await showErrorModal(
|
||||||
|
context,
|
||||||
|
translate('account_page.missing_account_title'),
|
||||||
|
translate('account_page.missing_account_text'));
|
||||||
|
// Delete account
|
||||||
|
await ref
|
||||||
|
.read(localAccountsProvider.notifier)
|
||||||
|
.deleteAccount(activeUserLogin);
|
||||||
|
});
|
||||||
|
return waitingPage(context);
|
||||||
|
case AccountInfoStatus.accountInvalid:
|
||||||
|
Future.delayed(0.ms, () async {
|
||||||
|
await showErrorModal(
|
||||||
|
context,
|
||||||
|
translate('account_page.invalid_account_title'),
|
||||||
|
translate('account_page.invalid_account_text'));
|
||||||
|
// Delete account
|
||||||
|
await ref
|
||||||
|
.read(localAccountsProvider.notifier)
|
||||||
|
.deleteAccount(activeUserLogin);
|
||||||
|
});
|
||||||
|
return waitingPage(context);
|
||||||
|
case AccountInfoStatus.accountLocked:
|
||||||
|
// Show unlock widget
|
||||||
|
return buildUnlockAccount(context, localAccounts);
|
||||||
|
case AccountInfoStatus.accountReady:
|
||||||
|
return buildUserAccount(
|
||||||
|
context,
|
||||||
|
localAccounts,
|
||||||
|
activeUserLogin,
|
||||||
|
account.account!,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
lib/pages/main_pager/chats_page.dart
Normal file
30
lib/pages/main_pager/chats_page.dart
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
|
class ChatsPage extends ConsumerStatefulWidget {
|
||||||
|
const ChatsPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
ChatsPageState createState() => ChatsPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChatsPageState extends ConsumerState<ChatsPage> {
|
||||||
|
final _unfocusNode = FocusNode();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_unfocusNode.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
// ignore: prefer_expression_function_bodies
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Center(child: Text("Conversations Page"));
|
||||||
|
}
|
||||||
|
}
|
30
lib/pages/main_pager/contacts_page.dart
Normal file
30
lib/pages/main_pager/contacts_page.dart
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
|
class ContactsPage extends ConsumerStatefulWidget {
|
||||||
|
const ContactsPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
ContactsPageState createState() => ContactsPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class ContactsPageState extends ConsumerState<ContactsPage> {
|
||||||
|
final _unfocusNode = FocusNode();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_unfocusNode.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
// ignore: prefer_expression_function_bodies
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Center(child: Text("Contacts Page"));
|
||||||
|
}
|
||||||
|
}
|
180
lib/pages/main_pager/main_pager.dart
Normal file
180
lib/pages/main_pager/main_pager.dart
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/rendering.dart';
|
||||||
|
import 'package:flutter_animate/flutter_animate.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:flutter_translate/flutter_translate.dart';
|
||||||
|
import 'package:stylish_bottom_bar/model/bar_items.dart';
|
||||||
|
import 'package:stylish_bottom_bar/stylish_bottom_bar.dart';
|
||||||
|
|
||||||
|
import 'account_page.dart';
|
||||||
|
import 'contacts_page.dart';
|
||||||
|
import 'chats_page.dart';
|
||||||
|
|
||||||
|
class MainPager extends ConsumerStatefulWidget {
|
||||||
|
const MainPager({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
MainPagerState createState() => MainPagerState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class MainPagerState extends ConsumerState<MainPager>
|
||||||
|
with TickerProviderStateMixin {
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
final _unfocusNode = FocusNode();
|
||||||
|
|
||||||
|
final _pageController = PageController();
|
||||||
|
var _currentPage = 0;
|
||||||
|
|
||||||
|
final _selectedIconList = <IconData>[
|
||||||
|
Icons.chat,
|
||||||
|
Icons.contacts,
|
||||||
|
Icons.person
|
||||||
|
];
|
||||||
|
// final _unselectedIconList = <IconData>[
|
||||||
|
// Icons.chat_outlined,
|
||||||
|
// Icons.contacts_outlined,
|
||||||
|
// Icons.person_outlined
|
||||||
|
// ];
|
||||||
|
final _fabIconList = <IconData>[
|
||||||
|
Icons.add_comment_sharp,
|
||||||
|
Icons.person_add_sharp,
|
||||||
|
Icons.settings_sharp,
|
||||||
|
];
|
||||||
|
final _labelList = <String>[
|
||||||
|
translate('pager.chats'),
|
||||||
|
translate('pager.contacts'),
|
||||||
|
translate('pager.account'),
|
||||||
|
];
|
||||||
|
final List<Widget> _bottomBarPages = [
|
||||||
|
const ChatsPage(),
|
||||||
|
const ContactsPage(),
|
||||||
|
const AccountPage(),
|
||||||
|
];
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_unfocusNode.dispose();
|
||||||
|
_pageController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool onScrollNotification(ScrollNotification notification) {
|
||||||
|
if (notification is UserScrollNotification &&
|
||||||
|
notification.metrics.axis == Axis.vertical) {
|
||||||
|
switch (notification.direction) {
|
||||||
|
case ScrollDirection.forward:
|
||||||
|
// _hideBottomBarAnimationController.reverse();
|
||||||
|
// _fabAnimationController.forward(from: 0);
|
||||||
|
break;
|
||||||
|
case ScrollDirection.reverse:
|
||||||
|
// _hideBottomBarAnimationController.forward();
|
||||||
|
// _fabAnimationController.reverse(from: 1);
|
||||||
|
break;
|
||||||
|
case ScrollDirection.idle:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BottomBarItem buildBottomBarItem(int index) {
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
return BottomBarItem(
|
||||||
|
title: Text(_labelList[index]),
|
||||||
|
icon: Icon(_selectedIconList[index],
|
||||||
|
color: theme.colorScheme.onPrimaryContainer),
|
||||||
|
selectedIcon: Icon(_selectedIconList[index],
|
||||||
|
color: theme.colorScheme.onPrimaryContainer),
|
||||||
|
backgroundColor: theme.colorScheme.onPrimaryContainer,
|
||||||
|
//unSelectedColor: theme.colorScheme.primaryContainer,
|
||||||
|
//selectedColor: theme.colorScheme.primary,
|
||||||
|
//badge: const Text('9+'),
|
||||||
|
//showBadge: true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<BottomBarItem> _buildBottomBarItems() {
|
||||||
|
final bottomBarItems = List<BottomBarItem>.empty(growable: true);
|
||||||
|
for (var index = 0; index < _bottomBarPages.length; index++) {
|
||||||
|
final item = buildBottomBarItem(index);
|
||||||
|
bottomBarItems.add(item);
|
||||||
|
}
|
||||||
|
return bottomBarItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
// ignore: prefer_expression_function_bodies
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
return Scaffold(
|
||||||
|
extendBody: true,
|
||||||
|
body: NotificationListener<ScrollNotification>(
|
||||||
|
onNotification: onScrollNotification,
|
||||||
|
child: PageView(
|
||||||
|
controller: _pageController,
|
||||||
|
//physics: const NeverScrollableScrollPhysics(),
|
||||||
|
children: List.generate(
|
||||||
|
_bottomBarPages.length, (index) => _bottomBarPages[index]),
|
||||||
|
)),
|
||||||
|
// appBar: AppBar(
|
||||||
|
// toolbarHeight: 24,
|
||||||
|
// title: Text(
|
||||||
|
// 'C',
|
||||||
|
// style: Theme.of(context).textTheme.headlineSmall,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
bottomNavigationBar: StylishBottomBar(
|
||||||
|
backgroundColor: theme.colorScheme.primaryContainer,
|
||||||
|
// gradient: LinearGradient(
|
||||||
|
// begin: Alignment.topCenter,
|
||||||
|
// end: Alignment.bottomCenter,
|
||||||
|
// colors: <Color>[
|
||||||
|
// theme.colorScheme.primary,
|
||||||
|
// theme.colorScheme.primaryContainer,
|
||||||
|
// ]),
|
||||||
|
option: AnimatedBarOptions(
|
||||||
|
// iconSize: 32,
|
||||||
|
//barAnimation: BarAnimation.fade,
|
||||||
|
iconStyle: IconStyle.animated,
|
||||||
|
inkEffect: true,
|
||||||
|
inkColor: theme.colorScheme.primary,
|
||||||
|
//opacity: 0.3,
|
||||||
|
),
|
||||||
|
items: _buildBottomBarItems(),
|
||||||
|
hasNotch: true,
|
||||||
|
fabLocation: StylishBarFabLocation.end,
|
||||||
|
currentIndex: _currentPage,
|
||||||
|
onTap: (index) async {
|
||||||
|
await _pageController.animateToPage(index,
|
||||||
|
duration: 250.ms, curve: Curves.bounceOut);
|
||||||
|
setState(() {
|
||||||
|
_currentPage = index;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
|
||||||
|
floatingActionButton: FloatingActionButton(
|
||||||
|
shape: const RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(14))),
|
||||||
|
//foregroundColor: theme.colorScheme.secondary,
|
||||||
|
backgroundColor: theme.colorScheme.secondaryContainer,
|
||||||
|
child: Icon(
|
||||||
|
_fabIconList[_currentPage],
|
||||||
|
color: theme.colorScheme.onSecondaryContainer,
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
// xxx
|
||||||
|
},
|
||||||
|
),
|
||||||
|
floatingActionButtonLocation: FloatingActionButtonLocation.endDocked,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ import '../components/default_app_bar.dart';
|
||||||
import '../entities/proto.dart' as proto;
|
import '../entities/proto.dart' as proto;
|
||||||
import '../providers/local_accounts.dart';
|
import '../providers/local_accounts.dart';
|
||||||
import '../providers/logins.dart';
|
import '../providers/logins.dart';
|
||||||
|
import '../providers/window_control.dart';
|
||||||
import '../tools/tools.dart';
|
import '../tools/tools.dart';
|
||||||
import '../veilid_support/veilid_support.dart';
|
import '../veilid_support/veilid_support.dart';
|
||||||
|
|
||||||
|
@ -111,8 +112,7 @@ class NewAccountPageState extends ConsumerState<NewAccountPage> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
enableTitleBar(true);
|
ref.watch(windowControlProvider);
|
||||||
portraitOnly();
|
|
||||||
|
|
||||||
final localAccounts = ref.watch(localAccountsProvider);
|
final localAccounts = ref.watch(localAccountsProvider);
|
||||||
final logins = ref.watch(loginsProvider);
|
final logins = ref.watch(loginsProvider);
|
||||||
|
@ -132,15 +132,8 @@ class NewAccountPageState extends ConsumerState<NewAccountPage> {
|
||||||
try {
|
try {
|
||||||
await createAccount();
|
await createAccount();
|
||||||
} on Exception catch (e) {
|
} on Exception catch (e) {
|
||||||
await QuickAlert.show(
|
await showErrorModal(
|
||||||
context: context,
|
context, translate('new_account_page.error'), 'Exception: $e');
|
||||||
type: QuickAlertType.error,
|
|
||||||
title: translate('new_account_page.error'),
|
|
||||||
text: 'Exception: $e',
|
|
||||||
//backgroundColor: Colors.black,
|
|
||||||
//titleColor: Colors.white,
|
|
||||||
//textColor: Colors.white,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
).paddingSymmetric(horizontal: 24, vertical: 8),
|
).paddingSymmetric(horizontal: 24, vertical: 8),
|
||||||
|
|
112
lib/providers/account.dart
Normal file
112
lib/providers/account.dart
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
import 'package:veilid/veilid.dart';
|
||||||
|
|
||||||
|
import '../entities/entities.dart';
|
||||||
|
import '../entities/proto.dart' as proto;
|
||||||
|
import '../veilid_support/veilid_support.dart';
|
||||||
|
|
||||||
|
import 'local_accounts.dart';
|
||||||
|
import 'logins.dart';
|
||||||
|
|
||||||
|
part 'account.g.dart';
|
||||||
|
|
||||||
|
enum AccountInfoStatus {
|
||||||
|
noAccount,
|
||||||
|
accountInvalid,
|
||||||
|
accountLocked,
|
||||||
|
accountReady,
|
||||||
|
}
|
||||||
|
|
||||||
|
class AccountInfo {
|
||||||
|
AccountInfo({
|
||||||
|
required this.status,
|
||||||
|
required this.active,
|
||||||
|
this.account,
|
||||||
|
});
|
||||||
|
|
||||||
|
AccountInfoStatus status;
|
||||||
|
bool active;
|
||||||
|
proto.Account? account;
|
||||||
|
}
|
||||||
|
|
||||||
|
@riverpod
|
||||||
|
Future<AccountInfo> fetchAccount(FetchAccountRef ref,
|
||||||
|
{required TypedKey accountMasterRecordKey}) async {
|
||||||
|
// Get which local account we want to fetch the profile for
|
||||||
|
final veilid = await eventualVeilid.future;
|
||||||
|
final localAccount = await ref.watch(
|
||||||
|
fetchLocalAccountProvider(accountMasterRecordKey: accountMasterRecordKey)
|
||||||
|
.future);
|
||||||
|
if (localAccount == null) {
|
||||||
|
// Local account does not exist
|
||||||
|
return AccountInfo(status: AccountInfoStatus.noAccount, active: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// See if we've logged into this account or if it is locked
|
||||||
|
final activeUserLogin = await ref.watch(loginsProvider.future
|
||||||
|
.select((value) async => (await value).activeUserLogin));
|
||||||
|
final active = activeUserLogin == accountMasterRecordKey;
|
||||||
|
|
||||||
|
final login = await ref.watch(
|
||||||
|
fetchLoginProvider(accountMasterRecordKey: accountMasterRecordKey)
|
||||||
|
.future);
|
||||||
|
if (login == null) {
|
||||||
|
// Account was locked
|
||||||
|
return AccountInfo(status: AccountInfoStatus.accountLocked, active: active);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the identity key to get the account keys
|
||||||
|
final dhtctx = (await veilid.routingContext())
|
||||||
|
.withPrivacy()
|
||||||
|
.withSequencing(Sequencing.ensureOrdered);
|
||||||
|
final identityRecordCrypto = await DHTRecordCryptoPrivate.fromSecret(
|
||||||
|
localAccount.identityMaster.identityRecordKey.kind,
|
||||||
|
login.identitySecret.value);
|
||||||
|
|
||||||
|
late final TypedKey accountRecordKey;
|
||||||
|
late final KeyPair accountRecordOwner;
|
||||||
|
|
||||||
|
await (await DHTRecord.openRead(
|
||||||
|
dhtctx, localAccount.identityMaster.identityRecordKey,
|
||||||
|
crypto: identityRecordCrypto))
|
||||||
|
.scope((identityRec) async {
|
||||||
|
final identity = await identityRec.getJson(Identity.fromJson);
|
||||||
|
if (identity == null) {
|
||||||
|
// Identity could not be read or decrypted from DHT
|
||||||
|
return AccountInfo(
|
||||||
|
status: AccountInfoStatus.accountInvalid, active: active);
|
||||||
|
}
|
||||||
|
final accountRecords = IMapOfSets.from(identity.accountRecords);
|
||||||
|
final vcAccounts = accountRecords.get(veilidChatAccountKey);
|
||||||
|
if (vcAccounts.length != 1) {
|
||||||
|
// No veilidchat account, or multiple accounts
|
||||||
|
// somehow associated with identity
|
||||||
|
return AccountInfo(
|
||||||
|
status: AccountInfoStatus.accountInvalid, active: active);
|
||||||
|
}
|
||||||
|
final accountRecordInfo = vcAccounts.first;
|
||||||
|
accountRecordKey = accountRecordInfo.key;
|
||||||
|
accountRecordOwner = accountRecordInfo.owner;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Pull the account DHT key, decode it and return it
|
||||||
|
final accountRecordCrypto = await DHTRecordCryptoPrivate.fromSecret(
|
||||||
|
accountRecordKey.kind, accountRecordOwner.secret);
|
||||||
|
late final proto.Account account;
|
||||||
|
await (await DHTRecord.openRead(dhtctx, accountRecordKey,
|
||||||
|
crypto: accountRecordCrypto))
|
||||||
|
.scope((accountRec) async {
|
||||||
|
final protoAccount = await accountRec.getProtobuf(proto.Account.fromBuffer);
|
||||||
|
if (protoAccount == null) {
|
||||||
|
// Account could not be read or decrypted from DHT
|
||||||
|
return AccountInfo(
|
||||||
|
status: AccountInfoStatus.accountInvalid, active: active);
|
||||||
|
}
|
||||||
|
account = protoAccount;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Got account, decrypted and decoded
|
||||||
|
return AccountInfo(
|
||||||
|
status: AccountInfoStatus.accountReady, active: active, account: account);
|
||||||
|
}
|
113
lib/providers/account.g.dart
Normal file
113
lib/providers/account.g.dart
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'account.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
String _$fetchAccountHash() => r'4d94703d07a21509650e19f60ea67ac96a39742e';
|
||||||
|
|
||||||
|
/// Copied from Dart SDK
|
||||||
|
class _SystemHash {
|
||||||
|
_SystemHash._();
|
||||||
|
|
||||||
|
static int combine(int hash, int value) {
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = 0x1fffffff & (hash + value);
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
||||||
|
return hash ^ (hash >> 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int finish(int hash) {
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = hash ^ (hash >> 11);
|
||||||
|
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef FetchAccountRef = AutoDisposeFutureProviderRef<AccountInfo>;
|
||||||
|
|
||||||
|
/// See also [fetchAccount].
|
||||||
|
@ProviderFor(fetchAccount)
|
||||||
|
const fetchAccountProvider = FetchAccountFamily();
|
||||||
|
|
||||||
|
/// See also [fetchAccount].
|
||||||
|
class FetchAccountFamily extends Family<AsyncValue<AccountInfo>> {
|
||||||
|
/// See also [fetchAccount].
|
||||||
|
const FetchAccountFamily();
|
||||||
|
|
||||||
|
/// See also [fetchAccount].
|
||||||
|
FetchAccountProvider call({
|
||||||
|
required Typed<FixedEncodedString43> accountMasterRecordKey,
|
||||||
|
}) {
|
||||||
|
return FetchAccountProvider(
|
||||||
|
accountMasterRecordKey: accountMasterRecordKey,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
FetchAccountProvider getProviderOverride(
|
||||||
|
covariant FetchAccountProvider provider,
|
||||||
|
) {
|
||||||
|
return call(
|
||||||
|
accountMasterRecordKey: provider.accountMasterRecordKey,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||||
|
|
||||||
|
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||||
|
_allTransitiveDependencies;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? get name => r'fetchAccountProvider';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [fetchAccount].
|
||||||
|
class FetchAccountProvider extends AutoDisposeFutureProvider<AccountInfo> {
|
||||||
|
/// See also [fetchAccount].
|
||||||
|
FetchAccountProvider({
|
||||||
|
required this.accountMasterRecordKey,
|
||||||
|
}) : super.internal(
|
||||||
|
(ref) => fetchAccount(
|
||||||
|
ref,
|
||||||
|
accountMasterRecordKey: accountMasterRecordKey,
|
||||||
|
),
|
||||||
|
from: fetchAccountProvider,
|
||||||
|
name: r'fetchAccountProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$fetchAccountHash,
|
||||||
|
dependencies: FetchAccountFamily._dependencies,
|
||||||
|
allTransitiveDependencies:
|
||||||
|
FetchAccountFamily._allTransitiveDependencies,
|
||||||
|
);
|
||||||
|
|
||||||
|
final Typed<FixedEncodedString43> accountMasterRecordKey;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return other is FetchAccountProvider &&
|
||||||
|
other.accountMasterRecordKey == accountMasterRecordKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||||
|
hash = _SystemHash.combine(hash, accountMasterRecordKey.hashCode);
|
||||||
|
|
||||||
|
return _SystemHash.finish(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 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
|
|
@ -14,6 +14,8 @@ import 'logins.dart';
|
||||||
|
|
||||||
part 'local_accounts.g.dart';
|
part 'local_accounts.g.dart';
|
||||||
|
|
||||||
|
const String veilidChatAccountKey = 'com.veilid.veilidchat';
|
||||||
|
|
||||||
// Local account manager
|
// Local account manager
|
||||||
@riverpod
|
@riverpod
|
||||||
class LocalAccounts extends _$LocalAccounts
|
class LocalAccounts extends _$LocalAccounts
|
||||||
|
@ -90,6 +92,7 @@ class LocalAccounts extends _$LocalAccounts
|
||||||
encryptionKeyType: encryptionKeyType,
|
encryptionKeyType: encryptionKeyType,
|
||||||
biometricsEnabled: false,
|
biometricsEnabled: false,
|
||||||
hiddenAccount: false,
|
hiddenAccount: false,
|
||||||
|
name: account.profile.name,
|
||||||
);
|
);
|
||||||
|
|
||||||
/////// Add account with profile to DHT
|
/////// Add account with profile to DHT
|
||||||
|
@ -114,8 +117,14 @@ class LocalAccounts extends _$LocalAccounts
|
||||||
|
|
||||||
await identityRec.eventualUpdateJson(Identity.fromJson,
|
await identityRec.eventualUpdateJson(Identity.fromJson,
|
||||||
(oldIdentity) async {
|
(oldIdentity) async {
|
||||||
final accountRecords = IMapOfSets.from(oldIdentity.accountRecords)
|
final oldAccountRecords = IMapOfSets.from(oldIdentity.accountRecords);
|
||||||
.add('com.veilid.veilidchat', newAccountRecordInfo)
|
// Only allow one account per identity for veilidchat
|
||||||
|
if (oldAccountRecords.get(veilidChatAccountKey).isNotEmpty) {
|
||||||
|
throw StateError(
|
||||||
|
'Only one account per identity allowed for VeilidChat');
|
||||||
|
}
|
||||||
|
final accountRecords = oldAccountRecords
|
||||||
|
.add(veilidChatAccountKey, newAccountRecordInfo)
|
||||||
.asIMap();
|
.asIMap();
|
||||||
return oldIdentity.copyWith(accountRecords: accountRecords);
|
return oldIdentity.copyWith(accountRecords: accountRecords);
|
||||||
});
|
});
|
||||||
|
@ -151,3 +160,18 @@ class LocalAccounts extends _$LocalAccounts
|
||||||
|
|
||||||
/// Recover an account with the master identity secret
|
/// Recover an account with the master identity secret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@riverpod
|
||||||
|
Future<LocalAccount?> fetchLocalAccount(FetchLocalAccountRef ref,
|
||||||
|
{required TypedKey accountMasterRecordKey}) async {
|
||||||
|
final localAccounts = await ref.watch(localAccountsProvider.future);
|
||||||
|
try {
|
||||||
|
return localAccounts.firstWhere(
|
||||||
|
(e) => e.identityMaster.masterRecordKey == accountMasterRecordKey);
|
||||||
|
} on Exception catch (e) {
|
||||||
|
if (e is StateError) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6,7 +6,113 @@ part of 'local_accounts.dart';
|
||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$localAccountsHash() => r'f69de269e15fabb83d1afbb7fdb6eb7693d0ce24';
|
String _$fetchLocalAccountHash() => r'e9f8ea0dd15031cc8145532e9cac73ab7f0f81be';
|
||||||
|
|
||||||
|
/// Copied from Dart SDK
|
||||||
|
class _SystemHash {
|
||||||
|
_SystemHash._();
|
||||||
|
|
||||||
|
static int combine(int hash, int value) {
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = 0x1fffffff & (hash + value);
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
||||||
|
return hash ^ (hash >> 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int finish(int hash) {
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = hash ^ (hash >> 11);
|
||||||
|
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef FetchLocalAccountRef = AutoDisposeFutureProviderRef<LocalAccount?>;
|
||||||
|
|
||||||
|
/// See also [fetchLocalAccount].
|
||||||
|
@ProviderFor(fetchLocalAccount)
|
||||||
|
const fetchLocalAccountProvider = FetchLocalAccountFamily();
|
||||||
|
|
||||||
|
/// See also [fetchLocalAccount].
|
||||||
|
class FetchLocalAccountFamily extends Family<AsyncValue<LocalAccount?>> {
|
||||||
|
/// See also [fetchLocalAccount].
|
||||||
|
const FetchLocalAccountFamily();
|
||||||
|
|
||||||
|
/// See also [fetchLocalAccount].
|
||||||
|
FetchLocalAccountProvider call({
|
||||||
|
required Typed<FixedEncodedString43> accountMasterRecordKey,
|
||||||
|
}) {
|
||||||
|
return FetchLocalAccountProvider(
|
||||||
|
accountMasterRecordKey: accountMasterRecordKey,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
FetchLocalAccountProvider getProviderOverride(
|
||||||
|
covariant FetchLocalAccountProvider provider,
|
||||||
|
) {
|
||||||
|
return call(
|
||||||
|
accountMasterRecordKey: provider.accountMasterRecordKey,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||||
|
|
||||||
|
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||||
|
_allTransitiveDependencies;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? get name => r'fetchLocalAccountProvider';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [fetchLocalAccount].
|
||||||
|
class FetchLocalAccountProvider
|
||||||
|
extends AutoDisposeFutureProvider<LocalAccount?> {
|
||||||
|
/// See also [fetchLocalAccount].
|
||||||
|
FetchLocalAccountProvider({
|
||||||
|
required this.accountMasterRecordKey,
|
||||||
|
}) : super.internal(
|
||||||
|
(ref) => fetchLocalAccount(
|
||||||
|
ref,
|
||||||
|
accountMasterRecordKey: accountMasterRecordKey,
|
||||||
|
),
|
||||||
|
from: fetchLocalAccountProvider,
|
||||||
|
name: r'fetchLocalAccountProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$fetchLocalAccountHash,
|
||||||
|
dependencies: FetchLocalAccountFamily._dependencies,
|
||||||
|
allTransitiveDependencies:
|
||||||
|
FetchLocalAccountFamily._allTransitiveDependencies,
|
||||||
|
);
|
||||||
|
|
||||||
|
final Typed<FixedEncodedString43> accountMasterRecordKey;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return other is FetchLocalAccountProvider &&
|
||||||
|
other.accountMasterRecordKey == accountMasterRecordKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||||
|
hash = _SystemHash.combine(hash, accountMasterRecordKey.hashCode);
|
||||||
|
|
||||||
|
return _SystemHash.finish(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _$localAccountsHash() => r'c8214abbc9720449910e74e32fc52d53ca4453c0';
|
||||||
|
|
||||||
/// See also [LocalAccounts].
|
/// See also [LocalAccounts].
|
||||||
@ProviderFor(LocalAccounts)
|
@ProviderFor(LocalAccounts)
|
||||||
|
|
|
@ -163,3 +163,18 @@ class Logins extends _$Logins with AsyncTableDBBacked<ActiveLogins> {
|
||||||
state = AsyncValue.data(updated);
|
state = AsyncValue.data(updated);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@riverpod
|
||||||
|
Future<UserLogin?> fetchLogin(FetchLoginRef ref,
|
||||||
|
{required TypedKey accountMasterRecordKey}) async {
|
||||||
|
final activeLogins = await ref.watch(loginsProvider.future);
|
||||||
|
try {
|
||||||
|
return activeLogins.userLogins
|
||||||
|
.firstWhere((e) => e.accountMasterRecordKey == accountMasterRecordKey);
|
||||||
|
} on Exception catch (e) {
|
||||||
|
if (e is StateError) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,111 @@ part of 'logins.dart';
|
||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
|
String _$fetchLoginHash() => r'cfe13f5152f1275e6eccc698142abfd98170d9b9';
|
||||||
|
|
||||||
|
/// Copied from Dart SDK
|
||||||
|
class _SystemHash {
|
||||||
|
_SystemHash._();
|
||||||
|
|
||||||
|
static int combine(int hash, int value) {
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = 0x1fffffff & (hash + value);
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
||||||
|
return hash ^ (hash >> 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int finish(int hash) {
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = hash ^ (hash >> 11);
|
||||||
|
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef FetchLoginRef = AutoDisposeFutureProviderRef<UserLogin?>;
|
||||||
|
|
||||||
|
/// See also [fetchLogin].
|
||||||
|
@ProviderFor(fetchLogin)
|
||||||
|
const fetchLoginProvider = FetchLoginFamily();
|
||||||
|
|
||||||
|
/// See also [fetchLogin].
|
||||||
|
class FetchLoginFamily extends Family<AsyncValue<UserLogin?>> {
|
||||||
|
/// See also [fetchLogin].
|
||||||
|
const FetchLoginFamily();
|
||||||
|
|
||||||
|
/// See also [fetchLogin].
|
||||||
|
FetchLoginProvider call({
|
||||||
|
required Typed<FixedEncodedString43> accountMasterRecordKey,
|
||||||
|
}) {
|
||||||
|
return FetchLoginProvider(
|
||||||
|
accountMasterRecordKey: accountMasterRecordKey,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
FetchLoginProvider getProviderOverride(
|
||||||
|
covariant FetchLoginProvider provider,
|
||||||
|
) {
|
||||||
|
return call(
|
||||||
|
accountMasterRecordKey: provider.accountMasterRecordKey,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||||
|
|
||||||
|
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||||
|
_allTransitiveDependencies;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? get name => r'fetchLoginProvider';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [fetchLogin].
|
||||||
|
class FetchLoginProvider extends AutoDisposeFutureProvider<UserLogin?> {
|
||||||
|
/// See also [fetchLogin].
|
||||||
|
FetchLoginProvider({
|
||||||
|
required this.accountMasterRecordKey,
|
||||||
|
}) : super.internal(
|
||||||
|
(ref) => fetchLogin(
|
||||||
|
ref,
|
||||||
|
accountMasterRecordKey: accountMasterRecordKey,
|
||||||
|
),
|
||||||
|
from: fetchLoginProvider,
|
||||||
|
name: r'fetchLoginProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$fetchLoginHash,
|
||||||
|
dependencies: FetchLoginFamily._dependencies,
|
||||||
|
allTransitiveDependencies:
|
||||||
|
FetchLoginFamily._allTransitiveDependencies,
|
||||||
|
);
|
||||||
|
|
||||||
|
final Typed<FixedEncodedString43> accountMasterRecordKey;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return other is FetchLoginProvider &&
|
||||||
|
other.accountMasterRecordKey == accountMasterRecordKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||||
|
hash = _SystemHash.combine(hash, accountMasterRecordKey.hashCode);
|
||||||
|
|
||||||
|
return _SystemHash.finish(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String _$loginsHash() => r'ed9dbe91a248f662ccb0fac6edf5b1892cf2ef92';
|
String _$loginsHash() => r'ed9dbe91a248f662ccb0fac6edf5b1892cf2ef92';
|
||||||
|
|
||||||
/// See also [Logins].
|
/// See also [Logins].
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
export 'account_profile.dart';
|
||||||
export 'connection_state.dart';
|
export 'connection_state.dart';
|
||||||
export 'local_accounts.dart';
|
export 'local_accounts.dart';
|
||||||
export 'logins.dart';
|
export 'logins.dart';
|
||||||
|
export 'window_control.dart';
|
||||||
|
|
83
lib/providers/window_control.dart
Normal file
83
lib/providers/window_control.dart
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
import 'package:window_manager/window_manager.dart';
|
||||||
|
|
||||||
|
import '../tools/responsive.dart';
|
||||||
|
|
||||||
|
export 'package:window_manager/window_manager.dart' show TitleBarStyle;
|
||||||
|
|
||||||
|
part 'window_control.g.dart';
|
||||||
|
|
||||||
|
enum OrientationCapability {
|
||||||
|
normal,
|
||||||
|
portraitOnly,
|
||||||
|
landscapeOnly,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Local account manager
|
||||||
|
@riverpod
|
||||||
|
class WindowControl extends _$WindowControl {
|
||||||
|
/// Change window control
|
||||||
|
@override
|
||||||
|
FutureOr<bool> build() async {
|
||||||
|
await _doWindowSetup(TitleBarStyle.hidden, OrientationCapability.normal);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<void> initialize() async {
|
||||||
|
if (isDesktop) {
|
||||||
|
await windowManager.ensureInitialized();
|
||||||
|
|
||||||
|
const windowOptions = WindowOptions(
|
||||||
|
size: Size(768, 1024),
|
||||||
|
//minimumSize: Size(480, 640),
|
||||||
|
center: true,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
skipTaskbar: false,
|
||||||
|
);
|
||||||
|
await windowManager.waitUntilReadyToShow(windowOptions, () async {
|
||||||
|
await windowManager.show();
|
||||||
|
await windowManager.focus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _doWindowSetup(TitleBarStyle titleBarStyle,
|
||||||
|
OrientationCapability orientationCapability) async {
|
||||||
|
if (isDesktop) {
|
||||||
|
await windowManager.setTitleBarStyle(titleBarStyle);
|
||||||
|
} else {
|
||||||
|
switch (orientationCapability) {
|
||||||
|
case OrientationCapability.normal:
|
||||||
|
await SystemChrome.setPreferredOrientations([
|
||||||
|
DeviceOrientation.portraitUp,
|
||||||
|
DeviceOrientation.landscapeLeft,
|
||||||
|
DeviceOrientation.landscapeRight,
|
||||||
|
]);
|
||||||
|
case OrientationCapability.portraitOnly:
|
||||||
|
await SystemChrome.setPreferredOrientations([
|
||||||
|
DeviceOrientation.portraitUp,
|
||||||
|
]);
|
||||||
|
case OrientationCapability.landscapeOnly:
|
||||||
|
await SystemChrome.setPreferredOrientations([
|
||||||
|
DeviceOrientation.landscapeLeft,
|
||||||
|
DeviceOrientation.landscapeRight,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
/// Mutators and Selectors
|
||||||
|
|
||||||
|
/// Reorder accounts
|
||||||
|
Future<void> changeWindowSetup(TitleBarStyle titleBarStyle,
|
||||||
|
OrientationCapability orientationCapability) async {
|
||||||
|
state = const AsyncValue.loading();
|
||||||
|
await _doWindowSetup(titleBarStyle, orientationCapability);
|
||||||
|
state = const AsyncValue.data(true);
|
||||||
|
}
|
||||||
|
}
|
25
lib/providers/window_control.g.dart
Normal file
25
lib/providers/window_control.g.dart
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'window_control.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
String _$windowControlHash() => r'c6afcbe1d4bfcfc580c30393aac60624c5ceabe0';
|
||||||
|
|
||||||
|
/// See also [WindowControl].
|
||||||
|
@ProviderFor(WindowControl)
|
||||||
|
final windowControlProvider =
|
||||||
|
AutoDisposeAsyncNotifierProvider<WindowControl, bool>.internal(
|
||||||
|
WindowControl.new,
|
||||||
|
name: r'windowControlProvider',
|
||||||
|
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$windowControlHash,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef _$WindowControl = AutoDisposeAsyncNotifier<bool>;
|
||||||
|
// 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
|
|
@ -6,7 +6,7 @@ part of 'router_notifier.dart';
|
||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$routerNotifierHash() => r'ef31219dde5e12b2bb224c79ca13ab4f414c81b4';
|
String _$routerNotifierHash() => r'8e7b9debfa144253e25871edf920bf315f28a861';
|
||||||
|
|
||||||
/// See also [RouterNotifier].
|
/// See also [RouterNotifier].
|
||||||
@ProviderFor(RouterNotifier)
|
@ProviderFor(RouterNotifier)
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
|
||||||
import 'themes/themes.dart';
|
|
||||||
|
|
||||||
class ThemeService {
|
|
||||||
ThemeService._();
|
|
||||||
static late SharedPreferences prefs;
|
|
||||||
static ThemeService? _instance;
|
|
||||||
|
|
||||||
static Future<ThemeService> get instance async {
|
|
||||||
if (_instance == null) {
|
|
||||||
prefs = await SharedPreferences.getInstance();
|
|
||||||
_instance = ThemeService._();
|
|
||||||
}
|
|
||||||
return _instance!;
|
|
||||||
}
|
|
||||||
|
|
||||||
final allThemes = <String, ThemeData>{
|
|
||||||
'dark': darkTheme,
|
|
||||||
'light': lightTheme,
|
|
||||||
};
|
|
||||||
|
|
||||||
String get previousThemeName {
|
|
||||||
var themeName = prefs.getString('previousThemeName');
|
|
||||||
if (themeName == null) {
|
|
||||||
final isPlatformDark =
|
|
||||||
WidgetsBinding.instance.platformDispatcher.platformBrightness ==
|
|
||||||
Brightness.dark;
|
|
||||||
themeName = isPlatformDark ? 'dark' : 'light';
|
|
||||||
}
|
|
||||||
return themeName;
|
|
||||||
}
|
|
||||||
|
|
||||||
ThemeData get initial {
|
|
||||||
var themeName = prefs.getString('theme');
|
|
||||||
if (themeName == null) {
|
|
||||||
final isPlatformDark =
|
|
||||||
WidgetsBinding.instance.platformDispatcher.platformBrightness ==
|
|
||||||
Brightness.dark;
|
|
||||||
themeName = isPlatformDark ? 'dark' : 'light';
|
|
||||||
}
|
|
||||||
return allThemes[themeName] ?? allThemes['light']!;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> save(String newThemeName) async {
|
|
||||||
final currentThemeName = prefs.getString('theme');
|
|
||||||
if (currentThemeName != null) {
|
|
||||||
await prefs.setString('previousThemeName', currentThemeName);
|
|
||||||
}
|
|
||||||
await prefs.setString('theme', newThemeName);
|
|
||||||
}
|
|
||||||
|
|
||||||
ThemeData getByName(String name) => allThemes[name]!;
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
ThemeData darkTheme = ThemeData.dark();
|
|
||||||
|
|
||||||
// late Color primaryColor = const Color(0xFF343455);
|
|
||||||
// late Color secondaryColor = const Color(0xFF3D3E77);
|
|
||||||
// late Color tertiaryColor = const Color(0xFFBB108E);
|
|
||||||
// late Color alternate = const Color(0xFF5086DF);
|
|
||||||
// late Color primaryBackground = const Color(0xFF252534);
|
|
||||||
// late Color secondaryBackground = const Color(0xFF292D44);
|
|
||||||
// late Color primaryText = const Color(0xFFD0D0E0);
|
|
||||||
// late Color secondaryText = const Color(0xFFB0B0D0);
|
|
||||||
|
|
||||||
// late Color disabledText = Color(0x808F8F8F);
|
|
||||||
// late Color primaryEdge = Color(0xFF555594);
|
|
||||||
// late Color header = Color(0xFF8A8AD8);
|
|
||||||
// late Color textBackground = Color(0xFF181820);
|
|
||||||
// late Color active = Color(0xFF463BAD);
|
|
||||||
// late Color inactive = Color(0xFF2E2E3C);
|
|
|
@ -1,19 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
ThemeData lightTheme = ThemeData.light();
|
|
||||||
|
|
||||||
// late Color primaryColor = const Color(0xFF6667AB);
|
|
||||||
// late Color secondaryColor = const Color(0xFF7C7ED0);
|
|
||||||
// late Color tertiaryColor = const Color(0xFFF259C9);
|
|
||||||
// late Color alternate = const Color(0xFF77ABFF);
|
|
||||||
// late Color primaryBackground = const Color(0xFFA0A0D0);
|
|
||||||
// late Color secondaryBackground = const Color(0xFFB0B0D0);
|
|
||||||
// late Color primaryText = const Color(0xFF101010);
|
|
||||||
// late Color secondaryText = const Color(0xFF282840);
|
|
||||||
|
|
||||||
// late Color disabledText = Color(0x8047464F);
|
|
||||||
// late Color primaryEdge = Color(0xFF44447F);
|
|
||||||
// late Color header = Color(0xFFE0E0F0);
|
|
||||||
// late Color textBackground = Color(0xFFE0E0F0);
|
|
||||||
// late Color active = Color(0xFF5B4FFA);
|
|
||||||
// late Color inactive = Color(0xFF3E3E72);
|
|
|
@ -1,2 +0,0 @@
|
||||||
export 'dark.dart';
|
|
||||||
export 'light.dart';
|
|
|
@ -1,2 +0,0 @@
|
||||||
export 'theme_service.dart';
|
|
||||||
export 'themes/themes.dart';
|
|
|
@ -1,48 +0,0 @@
|
||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:window_manager/window_manager.dart';
|
|
||||||
|
|
||||||
Future<void> setupDesktopWindow() async {
|
|
||||||
if (Platform.isWindows || Platform.isLinux || Platform.isMacOS) {
|
|
||||||
await windowManager.ensureInitialized();
|
|
||||||
|
|
||||||
const windowOptions = WindowOptions(
|
|
||||||
size: Size(768, 1024),
|
|
||||||
minimumSize: Size(480, 640),
|
|
||||||
center: true,
|
|
||||||
backgroundColor: Colors.transparent,
|
|
||||||
skipTaskbar: false,
|
|
||||||
titleBarStyle: TitleBarStyle.hidden,
|
|
||||||
);
|
|
||||||
await windowManager.waitUntilReadyToShow(windowOptions, () async {
|
|
||||||
await windowManager.show();
|
|
||||||
await windowManager.focus();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> enableTitleBar(bool enabled) async {
|
|
||||||
if (Platform.isWindows || Platform.isLinux || Platform.isMacOS) {
|
|
||||||
if (enabled) {
|
|
||||||
await windowManager.setTitleBarStyle(TitleBarStyle.normal);
|
|
||||||
} else {
|
|
||||||
await windowManager.setTitleBarStyle(TitleBarStyle.hidden);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> portraitOnly() async {
|
|
||||||
await SystemChrome.setPreferredOrientations([
|
|
||||||
DeviceOrientation.portraitUp,
|
|
||||||
DeviceOrientation.portraitDown,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> landscapeOnly() async {
|
|
||||||
await SystemChrome.setPreferredOrientations([
|
|
||||||
DeviceOrientation.landscapeLeft,
|
|
||||||
DeviceOrientation.landscapeRight,
|
|
||||||
]);
|
|
||||||
}
|
|
445
lib/tools/radix_generator.dart
Normal file
445
lib/tools/radix_generator.dart
Normal file
|
@ -0,0 +1,445 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:radix_colors/radix_colors.dart';
|
||||||
|
|
||||||
|
enum RadixThemeColor {
|
||||||
|
scarlet, // tomato + red + violet
|
||||||
|
babydoll, // crimson + purple + pink
|
||||||
|
vapor, // pink + cyan + plum
|
||||||
|
gold, // yellow + amber + orange
|
||||||
|
garden, // grass + orange + brown
|
||||||
|
forest, // green + brown + amber
|
||||||
|
arctic, // sky + teal + violet
|
||||||
|
lapis, // blue + indigo + mint
|
||||||
|
eggplant, // violet + purple + indigo
|
||||||
|
lime, // lime + yellow + orange
|
||||||
|
grim, // mauve + slate + sage
|
||||||
|
}
|
||||||
|
|
||||||
|
enum _RadixBaseColor {
|
||||||
|
tomato,
|
||||||
|
red,
|
||||||
|
crimson,
|
||||||
|
pink,
|
||||||
|
plum,
|
||||||
|
purple,
|
||||||
|
violet,
|
||||||
|
indigo,
|
||||||
|
blue,
|
||||||
|
sky,
|
||||||
|
cyan,
|
||||||
|
teal,
|
||||||
|
mint,
|
||||||
|
green,
|
||||||
|
grass,
|
||||||
|
lime,
|
||||||
|
yellow,
|
||||||
|
amber,
|
||||||
|
orange,
|
||||||
|
brown,
|
||||||
|
}
|
||||||
|
|
||||||
|
RadixColor _radixGraySteps(
|
||||||
|
Brightness brightness, bool alpha, _RadixBaseColor baseColor) {
|
||||||
|
switch (baseColor) {
|
||||||
|
case _RadixBaseColor.tomato:
|
||||||
|
case _RadixBaseColor.red:
|
||||||
|
case _RadixBaseColor.crimson:
|
||||||
|
case _RadixBaseColor.pink:
|
||||||
|
case _RadixBaseColor.plum:
|
||||||
|
case _RadixBaseColor.purple:
|
||||||
|
case _RadixBaseColor.violet:
|
||||||
|
return alpha
|
||||||
|
? (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.mauveA
|
||||||
|
: RadixColors.mauveA)
|
||||||
|
: (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.mauve
|
||||||
|
: RadixColors.mauve);
|
||||||
|
case _RadixBaseColor.indigo:
|
||||||
|
case _RadixBaseColor.blue:
|
||||||
|
case _RadixBaseColor.sky:
|
||||||
|
case _RadixBaseColor.cyan:
|
||||||
|
return alpha
|
||||||
|
? (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.slateA
|
||||||
|
: RadixColors.slateA)
|
||||||
|
: (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.slate
|
||||||
|
: RadixColors.slate);
|
||||||
|
case _RadixBaseColor.teal:
|
||||||
|
case _RadixBaseColor.mint:
|
||||||
|
case _RadixBaseColor.green:
|
||||||
|
return alpha
|
||||||
|
? (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.sageA
|
||||||
|
: RadixColors.sageA)
|
||||||
|
: (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.sage
|
||||||
|
: RadixColors.sage);
|
||||||
|
case _RadixBaseColor.lime:
|
||||||
|
case _RadixBaseColor.grass:
|
||||||
|
return alpha
|
||||||
|
? (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.oliveA
|
||||||
|
: RadixColors.oliveA)
|
||||||
|
: (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.olive
|
||||||
|
: RadixColors.olive);
|
||||||
|
case _RadixBaseColor.yellow:
|
||||||
|
case _RadixBaseColor.amber:
|
||||||
|
case _RadixBaseColor.orange:
|
||||||
|
case _RadixBaseColor.brown:
|
||||||
|
return alpha
|
||||||
|
? (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.sandA
|
||||||
|
: RadixColors.sandA)
|
||||||
|
: (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.sand
|
||||||
|
: RadixColors.sand);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RadixColor _radixColorSteps(
|
||||||
|
Brightness brightness, bool alpha, _RadixBaseColor baseColor) {
|
||||||
|
switch (baseColor) {
|
||||||
|
case _RadixBaseColor.tomato:
|
||||||
|
return alpha
|
||||||
|
? (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.tomatoA
|
||||||
|
: RadixColors.tomatoA)
|
||||||
|
: (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.tomato
|
||||||
|
: RadixColors.tomato);
|
||||||
|
case _RadixBaseColor.red:
|
||||||
|
return alpha
|
||||||
|
? (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.redA
|
||||||
|
: RadixColors.redA)
|
||||||
|
: (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.red
|
||||||
|
: RadixColors.red);
|
||||||
|
case _RadixBaseColor.crimson:
|
||||||
|
return alpha
|
||||||
|
? (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.crimsonA
|
||||||
|
: RadixColors.crimsonA)
|
||||||
|
: (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.crimson
|
||||||
|
: RadixColors.crimson);
|
||||||
|
case _RadixBaseColor.pink:
|
||||||
|
return alpha
|
||||||
|
? (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.pinkA
|
||||||
|
: RadixColors.pinkA)
|
||||||
|
: (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.pink
|
||||||
|
: RadixColors.pink);
|
||||||
|
case _RadixBaseColor.plum:
|
||||||
|
return alpha
|
||||||
|
? (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.plumA
|
||||||
|
: RadixColors.plumA)
|
||||||
|
: (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.plum
|
||||||
|
: RadixColors.plum);
|
||||||
|
case _RadixBaseColor.purple:
|
||||||
|
return alpha
|
||||||
|
? (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.purpleA
|
||||||
|
: RadixColors.purpleA)
|
||||||
|
: (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.purple
|
||||||
|
: RadixColors.purple);
|
||||||
|
case _RadixBaseColor.violet:
|
||||||
|
return alpha
|
||||||
|
? (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.violetA
|
||||||
|
: RadixColors.violetA)
|
||||||
|
: (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.violet
|
||||||
|
: RadixColors.violet);
|
||||||
|
case _RadixBaseColor.indigo:
|
||||||
|
return alpha
|
||||||
|
? (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.indigoA
|
||||||
|
: RadixColors.indigoA)
|
||||||
|
: (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.indigo
|
||||||
|
: RadixColors.indigo);
|
||||||
|
case _RadixBaseColor.blue:
|
||||||
|
return alpha
|
||||||
|
? (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.blueA
|
||||||
|
: RadixColors.blueA)
|
||||||
|
: (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.blue
|
||||||
|
: RadixColors.blue);
|
||||||
|
case _RadixBaseColor.sky:
|
||||||
|
return alpha
|
||||||
|
? (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.skyA
|
||||||
|
: RadixColors.skyA)
|
||||||
|
: (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.sky
|
||||||
|
: RadixColors.sky);
|
||||||
|
case _RadixBaseColor.cyan:
|
||||||
|
return alpha
|
||||||
|
? (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.cyanA
|
||||||
|
: RadixColors.cyanA)
|
||||||
|
: (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.cyan
|
||||||
|
: RadixColors.cyan);
|
||||||
|
case _RadixBaseColor.teal:
|
||||||
|
return alpha
|
||||||
|
? (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.tealA
|
||||||
|
: RadixColors.tealA)
|
||||||
|
: (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.teal
|
||||||
|
: RadixColors.teal);
|
||||||
|
case _RadixBaseColor.mint:
|
||||||
|
return alpha
|
||||||
|
? (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.mintA
|
||||||
|
: RadixColors.mintA)
|
||||||
|
: (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.mint
|
||||||
|
: RadixColors.mint);
|
||||||
|
case _RadixBaseColor.green:
|
||||||
|
return alpha
|
||||||
|
? (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.greenA
|
||||||
|
: RadixColors.greenA)
|
||||||
|
: (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.green
|
||||||
|
: RadixColors.green);
|
||||||
|
case _RadixBaseColor.grass:
|
||||||
|
return alpha
|
||||||
|
? (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.grassA
|
||||||
|
: RadixColors.grassA)
|
||||||
|
: (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.grass
|
||||||
|
: RadixColors.grass);
|
||||||
|
case _RadixBaseColor.lime:
|
||||||
|
return alpha
|
||||||
|
? (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.limeA
|
||||||
|
: RadixColors.limeA)
|
||||||
|
: (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.lime
|
||||||
|
: RadixColors.lime);
|
||||||
|
case _RadixBaseColor.yellow:
|
||||||
|
return alpha
|
||||||
|
? (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.yellowA
|
||||||
|
: RadixColors.yellowA)
|
||||||
|
: (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.yellow
|
||||||
|
: RadixColors.yellow);
|
||||||
|
case _RadixBaseColor.amber:
|
||||||
|
return alpha
|
||||||
|
? (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.amberA
|
||||||
|
: RadixColors.amberA)
|
||||||
|
: (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.amber
|
||||||
|
: RadixColors.amber);
|
||||||
|
case _RadixBaseColor.orange:
|
||||||
|
return alpha
|
||||||
|
? (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.orangeA
|
||||||
|
: RadixColors.orangeA)
|
||||||
|
: (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.orange
|
||||||
|
: RadixColors.orange);
|
||||||
|
case _RadixBaseColor.brown:
|
||||||
|
return alpha
|
||||||
|
? (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.brownA
|
||||||
|
: RadixColors.brownA)
|
||||||
|
: (brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.brown
|
||||||
|
: RadixColors.brown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorScheme _radixColorScheme(
|
||||||
|
// ignore: prefer_expression_function_bodies
|
||||||
|
Brightness brightness,
|
||||||
|
RadixThemeColor themeColor) {
|
||||||
|
late RadixColor primaryScale;
|
||||||
|
late RadixColor primaryAlphaScale;
|
||||||
|
late RadixColor secondaryScale;
|
||||||
|
late RadixColor tertiaryScale;
|
||||||
|
late RadixColor grayScale;
|
||||||
|
late RadixColor errorScale;
|
||||||
|
|
||||||
|
switch (themeColor) {
|
||||||
|
// tomato + red + violet
|
||||||
|
case RadixThemeColor.scarlet:
|
||||||
|
primaryScale =
|
||||||
|
_radixColorSteps(brightness, false, _RadixBaseColor.tomato);
|
||||||
|
primaryAlphaScale =
|
||||||
|
_radixColorSteps(brightness, true, _RadixBaseColor.tomato);
|
||||||
|
secondaryScale = _radixColorSteps(brightness, false, _RadixBaseColor.red);
|
||||||
|
tertiaryScale =
|
||||||
|
_radixColorSteps(brightness, false, _RadixBaseColor.violet);
|
||||||
|
grayScale = _radixGraySteps(brightness, false, _RadixBaseColor.tomato);
|
||||||
|
errorScale = _radixColorSteps(brightness, false, _RadixBaseColor.yellow);
|
||||||
|
// crimson + purple + pink
|
||||||
|
case RadixThemeColor.babydoll:
|
||||||
|
primaryScale =
|
||||||
|
_radixColorSteps(brightness, false, _RadixBaseColor.crimson);
|
||||||
|
primaryAlphaScale =
|
||||||
|
_radixColorSteps(brightness, true, _RadixBaseColor.crimson);
|
||||||
|
secondaryScale =
|
||||||
|
_radixColorSteps(brightness, false, _RadixBaseColor.purple);
|
||||||
|
tertiaryScale = _radixColorSteps(brightness, false, _RadixBaseColor.pink);
|
||||||
|
grayScale = _radixGraySteps(brightness, false, _RadixBaseColor.crimson);
|
||||||
|
errorScale = _radixColorSteps(brightness, false, _RadixBaseColor.orange);
|
||||||
|
// pink + cyan + plum
|
||||||
|
case RadixThemeColor.vapor:
|
||||||
|
primaryScale = _radixColorSteps(brightness, false, _RadixBaseColor.pink);
|
||||||
|
primaryAlphaScale =
|
||||||
|
_radixColorSteps(brightness, true, _RadixBaseColor.pink);
|
||||||
|
secondaryScale =
|
||||||
|
_radixColorSteps(brightness, false, _RadixBaseColor.cyan);
|
||||||
|
tertiaryScale = _radixColorSteps(brightness, false, _RadixBaseColor.plum);
|
||||||
|
grayScale = _radixGraySteps(brightness, false, _RadixBaseColor.pink);
|
||||||
|
errorScale = _radixColorSteps(brightness, false, _RadixBaseColor.red);
|
||||||
|
// yellow + amber + orange
|
||||||
|
case RadixThemeColor.gold:
|
||||||
|
primaryScale =
|
||||||
|
_radixColorSteps(brightness, false, _RadixBaseColor.yellow);
|
||||||
|
primaryAlphaScale =
|
||||||
|
_radixColorSteps(brightness, true, _RadixBaseColor.yellow);
|
||||||
|
secondaryScale =
|
||||||
|
_radixColorSteps(brightness, false, _RadixBaseColor.amber);
|
||||||
|
tertiaryScale =
|
||||||
|
_radixColorSteps(brightness, false, _RadixBaseColor.orange);
|
||||||
|
grayScale = _radixGraySteps(brightness, false, _RadixBaseColor.yellow);
|
||||||
|
errorScale = _radixColorSteps(brightness, false, _RadixBaseColor.red);
|
||||||
|
// grass + orange + brown
|
||||||
|
case RadixThemeColor.garden:
|
||||||
|
primaryScale = _radixColorSteps(brightness, false, _RadixBaseColor.grass);
|
||||||
|
primaryAlphaScale =
|
||||||
|
_radixColorSteps(brightness, true, _RadixBaseColor.grass);
|
||||||
|
secondaryScale =
|
||||||
|
_radixColorSteps(brightness, false, _RadixBaseColor.orange);
|
||||||
|
tertiaryScale =
|
||||||
|
_radixColorSteps(brightness, false, _RadixBaseColor.brown);
|
||||||
|
grayScale = _radixGraySteps(brightness, false, _RadixBaseColor.grass);
|
||||||
|
errorScale = _radixColorSteps(brightness, false, _RadixBaseColor.tomato);
|
||||||
|
// green + brown + amber
|
||||||
|
case RadixThemeColor.forest:
|
||||||
|
primaryScale = _radixColorSteps(brightness, false, _RadixBaseColor.green);
|
||||||
|
primaryAlphaScale =
|
||||||
|
_radixColorSteps(brightness, true, _RadixBaseColor.green);
|
||||||
|
secondaryScale =
|
||||||
|
_radixColorSteps(brightness, false, _RadixBaseColor.brown);
|
||||||
|
tertiaryScale =
|
||||||
|
_radixColorSteps(brightness, false, _RadixBaseColor.amber);
|
||||||
|
grayScale = _radixGraySteps(brightness, false, _RadixBaseColor.green);
|
||||||
|
errorScale = _radixColorSteps(brightness, false, _RadixBaseColor.tomato);
|
||||||
|
// sky + teal + violet
|
||||||
|
case RadixThemeColor.arctic:
|
||||||
|
primaryScale = _radixColorSteps(brightness, false, _RadixBaseColor.sky);
|
||||||
|
primaryAlphaScale =
|
||||||
|
_radixColorSteps(brightness, true, _RadixBaseColor.sky);
|
||||||
|
secondaryScale =
|
||||||
|
_radixColorSteps(brightness, false, _RadixBaseColor.teal);
|
||||||
|
tertiaryScale =
|
||||||
|
_radixColorSteps(brightness, false, _RadixBaseColor.violet);
|
||||||
|
grayScale = _radixGraySteps(brightness, false, _RadixBaseColor.sky);
|
||||||
|
errorScale = _radixColorSteps(brightness, false, _RadixBaseColor.crimson);
|
||||||
|
// blue + indigo + mint
|
||||||
|
case RadixThemeColor.lapis:
|
||||||
|
primaryScale = _radixColorSteps(brightness, false, _RadixBaseColor.blue);
|
||||||
|
primaryAlphaScale =
|
||||||
|
_radixColorSteps(brightness, true, _RadixBaseColor.blue);
|
||||||
|
secondaryScale =
|
||||||
|
_radixColorSteps(brightness, false, _RadixBaseColor.indigo);
|
||||||
|
tertiaryScale = _radixColorSteps(brightness, false, _RadixBaseColor.mint);
|
||||||
|
grayScale = _radixGraySteps(brightness, false, _RadixBaseColor.blue);
|
||||||
|
errorScale = _radixColorSteps(brightness, false, _RadixBaseColor.crimson);
|
||||||
|
// violet + purple + indigo
|
||||||
|
case RadixThemeColor.eggplant:
|
||||||
|
primaryScale =
|
||||||
|
_radixColorSteps(brightness, false, _RadixBaseColor.violet);
|
||||||
|
primaryAlphaScale =
|
||||||
|
_radixColorSteps(brightness, true, _RadixBaseColor.violet);
|
||||||
|
secondaryScale =
|
||||||
|
_radixColorSteps(brightness, false, _RadixBaseColor.purple);
|
||||||
|
tertiaryScale =
|
||||||
|
_radixColorSteps(brightness, false, _RadixBaseColor.indigo);
|
||||||
|
grayScale = _radixGraySteps(brightness, false, _RadixBaseColor.violet);
|
||||||
|
errorScale = _radixColorSteps(brightness, false, _RadixBaseColor.crimson);
|
||||||
|
// lime + yellow + orange
|
||||||
|
case RadixThemeColor.lime:
|
||||||
|
primaryScale = _radixColorSteps(brightness, false, _RadixBaseColor.lime);
|
||||||
|
primaryAlphaScale =
|
||||||
|
_radixColorSteps(brightness, true, _RadixBaseColor.lime);
|
||||||
|
secondaryScale =
|
||||||
|
_radixColorSteps(brightness, false, _RadixBaseColor.yellow);
|
||||||
|
tertiaryScale =
|
||||||
|
_radixColorSteps(brightness, false, _RadixBaseColor.orange);
|
||||||
|
grayScale = _radixGraySteps(brightness, false, _RadixBaseColor.lime);
|
||||||
|
errorScale = _radixColorSteps(brightness, false, _RadixBaseColor.red);
|
||||||
|
// mauve + slate + sage
|
||||||
|
case RadixThemeColor.grim:
|
||||||
|
primaryScale = _radixGraySteps(brightness, false, _RadixBaseColor.tomato);
|
||||||
|
primaryAlphaScale =
|
||||||
|
_radixColorSteps(brightness, true, _RadixBaseColor.tomato);
|
||||||
|
secondaryScale =
|
||||||
|
_radixColorSteps(brightness, false, _RadixBaseColor.indigo);
|
||||||
|
tertiaryScale = _radixColorSteps(brightness, false, _RadixBaseColor.teal);
|
||||||
|
grayScale = brightness == Brightness.dark
|
||||||
|
? RadixColors.dark.gray
|
||||||
|
: RadixColors.gray;
|
||||||
|
errorScale = _radixColorSteps(brightness, false, _RadixBaseColor.red);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ColorScheme(
|
||||||
|
brightness: brightness,
|
||||||
|
primary: primaryScale.step9,
|
||||||
|
onPrimary: primaryScale.step12,
|
||||||
|
primaryContainer: primaryScale.step3,
|
||||||
|
onPrimaryContainer: primaryScale.step11,
|
||||||
|
secondary: secondaryScale.step9,
|
||||||
|
onSecondary: secondaryScale.step12,
|
||||||
|
secondaryContainer: secondaryScale.step3,
|
||||||
|
onSecondaryContainer: secondaryScale.step11,
|
||||||
|
tertiary: tertiaryScale.step9,
|
||||||
|
onTertiary: tertiaryScale.step12,
|
||||||
|
tertiaryContainer: tertiaryScale.step3,
|
||||||
|
onTertiaryContainer: tertiaryScale.step11,
|
||||||
|
error: errorScale.step9,
|
||||||
|
onError: errorScale.step12,
|
||||||
|
errorContainer: errorScale.step3,
|
||||||
|
onErrorContainer: errorScale.step11,
|
||||||
|
background: primaryScale.step1, //gray scale?
|
||||||
|
onBackground: primaryScale.step12,
|
||||||
|
surface: primaryScale.step2, //gray scale?
|
||||||
|
onSurface: primaryScale.step11,
|
||||||
|
surfaceVariant: primaryScale.step3, //gray scale?
|
||||||
|
onSurfaceVariant: primaryScale.step11,
|
||||||
|
outline: primaryScale.step7,
|
||||||
|
outlineVariant: primaryScale.step6,
|
||||||
|
shadow: RadixColors.dark.gray.step1,
|
||||||
|
scrim: primaryScale.step4,
|
||||||
|
inverseSurface: primaryScale.step11,
|
||||||
|
onInverseSurface: primaryScale.step2,
|
||||||
|
inversePrimary: primaryScale.step10,
|
||||||
|
surfaceTint: primaryAlphaScale.step9,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ThemeData radixGenerator(Brightness brightness, RadixThemeColor themeColor) {
|
||||||
|
TextTheme? textTheme;
|
||||||
|
return ThemeData.from(
|
||||||
|
colorScheme: _radixColorScheme(brightness, themeColor),
|
||||||
|
textTheme: textTheme,
|
||||||
|
useMaterial3: true);
|
||||||
|
}
|
|
@ -6,6 +6,8 @@ import 'package:flutter/material.dart';
|
||||||
bool get isAndroid => !kIsWeb && Platform.isAndroid;
|
bool get isAndroid => !kIsWeb && Platform.isAndroid;
|
||||||
bool get isiOS => !kIsWeb && Platform.isIOS;
|
bool get isiOS => !kIsWeb && Platform.isIOS;
|
||||||
bool get isWeb => kIsWeb;
|
bool get isWeb => kIsWeb;
|
||||||
|
bool get isDesktop =>
|
||||||
|
Platform.isWindows || Platform.isLinux || Platform.isMacOS;
|
||||||
|
|
||||||
const kMobileWidthCutoff = 479.0;
|
const kMobileWidthCutoff = 479.0;
|
||||||
|
|
||||||
|
|
91
lib/tools/theme_service.dart
Normal file
91
lib/tools/theme_service.dart
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
import '../entities/preferences.dart';
|
||||||
|
import 'radix_generator.dart';
|
||||||
|
|
||||||
|
class ThemeService {
|
||||||
|
ThemeService._();
|
||||||
|
static late SharedPreferences prefs;
|
||||||
|
static ThemeService? _instance;
|
||||||
|
|
||||||
|
static Future<ThemeService> get instance async {
|
||||||
|
if (_instance == null) {
|
||||||
|
prefs = await SharedPreferences.getInstance();
|
||||||
|
_instance = ThemeService._();
|
||||||
|
}
|
||||||
|
return _instance!;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool get isPlatformDark =>
|
||||||
|
WidgetsBinding.instance.platformDispatcher.platformBrightness ==
|
||||||
|
Brightness.dark;
|
||||||
|
|
||||||
|
ThemeData get initial {
|
||||||
|
final themePreferencesJson = prefs.getString('themePreferences');
|
||||||
|
final themePreferences = themePreferencesJson != null
|
||||||
|
? ThemePreferences.fromJson(themePreferencesJson)
|
||||||
|
: const ThemePreferences(
|
||||||
|
colorPreference: ColorPreference.vapor,
|
||||||
|
brightnessPreference: BrightnessPreference.system,
|
||||||
|
displayScale: 1,
|
||||||
|
);
|
||||||
|
return get(themePreferences);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> save(ThemePreferences themePreferences) async {
|
||||||
|
await prefs.setString(
|
||||||
|
'themePreferences', jsonEncode(themePreferences.toJson()));
|
||||||
|
}
|
||||||
|
|
||||||
|
ThemeData get(ThemePreferences themePreferences) {
|
||||||
|
late final Brightness brightness;
|
||||||
|
switch (themePreferences.brightnessPreference) {
|
||||||
|
case BrightnessPreference.system:
|
||||||
|
if (isPlatformDark) {
|
||||||
|
brightness = Brightness.dark;
|
||||||
|
} else {
|
||||||
|
brightness = Brightness.light;
|
||||||
|
}
|
||||||
|
case BrightnessPreference.light:
|
||||||
|
brightness = Brightness.light;
|
||||||
|
case BrightnessPreference.dark:
|
||||||
|
brightness = Brightness.dark;
|
||||||
|
}
|
||||||
|
|
||||||
|
late final ThemeData themeData;
|
||||||
|
switch (themePreferences.colorPreference) {
|
||||||
|
// Special cases
|
||||||
|
case ColorPreference.contrast:
|
||||||
|
// xxx do contrastGenerator
|
||||||
|
themeData = radixGenerator(brightness, RadixThemeColor.grim);
|
||||||
|
// Generate from Radix
|
||||||
|
case ColorPreference.scarlet:
|
||||||
|
themeData = radixGenerator(brightness, RadixThemeColor.scarlet);
|
||||||
|
case ColorPreference.babydoll:
|
||||||
|
themeData = radixGenerator(brightness, RadixThemeColor.babydoll);
|
||||||
|
case ColorPreference.vapor:
|
||||||
|
themeData = radixGenerator(brightness, RadixThemeColor.vapor);
|
||||||
|
case ColorPreference.gold:
|
||||||
|
themeData = radixGenerator(brightness, RadixThemeColor.gold);
|
||||||
|
case ColorPreference.garden:
|
||||||
|
themeData = radixGenerator(brightness, RadixThemeColor.garden);
|
||||||
|
case ColorPreference.forest:
|
||||||
|
themeData = radixGenerator(brightness, RadixThemeColor.forest);
|
||||||
|
case ColorPreference.arctic:
|
||||||
|
themeData = radixGenerator(brightness, RadixThemeColor.arctic);
|
||||||
|
case ColorPreference.lapis:
|
||||||
|
themeData = radixGenerator(brightness, RadixThemeColor.lapis);
|
||||||
|
case ColorPreference.eggplant:
|
||||||
|
themeData = radixGenerator(brightness, RadixThemeColor.eggplant);
|
||||||
|
case ColorPreference.lime:
|
||||||
|
themeData = radixGenerator(brightness, RadixThemeColor.lime);
|
||||||
|
case ColorPreference.grim:
|
||||||
|
themeData = radixGenerator(brightness, RadixThemeColor.grim);
|
||||||
|
}
|
||||||
|
|
||||||
|
return themeData;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,9 @@
|
||||||
export 'animations.dart';
|
export 'animations.dart';
|
||||||
export 'desktop_control.dart';
|
|
||||||
export 'external_stream_state.dart';
|
export 'external_stream_state.dart';
|
||||||
export 'json_tools.dart';
|
export 'json_tools.dart';
|
||||||
export 'phono_byte.dart';
|
export 'phono_byte.dart';
|
||||||
export 'protobuf_tools.dart';
|
export 'protobuf_tools.dart';
|
||||||
|
export 'radix_generator.dart';
|
||||||
export 'responsive.dart';
|
export 'responsive.dart';
|
||||||
|
export 'theme_service.dart';
|
||||||
export 'widget_helpers.dart';
|
export 'widget_helpers.dart';
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:blurry_modal_progress_hud/blurry_modal_progress_hud.dart';
|
import 'package:blurry_modal_progress_hud/blurry_modal_progress_hud.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
||||||
|
import 'package:quickalert/quickalert.dart';
|
||||||
|
|
||||||
extension BorderExt on Widget {
|
extension BorderExt on Widget {
|
||||||
DecoratedBox debugBorder() => DecoratedBox(
|
DecoratedBox debugBorder() => DecoratedBox(
|
||||||
|
@ -13,10 +14,29 @@ extension ModalProgressExt on Widget {
|
||||||
BlurryModalProgressHUD(
|
BlurryModalProgressHUD(
|
||||||
inAsyncCall: isLoading,
|
inAsyncCall: isLoading,
|
||||||
blurEffectIntensity: 4,
|
blurEffectIntensity: 4,
|
||||||
progressIndicator: SpinKitFoldingCube(
|
progressIndicator: buildProgressIndicator(context),
|
||||||
color: Theme.of(context).highlightColor,
|
|
||||||
size: 90,
|
|
||||||
),
|
|
||||||
color: Theme.of(context).shadowColor,
|
color: Theme.of(context).shadowColor,
|
||||||
child: this);
|
child: this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget buildProgressIndicator(BuildContext context) => SpinKitFoldingCube(
|
||||||
|
color: Theme.of(context).highlightColor,
|
||||||
|
size: 90,
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget waitingPage(BuildContext context) => ColoredBox(
|
||||||
|
color: Theme.of(context).scaffoldBackgroundColor,
|
||||||
|
child: Center(child: buildProgressIndicator(context)));
|
||||||
|
|
||||||
|
Future<void> showErrorModal(
|
||||||
|
BuildContext context, String title, String text) async {
|
||||||
|
await QuickAlert.show(
|
||||||
|
context: context,
|
||||||
|
type: QuickAlertType.error,
|
||||||
|
title: title,
|
||||||
|
text: text,
|
||||||
|
//backgroundColor: Colors.black,
|
||||||
|
//titleColor: Colors.white,
|
||||||
|
//textColor: Colors.white,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -129,6 +129,17 @@ class DHTRecord {
|
||||||
return jsonDecodeBytes(fromJson, data);
|
return jsonDecodeBytes(fromJson, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<T?> getProtobuf<T extends GeneratedMessage>(
|
||||||
|
T Function(List<int> i) fromBuffer,
|
||||||
|
{int subkey = -1,
|
||||||
|
bool forceRefresh = false}) async {
|
||||||
|
final data = await get(subkey: subkey, forceRefresh: forceRefresh);
|
||||||
|
if (data == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return fromBuffer(data.toList());
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> eventualWriteBytes(Uint8List newValue, {int subkey = -1}) async {
|
Future<void> eventualWriteBytes(Uint8List newValue, {int subkey = -1}) async {
|
||||||
subkey = subkeyOrDefault(subkey);
|
subkey = subkeyOrDefault(subkey);
|
||||||
newValue = await crypto.encrypt(newValue, subkey);
|
newValue = await crypto.encrypt(newValue, subkey);
|
||||||
|
|
24
pubspec.lock
24
pubspec.lock
|
@ -233,6 +233,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.5"
|
version: "2.0.5"
|
||||||
|
circular_reveal_animation:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: circular_reveal_animation
|
||||||
|
sha256: "198f5a1fa27384dcf950807e0ae07a0da857c04df6233f7468755ee9db102b0c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.1"
|
||||||
cli_util:
|
cli_util:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -669,6 +677,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.4"
|
version: "1.0.4"
|
||||||
|
multi_split_view:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: multi_split_view
|
||||||
|
sha256: d68e129bff71fc9e6b66de59e1b79deaf4b91f30940130bfbd2d704c1c713499
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.0"
|
||||||
octo_image:
|
octo_image:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -1050,6 +1066,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0"
|
version: "1.2.0"
|
||||||
|
stylish_bottom_bar:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: stylish_bottom_bar
|
||||||
|
sha256: "54970e4753b4273239b6dea0d1175c56beabcf39b5c65df4cbf86f1b86568d2b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.3"
|
||||||
synchronized:
|
synchronized:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -16,6 +16,7 @@ dependencies:
|
||||||
change_case: ^1.1.0
|
change_case: ^1.1.0
|
||||||
charcode: ^1.3.1
|
charcode: ^1.3.1
|
||||||
circular_profile_avatar: ^2.0.5
|
circular_profile_avatar: ^2.0.5
|
||||||
|
circular_reveal_animation: ^2.0.1
|
||||||
cupertino_icons: ^1.0.2
|
cupertino_icons: ^1.0.2
|
||||||
equatable: ^2.0.5
|
equatable: ^2.0.5
|
||||||
fast_immutable_collections: ^9.1.5
|
fast_immutable_collections: ^9.1.5
|
||||||
|
@ -38,6 +39,7 @@ dependencies:
|
||||||
intl: ^0.18.0
|
intl: ^0.18.0
|
||||||
json_annotation: ^4.8.1
|
json_annotation: ^4.8.1
|
||||||
loggy: ^2.0.3
|
loggy: ^2.0.3
|
||||||
|
multi_split_view: ^2.4.0
|
||||||
path: ^1.8.2
|
path: ^1.8.2
|
||||||
path_provider: ^2.0.11
|
path_provider: ^2.0.11
|
||||||
protobuf: ^3.0.0
|
protobuf: ^3.0.0
|
||||||
|
@ -47,6 +49,7 @@ dependencies:
|
||||||
riverpod_annotation: ^2.1.1
|
riverpod_annotation: ^2.1.1
|
||||||
shared_preferences: ^2.0.15
|
shared_preferences: ^2.0.15
|
||||||
signal_strength_indicator: ^0.4.1
|
signal_strength_indicator: ^0.4.1
|
||||||
|
stylish_bottom_bar: ^1.0.3
|
||||||
uuid: ^3.0.7
|
uuid: ^3.0.7
|
||||||
veilid:
|
veilid:
|
||||||
# veilid: ^0.0.1
|
# veilid: ^0.0.1
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue