mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2025-01-11 18:39:45 +00:00
Implement recovery domain page frontend
This commit is contained in:
parent
ce3e046f5a
commit
01b1f7462d
|
@ -22,7 +22,7 @@
|
||||||
"nickname": "Nickname",
|
"nickname": "Nickname",
|
||||||
"loading": "Loading...",
|
"loading": "Loading...",
|
||||||
"later": "Skip to setup later",
|
"later": "Skip to setup later",
|
||||||
"connect_to_existing": "Connect to existing server",
|
"connect_to_existing": "Connect to an existing server",
|
||||||
"reset": "Reset",
|
"reset": "Reset",
|
||||||
"details": "Details",
|
"details": "Details",
|
||||||
"no_data": "No data",
|
"no_data": "No data",
|
||||||
|
@ -283,6 +283,11 @@
|
||||||
"finish": "Everything is initialized",
|
"finish": "Everything is initialized",
|
||||||
"checks": "Checks have been completed \n{} ouf of {}"
|
"checks": "Checks have been completed \n{} ouf of {}"
|
||||||
},
|
},
|
||||||
|
"recovering": {
|
||||||
|
"recovery_main_header": "Connect to an existing server",
|
||||||
|
"domain_recovery_description": "Enter a server domain you want to get access for",
|
||||||
|
"domain_recover_placeholder": "Your domain"
|
||||||
|
},
|
||||||
"modals": {
|
"modals": {
|
||||||
"_comment": "messages in modals",
|
"_comment": "messages in modals",
|
||||||
"1": "Server with such name, already exist",
|
"1": "Server with such name, already exist",
|
||||||
|
|
|
@ -71,4 +71,5 @@ class BNames {
|
||||||
static String sshConfig = 'sshConfig';
|
static String sshConfig = 'sshConfig';
|
||||||
static String sshPrivateKey = "sshPrivateKey";
|
static String sshPrivateKey = "sshPrivateKey";
|
||||||
static String sshPublicKey = "sshPublicKey";
|
static String sshPublicKey = "sshPublicKey";
|
||||||
|
static String serverDomain = "serverDomain";
|
||||||
}
|
}
|
||||||
|
|
|
@ -239,6 +239,10 @@ class AppConfigRepository {
|
||||||
await getIt<ApiConfigModel>().storeHetznerKey(key);
|
await getIt<ApiConfigModel>().storeHetznerKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> saveServerDomain(String domain) async {
|
||||||
|
await getIt<ApiConfigModel>().storeServerDomain(domain);
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> saveBackblazeKey(BackblazeCredential backblazeCredential) async {
|
Future<void> saveBackblazeKey(BackblazeCredential backblazeCredential) async {
|
||||||
await getIt<ApiConfigModel>().storeBackblazeCredential(backblazeCredential);
|
await getIt<ApiConfigModel>().storeBackblazeCredential(backblazeCredential);
|
||||||
}
|
}
|
||||||
|
|
|
@ -240,3 +240,39 @@ class AppConfigFinished extends AppConfigState {
|
||||||
isServerResetedFirstTime,
|
isServerResetedFirstTime,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AppRecovery extends AppConfigState {
|
||||||
|
const AppRecovery({
|
||||||
|
required String hetznerKey,
|
||||||
|
required String cloudFlareKey,
|
||||||
|
required BackblazeCredential backblazeCredential,
|
||||||
|
required CloudFlareDomain cloudFlareDomain,
|
||||||
|
required User rootUser,
|
||||||
|
required HetznerServerDetails hetznerServer,
|
||||||
|
required bool isServerStarted,
|
||||||
|
required bool isServerResetedFirstTime,
|
||||||
|
required bool isServerResetedSecondTime,
|
||||||
|
}) : super(
|
||||||
|
hetznerKey: hetznerKey,
|
||||||
|
cloudFlareKey: cloudFlareKey,
|
||||||
|
backblazeCredential: backblazeCredential,
|
||||||
|
cloudFlareDomain: cloudFlareDomain,
|
||||||
|
rootUser: rootUser,
|
||||||
|
hetznerServer: hetznerServer,
|
||||||
|
isServerStarted: isServerStarted,
|
||||||
|
isServerResetedFirstTime: isServerResetedFirstTime,
|
||||||
|
isServerResetedSecondTime: isServerResetedSecondTime,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [
|
||||||
|
hetznerKey,
|
||||||
|
cloudFlareKey,
|
||||||
|
backblazeCredential,
|
||||||
|
cloudFlareDomain,
|
||||||
|
rootUser,
|
||||||
|
hetznerServer,
|
||||||
|
isServerStarted,
|
||||||
|
isServerResetedFirstTime,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:cubit_form/cubit_form.dart';
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:selfprivacy/logic/api_maps/hetzner.dart';
|
||||||
|
import 'package:selfprivacy/logic/cubit/app_config/app_config_cubit.dart';
|
||||||
|
import 'package:selfprivacy/logic/cubit/forms/validations/validations.dart';
|
||||||
|
|
||||||
|
class RecoveryDomainFormCubit extends FormCubit {
|
||||||
|
RecoveryDomainFormCubit(this.initializingCubit) {
|
||||||
|
var regExp = RegExp(r"\s+|[-!$%^&*()@+|~=`{}\[\]:<>?,.\/]");
|
||||||
|
apiKey = FieldCubit(
|
||||||
|
initalValue: '',
|
||||||
|
validations: [
|
||||||
|
RequiredStringValidation('validations.required'.tr()),
|
||||||
|
ValidationModel<String>(
|
||||||
|
(s) => regExp.hasMatch(s), 'validations.key_format'.tr()),
|
||||||
|
LengthStringNotEqualValidation(64)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
super.addFields([apiKey]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOr<void> onSubmit() async {
|
||||||
|
initializingCubit.setHetznerKey(apiKey.state.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
final AppConfigCubit initializingCubit;
|
||||||
|
|
||||||
|
late final FieldCubit<String> apiKey;
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOr<bool> asyncValidation() async {
|
||||||
|
late bool isKeyValid;
|
||||||
|
HetznerApi apiClient = HetznerApi(isWithToken: false);
|
||||||
|
|
||||||
|
try {
|
||||||
|
isKeyValid = await apiClient.isValid(apiKey.state.value);
|
||||||
|
} catch (e) {
|
||||||
|
addError(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isKeyValid) {
|
||||||
|
apiKey.setError('bad key');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,12 +11,14 @@ class ApiConfigModel {
|
||||||
HetznerServerDetails? get hetznerServer => _hetznerServer;
|
HetznerServerDetails? get hetznerServer => _hetznerServer;
|
||||||
String? get hetznerKey => _hetznerKey;
|
String? get hetznerKey => _hetznerKey;
|
||||||
String? get cloudFlareKey => _cloudFlareKey;
|
String? get cloudFlareKey => _cloudFlareKey;
|
||||||
|
String? get serverDomain => _serverDomain;
|
||||||
BackblazeCredential? get backblazeCredential => _backblazeCredential;
|
BackblazeCredential? get backblazeCredential => _backblazeCredential;
|
||||||
CloudFlareDomain? get cloudFlareDomain => _cloudFlareDomain;
|
CloudFlareDomain? get cloudFlareDomain => _cloudFlareDomain;
|
||||||
BackblazeBucket? get backblazeBucket => _backblazeBucket;
|
BackblazeBucket? get backblazeBucket => _backblazeBucket;
|
||||||
|
|
||||||
String? _hetznerKey;
|
String? _hetznerKey;
|
||||||
String? _cloudFlareKey;
|
String? _cloudFlareKey;
|
||||||
|
String? _serverDomain;
|
||||||
HetznerServerDetails? _hetznerServer;
|
HetznerServerDetails? _hetznerServer;
|
||||||
BackblazeCredential? _backblazeCredential;
|
BackblazeCredential? _backblazeCredential;
|
||||||
CloudFlareDomain? _cloudFlareDomain;
|
CloudFlareDomain? _cloudFlareDomain;
|
||||||
|
@ -32,6 +34,11 @@ class ApiConfigModel {
|
||||||
_cloudFlareKey = value;
|
_cloudFlareKey = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> storeServerDomain(String value) async {
|
||||||
|
await _box.put(BNames.serverDomain, value);
|
||||||
|
_serverDomain = value;
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> storeBackblazeCredential(BackblazeCredential value) async {
|
Future<void> storeBackblazeCredential(BackblazeCredential value) async {
|
||||||
await _box.put(BNames.backblazeKey, value);
|
await _box.put(BNames.backblazeKey, value);
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import 'package:selfprivacy/ui/components/pre_styled_buttons/pre_styled_buttons.
|
||||||
class BrandHeader extends StatelessWidget {
|
class BrandHeader extends StatelessWidget {
|
||||||
const BrandHeader({
|
const BrandHeader({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.title,
|
this.title = "",
|
||||||
this.hasBackButton = false,
|
this.hasBackButton = false,
|
||||||
this.hasFlashButton = false,
|
this.hasFlashButton = false,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
|
@ -4,11 +4,11 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:selfprivacy/config/brand_theme.dart';
|
import 'package:selfprivacy/config/brand_theme.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/app_config/app_config_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/app_config/app_config_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/forms/factories/field_cubit_factory.dart';
|
import 'package:selfprivacy/logic/cubit/forms/factories/field_cubit_factory.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/forms/initializing/backblaze_form_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/forms/setup/initializing/backblaze_form_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/forms/initializing/cloudflare_form_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/forms/setup/initializing/cloudflare_form_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/forms/initializing/domain_cloudflare.dart';
|
import 'package:selfprivacy/logic/cubit/forms/setup/initializing/domain_cloudflare.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/forms/initializing/hetzner_form_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/forms/setup/initializing/hetzner_form_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/forms/initializing/root_user_form_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/forms/setup/initializing/root_user_form_cubit.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_bottom_sheet/brand_bottom_sheet.dart';
|
import 'package:selfprivacy/ui/components/brand_bottom_sheet/brand_bottom_sheet.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_button/brand_button.dart';
|
import 'package:selfprivacy/ui/components/brand_button/brand_button.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_cards/brand_cards.dart';
|
import 'package:selfprivacy/ui/components/brand_cards/brand_cards.dart';
|
||||||
|
@ -104,10 +104,8 @@ class InitializingPage extends StatelessWidget {
|
||||||
child: BrandButton.text(
|
child: BrandButton.text(
|
||||||
title: 'basis.connect_to_existing'.tr(),
|
title: 'basis.connect_to_existing'.tr(),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.of(context).pushAndRemoveUntil(
|
Navigator.of(context)
|
||||||
materialRoute(RecoveryDomain()),
|
.push(materialRoute(RecoveryDomain()));
|
||||||
(predicate) => false,
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,54 +1,75 @@
|
||||||
import 'package:cubit_form/cubit_form.dart';
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/app_config/app_config_cubit.dart';
|
|
||||||
import 'package:selfprivacy/ui/components/brand_button/brand_button.dart';
|
import 'package:selfprivacy/ui/components/brand_button/brand_button.dart';
|
||||||
import 'package:selfprivacy/ui/pages/rootRoute.dart';
|
import 'package:selfprivacy/ui/components/brand_hero_screen/brand_hero_screen.dart';
|
||||||
import 'package:selfprivacy/utils/route_transitions/basic.dart';
|
|
||||||
|
|
||||||
class RecoveryDomain extends StatelessWidget {
|
class RecoveryDomain extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
State<RecoveryDomain> createState() => _RecoveryDomainState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _RecoveryDomainState extends State<RecoveryDomain> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var cubit = context.watch<AppConfigCubit>();
|
return BrandHeroScreen(
|
||||||
return BlocListener<AppConfigCubit, AppConfigState>(
|
|
||||||
listener: (context, state) {
|
|
||||||
if (cubit.state is AppConfigFinished) {
|
|
||||||
Navigator.of(context).pushReplacement(materialRoute(RootPage()));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: SafeArea(
|
|
||||||
child: Scaffold(
|
|
||||||
body: SingleChildScrollView(
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
children: [
|
||||||
ConstrainedBox(
|
TextField(
|
||||||
constraints: BoxConstraints(
|
decoration: InputDecoration(
|
||||||
minHeight: MediaQuery.of(context).size.height -
|
border: OutlineInputBorder(),
|
||||||
MediaQuery.of(context).padding.top -
|
labelText: "recovering.domain_recover_placeholder".tr(),
|
||||||
MediaQuery.of(context).padding.bottom -
|
|
||||||
566,
|
|
||||||
),
|
),
|
||||||
child: Container(
|
),
|
||||||
alignment: Alignment.center,
|
SizedBox(height: 16),
|
||||||
child: BrandButton.text(
|
BrandButton.rised(
|
||||||
title: cubit.state is AppConfigFinished
|
onPressed: () {},
|
||||||
? 'basis.close'.tr()
|
text: "more.continue".tr(),
|
||||||
: 'basis.later'.tr(),
|
),
|
||||||
onPressed: () {
|
],
|
||||||
Navigator.of(context).pushAndRemoveUntil(
|
heroTitle: "recovering.recovery_main_header".tr(),
|
||||||
materialRoute(RootPage()),
|
heroSubtitle: "recovering.domain_recovery_description".tr(),
|
||||||
(predicate) => false,
|
hasBackButton: true,
|
||||||
|
hasFlashButton: false,
|
||||||
|
heroIcon: Icons.link,
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*class RecoveryDomain extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SafeArea(
|
||||||
|
child: Scaffold(
|
||||||
|
appBar: PreferredSize(
|
||||||
|
preferredSize: Size.fromHeight(52),
|
||||||
|
child: BrandHeader(hasBackButton: true),
|
||||||
|
),
|
||||||
|
body: ListView(
|
||||||
|
padding: EdgeInsets.all(16),
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"recovering.recovery_main_header".tr(),
|
||||||
|
style: Theme.of(context).textTheme.headlineMedium,
|
||||||
|
),
|
||||||
|
SizedBox(height: 18),
|
||||||
|
Text(
|
||||||
|
"recovering.domain_recovery_description".tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodyLarge,
|
||||||
|
),
|
||||||
|
SizedBox(height: 18),
|
||||||
|
TextField(
|
||||||
|
decoration: InputDecoration(
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
labelText: "recovering.domain_recover_placeholder".tr(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
SizedBox(height: 18),
|
||||||
|
BrandButton.rised(
|
||||||
|
onPressed: () {},
|
||||||
|
text: "more.continue".tr(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}*/
|
Loading…
Reference in a new issue