mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2025-01-26 18:56:38 +00:00
Implement recovery by old token pages with mock .md
Co-authored-by: Inex Code <inex.code@selfprivacy.org>
This commit is contained in:
parent
d8568fc82f
commit
6fd7f9400d
15
assets/markdown/how_fallback_old-en.md
Normal file
15
assets/markdown/how_fallback_old-en.md
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
### How to get Cloudflare API Token
|
||||||
|
1. Visit the following link: https://dash.cloudflare.com/
|
||||||
|
2. the right corner, click on the profile icon (a man in a circle). For the mobile version of the site, in the upper left corner, click the **Menu** button (three horizontal bars), in the dropdown menu, click on **My Profile**
|
||||||
|
3. There are four configuration categories to choose from: *Communication*, *Authentication*, **API Tokens**, *Session*. Choose **API Tokens**.
|
||||||
|
4. Click on **Create Token** button.
|
||||||
|
5. Go down to the bottom and see the **Create Custom Token** field and press **Get Started** button on the right side.
|
||||||
|
6. In the **Token Name** field, give your token a name.
|
||||||
|
7. Next we have Permissions. In the leftmost field, select **Zone**. In the longest field, center, select **DNS**. In the rightmost field, select **Edit**.
|
||||||
|
8. Next, right under this line, click Add More. Similar field will appear.
|
||||||
|
9. In the leftmost field of the new line, select, similar to the last line — **Zone**. In the center — a little different. Here choose the same as in the left — **Zone**. In the rightmost field, select **Read**.
|
||||||
|
10. Next look at **Zone Resources**. Under this inscription there is a line with two fields. The left must have **Include** and the right must have **Specific Zone**. Once you select Specific Zone, another field appears on the right. Choose your domain in it.
|
||||||
|
11. Flick to the bottom and press the blue **Continue to Summary** button.
|
||||||
|
12. Check if you got everything right. A similar string must be present: *Domain — DNS:Edit, Zone:Read*.
|
||||||
|
13. Click on **Create Token**.
|
||||||
|
14. We copy the created token, and save it in a reliable place (preferably in the password manager).
|
13
assets/markdown/how_fallback_old-ru.md
Normal file
13
assets/markdown/how_fallback_old-ru.md
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
### Как получить Cloudflare API Token
|
||||||
|
1. Переходим по [ссылке](https://dash.cloudflare.com/) и авторизуемся в ранее созданном аккаунте. https://dash.cloudflare.com/
|
||||||
|
В правом углу кликаем на иконку профиля (человечек в кружочке). Для мобильной версии сайта, в верхнем левом углу, нажимаем кнопку **Меню** (три горизонтальных полоски), в выпавшем меню, ищем пункт **My Profile**.
|
||||||
|
3. Нам предлагается на выбор, четыре категории настройки: **Preferences**, **Authentication**, **API Tokens**, **Sessions**. Выбираем **API Tokens**.
|
||||||
|
4. Самым первым пунктом видим кнопку **Create Token**. С полной уверенностью в себе и желанием обрести приватность, нажимаем на неё.
|
||||||
|
5. Спускаемся в самый низ и видим поле **Create Custom Token** и кнопку **Get Started** с правой стороны. Нажимаем.
|
||||||
|
6. В поле **Token Name** даём своему токену имя. Можете покреативить и отнестись к этому как к наименованию домашнего зверька :)
|
||||||
|
7. Далее, у нас **Permissions**. В первом поле выбираем Zone. Во втором поле, по центру, выбираем **DNS**. В последнем поле выбираем **Edit**.
|
||||||
|
8. Далее смотрим на **Zone Resources**. Под этой надписью есть строка с двумя полями. В первом должно быть **Include**, а во втором — **Specific Zone**. Как только Вы выберите **Specific Zone**, справа появится ещё одно поле. В нём выбираем наш домен.
|
||||||
|
9. Листаем в самый низ и нажимаем на синюю кнопку **Continue to Summary**.
|
||||||
|
10. Проверяем, всё ли мы правильно выбрали. Должна присутствовать подобная строка: ваш.домен — **DNS:Edit, Zone:Read**.
|
||||||
|
11. Нажимаем **Create Token**.
|
||||||
|
12. Копируем созданный токен, и сохраняем его в надёжном месте (желательно — в менеджере паролей).
|
15
assets/markdown/how_fallback_ssh-en.md
Normal file
15
assets/markdown/how_fallback_ssh-en.md
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
### How to get Cloudflare API Token
|
||||||
|
1. Visit the following link: https://dash.cloudflare.com/
|
||||||
|
2. the right corner, click on the profile icon (a man in a circle). For the mobile version of the site, in the upper left corner, click the **Menu** button (three horizontal bars), in the dropdown menu, click on **My Profile**
|
||||||
|
3. There are four configuration categories to choose from: *Communication*, *Authentication*, **API Tokens**, *Session*. Choose **API Tokens**.
|
||||||
|
4. Click on **Create Token** button.
|
||||||
|
5. Go down to the bottom and see the **Create Custom Token** field and press **Get Started** button on the right side.
|
||||||
|
6. In the **Token Name** field, give your token a name.
|
||||||
|
7. Next we have Permissions. In the leftmost field, select **Zone**. In the longest field, center, select **DNS**. In the rightmost field, select **Edit**.
|
||||||
|
8. Next, right under this line, click Add More. Similar field will appear.
|
||||||
|
9. In the leftmost field of the new line, select, similar to the last line — **Zone**. In the center — a little different. Here choose the same as in the left — **Zone**. In the rightmost field, select **Read**.
|
||||||
|
10. Next look at **Zone Resources**. Under this inscription there is a line with two fields. The left must have **Include** and the right must have **Specific Zone**. Once you select Specific Zone, another field appears on the right. Choose your domain in it.
|
||||||
|
11. Flick to the bottom and press the blue **Continue to Summary** button.
|
||||||
|
12. Check if you got everything right. A similar string must be present: *Domain — DNS:Edit, Zone:Read*.
|
||||||
|
13. Click on **Create Token**.
|
||||||
|
14. We copy the created token, and save it in a reliable place (preferably in the password manager).
|
13
assets/markdown/how_fallback_ssh-ru.md
Normal file
13
assets/markdown/how_fallback_ssh-ru.md
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
### Как получить Cloudflare API Token
|
||||||
|
1. Переходим по [ссылке](https://dash.cloudflare.com/) и авторизуемся в ранее созданном аккаунте. https://dash.cloudflare.com/
|
||||||
|
В правом углу кликаем на иконку профиля (человечек в кружочке). Для мобильной версии сайта, в верхнем левом углу, нажимаем кнопку **Меню** (три горизонтальных полоски), в выпавшем меню, ищем пункт **My Profile**.
|
||||||
|
3. Нам предлагается на выбор, четыре категории настройки: **Preferences**, **Authentication**, **API Tokens**, **Sessions**. Выбираем **API Tokens**.
|
||||||
|
4. Самым первым пунктом видим кнопку **Create Token**. С полной уверенностью в себе и желанием обрести приватность, нажимаем на неё.
|
||||||
|
5. Спускаемся в самый низ и видим поле **Create Custom Token** и кнопку **Get Started** с правой стороны. Нажимаем.
|
||||||
|
6. В поле **Token Name** даём своему токену имя. Можете покреативить и отнестись к этому как к наименованию домашнего зверька :)
|
||||||
|
7. Далее, у нас **Permissions**. В первом поле выбираем Zone. Во втором поле, по центру, выбираем **DNS**. В последнем поле выбираем **Edit**.
|
||||||
|
8. Далее смотрим на **Zone Resources**. Под этой надписью есть строка с двумя полями. В первом должно быть **Include**, а во втором — **Specific Zone**. Как только Вы выберите **Specific Zone**, справа появится ещё одно поле. В нём выбираем наш домен.
|
||||||
|
9. Листаем в самый низ и нажимаем на синюю кнопку **Continue to Summary**.
|
||||||
|
10. Проверяем, всё ли мы правильно выбрали. Должна присутствовать подобная строка: ваш.домен — **DNS:Edit, Zone:Read**.
|
||||||
|
11. Нажимаем **Create Token**.
|
||||||
|
12. Копируем созданный токен, и сохраняем его в надёжном месте (желательно — в менеджере паролей).
|
15
assets/markdown/how_fallback_terminal-en.md
Normal file
15
assets/markdown/how_fallback_terminal-en.md
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
### How to get Cloudflare API Token
|
||||||
|
1. Visit the following link: https://dash.cloudflare.com/
|
||||||
|
2. the right corner, click on the profile icon (a man in a circle). For the mobile version of the site, in the upper left corner, click the **Menu** button (three horizontal bars), in the dropdown menu, click on **My Profile**
|
||||||
|
3. There are four configuration categories to choose from: *Communication*, *Authentication*, **API Tokens**, *Session*. Choose **API Tokens**.
|
||||||
|
4. Click on **Create Token** button.
|
||||||
|
5. Go down to the bottom and see the **Create Custom Token** field and press **Get Started** button on the right side.
|
||||||
|
6. In the **Token Name** field, give your token a name.
|
||||||
|
7. Next we have Permissions. In the leftmost field, select **Zone**. In the longest field, center, select **DNS**. In the rightmost field, select **Edit**.
|
||||||
|
8. Next, right under this line, click Add More. Similar field will appear.
|
||||||
|
9. In the leftmost field of the new line, select, similar to the last line — **Zone**. In the center — a little different. Here choose the same as in the left — **Zone**. In the rightmost field, select **Read**.
|
||||||
|
10. Next look at **Zone Resources**. Under this inscription there is a line with two fields. The left must have **Include** and the right must have **Specific Zone**. Once you select Specific Zone, another field appears on the right. Choose your domain in it.
|
||||||
|
11. Flick to the bottom and press the blue **Continue to Summary** button.
|
||||||
|
12. Check if you got everything right. A similar string must be present: *Domain — DNS:Edit, Zone:Read*.
|
||||||
|
13. Click on **Create Token**.
|
||||||
|
14. We copy the created token, and save it in a reliable place (preferably in the password manager).
|
13
assets/markdown/how_fallback_terminal-ru.md
Normal file
13
assets/markdown/how_fallback_terminal-ru.md
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
### Как получить Cloudflare API Token
|
||||||
|
1. Переходим по [ссылке](https://dash.cloudflare.com/) и авторизуемся в ранее созданном аккаунте. https://dash.cloudflare.com/
|
||||||
|
В правом углу кликаем на иконку профиля (человечек в кружочке). Для мобильной версии сайта, в верхнем левом углу, нажимаем кнопку **Меню** (три горизонтальных полоски), в выпавшем меню, ищем пункт **My Profile**.
|
||||||
|
3. Нам предлагается на выбор, четыре категории настройки: **Preferences**, **Authentication**, **API Tokens**, **Sessions**. Выбираем **API Tokens**.
|
||||||
|
4. Самым первым пунктом видим кнопку **Create Token**. С полной уверенностью в себе и желанием обрести приватность, нажимаем на неё.
|
||||||
|
5. Спускаемся в самый низ и видим поле **Create Custom Token** и кнопку **Get Started** с правой стороны. Нажимаем.
|
||||||
|
6. В поле **Token Name** даём своему токену имя. Можете покреативить и отнестись к этому как к наименованию домашнего зверька :)
|
||||||
|
7. Далее, у нас **Permissions**. В первом поле выбираем Zone. Во втором поле, по центру, выбираем **DNS**. В последнем поле выбираем **Edit**.
|
||||||
|
8. Далее смотрим на **Zone Resources**. Под этой надписью есть строка с двумя полями. В первом должно быть **Include**, а во втором — **Specific Zone**. Как только Вы выберите **Specific Zone**, справа появится ещё одно поле. В нём выбираем наш домен.
|
||||||
|
9. Листаем в самый низ и нажимаем на синюю кнопку **Continue to Summary**.
|
||||||
|
10. Проверяем, всё ли мы правильно выбрали. Должна присутствовать подобная строка: ваш.домен — **DNS:Edit, Zone:Read**.
|
||||||
|
11. Нажимаем **Create Token**.
|
||||||
|
12. Копируем созданный токен, и сохраняем его в надёжном месте (желательно — в менеджере паролей).
|
|
@ -296,7 +296,7 @@
|
||||||
"method_device_button": "I have received my token",
|
"method_device_button": "I have received my token",
|
||||||
"method_device_input_description": "Enter your authorization token",
|
"method_device_input_description": "Enter your authorization token",
|
||||||
"method_device_input_placeholder": "Token",
|
"method_device_input_placeholder": "Token",
|
||||||
"method_recovery_input_description": "Enter your recovery token",
|
"method_recovery_input_description": "Enter your recovery key",
|
||||||
"fallback_select_description": "What exactly do you have? Pick the first available option:",
|
"fallback_select_description": "What exactly do you have? Pick the first available option:",
|
||||||
"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.",
|
||||||
|
|
|
@ -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.initializingCubit) {
|
BackblazeFormCubit(this.serverSetupCubit) {
|
||||||
//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 {
|
||||||
initializingCubit.setBackblazeKey(
|
serverSetupCubit.setBackblazeKey(
|
||||||
keyId.state.value,
|
keyId.state.value,
|
||||||
applicationKey.state.value,
|
applicationKey.state.value,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final ServerInstallationCubit initializingCubit;
|
final ServerInstallationCubit serverSetupCubit;
|
||||||
|
|
||||||
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.initializingCubit) : super(Initial());
|
DomainSetupCubit(this.serverSetupCubit) : super(Initial());
|
||||||
|
|
||||||
final ServerInstallationCubit initializingCubit;
|
final ServerInstallationCubit serverSetupCubit;
|
||||||
|
|
||||||
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,
|
||||||
);
|
);
|
||||||
|
|
||||||
initializingCubit.setDomain(domain);
|
serverSetupCubit.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.initializingCubit) {
|
HetznerFormCubit(this.serverSetupCubit) {
|
||||||
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 {
|
||||||
initializingCubit.setHetznerKey(apiKey.state.value);
|
serverSetupCubit.setHetznerKey(apiKey.state.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
final ServerInstallationCubit initializingCubit;
|
final ServerInstallationCubit serverSetupCubit;
|
||||||
|
|
||||||
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.initializingCubit, final FieldCubitFactory fieldFactory) {
|
this.serverSetupCubit, 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,
|
||||||
);
|
);
|
||||||
initializingCubit.setRootUser(user);
|
serverSetupCubit.setRootUser(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
final ServerInstallationCubit initializingCubit;
|
final ServerInstallationCubit serverSetupCubit;
|
||||||
|
|
||||||
late final FieldCubit<String> userName;
|
late final FieldCubit<String> userName;
|
||||||
late final FieldCubit<String> password;
|
late final FieldCubit<String> password;
|
||||||
|
|
|
@ -43,6 +43,10 @@ class RecoveryDomainFormCubit extends FormCubit {
|
||||||
return domainValid;
|
return domainValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FutureOr<void> setCustomError(String error) {
|
||||||
|
serverDomainField.setError(error);
|
||||||
|
}
|
||||||
|
|
||||||
final ServerInstallationCubit initializingCubit;
|
final ServerInstallationCubit initializingCubit;
|
||||||
late final FieldCubit<String> serverDomainField;
|
late final FieldCubit<String> serverDomainField;
|
||||||
}
|
}
|
||||||
|
|
|
@ -305,6 +305,46 @@ class ServerInstallationCubit extends Cubit<ServerInstallationState> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void revertRecoveryStep() {
|
||||||
|
final dataState = this.state as ServerInstallationRecovery;
|
||||||
|
switch (dataState.currentStep) {
|
||||||
|
case RecoveryStep.Selecting:
|
||||||
|
emit(ServerInstallationEmpty());
|
||||||
|
break;
|
||||||
|
case RecoveryStep.RecoveryKey:
|
||||||
|
case RecoveryStep.NewDeviceKey:
|
||||||
|
case RecoveryStep.OldToken:
|
||||||
|
emit(dataState.copyWith(
|
||||||
|
currentStep: RecoveryStep.Selecting,
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
// We won't revert steps after client is authorized
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void selectRecoveryMethod(ServerRecoveryMethods method) {
|
||||||
|
final dataState = this.state as ServerInstallationRecovery;
|
||||||
|
switch (method) {
|
||||||
|
case ServerRecoveryMethods.newDeviceKey:
|
||||||
|
emit(dataState.copyWith(
|
||||||
|
currentStep: RecoveryStep.NewDeviceKey,
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case ServerRecoveryMethods.recoveryKey:
|
||||||
|
emit(dataState.copyWith(
|
||||||
|
currentStep: RecoveryStep.RecoveryKey,
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case ServerRecoveryMethods.oldToken:
|
||||||
|
emit(dataState.copyWith(
|
||||||
|
currentStep: RecoveryStep.OldToken,
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void clearAppConfig() {
|
void clearAppConfig() {
|
||||||
closeTimer();
|
closeTimer();
|
||||||
|
|
||||||
|
|
|
@ -9,11 +9,13 @@ class BrandHeader extends StatelessWidget {
|
||||||
this.title = "",
|
this.title = "",
|
||||||
this.hasBackButton = false,
|
this.hasBackButton = false,
|
||||||
this.hasFlashButton = false,
|
this.hasFlashButton = false,
|
||||||
|
this.onBackButtonPressed,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final String title;
|
final String title;
|
||||||
final bool hasBackButton;
|
final bool hasBackButton;
|
||||||
final bool hasFlashButton;
|
final bool hasFlashButton;
|
||||||
|
final VoidCallback? onBackButtonPressed;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -29,7 +31,8 @@ class BrandHeader extends StatelessWidget {
|
||||||
if (hasBackButton) ...[
|
if (hasBackButton) ...[
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(BrandIcons.arrow_left),
|
icon: Icon(BrandIcons.arrow_left),
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
onPressed:
|
||||||
|
onBackButtonPressed ?? () => Navigator.of(context).pop(),
|
||||||
),
|
),
|
||||||
SizedBox(width: 10),
|
SizedBox(width: 10),
|
||||||
],
|
],
|
||||||
|
|
|
@ -11,6 +11,7 @@ class BrandHeroScreen extends StatelessWidget {
|
||||||
this.heroIcon,
|
this.heroIcon,
|
||||||
this.heroTitle,
|
this.heroTitle,
|
||||||
this.heroSubtitle,
|
this.heroSubtitle,
|
||||||
|
this.onBackButtonPressed,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final List<Widget> children;
|
final List<Widget> children;
|
||||||
|
@ -20,6 +21,7 @@ class BrandHeroScreen extends StatelessWidget {
|
||||||
final IconData? heroIcon;
|
final IconData? heroIcon;
|
||||||
final String? heroTitle;
|
final String? heroTitle;
|
||||||
final String? heroSubtitle;
|
final String? heroSubtitle;
|
||||||
|
final VoidCallback? onBackButtonPressed;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -31,6 +33,7 @@ class BrandHeroScreen extends StatelessWidget {
|
||||||
title: headerTitle,
|
title: headerTitle,
|
||||||
hasBackButton: hasBackButton,
|
hasBackButton: hasBackButton,
|
||||||
hasFlashButton: hasFlashButton,
|
hasFlashButton: hasFlashButton,
|
||||||
|
onBackButtonPressed: onBackButtonPressed,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: ListView(
|
body: ListView(
|
||||||
|
@ -48,9 +51,7 @@ class BrandHeroScreen extends StatelessWidget {
|
||||||
if (heroTitle != null)
|
if (heroTitle != null)
|
||||||
Text(
|
Text(
|
||||||
heroTitle!,
|
heroTitle!,
|
||||||
style: Theme.of(context).textTheme.headlineMedium?.copyWith(
|
style: Theme.of(context).textTheme.headlineMedium,
|
||||||
color: Colors.black,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.start,
|
textAlign: TextAlign.start,
|
||||||
),
|
),
|
||||||
SizedBox(height: 8.0),
|
SizedBox(height: 8.0),
|
||||||
|
|
|
@ -17,7 +17,7 @@ import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_timer/brand_timer.dart';
|
import 'package:selfprivacy/ui/components/brand_timer/brand_timer.dart';
|
||||||
import 'package:selfprivacy/ui/components/progress_bar/progress_bar.dart';
|
import 'package:selfprivacy/ui/components/progress_bar/progress_bar.dart';
|
||||||
import 'package:selfprivacy/ui/pages/rootRoute.dart';
|
import 'package:selfprivacy/ui/pages/rootRoute.dart';
|
||||||
import 'package:selfprivacy/ui/pages/setup/recovering/recovery_domain.dart';
|
import 'package:selfprivacy/ui/pages/setup/recovering/recovery_routing.dart';
|
||||||
import 'package:selfprivacy/ui/pages/setup/recovering/recovery_method_select.dart';
|
import 'package:selfprivacy/ui/pages/setup/recovering/recovery_method_select.dart';
|
||||||
import 'package:selfprivacy/utils/route_transitions/basic.dart';
|
import 'package:selfprivacy/utils/route_transitions/basic.dart';
|
||||||
|
|
||||||
|
@ -37,6 +37,10 @@ class InitializingPage extends StatelessWidget {
|
||||||
() => _stepCheck(cubit),
|
() => _stepCheck(cubit),
|
||||||
() => Container(child: Center(child: Text('initializing.finish'.tr())))
|
() => Container(child: Center(child: Text('initializing.finish'.tr())))
|
||||||
][cubit.state.progress.index]();
|
][cubit.state.progress.index]();
|
||||||
|
|
||||||
|
if (cubit is ServerInstallationRecovery) {
|
||||||
|
return RecoveryRouting();
|
||||||
|
}
|
||||||
return BlocListener<ServerInstallationCubit, ServerInstallationState>(
|
return BlocListener<ServerInstallationCubit, ServerInstallationState>(
|
||||||
listener: (context, state) {
|
listener: (context, state) {
|
||||||
if (cubit.state is ServerInstallationFinished) {
|
if (cubit.state is ServerInstallationFinished) {
|
||||||
|
|
|
@ -1,13 +1,35 @@
|
||||||
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/forms/factories/field_cubit_factory.dart';
|
|
||||||
import 'package:selfprivacy/logic/cubit/forms/setup/recovering/recovery_device_form_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/forms/setup/recovering/recovery_device_form_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_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/utils/route_transitions/basic.dart';
|
||||||
|
import 'package:cubit_form/cubit_form.dart';
|
||||||
|
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
|
||||||
|
import 'package:selfprivacy/logic/cubit/forms/factories/field_cubit_factory.dart';
|
||||||
|
|
||||||
class RecoveryMethodDevice2 extends StatelessWidget {
|
class RecoverByNewDeviceKeyInstruction extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BrandHeroScreen(
|
||||||
|
heroTitle: "recovering.recovery_main_header".tr(),
|
||||||
|
heroSubtitle: "recovering.method_device_description".tr(),
|
||||||
|
hasBackButton: true,
|
||||||
|
hasFlashButton: false,
|
||||||
|
onBackButtonPressed: () =>
|
||||||
|
context.read<ServerInstallationCubit>().revertRecoveryStep(),
|
||||||
|
children: [
|
||||||
|
FilledButton(
|
||||||
|
title: "recovering.method_device_button".tr(),
|
||||||
|
onPressed: () => Navigator.of(context)
|
||||||
|
.push(materialRoute(RecoverByNewDeviceKeyInput())),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RecoverByNewDeviceKeyInput extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var appConfig = context.watch<ServerInstallationCubit>();
|
var appConfig = context.watch<ServerInstallationCubit>();
|
79
lib/ui/pages/setup/recovering/recover_by_old_token.dart
Normal file
79
lib/ui/pages/setup/recovering/recover_by_old_token.dart
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:selfprivacy/logic/cubit/forms/setup/recovering/recovery_device_form_cubit.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_md/brand_md.dart';
|
||||||
|
import 'package:selfprivacy/utils/route_transitions/basic.dart';
|
||||||
|
import 'package:cubit_form/cubit_form.dart';
|
||||||
|
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
|
||||||
|
import 'package:selfprivacy/logic/cubit/forms/factories/field_cubit_factory.dart';
|
||||||
|
|
||||||
|
class RecoverByOldTokenInstruction extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
RecoverByOldTokenInstruction({required this.instructionFilename});
|
||||||
|
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BrandHeroScreen(
|
||||||
|
heroTitle: "recovering.recovery_main_header".tr(),
|
||||||
|
hasBackButton: true,
|
||||||
|
hasFlashButton: false,
|
||||||
|
onBackButtonPressed: () =>
|
||||||
|
context.read<ServerInstallationCubit>().revertRecoveryStep(),
|
||||||
|
children: [
|
||||||
|
BrandMarkdown(
|
||||||
|
fileName: instructionFilename,
|
||||||
|
),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
FilledButton(
|
||||||
|
title: "recovering.method_device_button".tr(),
|
||||||
|
onPressed: () =>
|
||||||
|
Navigator.of(context).push(materialRoute(RecoverByOldToken())),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String instructionFilename;
|
||||||
|
}
|
||||||
|
|
||||||
|
class RecoverByOldToken extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var appConfig = context.watch<ServerInstallationCubit>();
|
||||||
|
|
||||||
|
return BlocProvider(
|
||||||
|
create: (context) =>
|
||||||
|
RecoveryDeviceFormCubit(appConfig, FieldCubitFactory(context)),
|
||||||
|
child: Builder(
|
||||||
|
builder: (context) {
|
||||||
|
var formCubitState = context.watch<RecoveryDeviceFormCubit>().state;
|
||||||
|
|
||||||
|
return BrandHeroScreen(
|
||||||
|
heroTitle: "recovering.recovery_main_header".tr(),
|
||||||
|
heroSubtitle: "recovering.method_device_input_description".tr(),
|
||||||
|
hasBackButton: true,
|
||||||
|
hasFlashButton: false,
|
||||||
|
children: [
|
||||||
|
CubitFormTextField(
|
||||||
|
formFieldCubit:
|
||||||
|
context.read<RecoveryDeviceFormCubit>().tokenField,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
labelText: "recovering.method_device_input_placeholder".tr(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
FilledButton(
|
||||||
|
title: "more.continue".tr(),
|
||||||
|
onPressed: formCubitState.isSubmitting
|
||||||
|
? null
|
||||||
|
: () => context.read<RecoveryDeviceFormCubit>().trySubmit(),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ import 'package:selfprivacy/logic/cubit/server_installation/server_installation_
|
||||||
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';
|
||||||
|
|
||||||
class RecoveryMethodToken extends StatelessWidget {
|
class RecoverByRecoveryKey extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var appConfig = context.watch<ServerInstallationCubit>();
|
var appConfig = context.watch<ServerInstallationCubit>();
|
||||||
|
@ -24,6 +24,8 @@ class RecoveryMethodToken extends StatelessWidget {
|
||||||
heroSubtitle: "recovering.method_recovery_input_description".tr(),
|
heroSubtitle: "recovering.method_recovery_input_description".tr(),
|
||||||
hasBackButton: true,
|
hasBackButton: true,
|
||||||
hasFlashButton: false,
|
hasFlashButton: false,
|
||||||
|
onBackButtonPressed: () =>
|
||||||
|
context.read<ServerInstallationCubit>().revertRecoveryStep(),
|
||||||
children: [
|
children: [
|
||||||
CubitFormTextField(
|
CubitFormTextField(
|
||||||
formFieldCubit:
|
formFieldCubit:
|
|
@ -1,49 +0,0 @@
|
||||||
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/factories/field_cubit_factory.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 RecoveryDomain extends StatelessWidget {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
var serverInstallation = context.watch<ServerInstallationCubit>();
|
|
||||||
|
|
||||||
return BlocProvider(
|
|
||||||
create: (context) => RecoveryDomainFormCubit(
|
|
||||||
serverInstallation, FieldCubitFactory(context)),
|
|
||||||
child: Builder(
|
|
||||||
builder: (context) {
|
|
||||||
var formCubitState = context.watch<RecoveryDomainFormCubit>().state;
|
|
||||||
|
|
||||||
return BrandHeroScreen(
|
|
||||||
heroTitle: "recovering.recovery_main_header".tr(),
|
|
||||||
heroSubtitle: "recovering.domain_recovery_description".tr(),
|
|
||||||
hasBackButton: true,
|
|
||||||
hasFlashButton: false,
|
|
||||||
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(),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:selfprivacy/ui/components/brand_cards/brand_cards.dart';
|
|
||||||
import 'package:selfprivacy/ui/components/brand_hero_screen/brand_hero_screen.dart';
|
|
||||||
import 'package:selfprivacy/utils/route_transitions/basic.dart';
|
|
||||||
import 'package:selfprivacy/ui/pages/rootRoute.dart';
|
|
||||||
|
|
||||||
class RecoveryFallbackSelect extends StatelessWidget {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return BrandHeroScreen(
|
|
||||||
heroTitle: "recovering.recovery_main_header".tr(),
|
|
||||||
heroSubtitle: "recovering.fallback_select_description".tr(),
|
|
||||||
hasBackButton: true,
|
|
||||||
hasFlashButton: false,
|
|
||||||
children: [
|
|
||||||
BrandCards.outlined(
|
|
||||||
child: ListTile(
|
|
||||||
title: Text(
|
|
||||||
"recovering.fallback_select_token_copy".tr(),
|
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
|
||||||
),
|
|
||||||
leading: Icon(Icons.vpn_key),
|
|
||||||
onTap: () => Navigator.of(context).push(materialRoute(RootPage())),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(height: 16),
|
|
||||||
BrandCards.outlined(
|
|
||||||
child: ListTile(
|
|
||||||
title: Text(
|
|
||||||
"recovering.fallback_select_root_ssh".tr(),
|
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
|
||||||
),
|
|
||||||
leading: Icon(Icons.terminal),
|
|
||||||
onTap: () => Navigator.of(context).push(materialRoute(RootPage())),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(height: 16),
|
|
||||||
BrandCards.outlined(
|
|
||||||
child: ListTile(
|
|
||||||
title: Text(
|
|
||||||
"recovering.fallback_select_provider_console".tr(),
|
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
|
||||||
),
|
|
||||||
subtitle: Text(
|
|
||||||
"recovering.fallback_select_provider_console_hint".tr(),
|
|
||||||
style: Theme.of(context).textTheme.bodyMedium,
|
|
||||||
),
|
|
||||||
leading: Icon(Icons.web),
|
|
||||||
onTap: () => Navigator.of(context).push(materialRoute(RootPage())),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.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/pages/setup/recovering/recovery_method_device_2.dart';
|
|
||||||
import 'package:selfprivacy/utils/route_transitions/basic.dart';
|
|
||||||
|
|
||||||
class RecoveryMethodDevice1 extends StatelessWidget {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return BrandHeroScreen(
|
|
||||||
heroTitle: "recovering.recovery_main_header".tr(),
|
|
||||||
heroSubtitle: "recovering.method_device_description".tr(),
|
|
||||||
hasBackButton: true,
|
|
||||||
hasFlashButton: false,
|
|
||||||
children: [
|
|
||||||
FilledButton(
|
|
||||||
title: "recovering.method_device_button".tr(),
|
|
||||||
onPressed: () => Navigator.of(context)
|
|
||||||
.push(materialRoute(RecoveryMethodDevice2())),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +1,11 @@
|
||||||
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/server_installation/server_installation_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/components/brand_cards/brand_cards.dart';
|
import 'package:selfprivacy/ui/components/brand_cards/brand_cards.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/recovery_fallback_select.dart';
|
import 'package:selfprivacy/ui/pages/setup/recovering/recover_by_old_token.dart';
|
||||||
import 'package:selfprivacy/ui/pages/setup/recovering/recovery_method_device_1.dart';
|
|
||||||
import 'package:selfprivacy/ui/pages/setup/recovering/recovery_method_token.dart';
|
|
||||||
import 'package:selfprivacy/utils/route_transitions/basic.dart';
|
import 'package:selfprivacy/utils/route_transitions/basic.dart';
|
||||||
import 'package:selfprivacy/ui/pages/rootRoute.dart';
|
|
||||||
|
|
||||||
class RecoveryMethodSelect extends StatelessWidget {
|
class RecoveryMethodSelect extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
|
@ -25,8 +23,9 @@ class RecoveryMethodSelect extends StatelessWidget {
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
),
|
),
|
||||||
leading: Icon(Icons.offline_share_outlined),
|
leading: Icon(Icons.offline_share_outlined),
|
||||||
onTap: () => Navigator.of(context)
|
onTap: () => context
|
||||||
.push(materialRoute(RecoveryMethodDevice1())),
|
.read<ServerInstallationCubit>()
|
||||||
|
.selectRecoveryMethod(ServerRecoveryMethods.newDeviceKey),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 16),
|
SizedBox(height: 16),
|
||||||
|
@ -37,17 +36,77 @@ class RecoveryMethodSelect extends StatelessWidget {
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
),
|
),
|
||||||
leading: Icon(Icons.password_outlined),
|
leading: Icon(Icons.password_outlined),
|
||||||
onTap: () => Navigator.of(context)
|
onTap: () => context
|
||||||
.push(materialRoute(RecoveryMethodToken())),
|
.read<ServerInstallationCubit>()
|
||||||
|
.selectRecoveryMethod(ServerRecoveryMethods.recoveryKey),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 16),
|
SizedBox(height: 16),
|
||||||
BrandButton.text(
|
BrandButton.text(
|
||||||
title: "recovering.method_select_nothing".tr(),
|
title: "recovering.method_select_nothing".tr(),
|
||||||
onPressed: () => Navigator.of(context)
|
onPressed: () => Navigator.of(context)
|
||||||
.push(materialRoute(RecoveryFallbackSelect())),
|
.push(materialRoute(RecoveryFallbackMethodSelect())),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class RecoveryFallbackMethodSelect extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BrandHeroScreen(
|
||||||
|
heroTitle: "recovering.recovery_main_header".tr(),
|
||||||
|
heroSubtitle: "recovering.fallback_select_description".tr(),
|
||||||
|
hasBackButton: true,
|
||||||
|
hasFlashButton: false,
|
||||||
|
children: [
|
||||||
|
BrandCards.outlined(
|
||||||
|
child: ListTile(
|
||||||
|
title: Text(
|
||||||
|
"recovering.fallback_select_token_copy".tr(),
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
),
|
||||||
|
leading: Icon(Icons.vpn_key),
|
||||||
|
onTap: () => Navigator.of(context)
|
||||||
|
.push(materialRoute(RecoverByOldTokenInstruction(
|
||||||
|
instructionFilename: 'how_fallback_old',
|
||||||
|
))),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
BrandCards.outlined(
|
||||||
|
child: ListTile(
|
||||||
|
title: Text(
|
||||||
|
"recovering.fallback_select_root_ssh".tr(),
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
),
|
||||||
|
leading: Icon(Icons.terminal),
|
||||||
|
onTap: () => Navigator.of(context)
|
||||||
|
.push(materialRoute(RecoverByOldTokenInstruction(
|
||||||
|
instructionFilename: 'how_fallback_ssh',
|
||||||
|
))),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
BrandCards.outlined(
|
||||||
|
child: ListTile(
|
||||||
|
title: Text(
|
||||||
|
"recovering.fallback_select_provider_console".tr(),
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
),
|
||||||
|
subtitle: Text(
|
||||||
|
"recovering.fallback_select_provider_console_hint".tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
leading: Icon(Icons.web),
|
||||||
|
onTap: () => Navigator.of(context)
|
||||||
|
.push(materialRoute(RecoverByOldTokenInstruction(
|
||||||
|
instructionFilename: 'how_fallback_terminal',
|
||||||
|
))),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
109
lib/ui/pages/setup/recovering/recovery_routing.dart
Normal file
109
lib/ui/pages/setup/recovering/recovery_routing.dart
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
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/factories/field_cubit_factory.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';
|
||||||
|
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/recovery_method_select.dart';
|
||||||
|
|
||||||
|
class RecoveryRouting extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var serverInstallation = context.watch<ServerInstallationCubit>();
|
||||||
|
|
||||||
|
StatelessWidget currentPage = SelectDomainToRecover();
|
||||||
|
|
||||||
|
if (serverInstallation is ServerInstallationRecovery) {
|
||||||
|
final state = (serverInstallation as ServerInstallationRecovery);
|
||||||
|
switch (state.currentStep) {
|
||||||
|
case RecoveryStep.Selecting:
|
||||||
|
if (state.recoveryCapabilities != ServerRecoveryCapabilities.none)
|
||||||
|
currentPage = RecoveryMethodSelect();
|
||||||
|
break;
|
||||||
|
case RecoveryStep.RecoveryKey:
|
||||||
|
currentPage = RecoverByRecoveryKey();
|
||||||
|
break;
|
||||||
|
case RecoveryStep.NewDeviceKey:
|
||||||
|
currentPage = RecoverByNewDeviceKeyInstruction();
|
||||||
|
break;
|
||||||
|
case RecoveryStep.OldToken:
|
||||||
|
break;
|
||||||
|
case RecoveryStep.HetznerToken:
|
||||||
|
break;
|
||||||
|
case RecoveryStep.CloudflareToken:
|
||||||
|
break;
|
||||||
|
case RecoveryStep.BackblazeToken:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return AnimatedSwitcher(
|
||||||
|
duration: Duration(milliseconds: 300),
|
||||||
|
child: currentPage,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SelectDomainToRecover extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var serverInstallation = context.watch<ServerInstallationCubit>();
|
||||||
|
|
||||||
|
return BlocProvider(
|
||||||
|
create: (context) => RecoveryDomainFormCubit(
|
||||||
|
serverInstallation, FieldCubitFactory(context)),
|
||||||
|
child: 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(),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue