mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2025-01-11 10:29:39 +00:00
Improve server endpoints, add recovery page
- Handle Dio error codes properly to avoid exceptions - Improve en and ru assets - Improve dns recordings failure handling - Add recovery button to initializing page - Add recovery pages group
This commit is contained in:
parent
31be961dd0
commit
ce3e046f5a
|
@ -21,7 +21,8 @@
|
|||
"saving": "Saving..",
|
||||
"nickname": "Nickname",
|
||||
"loading": "Loading...",
|
||||
"later": "I will setup it later",
|
||||
"later": "Skip to setup later",
|
||||
"connect_to_existing": "Connect to existing server",
|
||||
"reset": "Reset",
|
||||
"details": "Details",
|
||||
"no_data": "No data",
|
||||
|
|
|
@ -21,7 +21,8 @@
|
|||
"saving": "Сохранение…",
|
||||
"nickname": "Никнейм",
|
||||
"loading": "Загрузка",
|
||||
"later": "Настрою потом",
|
||||
"later": "Пропустить и настроить потом",
|
||||
"connect_to_existing": "Подключиться к существующему серверу",
|
||||
"reset": "Сбросить",
|
||||
"details": "Детальная информация",
|
||||
"no_data": "Нет данных",
|
||||
|
|
|
@ -58,7 +58,17 @@ class ServerApi extends ApiMap {
|
|||
|
||||
var client = await getClient();
|
||||
try {
|
||||
response = await client.get('/services/status');
|
||||
response = await client.get(
|
||||
'/services/status',
|
||||
options: Options(
|
||||
contentType: 'application/json',
|
||||
receiveDataWhenStatusError: true,
|
||||
followRedirects: false,
|
||||
validateStatus: (status) {
|
||||
return (status != null) &&
|
||||
(status < HttpStatus.internalServerError);
|
||||
}),
|
||||
);
|
||||
res = response.statusCode == HttpStatus.ok;
|
||||
} catch (e) {
|
||||
res = false;
|
||||
|
@ -129,7 +139,17 @@ class ServerApi extends ApiMap {
|
|||
Response response;
|
||||
|
||||
var client = await getClient();
|
||||
response = await client.get('/users');
|
||||
response = await client.get(
|
||||
'/users',
|
||||
options: Options(
|
||||
contentType: 'application/json',
|
||||
receiveDataWhenStatusError: true,
|
||||
followRedirects: false,
|
||||
validateStatus: (status) {
|
||||
return (status != null) &&
|
||||
(status < HttpStatus.internalServerError);
|
||||
}),
|
||||
);
|
||||
try {
|
||||
for (var user in response.data) {
|
||||
res.add(user.toString());
|
||||
|
@ -155,6 +175,14 @@ class ServerApi extends ApiMap {
|
|||
data: {
|
||||
'public_key': sshKey,
|
||||
},
|
||||
options: Options(
|
||||
contentType: 'application/json',
|
||||
receiveDataWhenStatusError: true,
|
||||
followRedirects: false,
|
||||
validateStatus: (status) {
|
||||
return (status != null) &&
|
||||
(status < HttpStatus.internalServerError);
|
||||
}),
|
||||
);
|
||||
|
||||
close(client);
|
||||
|
@ -174,6 +202,14 @@ class ServerApi extends ApiMap {
|
|||
response = await client.put(
|
||||
'/services/ssh/key/send',
|
||||
data: {"public_key": ssh},
|
||||
options: Options(
|
||||
contentType: 'application/json',
|
||||
receiveDataWhenStatusError: true,
|
||||
followRedirects: false,
|
||||
validateStatus: (status) {
|
||||
return (status != null) &&
|
||||
(status < HttpStatus.internalServerError);
|
||||
}),
|
||||
);
|
||||
close(client);
|
||||
|
||||
|
@ -191,7 +227,17 @@ class ServerApi extends ApiMap {
|
|||
Response response;
|
||||
|
||||
var client = await getClient();
|
||||
response = await client.get('/services/ssh/keys/${user.login}');
|
||||
response = await client.get(
|
||||
'/services/ssh/keys/${user.login}',
|
||||
options: Options(
|
||||
contentType: 'application/json',
|
||||
receiveDataWhenStatusError: true,
|
||||
followRedirects: false,
|
||||
validateStatus: (status) {
|
||||
return (status != null) &&
|
||||
(status < HttpStatus.internalServerError);
|
||||
}),
|
||||
);
|
||||
try {
|
||||
res = (response.data as List<dynamic>).map((e) => e as String).toList();
|
||||
} catch (e) {
|
||||
|
@ -215,8 +261,18 @@ class ServerApi extends ApiMap {
|
|||
Response response;
|
||||
|
||||
var client = await getClient();
|
||||
response = await client.delete('/services/ssh/keys/${user.login}',
|
||||
data: {"public_key": sshKey});
|
||||
response = await client.delete(
|
||||
'/services/ssh/keys/${user.login}',
|
||||
data: {"public_key": sshKey},
|
||||
options: Options(
|
||||
contentType: 'application/json',
|
||||
receiveDataWhenStatusError: true,
|
||||
followRedirects: false,
|
||||
validateStatus: (status) {
|
||||
return (status != null) &&
|
||||
(status < HttpStatus.internalServerError);
|
||||
}),
|
||||
);
|
||||
close(client);
|
||||
|
||||
return ApiResponse<void>(
|
||||
|
@ -237,8 +293,13 @@ class ServerApi extends ApiMap {
|
|||
response = await client.delete(
|
||||
'/users/${user.login}',
|
||||
options: Options(
|
||||
contentType: 'application/json',
|
||||
),
|
||||
contentType: 'application/json',
|
||||
receiveDataWhenStatusError: true,
|
||||
followRedirects: false,
|
||||
validateStatus: (status) {
|
||||
return (status != null) &&
|
||||
(status < HttpStatus.internalServerError);
|
||||
}),
|
||||
);
|
||||
res = response.statusCode == HttpStatus.ok ||
|
||||
response.statusCode == HttpStatus.notFound;
|
||||
|
@ -262,6 +323,14 @@ class ServerApi extends ApiMap {
|
|||
try {
|
||||
response = await client.get(
|
||||
'/system/configuration/apply',
|
||||
options: Options(
|
||||
contentType: 'application/json',
|
||||
receiveDataWhenStatusError: true,
|
||||
followRedirects: false,
|
||||
validateStatus: (status) {
|
||||
return (status != null) &&
|
||||
(status < HttpStatus.internalServerError);
|
||||
}),
|
||||
);
|
||||
|
||||
res = response.statusCode == HttpStatus.ok;
|
||||
|
@ -276,13 +345,33 @@ class ServerApi extends ApiMap {
|
|||
|
||||
Future<void> switchService(ServiceTypes type, bool needToTurnOn) async {
|
||||
var client = await getClient();
|
||||
client.post('/services/${type.url}/${needToTurnOn ? 'enable' : 'disable'}');
|
||||
client.post(
|
||||
'/services/${type.url}/${needToTurnOn ? 'enable' : 'disable'}',
|
||||
options: Options(
|
||||
contentType: 'application/json',
|
||||
receiveDataWhenStatusError: true,
|
||||
followRedirects: false,
|
||||
validateStatus: (status) {
|
||||
return (status != null) &&
|
||||
(status < HttpStatus.internalServerError);
|
||||
}),
|
||||
);
|
||||
close(client);
|
||||
}
|
||||
|
||||
Future<Map<ServiceTypes, bool>> servicesPowerCheck() async {
|
||||
var client = await getClient();
|
||||
Response response = await client.get('/services/status');
|
||||
Response response = await client.get(
|
||||
'/services/status',
|
||||
options: Options(
|
||||
contentType: 'application/json',
|
||||
receiveDataWhenStatusError: true,
|
||||
followRedirects: false,
|
||||
validateStatus: (status) {
|
||||
return (status != null) &&
|
||||
(status < HttpStatus.internalServerError);
|
||||
}),
|
||||
);
|
||||
|
||||
close(client);
|
||||
return {
|
||||
|
@ -303,13 +392,31 @@ class ServerApi extends ApiMap {
|
|||
'accountKey': bucket.applicationKey,
|
||||
'bucket': bucket.bucketName,
|
||||
},
|
||||
options: Options(
|
||||
contentType: 'application/json',
|
||||
receiveDataWhenStatusError: true,
|
||||
followRedirects: false,
|
||||
validateStatus: (status) {
|
||||
return (status != null) &&
|
||||
(status < HttpStatus.internalServerError);
|
||||
}),
|
||||
);
|
||||
close(client);
|
||||
}
|
||||
|
||||
Future<void> startBackup() async {
|
||||
var client = await getClient();
|
||||
client.put('/services/restic/backup/create');
|
||||
client.put(
|
||||
'/services/restic/backup/create',
|
||||
options: Options(
|
||||
contentType: 'application/json',
|
||||
receiveDataWhenStatusError: true,
|
||||
followRedirects: false,
|
||||
validateStatus: (status) {
|
||||
return (status != null) &&
|
||||
(status < HttpStatus.internalServerError);
|
||||
}),
|
||||
);
|
||||
close(client);
|
||||
}
|
||||
|
||||
|
@ -320,6 +427,14 @@ class ServerApi extends ApiMap {
|
|||
try {
|
||||
response = await client.get(
|
||||
'/services/restic/backup/list',
|
||||
options: Options(
|
||||
contentType: 'application/json',
|
||||
receiveDataWhenStatusError: true,
|
||||
followRedirects: false,
|
||||
validateStatus: (status) {
|
||||
return (status != null) &&
|
||||
(status < HttpStatus.internalServerError);
|
||||
}),
|
||||
);
|
||||
return response.data.map<Backup>((e) => Backup.fromJson(e)).toList();
|
||||
} catch (e) {
|
||||
|
@ -336,6 +451,14 @@ class ServerApi extends ApiMap {
|
|||
try {
|
||||
response = await client.get(
|
||||
'/services/restic/backup/status',
|
||||
options: Options(
|
||||
contentType: 'application/json',
|
||||
receiveDataWhenStatusError: true,
|
||||
followRedirects: false,
|
||||
validateStatus: (status) {
|
||||
return (status != null) &&
|
||||
(status < HttpStatus.internalServerError);
|
||||
}),
|
||||
);
|
||||
return BackupStatus.fromJson(response.data);
|
||||
} catch (e) {
|
||||
|
@ -352,40 +475,101 @@ class ServerApi extends ApiMap {
|
|||
|
||||
Future<void> forceBackupListReload() async {
|
||||
var client = await getClient();
|
||||
client.get('/services/restic/backup/reload');
|
||||
client.get(
|
||||
'/services/restic/backup/reload',
|
||||
options: Options(
|
||||
contentType: 'application/json',
|
||||
receiveDataWhenStatusError: true,
|
||||
followRedirects: false,
|
||||
validateStatus: (status) {
|
||||
return (status != null) &&
|
||||
(status < HttpStatus.internalServerError);
|
||||
}),
|
||||
);
|
||||
close(client);
|
||||
}
|
||||
|
||||
Future<void> restoreBackup(String backupId) async {
|
||||
var client = await getClient();
|
||||
client.put('/services/restic/backup/restore', data: {'backupId': backupId});
|
||||
client.put(
|
||||
'/services/restic/backup/restore',
|
||||
data: {'backupId': backupId},
|
||||
options: Options(
|
||||
contentType: 'application/json',
|
||||
receiveDataWhenStatusError: true,
|
||||
followRedirects: false,
|
||||
validateStatus: (status) {
|
||||
return (status != null) &&
|
||||
(status < HttpStatus.internalServerError);
|
||||
}),
|
||||
);
|
||||
close(client);
|
||||
}
|
||||
|
||||
Future<bool> pullConfigurationUpdate() async {
|
||||
var client = await getClient();
|
||||
Response response = await client.get('/system/configuration/pull');
|
||||
Response response = await client.get(
|
||||
'/system/configuration/pull',
|
||||
options: Options(
|
||||
contentType: 'application/json',
|
||||
receiveDataWhenStatusError: true,
|
||||
followRedirects: false,
|
||||
validateStatus: (status) {
|
||||
return (status != null) &&
|
||||
(status < HttpStatus.internalServerError);
|
||||
}),
|
||||
);
|
||||
close(client);
|
||||
return response.statusCode == HttpStatus.ok;
|
||||
}
|
||||
|
||||
Future<bool> reboot() async {
|
||||
var client = await getClient();
|
||||
Response response = await client.get('/system/reboot');
|
||||
Response response = await client.get(
|
||||
'/system/reboot',
|
||||
options: Options(
|
||||
contentType: 'application/json',
|
||||
receiveDataWhenStatusError: true,
|
||||
followRedirects: false,
|
||||
validateStatus: (status) {
|
||||
return (status != null) &&
|
||||
(status < HttpStatus.internalServerError);
|
||||
}),
|
||||
);
|
||||
close(client);
|
||||
return response.statusCode == HttpStatus.ok;
|
||||
}
|
||||
|
||||
Future<bool> upgrade() async {
|
||||
var client = await getClient();
|
||||
Response response = await client.get('/system/configuration/upgrade');
|
||||
Response response = await client.get(
|
||||
'/system/configuration/upgrade',
|
||||
options: Options(
|
||||
contentType: 'application/json',
|
||||
receiveDataWhenStatusError: true,
|
||||
followRedirects: false,
|
||||
validateStatus: (status) {
|
||||
return (status != null) &&
|
||||
(status < HttpStatus.internalServerError);
|
||||
}),
|
||||
);
|
||||
close(client);
|
||||
return response.statusCode == HttpStatus.ok;
|
||||
}
|
||||
|
||||
Future<AutoUpgradeSettings> getAutoUpgradeSettings() async {
|
||||
var client = await getClient();
|
||||
Response response = await client.get('/system/configuration/autoUpgrade');
|
||||
Response response = await client.get(
|
||||
'/system/configuration/autoUpgrade',
|
||||
options: Options(
|
||||
contentType: 'application/json',
|
||||
receiveDataWhenStatusError: true,
|
||||
followRedirects: false,
|
||||
validateStatus: (status) {
|
||||
return (status != null) &&
|
||||
(status < HttpStatus.internalServerError);
|
||||
}),
|
||||
);
|
||||
close(client);
|
||||
return AutoUpgradeSettings.fromJson(response.data);
|
||||
}
|
||||
|
@ -395,13 +579,31 @@ class ServerApi extends ApiMap {
|
|||
await client.put(
|
||||
'/system/configuration/autoUpgrade',
|
||||
data: settings.toJson(),
|
||||
options: Options(
|
||||
contentType: 'application/json',
|
||||
receiveDataWhenStatusError: true,
|
||||
followRedirects: false,
|
||||
validateStatus: (status) {
|
||||
return (status != null) &&
|
||||
(status < HttpStatus.internalServerError);
|
||||
}),
|
||||
);
|
||||
close(client);
|
||||
}
|
||||
|
||||
Future<TimeZoneSettings> getServerTimezone() async {
|
||||
var client = await getClient();
|
||||
Response response = await client.get('/system/configuration/timezone');
|
||||
Response response = await client.get(
|
||||
'/system/configuration/timezone',
|
||||
options: Options(
|
||||
contentType: 'application/json',
|
||||
receiveDataWhenStatusError: true,
|
||||
followRedirects: false,
|
||||
validateStatus: (status) {
|
||||
return (status != null) &&
|
||||
(status < HttpStatus.internalServerError);
|
||||
}),
|
||||
);
|
||||
close(client);
|
||||
|
||||
return TimeZoneSettings.fromString(response.data);
|
||||
|
@ -412,20 +614,45 @@ class ServerApi extends ApiMap {
|
|||
await client.put(
|
||||
'/system/configuration/timezone',
|
||||
data: settings.toJson(),
|
||||
options: Options(
|
||||
contentType: 'application/json',
|
||||
receiveDataWhenStatusError: true,
|
||||
followRedirects: false,
|
||||
validateStatus: (status) {
|
||||
return (status != null) &&
|
||||
(status < HttpStatus.internalServerError);
|
||||
}),
|
||||
);
|
||||
close(client);
|
||||
}
|
||||
|
||||
Future<String> getDkim() async {
|
||||
Future<String?> getDkim() async {
|
||||
var client = await getClient();
|
||||
Response response = await client.get('/services/mailserver/dkim');
|
||||
Response response = await client.get(
|
||||
'/services/mailserver/dkim',
|
||||
options: Options(
|
||||
contentType: 'application/json',
|
||||
receiveDataWhenStatusError: true,
|
||||
followRedirects: false,
|
||||
validateStatus: (status) {
|
||||
return (status != null) &&
|
||||
(status < HttpStatus.internalServerError);
|
||||
}),
|
||||
);
|
||||
close(client);
|
||||
|
||||
// if got 404 raise exception
|
||||
if (response.statusCode == HttpStatus.notFound) {
|
||||
if (response.statusCode == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (response.statusCode == HttpStatus.notFound || response.data == null) {
|
||||
throw Exception('No DKIM key found');
|
||||
}
|
||||
|
||||
if (response.statusCode != HttpStatus.ok) {
|
||||
return "";
|
||||
}
|
||||
|
||||
final base64toString = utf8.fuse(base64);
|
||||
|
||||
return base64toString
|
||||
|
|
|
@ -206,7 +206,7 @@ class AppConfigRepository {
|
|||
|
||||
var dkimRecordString = await api.getDkim();
|
||||
|
||||
await cloudflareApi.setDkim(dkimRecordString, cloudFlareDomain);
|
||||
await cloudflareApi.setDkim(dkimRecordString ?? "", cloudFlareDomain);
|
||||
}
|
||||
|
||||
Future<bool> isHttpServerWorking() async {
|
||||
|
|
|
@ -97,11 +97,11 @@ class DnsRecordsCubit extends AppConfigDependendCubit<DnsRecordsState> {
|
|||
emit(state.copyWith(dnsState: DnsRecordsStatus.refreshing));
|
||||
final CloudFlareDomain? domain = appConfigCubit.state.cloudFlareDomain;
|
||||
final String? ipAddress = appConfigCubit.state.hetznerServer?.ip4;
|
||||
final dkimPublicKey = await api.getDkim();
|
||||
final String? dkimPublicKey = await api.getDkim();
|
||||
await cloudflare.removeSimilarRecords(cloudFlareDomain: domain!);
|
||||
await cloudflare.createMultipleDnsRecords(
|
||||
cloudFlareDomain: domain, ip4: ipAddress);
|
||||
await cloudflare.setDkim(dkimPublicKey, domain);
|
||||
await cloudflare.setDkim(dkimPublicKey ?? "", domain);
|
||||
await load();
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:selfprivacy/config/hive_config.dart';
|
||||
import 'package:selfprivacy/ui/pages/initializing/initializing.dart';
|
||||
import 'package:selfprivacy/ui/pages/setup/initializing.dart';
|
||||
import 'package:selfprivacy/ui/pages/onboarding/onboarding.dart';
|
||||
import 'package:selfprivacy/ui/pages/rootRoute.dart';
|
||||
import 'package:wakelock/wakelock.dart';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:selfprivacy/config/brand_colors.dart';
|
||||
import 'package:selfprivacy/config/text_themes.dart';
|
||||
import 'package:selfprivacy/ui/pages/initializing/initializing.dart';
|
||||
import 'package:selfprivacy/ui/pages/setup/initializing.dart';
|
||||
import 'package:selfprivacy/utils/route_transitions/basic.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import 'package:selfprivacy/ui/components/brand_divider/brand_divider.dart';
|
|||
import 'package:selfprivacy/ui/components/brand_header/brand_header.dart';
|
||||
import 'package:selfprivacy/ui/components/brand_icons/brand_icons.dart';
|
||||
import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
|
||||
import 'package:selfprivacy/ui/pages/initializing/initializing.dart';
|
||||
import 'package:selfprivacy/ui/pages/setup/initializing.dart';
|
||||
import 'package:selfprivacy/ui/pages/onboarding/onboarding.dart';
|
||||
import 'package:selfprivacy/ui/pages/rootRoute.dart';
|
||||
import 'package:selfprivacy/ui/pages/ssh_keys/ssh_keys.dart';
|
||||
|
|
|
@ -17,13 +17,14 @@ 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/progress_bar/progress_bar.dart';
|
||||
import 'package:selfprivacy/ui/pages/rootRoute.dart';
|
||||
import 'package:selfprivacy/ui/pages/setup/recovering/recovery_domain.dart';
|
||||
import 'package:selfprivacy/utils/route_transitions/basic.dart';
|
||||
|
||||
class InitializingPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var cubit = context.watch<AppConfigCubit>();
|
||||
var actualPage = [
|
||||
var actualInitializingPage = [
|
||||
() => _stepHetzner(cubit),
|
||||
() => _stepCloudflare(cubit),
|
||||
() => _stepBackblaze(cubit),
|
||||
|
@ -69,7 +70,7 @@ class InitializingPage extends StatelessWidget {
|
|||
_addCard(
|
||||
AnimatedSwitcher(
|
||||
duration: Duration(milliseconds: 300),
|
||||
child: actualPage,
|
||||
child: actualInitializingPage,
|
||||
),
|
||||
),
|
||||
ConstrainedBox(
|
||||
|
@ -79,19 +80,38 @@ class InitializingPage extends StatelessWidget {
|
|||
MediaQuery.of(context).padding.bottom -
|
||||
566,
|
||||
),
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
child: BrandButton.text(
|
||||
title: cubit.state is AppConfigFinished
|
||||
? 'basis.close'.tr()
|
||||
: 'basis.later'.tr(),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pushAndRemoveUntil(
|
||||
materialRoute(RootPage()),
|
||||
(predicate) => false,
|
||||
);
|
||||
},
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
alignment: Alignment.center,
|
||||
child: BrandButton.text(
|
||||
title: cubit.state is AppConfigFinished
|
||||
? 'basis.close'.tr()
|
||||
: 'basis.later'.tr(),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pushAndRemoveUntil(
|
||||
materialRoute(RootPage()),
|
||||
(predicate) => false,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
(cubit.state is AppConfigFinished)
|
||||
? Container()
|
||||
: Container(
|
||||
alignment: Alignment.center,
|
||||
child: BrandButton.text(
|
||||
title: 'basis.connect_to_existing'.tr(),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pushAndRemoveUntil(
|
||||
materialRoute(RecoveryDomain()),
|
||||
(predicate) => false,
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
)),
|
||||
],
|
||||
),
|
54
lib/ui/pages/setup/recovering/recovery_domain.dart
Normal file
54
lib/ui/pages/setup/recovering/recovery_domain.dart
Normal file
|
@ -0,0 +1,54 @@
|
|||
import 'package:cubit_form/cubit_form.dart';
|
||||
import 'package:easy_localization/easy_localization.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/pages/rootRoute.dart';
|
||||
import 'package:selfprivacy/utils/route_transitions/basic.dart';
|
||||
|
||||
class RecoveryDomain extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var cubit = context.watch<AppConfigCubit>();
|
||||
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: [
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
minHeight: MediaQuery.of(context).size.height -
|
||||
MediaQuery.of(context).padding.top -
|
||||
MediaQuery.of(context).padding.bottom -
|
||||
566,
|
||||
),
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
child: BrandButton.text(
|
||||
title: cubit.state is AppConfigFinished
|
||||
? 'basis.close'.tr()
|
||||
: 'basis.later'.tr(),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pushAndRemoveUntil(
|
||||
materialRoute(RootPage()),
|
||||
(predicate) => false,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue