mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2025-01-27 11:16:45 +00:00
Implement pages for server confirmation on restoring access
Co-authored-by: Inex Code <inex.code@selfprivacy.org>
This commit is contained in:
parent
6fd7f9400d
commit
eaa1ba143c
|
@ -274,7 +274,6 @@
|
||||||
"15": "Server created. DNS checks and server boot in progress...",
|
"15": "Server created. DNS checks and server boot in progress...",
|
||||||
"16": "Until the next check: ",
|
"16": "Until the next check: ",
|
||||||
"17": "Check",
|
"17": "Check",
|
||||||
"18": "How to obtain Hetzner API Token",
|
|
||||||
"19": "1 Go via this link ",
|
"19": "1 Go via this link ",
|
||||||
"20": "\n",
|
"20": "\n",
|
||||||
"21": "One more restart to apply your security certificates.",
|
"21": "One more restart to apply your security certificates.",
|
||||||
|
@ -301,7 +300,15 @@
|
||||||
"fallback_select_token_copy": "Copy of auth token from other version of the application.",
|
"fallback_select_token_copy": "Copy of auth token from other version of the application.",
|
||||||
"fallback_select_root_ssh": "Root SSH access to the server.",
|
"fallback_select_root_ssh": "Root SSH access to the server.",
|
||||||
"fallback_select_provider_console": "Access to the server console of my prodiver.",
|
"fallback_select_provider_console": "Access to the server console of my prodiver.",
|
||||||
"fallback_select_provider_console_hint": "For example: Hetzner."
|
"fallback_select_provider_console_hint": "For example: Hetzner.",
|
||||||
|
"hetzner_connected": "Connect to Hetzner",
|
||||||
|
"hetzner_connected_description": "Communication established. Enter Hetzner token with access to {}:",
|
||||||
|
"hetzner_connected_placeholder": "Hetzner token",
|
||||||
|
"confirm_server": "Confirm server",
|
||||||
|
"confirm_server_description": "Found your server! Confirm it is correct.",
|
||||||
|
"confirm_server_accept": "Yes! That's it",
|
||||||
|
"confirm_server_decline": "Choose a different server"
|
||||||
|
|
||||||
},
|
},
|
||||||
"modals": {
|
"modals": {
|
||||||
"_comment": "messages in modals",
|
"_comment": "messages in modals",
|
||||||
|
|
|
@ -55,19 +55,6 @@ class HetznerApi extends ApiMap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> isFreeToCreate() async {
|
|
||||||
var client = await getClient();
|
|
||||||
|
|
||||||
Response serversReponse = await client.get('/servers');
|
|
||||||
List servers = serversReponse.data['servers'];
|
|
||||||
var server = servers.firstWhere(
|
|
||||||
(el) => el['name'] == 'selfprivacy-server',
|
|
||||||
orElse: null,
|
|
||||||
);
|
|
||||||
client.close();
|
|
||||||
return server == null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<ServerVolume> createVolume() async {
|
Future<ServerVolume> createVolume() async {
|
||||||
var client = await getClient();
|
var client = await getClient();
|
||||||
Response dbCreateResponse = await client.post(
|
Response dbCreateResponse = await client.post(
|
||||||
|
@ -237,6 +224,16 @@ class HetznerApi extends ApiMap {
|
||||||
return HetznerServerInfo.fromJson(response.data!['server']);
|
return HetznerServerInfo.fromJson(response.data!['server']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<List<HetznerServerInfo>> getServers() async {
|
||||||
|
var client = await getClient();
|
||||||
|
Response response = await client.get('/servers');
|
||||||
|
close(client);
|
||||||
|
|
||||||
|
return (response.data!['servers'] as List)
|
||||||
|
.map((e) => HetznerServerInfo.fromJson(e))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> createReverseDns({
|
Future<void> createReverseDns({
|
||||||
required String ip4,
|
required String ip4,
|
||||||
required String domainName,
|
required String domainName,
|
||||||
|
|
|
@ -6,7 +6,7 @@ import 'package:selfprivacy/logic/models/hive/backblaze_credential.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
|
||||||
class BackblazeFormCubit extends FormCubit {
|
class BackblazeFormCubit extends FormCubit {
|
||||||
BackblazeFormCubit(this.serverSetupCubit) {
|
BackblazeFormCubit(this.serverInstallationCubit) {
|
||||||
//var regExp = RegExp(r"\s+|[-!$%^&*()@+|~=`{}\[\]:<>?,.\/]");
|
//var regExp = RegExp(r"\s+|[-!$%^&*()@+|~=`{}\[\]:<>?,.\/]");
|
||||||
keyId = FieldCubit(
|
keyId = FieldCubit(
|
||||||
initalValue: '',
|
initalValue: '',
|
||||||
|
@ -27,13 +27,13 @@ class BackblazeFormCubit extends FormCubit {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
FutureOr<void> onSubmit() async {
|
FutureOr<void> onSubmit() async {
|
||||||
serverSetupCubit.setBackblazeKey(
|
serverInstallationCubit.setBackblazeKey(
|
||||||
keyId.state.value,
|
keyId.state.value,
|
||||||
applicationKey.state.value,
|
applicationKey.state.value,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final ServerInstallationCubit serverSetupCubit;
|
final ServerInstallationCubit serverInstallationCubit;
|
||||||
|
|
||||||
late final FieldCubit<String> keyId;
|
late final FieldCubit<String> keyId;
|
||||||
late final FieldCubit<String> applicationKey;
|
late final FieldCubit<String> applicationKey;
|
||||||
|
|
|
@ -4,9 +4,9 @@ import 'package:selfprivacy/logic/cubit/server_installation/server_installation_
|
||||||
import 'package:selfprivacy/logic/models/hive/server_domain.dart';
|
import 'package:selfprivacy/logic/models/hive/server_domain.dart';
|
||||||
|
|
||||||
class DomainSetupCubit extends Cubit<DomainSetupState> {
|
class DomainSetupCubit extends Cubit<DomainSetupState> {
|
||||||
DomainSetupCubit(this.serverSetupCubit) : super(Initial());
|
DomainSetupCubit(this.serverInstallationCubit) : super(Initial());
|
||||||
|
|
||||||
final ServerInstallationCubit serverSetupCubit;
|
final ServerInstallationCubit serverInstallationCubit;
|
||||||
|
|
||||||
Future<void> load() async {
|
Future<void> load() async {
|
||||||
emit(Loading(LoadingTypes.loadingDomain));
|
emit(Loading(LoadingTypes.loadingDomain));
|
||||||
|
@ -42,7 +42,7 @@ class DomainSetupCubit extends Cubit<DomainSetupState> {
|
||||||
provider: DnsProvider.Cloudflare,
|
provider: DnsProvider.Cloudflare,
|
||||||
);
|
);
|
||||||
|
|
||||||
serverSetupCubit.setDomain(domain);
|
serverInstallationCubit.setDomain(domain);
|
||||||
emit(DomainSet());
|
emit(DomainSet());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import 'package:selfprivacy/logic/cubit/server_installation/server_installation_
|
||||||
import 'package:selfprivacy/logic/cubit/forms/validations/validations.dart';
|
import 'package:selfprivacy/logic/cubit/forms/validations/validations.dart';
|
||||||
|
|
||||||
class HetznerFormCubit extends FormCubit {
|
class HetznerFormCubit extends FormCubit {
|
||||||
HetznerFormCubit(this.serverSetupCubit) {
|
HetznerFormCubit(this.serverInstallationCubit) {
|
||||||
var regExp = RegExp(r"\s+|[-!$%^&*()@+|~=`{}\[\]:<>?,.\/]");
|
var regExp = RegExp(r"\s+|[-!$%^&*()@+|~=`{}\[\]:<>?,.\/]");
|
||||||
apiKey = FieldCubit(
|
apiKey = FieldCubit(
|
||||||
initalValue: '',
|
initalValue: '',
|
||||||
|
@ -24,10 +24,10 @@ class HetznerFormCubit extends FormCubit {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
FutureOr<void> onSubmit() async {
|
FutureOr<void> onSubmit() async {
|
||||||
serverSetupCubit.setHetznerKey(apiKey.state.value);
|
serverInstallationCubit.setHetznerKey(apiKey.state.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
final ServerInstallationCubit serverSetupCubit;
|
final ServerInstallationCubit serverInstallationCubit;
|
||||||
|
|
||||||
late final FieldCubit<String> apiKey;
|
late final FieldCubit<String> apiKey;
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import 'package:selfprivacy/logic/models/hive/user.dart';
|
||||||
|
|
||||||
class RootUserFormCubit extends FormCubit {
|
class RootUserFormCubit extends FormCubit {
|
||||||
RootUserFormCubit(
|
RootUserFormCubit(
|
||||||
this.serverSetupCubit, final FieldCubitFactory fieldFactory) {
|
this.serverInstallationCubit, final FieldCubitFactory fieldFactory) {
|
||||||
userName = fieldFactory.createUserLoginField();
|
userName = fieldFactory.createUserLoginField();
|
||||||
password = fieldFactory.createUserPasswordField();
|
password = fieldFactory.createUserPasswordField();
|
||||||
|
|
||||||
|
@ -22,10 +22,10 @@ class RootUserFormCubit extends FormCubit {
|
||||||
login: userName.state.value,
|
login: userName.state.value,
|
||||||
password: password.state.value,
|
password: password.state.value,
|
||||||
);
|
);
|
||||||
serverSetupCubit.setRootUser(user);
|
serverInstallationCubit.setRootUser(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
final ServerInstallationCubit serverSetupCubit;
|
final ServerInstallationCubit serverInstallationCubit;
|
||||||
|
|
||||||
late final FieldCubit<String> userName;
|
late final FieldCubit<String> userName;
|
||||||
late final FieldCubit<String> password;
|
late final FieldCubit<String> password;
|
||||||
|
|
|
@ -47,6 +47,14 @@ class ServerInstallationCubit extends Cubit<ServerInstallationState> {
|
||||||
|
|
||||||
void setHetznerKey(String hetznerKey) async {
|
void setHetznerKey(String hetznerKey) async {
|
||||||
await repository.saveHetznerKey(hetznerKey);
|
await repository.saveHetznerKey(hetznerKey);
|
||||||
|
|
||||||
|
if (state is ServerInstallationRecovery) {
|
||||||
|
emit((state as ServerInstallationRecovery).copyWith(
|
||||||
|
hetznerKey: hetznerKey,
|
||||||
|
currentStep: RecoveryStep.ServerSelection,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
emit((state as ServerInstallationNotFinished)
|
emit((state as ServerInstallationNotFinished)
|
||||||
.copyWith(hetznerKey: hetznerKey));
|
.copyWith(hetznerKey: hetznerKey));
|
||||||
}
|
}
|
||||||
|
@ -318,6 +326,11 @@ class ServerInstallationCubit extends Cubit<ServerInstallationState> {
|
||||||
currentStep: RecoveryStep.Selecting,
|
currentStep: RecoveryStep.Selecting,
|
||||||
));
|
));
|
||||||
break;
|
break;
|
||||||
|
case RecoveryStep.ServerSelection:
|
||||||
|
emit(dataState.copyWith(
|
||||||
|
currentStep: RecoveryStep.HetznerToken,
|
||||||
|
));
|
||||||
|
break;
|
||||||
// We won't revert steps after client is authorized
|
// We won't revert steps after client is authorized
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -261,6 +261,7 @@ enum RecoveryStep {
|
||||||
NewDeviceKey,
|
NewDeviceKey,
|
||||||
OldToken,
|
OldToken,
|
||||||
HetznerToken,
|
HetznerToken,
|
||||||
|
ServerSelection,
|
||||||
CloudflareToken,
|
CloudflareToken,
|
||||||
BackblazeToken,
|
BackblazeToken,
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,9 @@ class HetznerServerInfo {
|
||||||
@JsonKey(name: 'datacenter', fromJson: HetznerServerInfo.locationFromJson)
|
@JsonKey(name: 'datacenter', fromJson: HetznerServerInfo.locationFromJson)
|
||||||
final HetznerLocation location;
|
final HetznerLocation location;
|
||||||
|
|
||||||
|
@JsonKey(name: 'public_net')
|
||||||
|
final HetznerPublicNetInfo publicNet;
|
||||||
|
|
||||||
static HetznerLocation locationFromJson(Map json) =>
|
static HetznerLocation locationFromJson(Map json) =>
|
||||||
HetznerLocation.fromJson(json['location']);
|
HetznerLocation.fromJson(json['location']);
|
||||||
|
|
||||||
|
@ -28,9 +31,34 @@ class HetznerServerInfo {
|
||||||
this.created,
|
this.created,
|
||||||
this.serverType,
|
this.serverType,
|
||||||
this.location,
|
this.location,
|
||||||
|
this.publicNet,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsonSerializable()
|
||||||
|
class HetznerPublicNetInfo {
|
||||||
|
final HetznerIp4 ip4;
|
||||||
|
|
||||||
|
static HetznerPublicNetInfo fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$HetznerPublicNetInfoFromJson(json);
|
||||||
|
|
||||||
|
HetznerPublicNetInfo(this.ip4);
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonSerializable()
|
||||||
|
class HetznerIp4 {
|
||||||
|
final bool blocked;
|
||||||
|
@JsonKey(name: 'dns_ptr')
|
||||||
|
final String reverseDns;
|
||||||
|
final int id;
|
||||||
|
final String ip;
|
||||||
|
|
||||||
|
static HetznerIp4 fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$HetznerIp4FromJson(json);
|
||||||
|
|
||||||
|
HetznerIp4(this.id, this.ip, this.blocked, this.reverseDns);
|
||||||
|
}
|
||||||
|
|
||||||
enum ServerStatus {
|
enum ServerStatus {
|
||||||
running,
|
running,
|
||||||
initializing,
|
initializing,
|
||||||
|
|
|
@ -15,6 +15,7 @@ HetznerServerInfo _$HetznerServerInfoFromJson(Map<String, dynamic> json) =>
|
||||||
HetznerServerTypeInfo.fromJson(
|
HetznerServerTypeInfo.fromJson(
|
||||||
json['server_type'] as Map<String, dynamic>),
|
json['server_type'] as Map<String, dynamic>),
|
||||||
HetznerServerInfo.locationFromJson(json['datacenter'] as Map),
|
HetznerServerInfo.locationFromJson(json['datacenter'] as Map),
|
||||||
|
HetznerPublicNetInfo.fromJson(json['public_net'] as Map<String, dynamic>),
|
||||||
);
|
);
|
||||||
|
|
||||||
const _$ServerStatusEnumMap = {
|
const _$ServerStatusEnumMap = {
|
||||||
|
@ -29,6 +30,19 @@ const _$ServerStatusEnumMap = {
|
||||||
ServerStatus.unknown: 'unknown',
|
ServerStatus.unknown: 'unknown',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
HetznerPublicNetInfo _$HetznerPublicNetInfoFromJson(
|
||||||
|
Map<String, dynamic> json) =>
|
||||||
|
HetznerPublicNetInfo(
|
||||||
|
HetznerIp4.fromJson(json['ip4'] as Map<String, dynamic>),
|
||||||
|
);
|
||||||
|
|
||||||
|
HetznerIp4 _$HetznerIp4FromJson(Map<String, dynamic> json) => HetznerIp4(
|
||||||
|
json['id'] as int,
|
||||||
|
json['ip'] as String,
|
||||||
|
json['blocked'] as bool,
|
||||||
|
json['dns_ptr'] as String,
|
||||||
|
);
|
||||||
|
|
||||||
HetznerServerTypeInfo _$HetznerServerTypeInfoFromJson(
|
HetznerServerTypeInfo _$HetznerServerTypeInfoFromJson(
|
||||||
Map<String, dynamic> json) =>
|
Map<String, dynamic> json) =>
|
||||||
HetznerServerTypeInfo(
|
HetznerServerTypeInfo(
|
||||||
|
|
|
@ -23,6 +23,9 @@ class BrandCards {
|
||||||
static Widget outlined({required Widget child}) => _OutlinedCard(
|
static Widget outlined({required Widget child}) => _OutlinedCard(
|
||||||
child: child,
|
child: child,
|
||||||
);
|
);
|
||||||
|
static Widget filled({required Widget child}) => _FilledCard(
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class _BrandCard extends StatelessWidget {
|
class _BrandCard extends StatelessWidget {
|
||||||
|
@ -78,6 +81,27 @@ class _OutlinedCard extends StatelessWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _FilledCard extends StatelessWidget {
|
||||||
|
const _FilledCard({
|
||||||
|
Key? key,
|
||||||
|
required this.child,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
final Widget child;
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Card(
|
||||||
|
elevation: 0.0,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||||
|
),
|
||||||
|
clipBehavior: Clip.antiAlias,
|
||||||
|
child: child,
|
||||||
|
color: Theme.of(context).colorScheme.surfaceVariant,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final bigShadow = [
|
final bigShadow = [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
offset: Offset(0, 4),
|
offset: Offset(0, 4),
|
||||||
|
|
|
@ -124,9 +124,9 @@ class InitializingPage extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _stepHetzner(ServerInstallationCubit initializingCubit) {
|
Widget _stepHetzner(ServerInstallationCubit serverInstallationCubit) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => HetznerFormCubit(initializingCubit),
|
create: (context) => HetznerFormCubit(serverInstallationCubit),
|
||||||
child: Builder(builder: (context) {
|
child: Builder(builder: (context) {
|
||||||
var formCubitState = context.watch<HetznerFormCubit>().state;
|
var formCubitState = context.watch<HetznerFormCubit>().state;
|
||||||
return Column(
|
return Column(
|
||||||
|
|
|
@ -27,8 +27,9 @@ class RecoverByOldTokenInstruction extends StatelessWidget {
|
||||||
SizedBox(height: 16),
|
SizedBox(height: 16),
|
||||||
FilledButton(
|
FilledButton(
|
||||||
title: "recovering.method_device_button".tr(),
|
title: "recovering.method_device_button".tr(),
|
||||||
onPressed: () =>
|
onPressed: () => context
|
||||||
Navigator.of(context).push(materialRoute(RecoverByOldToken())),
|
.read<ServerInstallationCubit>()
|
||||||
|
.selectRecoveryMethod(ServerRecoveryMethods.oldToken),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
62
lib/ui/pages/setup/recovering/recovery_confirm_server.dart
Normal file
62
lib/ui/pages/setup/recovering/recovery_confirm_server.dart
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
import 'package:cubit_form/cubit_form.dart';
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
|
||||||
|
import 'package:selfprivacy/logic/cubit/forms/setup/recovering/recovery_domain_form_cubit.dart';
|
||||||
|
import 'package:selfprivacy/ui/components/brand_button/FilledButton.dart';
|
||||||
|
import 'package:selfprivacy/ui/components/brand_hero_screen/brand_hero_screen.dart';
|
||||||
|
|
||||||
|
class RecoveryConfirmServer extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var serverInstallation = context.watch<ServerInstallationCubit>();
|
||||||
|
|
||||||
|
return Builder(
|
||||||
|
builder: (context) {
|
||||||
|
var formCubitState = context.watch<RecoveryDomainFormCubit>().state;
|
||||||
|
|
||||||
|
return BlocListener<ServerInstallationCubit, ServerInstallationState>(
|
||||||
|
listener: (context, state) {
|
||||||
|
if (state is ServerInstallationRecovery) {
|
||||||
|
if (state.currentStep == RecoveryStep.Selecting) {
|
||||||
|
if (state.recoveryCapabilities ==
|
||||||
|
ServerRecoveryCapabilities.none) {
|
||||||
|
context
|
||||||
|
.read<RecoveryDomainFormCubit>()
|
||||||
|
.setCustomError("recovering.domain_recover_error".tr());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: BrandHeroScreen(
|
||||||
|
heroTitle: "recovering.recovery_main_header".tr(),
|
||||||
|
heroSubtitle: "recovering.domain_recovery_description".tr(),
|
||||||
|
hasBackButton: true,
|
||||||
|
hasFlashButton: false,
|
||||||
|
onBackButtonPressed:
|
||||||
|
serverInstallation is ServerInstallationRecovery
|
||||||
|
? () => serverInstallation.clearAppConfig()
|
||||||
|
: null,
|
||||||
|
children: [
|
||||||
|
CubitFormTextField(
|
||||||
|
formFieldCubit:
|
||||||
|
context.read<RecoveryDomainFormCubit>().serverDomainField,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
labelText: "recovering.domain_recover_placeholder".tr(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
FilledButton(
|
||||||
|
title: "more.continue".tr(),
|
||||||
|
onPressed: formCubitState.isSubmitting
|
||||||
|
? null
|
||||||
|
: () => context.read<RecoveryDomainFormCubit>().trySubmit(),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:selfprivacy/config/brand_theme.dart';
|
||||||
|
import 'package:selfprivacy/logic/cubit/forms/setup/initializing/hetzner_form_cubit.dart';
|
||||||
|
import 'package:selfprivacy/ui/components/brand_bottom_sheet/brand_bottom_sheet.dart';
|
||||||
|
import 'package:selfprivacy/ui/components/brand_button/FilledButton.dart';
|
||||||
|
import 'package:selfprivacy/ui/components/brand_button/brand_button.dart';
|
||||||
|
import 'package:selfprivacy/ui/components/brand_hero_screen/brand_hero_screen.dart';
|
||||||
|
import 'package:cubit_form/cubit_form.dart';
|
||||||
|
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
|
||||||
|
import 'package:selfprivacy/ui/components/brand_md/brand_md.dart';
|
||||||
|
|
||||||
|
class RecoveryHetznerConnected extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var appConfig = context.watch<ServerInstallationCubit>();
|
||||||
|
|
||||||
|
return BlocProvider(
|
||||||
|
create: (context) => HetznerFormCubit(appConfig),
|
||||||
|
child: Builder(
|
||||||
|
builder: (context) {
|
||||||
|
var formCubitState = context.watch<HetznerFormCubit>().state;
|
||||||
|
|
||||||
|
return BrandHeroScreen(
|
||||||
|
heroTitle: "recovering.hetzner_connected".tr(),
|
||||||
|
heroSubtitle: "recovering.hetzner_connected_description".tr(),
|
||||||
|
hasBackButton: true,
|
||||||
|
hasFlashButton: false,
|
||||||
|
children: [
|
||||||
|
CubitFormTextField(
|
||||||
|
formFieldCubit: context.read<HetznerFormCubit>().apiKey,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
labelText: "recovering.hetzner_connected_placeholder".tr(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
FilledButton(
|
||||||
|
title: "more.continue".tr(),
|
||||||
|
onPressed: formCubitState.isSubmitting
|
||||||
|
? null
|
||||||
|
: () => context.read<HetznerFormCubit>().trySubmit(),
|
||||||
|
),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
BrandButton.text(
|
||||||
|
title: 'initializing.how'.tr(),
|
||||||
|
onPressed: () => showModalBottomSheet<void>(
|
||||||
|
context: context,
|
||||||
|
isScrollControlled: true,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return BrandBottomSheet(
|
||||||
|
isExpended: true,
|
||||||
|
child: Padding(
|
||||||
|
padding: paddingH15V0,
|
||||||
|
child: BrandMarkdown(
|
||||||
|
fileName: 'how_hetzner',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ import 'package:selfprivacy/logic/cubit/forms/factories/field_cubit_factory.dart
|
||||||
import 'package:selfprivacy/logic/cubit/forms/setup/recovering/recovery_domain_form_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/forms/setup/recovering/recovery_domain_form_cubit.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_button/FilledButton.dart';
|
import 'package:selfprivacy/ui/components/brand_button/FilledButton.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_hero_screen/brand_hero_screen.dart';
|
import 'package:selfprivacy/ui/components/brand_hero_screen/brand_hero_screen.dart';
|
||||||
|
import 'package:selfprivacy/ui/pages/setup/recovering/recover_by_old_token.dart';
|
||||||
import 'package:selfprivacy/ui/pages/setup/recovering/recover_by_recovery_key.dart';
|
import 'package:selfprivacy/ui/pages/setup/recovering/recover_by_recovery_key.dart';
|
||||||
import 'package:selfprivacy/ui/pages/setup/recovering/recover_by_new_device_key.dart';
|
import 'package:selfprivacy/ui/pages/setup/recovering/recover_by_new_device_key.dart';
|
||||||
import 'package:selfprivacy/ui/pages/setup/recovering/recovery_method_select.dart';
|
import 'package:selfprivacy/ui/pages/setup/recovering/recovery_method_select.dart';
|
||||||
|
@ -31,9 +32,12 @@ class RecoveryRouting extends StatelessWidget {
|
||||||
currentPage = RecoverByNewDeviceKeyInstruction();
|
currentPage = RecoverByNewDeviceKeyInstruction();
|
||||||
break;
|
break;
|
||||||
case RecoveryStep.OldToken:
|
case RecoveryStep.OldToken:
|
||||||
|
currentPage = RecoverByOldToken();
|
||||||
break;
|
break;
|
||||||
case RecoveryStep.HetznerToken:
|
case RecoveryStep.HetznerToken:
|
||||||
break;
|
break;
|
||||||
|
case RecoveryStep.ServerSelection:
|
||||||
|
break;
|
||||||
case RecoveryStep.CloudflareToken:
|
case RecoveryStep.CloudflareToken:
|
||||||
break;
|
break;
|
||||||
case RecoveryStep.BackblazeToken:
|
case RecoveryStep.BackblazeToken:
|
||||||
|
|
Loading…
Reference in a new issue