refactor(initializing): Refresh the server istallation UI
parent
040de69268
commit
b007fec75b
|
@ -0,0 +1,6 @@
|
||||||
|
<svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M12.0013 24.0128V19.3592C16.927 19.3592 20.7505 14.4743 18.8591 9.2901C18.1652 7.37152 16.6276 5.83395 14.709 5.14C9.52482 3.26224 4.63995 7.07217 4.63995 11.9979H0C0 4.14669 7.59264 -1.97641 15.8248 0.595295C19.417 1.72467 22.2881 4.58211 23.4038 8.17433C25.9755 16.4201 19.8661 24.0128 12.0013 24.0128Z" fill="white"/>
|
||||||
|
<path d="M12.0149 19.3729H7.38855V14.7466H12.0149V19.3729Z" fill="white"/>
|
||||||
|
<path d="M7.38861 22.9376H3.82361V19.3726H7.38861V22.9376Z" fill="white"/>
|
||||||
|
<path d="M3.82354 19.373H0.843628V16.3931H3.82354V19.373Z" fill="white"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 657 B |
|
@ -0,0 +1,10 @@
|
||||||
|
<svg width="24" height="23" viewBox="0 0 24 23" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_51804_9018)">
|
||||||
|
<path d="M22.5704 0H19.3252C18.5948 0 18.2817 0.302609 18.2817 1.04348V9.25565H5.35304V1.04348C5.35304 0.313043 5.05044 0 4.30957 0H1.04348C0.302609 0 0 0.302609 0 1.04348V22.1739C0 22.9148 0.302609 23.2174 1.04348 23.2174H4.30957C5.04 23.2174 5.35304 22.9252 5.35304 22.1739V13.8261H18.2922V22.1739C18.2922 22.9043 18.5948 23.2174 19.3357 23.2174H22.5809C23.3113 23.2174 23.6243 22.9148 23.6243 22.1739V1.04348C23.6035 0.333913 23.3009 0 22.5704 0Z" fill="white"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_51804_9018">
|
||||||
|
<rect width="24" height="22.9565" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 722 B |
File diff suppressed because it is too large
Load Diff
|
@ -90,7 +90,8 @@ class BackblazeApi extends ApiMap {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if (response.statusCode == HttpStatus.ok) {
|
if (response.statusCode == HttpStatus.ok) {
|
||||||
isTokenValid = response.data['allowed']['capabilities'].contains('listBuckets');
|
isTokenValid =
|
||||||
|
response.data['allowed']['capabilities'].contains('listBuckets');
|
||||||
} else if (response.statusCode == HttpStatus.unauthorized) {
|
} else if (response.statusCode == HttpStatus.unauthorized) {
|
||||||
isTokenValid = false;
|
isTokenValid = false;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:material_color_utilities/material_color_utilities.dart'
|
||||||
|
as color_utils;
|
||||||
|
import 'package:selfprivacy/config/brand_colors.dart';
|
||||||
import 'package:selfprivacy/config/hive_config.dart';
|
import 'package:selfprivacy/config/hive_config.dart';
|
||||||
|
import 'package:selfprivacy/theming/factory/app_theme_factory.dart';
|
||||||
|
|
||||||
export 'package:provider/provider.dart';
|
export 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
@ -20,7 +25,7 @@ class AppSettingsCubit extends Cubit<AppSettingsState> {
|
||||||
|
|
||||||
Box box = Hive.box(BNames.appSettingsBox);
|
Box box = Hive.box(BNames.appSettingsBox);
|
||||||
|
|
||||||
void load() {
|
void load() async {
|
||||||
final bool? isDarkModeOn = box.get(BNames.isDarkModeOn);
|
final bool? isDarkModeOn = box.get(BNames.isDarkModeOn);
|
||||||
final bool? isOnboardingShowing = box.get(BNames.isOnboardingShowing);
|
final bool? isOnboardingShowing = box.get(BNames.isOnboardingShowing);
|
||||||
emit(
|
emit(
|
||||||
|
@ -29,6 +34,14 @@ class AppSettingsCubit extends Cubit<AppSettingsState> {
|
||||||
isOnboardingShowing: isOnboardingShowing,
|
isOnboardingShowing: isOnboardingShowing,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
final color_utils.CorePalette? colorPalette =
|
||||||
|
await AppThemeFactory.getCorePalette();
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
corePalette: colorPalette,
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateDarkMode({required final bool isDarkModeOn}) {
|
void updateDarkMode({required final bool isDarkModeOn}) {
|
||||||
|
|
|
@ -4,20 +4,27 @@ class AppSettingsState extends Equatable {
|
||||||
const AppSettingsState({
|
const AppSettingsState({
|
||||||
required this.isDarkModeOn,
|
required this.isDarkModeOn,
|
||||||
required this.isOnboardingShowing,
|
required this.isOnboardingShowing,
|
||||||
|
this.corePalette,
|
||||||
});
|
});
|
||||||
|
|
||||||
final bool isDarkModeOn;
|
final bool isDarkModeOn;
|
||||||
final bool isOnboardingShowing;
|
final bool isOnboardingShowing;
|
||||||
|
final color_utils.CorePalette? corePalette;
|
||||||
|
|
||||||
AppSettingsState copyWith({
|
AppSettingsState copyWith({
|
||||||
final bool? isDarkModeOn,
|
final bool? isDarkModeOn,
|
||||||
final bool? isOnboardingShowing,
|
final bool? isOnboardingShowing,
|
||||||
|
final color_utils.CorePalette? corePalette,
|
||||||
}) =>
|
}) =>
|
||||||
AppSettingsState(
|
AppSettingsState(
|
||||||
isDarkModeOn: isDarkModeOn ?? this.isDarkModeOn,
|
isDarkModeOn: isDarkModeOn ?? this.isDarkModeOn,
|
||||||
isOnboardingShowing: isOnboardingShowing ?? this.isOnboardingShowing,
|
isOnboardingShowing: isOnboardingShowing ?? this.isOnboardingShowing,
|
||||||
|
corePalette: corePalette ?? this.corePalette,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
color_utils.CorePalette get corePaletteOrDefault =>
|
||||||
|
corePalette ?? color_utils.CorePalette.of(BrandColors.primary.value);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object> get props => [isDarkModeOn, isOnboardingShowing];
|
List<dynamic> get props => [isDarkModeOn, isOnboardingShowing, corePalette];
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,4 +95,15 @@ enum ServerProvider {
|
||||||
return unknown;
|
return unknown;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String get displayName {
|
||||||
|
switch (this) {
|
||||||
|
case ServerProvider.hetzner:
|
||||||
|
return 'Hetzner Cloud';
|
||||||
|
case ServerProvider.digitalOcean:
|
||||||
|
return 'Digital Ocean';
|
||||||
|
default:
|
||||||
|
return 'Unknown';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,7 @@ abstract class AppThemeFactory {
|
||||||
brightness: brightness,
|
brightness: brightness,
|
||||||
);
|
);
|
||||||
|
|
||||||
final ColorScheme colorScheme =
|
final ColorScheme colorScheme = dynamicColorsScheme ?? fallbackColorScheme;
|
||||||
dynamicColorsScheme ?? fallbackColorScheme;
|
|
||||||
|
|
||||||
final Typography appTypography = Typography.material2021();
|
final Typography appTypography = Typography.material2021();
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:selfprivacy/config/brand_colors.dart';
|
import 'package:selfprivacy/config/brand_colors.dart';
|
||||||
import 'package:selfprivacy/config/text_themes.dart';
|
import 'package:selfprivacy/config/text_themes.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/app_settings/app_settings_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/app_settings/app_settings_cubit.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
|
|
||||||
|
|
||||||
class ProgressBar extends StatefulWidget {
|
class ProgressBar extends StatefulWidget {
|
||||||
const ProgressBar({
|
const ProgressBar({
|
||||||
|
@ -63,13 +62,6 @@ class _ProgressBarState extends State<ProgressBar> {
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
BrandText.h2('Progress'),
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: even,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 7),
|
|
||||||
Container(
|
Container(
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
|
@ -98,11 +90,6 @@ class _ProgressBarState extends State<ProgressBar> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 5),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: odd,
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/app_settings/app_settings_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/app_settings/app_settings_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_text/brand_text.dart';
|
|
||||||
import 'package:selfprivacy/utils/route_transitions/basic.dart';
|
import 'package:selfprivacy/utils/route_transitions/basic.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
|
||||||
|
@ -49,11 +48,16 @@ class _OnboardingPageState extends State<OnboardingPage> {
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 30),
|
||||||
BrandText.h2(
|
Text(
|
||||||
'onboarding.page1_title'.tr(),
|
'onboarding.page1_title'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.headlineSmall,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 16),
|
||||||
BrandText.body2('onboarding.page1_text'.tr()),
|
Text(
|
||||||
|
'onboarding.page1_text'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
Flexible(
|
Flexible(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Image.asset(
|
child: Image.asset(
|
||||||
|
@ -86,34 +90,49 @@ class _OnboardingPageState extends State<OnboardingPage> {
|
||||||
maxHeight: MediaQuery.of(context).size.height,
|
maxHeight: MediaQuery.of(context).size.height,
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 30),
|
||||||
BrandText.h2('onboarding.page2_title'.tr()),
|
Text(
|
||||||
const SizedBox(height: 20),
|
'onboarding.page2_title'.tr(),
|
||||||
BrandText.body2('onboarding.page2_text'.tr()),
|
style: Theme.of(context).textTheme.headlineSmall,
|
||||||
const SizedBox(height: 20),
|
|
||||||
Center(
|
|
||||||
child: Image.asset(
|
|
||||||
_fileName(
|
|
||||||
context: context,
|
|
||||||
path: 'assets/images/onboarding',
|
|
||||||
fileExtention: 'png',
|
|
||||||
fileName: 'logos_line',
|
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
'onboarding.page2_text'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
'onboarding.page2_server_provider_title'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.titleLarge,
|
||||||
),
|
),
|
||||||
Flexible(
|
const SizedBox(height: 16),
|
||||||
child: Center(
|
Text(
|
||||||
child: Image.asset(
|
'onboarding.page2_server_provider_text'.tr(),
|
||||||
_fileName(
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
context: context,
|
|
||||||
path: 'assets/images/onboarding',
|
|
||||||
fileExtention: 'png',
|
|
||||||
fileName: 'onboarding2',
|
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
'onboarding.page2_dns_provider_title'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.titleLarge,
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
'onboarding.page2_dns_provider_text'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
'onboarding.page2_backup_provider_title'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.titleLarge,
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
'onboarding.page2_backup_provider_text'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
BrandButton.rised(
|
BrandButton.rised(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.read<AppSettingsCubit>().turnOffOnboarding();
|
context.read<AppSettingsCubit>().turnOffOnboarding();
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
import 'dart:ui';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:selfprivacy/config/brand_theme.dart';
|
import 'package:selfprivacy/config/brand_theme.dart';
|
||||||
|
|
|
@ -11,7 +11,6 @@ import 'package:selfprivacy/logic/cubit/forms/setup/initializing/domain_setup_cu
|
||||||
import 'package:selfprivacy/logic/cubit/forms/setup/initializing/root_user_form_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/forms/setup/initializing/root_user_form_cubit.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_bottom_sheet/brand_bottom_sheet.dart';
|
import 'package:selfprivacy/ui/components/brand_bottom_sheet/brand_bottom_sheet.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_button/brand_button.dart';
|
import 'package:selfprivacy/ui/components/brand_button/brand_button.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_cards/brand_cards.dart';
|
|
||||||
import 'package:selfprivacy/ui/components/brand_md/brand_md.dart';
|
import 'package:selfprivacy/ui/components/brand_md/brand_md.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
|
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';
|
||||||
|
@ -56,19 +55,23 @@ class InitializingPage extends StatelessWidget {
|
||||||
.pushReplacement(materialRoute(const RootPage()));
|
.pushReplacement(materialRoute(const RootPage()));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: SafeArea(
|
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
body: SingleChildScrollView(
|
appBar: AppBar(
|
||||||
child: Column(
|
actions: [
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
if (cubit.state is ServerInstallationFinished)
|
||||||
children: [
|
IconButton(
|
||||||
Padding(
|
icon: const Icon(Icons.check),
|
||||||
padding: paddingH15V0.copyWith(top: 10, bottom: 10),
|
onPressed: () {
|
||||||
child: cubit.state is ServerInstallationFinished
|
Navigator.of(context)
|
||||||
? const SizedBox(
|
.pushReplacement(materialRoute(const RootPage()));
|
||||||
height: 80,
|
},
|
||||||
)
|
)
|
||||||
: ProgressBar(
|
],
|
||||||
|
bottom: PreferredSize(
|
||||||
|
preferredSize: const Size.fromHeight(28),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
|
||||||
|
child: ProgressBar(
|
||||||
steps: const [
|
steps: const [
|
||||||
'Hosting',
|
'Hosting',
|
||||||
'Server Type',
|
'Server Type',
|
||||||
|
@ -82,13 +85,15 @@ class InitializingPage extends StatelessWidget {
|
||||||
activeIndex: cubit.state.porgressBar,
|
activeIndex: cubit.state.porgressBar,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (cubit.state.porgressBar ==
|
|
||||||
ServerSetupProgress.serverProviderFilled.index)
|
|
||||||
BrandText.h2(
|
|
||||||
'initializing.choose_location_type'.tr(),
|
|
||||||
),
|
),
|
||||||
_addCard(
|
),
|
||||||
AnimatedSwitcher(
|
body: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(16.0, 0, 16.0, 0.0),
|
||||||
|
child: AnimatedSwitcher(
|
||||||
duration: const Duration(milliseconds: 300),
|
duration: const Duration(milliseconds: 300),
|
||||||
child: actualInitializingPage,
|
child: actualInitializingPage,
|
||||||
),
|
),
|
||||||
|
@ -117,9 +122,7 @@ class InitializingPage extends StatelessWidget {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (cubit.state is ServerInstallationFinished)
|
if (cubit.state is ServerInstallationEmpty)
|
||||||
Container()
|
|
||||||
else
|
|
||||||
Container(
|
Container(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
child: BrandButton.text(
|
child: BrandButton.text(
|
||||||
|
@ -140,7 +143,6 @@ class InitializingPage extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -189,15 +191,16 @@ class InitializingPage extends StatelessWidget {
|
||||||
builder: (final context) => Column(
|
builder: (final context) => Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Image.asset(
|
Text(
|
||||||
'assets/images/logos/cloudflare.png',
|
'${'initializing.connect_to_server_provider'.tr()}Cloudflare',
|
||||||
width: 150,
|
style: Theme.of(context).textTheme.headlineSmall,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 16),
|
||||||
BrandText.h2('initializing.connect_cloudflare'.tr()),
|
Text(
|
||||||
const SizedBox(height: 10),
|
'initializing.manage_domain_dns'.tr(),
|
||||||
BrandText.body2('initializing.manage_domain_dns'.tr()),
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
const Spacer(),
|
),
|
||||||
|
const SizedBox(height: 32),
|
||||||
CubitFormTextField(
|
CubitFormTextField(
|
||||||
formFieldCubit: context.read<DnsProviderFormCubit>().apiKey,
|
formFieldCubit: context.read<DnsProviderFormCubit>().apiKey,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
|
@ -206,7 +209,7 @@ class InitializingPage extends StatelessWidget {
|
||||||
hintText: 'initializing.cloudflare_api_token'.tr(),
|
hintText: 'initializing.cloudflare_api_token'.tr(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const SizedBox(height: 32),
|
||||||
BrandButton.rised(
|
BrandButton.rised(
|
||||||
onPressed: () =>
|
onPressed: () =>
|
||||||
context.read<DnsProviderFormCubit>().trySubmit(),
|
context.read<DnsProviderFormCubit>().trySubmit(),
|
||||||
|
@ -236,14 +239,11 @@ class InitializingPage extends StatelessWidget {
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Image.asset(
|
Text(
|
||||||
'assets/images/logos/backblaze.png',
|
'${'initializing.connect_to_server_provider'.tr()}Backblaze',
|
||||||
height: 50,
|
style: Theme.of(context).textTheme.headlineSmall,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 32),
|
||||||
BrandText.h2('initializing.connect_backblaze_storage'.tr()),
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
const Spacer(),
|
|
||||||
CubitFormTextField(
|
CubitFormTextField(
|
||||||
formFieldCubit: context.read<BackblazeFormCubit>().keyId,
|
formFieldCubit: context.read<BackblazeFormCubit>().keyId,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
|
@ -252,7 +252,7 @@ class InitializingPage extends StatelessWidget {
|
||||||
hintText: 'KeyID',
|
hintText: 'KeyID',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const SizedBox(height: 16),
|
||||||
CubitFormTextField(
|
CubitFormTextField(
|
||||||
formFieldCubit:
|
formFieldCubit:
|
||||||
context.read<BackblazeFormCubit>().applicationKey,
|
context.read<BackblazeFormCubit>().applicationKey,
|
||||||
|
@ -262,7 +262,7 @@ class InitializingPage extends StatelessWidget {
|
||||||
hintText: 'Master Application Key',
|
hintText: 'Master Application Key',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const SizedBox(height: 32),
|
||||||
BrandButton.rised(
|
BrandButton.rised(
|
||||||
onPressed: formCubitState.isSubmitting
|
onPressed: formCubitState.isSubmitting
|
||||||
? null
|
? null
|
||||||
|
@ -292,60 +292,57 @@ class InitializingPage extends StatelessWidget {
|
||||||
builder: (final context) {
|
builder: (final context) {
|
||||||
final DomainSetupState state =
|
final DomainSetupState state =
|
||||||
context.watch<DomainSetupCubit>().state;
|
context.watch<DomainSetupCubit>().state;
|
||||||
return Column(
|
return SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Image.asset(
|
Text(
|
||||||
'assets/images/logos/cloudflare.png',
|
'initializing.use_this_domain'.tr(),
|
||||||
width: 150,
|
style: Theme.of(context).textTheme.headlineSmall,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 16),
|
||||||
BrandText.h2('basis.domain'.tr()),
|
Text(
|
||||||
const SizedBox(height: 10),
|
'initializing.use_this_domain_text'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 32),
|
||||||
if (state is Empty)
|
if (state is Empty)
|
||||||
BrandText.body2('initializing.no_connected_domains'.tr()),
|
Text(
|
||||||
|
'initializing.no_connected_domains'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
),
|
||||||
if (state is Loading)
|
if (state is Loading)
|
||||||
BrandText.body2(
|
Text(
|
||||||
state.type == LoadingTypes.loadingDomain
|
state.type == LoadingTypes.loadingDomain
|
||||||
? 'initializing.loading_domain_list'.tr()
|
? 'initializing.loading_domain_list'.tr()
|
||||||
: 'basis.saving'.tr(),
|
: 'basis.saving'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
),
|
),
|
||||||
if (state is MoreThenOne)
|
if (state is MoreThenOne)
|
||||||
BrandText.body2(
|
Text(
|
||||||
'initializing.found_more_domains'.tr(),
|
'initializing.found_more_domains'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
),
|
),
|
||||||
if (state is Loaded) ...[
|
if (state is Loaded) ...[
|
||||||
const SizedBox(height: 10),
|
|
||||||
Row(
|
Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.max,
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Text(
|
||||||
child: BrandText.h3(
|
|
||||||
state.domain,
|
state.domain,
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.headlineMedium
|
||||||
|
?.copyWith(
|
||||||
|
color:
|
||||||
|
Theme.of(context).colorScheme.onBackground,
|
||||||
|
),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
width: 56,
|
|
||||||
child: BrandButton.rised(
|
|
||||||
onPressed: () =>
|
|
||||||
context.read<DomainSetupCubit>().load(),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: const [
|
|
||||||
Icon(
|
|
||||||
Icons.refresh,
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
],
|
],
|
||||||
if (state is Empty) ...[
|
if (state is Empty) ...[
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 30),
|
||||||
|
@ -365,18 +362,15 @@ class InitializingPage extends StatelessWidget {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
if (state is Loaded) ...[
|
if (state is Loaded) ...[
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 32),
|
||||||
BrandButton.rised(
|
BrandButton.rised(
|
||||||
onPressed: () =>
|
onPressed: () =>
|
||||||
context.read<DomainSetupCubit>().saveDomain(),
|
context.read<DomainSetupCubit>().saveDomain(),
|
||||||
text: 'initializing.save_domain'.tr(),
|
text: 'initializing.save_domain'.tr(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
const SizedBox(
|
|
||||||
height: 10,
|
|
||||||
width: double.infinity,
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -393,12 +387,16 @@ class InitializingPage extends StatelessWidget {
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
BrandText.h2('initializing.create_master_account'.tr()),
|
Text(
|
||||||
const SizedBox(height: 10),
|
'initializing.create_master_account'.tr(),
|
||||||
BrandText.body2(
|
style: Theme.of(context).textTheme.headlineSmall,
|
||||||
'initializing.enter_username_and_password'.tr(),
|
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
'initializing.enter_username_and_password'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
if (formCubitState.isErrorShown) const SizedBox(height: 16),
|
||||||
if (formCubitState.isErrorShown)
|
if (formCubitState.isErrorShown)
|
||||||
Text(
|
Text(
|
||||||
'users.username_rule'.tr(),
|
'users.username_rule'.tr(),
|
||||||
|
@ -406,7 +404,7 @@ class InitializingPage extends StatelessWidget {
|
||||||
color: Theme.of(context).colorScheme.error,
|
color: Theme.of(context).colorScheme.error,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 32),
|
||||||
CubitFormTextField(
|
CubitFormTextField(
|
||||||
formFieldCubit: context.read<RootUserFormCubit>().userName,
|
formFieldCubit: context.read<RootUserFormCubit>().userName,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
|
@ -415,7 +413,7 @@ class InitializingPage extends StatelessWidget {
|
||||||
hintText: 'basis.username'.tr(),
|
hintText: 'basis.username'.tr(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 16),
|
||||||
BlocBuilder<FieldCubit<bool>, FieldCubitState<bool>>(
|
BlocBuilder<FieldCubit<bool>, FieldCubitState<bool>>(
|
||||||
bloc: context.read<RootUserFormCubit>().isVisible,
|
bloc: context.read<RootUserFormCubit>().isVisible,
|
||||||
builder: (final context, final state) {
|
builder: (final context, final state) {
|
||||||
|
@ -446,7 +444,7 @@ class InitializingPage extends StatelessWidget {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const SizedBox(height: 32),
|
||||||
BrandButton.rised(
|
BrandButton.rised(
|
||||||
onPressed: formCubitState.isSubmitting
|
onPressed: formCubitState.isSubmitting
|
||||||
? null
|
? null
|
||||||
|
@ -466,11 +464,16 @@ class InitializingPage extends StatelessWidget {
|
||||||
builder: (final context) => Column(
|
builder: (final context) => Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const Spacer(flex: 2),
|
Text(
|
||||||
BrandText.h2('initializing.final'.tr()),
|
'initializing.final'.tr(),
|
||||||
const SizedBox(height: 10),
|
style: Theme.of(context).textTheme.headlineSmall,
|
||||||
BrandText.body2('initializing.create_server'.tr()),
|
),
|
||||||
const Spacer(),
|
const SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
'initializing.create_server'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 128),
|
||||||
BrandButton.rised(
|
BrandButton.rised(
|
||||||
onPressed:
|
onPressed:
|
||||||
isLoading ? null : appConfigCubit.createServerAndSetDnsRecords,
|
isLoading ? null : appConfigCubit.createServerAndSetDnsRecords,
|
||||||
|
@ -505,16 +508,22 @@ class InitializingPage extends StatelessWidget {
|
||||||
doneCount = 0;
|
doneCount = 0;
|
||||||
}
|
}
|
||||||
return Builder(
|
return Builder(
|
||||||
builder: (final context) => Column(
|
builder: (final context) => SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(height: 15),
|
Text(
|
||||||
BrandText.h4(
|
|
||||||
'initializing.checks'.tr(args: [doneCount.toString(), '4']),
|
'initializing.checks'.tr(args: [doneCount.toString(), '4']),
|
||||||
|
style: Theme.of(context).textTheme.headlineSmall,
|
||||||
),
|
),
|
||||||
const Spacer(flex: 2),
|
const SizedBox(height: 16),
|
||||||
const SizedBox(height: 10),
|
if (text != null)
|
||||||
BrandText.body2(text),
|
Text(
|
||||||
|
text,
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 128),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
if (doneCount == 0 && state.dnsMatches != null)
|
if (doneCount == 0 && state.dnsMatches != null)
|
||||||
Column(
|
Column(
|
||||||
|
@ -523,7 +532,8 @@ class InitializingPage extends StatelessWidget {
|
||||||
final bool isCorrect = entry.value;
|
final bool isCorrect = entry.value;
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
if (isCorrect) const Icon(Icons.check, color: Colors.green),
|
if (isCorrect)
|
||||||
|
const Icon(Icons.check, color: Colors.green),
|
||||||
if (!isCorrect)
|
if (!isCorrect)
|
||||||
const Icon(Icons.schedule, color: Colors.amber),
|
const Icon(Icons.schedule, color: Colors.amber),
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
|
@ -536,24 +546,26 @@ class InitializingPage extends StatelessWidget {
|
||||||
if (!state.isLoading)
|
if (!state.isLoading)
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
BrandText.body2('initializing.until_the_next_check'.tr()),
|
Text(
|
||||||
|
'initializing.until_the_next_check'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
),
|
||||||
BrandTimer(
|
BrandTimer(
|
||||||
startDateTime: state.timerStart!,
|
startDateTime: state.timerStart!,
|
||||||
duration: state.duration!,
|
duration: state.duration!,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (state.isLoading) BrandText.body2('initializing.check'.tr()),
|
if (state.isLoading)
|
||||||
|
Text(
|
||||||
|
'initializing.check'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _addCard(final Widget child) => Container(
|
|
||||||
height: 450,
|
|
||||||
padding: paddingH15V0,
|
|
||||||
child: BrandCards.big(child: child),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _HowTo extends StatelessWidget {
|
class _HowTo extends StatelessWidget {
|
||||||
|
|
|
@ -1,13 +1,18 @@
|
||||||
import 'package:cubit_form/cubit_form.dart';
|
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:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:selfprivacy/config/brand_theme.dart';
|
import 'package:selfprivacy/config/brand_theme.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/app_config_dependent/authentication_dependend_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/app_config_dependent/authentication_dependend_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/forms/setup/initializing/provider_form_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/forms/setup/initializing/provider_form_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/models/hive/server_details.dart';
|
import 'package:selfprivacy/logic/models/hive/server_details.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_bottom_sheet/brand_bottom_sheet.dart';
|
import 'package:selfprivacy/ui/components/brand_bottom_sheet/brand_bottom_sheet.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_button/filled_button.dart';
|
import 'package:selfprivacy/ui/components/brand_button/filled_button.dart';
|
||||||
|
import 'package:selfprivacy/ui/components/brand_button/outlined_button.dart';
|
||||||
|
import 'package:selfprivacy/ui/components/brand_cards/outlined_card.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_md/brand_md.dart';
|
import 'package:selfprivacy/ui/components/brand_md/brand_md.dart';
|
||||||
|
import 'package:selfprivacy/ui/components/info_box/info_box.dart';
|
||||||
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
class ServerProviderPicker extends StatefulWidget {
|
class ServerProviderPicker extends StatefulWidget {
|
||||||
const ServerProviderPicker({
|
const ServerProviderPicker({
|
||||||
|
@ -96,13 +101,16 @@ class ProviderInputDataPage extends StatelessWidget {
|
||||||
Widget build(final BuildContext context) => Column(
|
Widget build(final BuildContext context) => Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
providerInfo.image,
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
Text(
|
Text(
|
||||||
'initializing.connect_to_server'.tr(),
|
"${'initializing.connect_to_server_provider'.tr()}${providerInfo.providerType.displayName}",
|
||||||
style: Theme.of(context).textTheme.titleLarge,
|
style: Theme.of(context).textTheme.headlineSmall,
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
'initializing.connect_to_server_provider_text'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 32),
|
||||||
CubitFormTextField(
|
CubitFormTextField(
|
||||||
formFieldCubit: providerCubit.apiKey,
|
formFieldCubit: providerCubit.apiKey,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
|
@ -111,13 +119,13 @@ class ProviderInputDataPage extends StatelessWidget {
|
||||||
hintText: 'Provider API Token',
|
hintText: 'Provider API Token',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const SizedBox(height: 32),
|
||||||
FilledButton(
|
FilledButton(
|
||||||
title: 'basis.connect'.tr(),
|
title: 'basis.connect'.tr(),
|
||||||
onPressed: () => providerCubit.trySubmit(),
|
onPressed: () => providerCubit.trySubmit(),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
OutlinedButton(
|
BrandOutlinedButton(
|
||||||
child: Text('initializing.how'.tr()),
|
child: Text('initializing.how'.tr()),
|
||||||
onPressed: () => showModalBottomSheet<void>(
|
onPressed: () => showModalBottomSheet<void>(
|
||||||
context: context,
|
context: context,
|
||||||
|
@ -154,51 +162,189 @@ class ProviderSelectionPage extends StatelessWidget {
|
||||||
final ServerInstallationCubit serverInstallationCubit;
|
final ServerInstallationCubit serverInstallationCubit;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(final BuildContext context) => Column(
|
Widget build(final BuildContext context) => SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
Text(
|
||||||
|
'initializing.connect_to_server'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.headlineSmall,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
Text(
|
Text(
|
||||||
'initializing.select_provider'.tr(),
|
'initializing.select_provider'.tr(),
|
||||||
style: Theme.of(context).textTheme.titleLarge,
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
Text(
|
OutlinedCard(
|
||||||
'initializing.place_where_data'.tr(),
|
child: Padding(
|
||||||
),
|
padding: const EdgeInsets.all(16.0),
|
||||||
const SizedBox(height: 10),
|
child: Column(
|
||||||
ConstrainedBox(
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
constraints: const BoxConstraints(
|
|
||||||
maxWidth: 320,
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
children: [
|
||||||
InkWell(
|
Row(
|
||||||
onTap: () {
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
padding: const EdgeInsets.all(10),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(40),
|
||||||
|
color: const Color(0xFFD50C2D),
|
||||||
|
),
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
'assets/images/logos/hetzner.svg',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
Text(
|
||||||
|
'Hetzner Cloud',
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
'initializing.select_provider_countries_title'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodyLarge,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'initializing.select_provider_countries_text_hetzner'
|
||||||
|
.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodySmall,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
'initializing.select_provider_price_title'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodyLarge,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'initializing.select_provider_price_text_hetzner'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodySmall,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
'initializing.select_provider_payment_title'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodyLarge,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'initializing.select_provider_payment_text_hetzner'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodySmall,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
'initializing.select_provider_email_notice'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodySmall,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
FilledButton(
|
||||||
|
title: 'basis.select'.tr(),
|
||||||
|
onPressed: () {
|
||||||
serverInstallationCubit
|
serverInstallationCubit
|
||||||
.setServerProviderType(ServerProvider.hetzner);
|
.setServerProviderType(ServerProvider.hetzner);
|
||||||
callback(ServerProvider.hetzner);
|
callback(ServerProvider.hetzner);
|
||||||
},
|
},
|
||||||
child: Image.asset(
|
),
|
||||||
'assets/images/logos/hetzner.png',
|
// Outlined button that will open website
|
||||||
width: 150,
|
BrandOutlinedButton(
|
||||||
|
onPressed: () =>
|
||||||
|
_launchURL('https://www.hetzner.com/cloud'),
|
||||||
|
title: 'initializing.select_provider_site_button'.tr(),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
|
||||||
width: 20,
|
|
||||||
),
|
),
|
||||||
InkWell(
|
const SizedBox(height: 16),
|
||||||
onTap: () {
|
OutlinedCard(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
padding: const EdgeInsets.all(10),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(40),
|
||||||
|
color: const Color(0xFF0080FF),
|
||||||
|
),
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
'assets/images/logos/digital_ocean.svg',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
Text(
|
||||||
|
'Digital Ocean',
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
'initializing.select_provider_countries_title'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodyLarge,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'initializing.select_provider_countries_text_do'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodySmall,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
'initializing.select_provider_price_title'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodyLarge,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'initializing.select_provider_price_text_do'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodySmall,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
'initializing.select_provider_payment_title'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodyLarge,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'initializing.select_provider_payment_text_do'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodySmall,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
FilledButton(
|
||||||
|
title: 'basis.select'.tr(),
|
||||||
|
onPressed: () {
|
||||||
serverInstallationCubit
|
serverInstallationCubit
|
||||||
.setServerProviderType(ServerProvider.digitalOcean);
|
.setServerProviderType(ServerProvider.digitalOcean);
|
||||||
callback(ServerProvider.digitalOcean);
|
callback(ServerProvider.digitalOcean);
|
||||||
},
|
},
|
||||||
child: Image.asset(
|
|
||||||
'assets/images/logos/digital_ocean.png',
|
|
||||||
width: 150,
|
|
||||||
),
|
),
|
||||||
|
// Outlined button that will open website
|
||||||
|
BrandOutlinedButton(
|
||||||
|
onPressed: () =>
|
||||||
|
_launchURL('https://www.digitalocean.com'),
|
||||||
|
title: 'initializing.select_provider_site_button'.tr(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
InfoBox(text: 'initializing.select_provider_notice'.tr()),
|
||||||
],
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _launchURL(final url) async {
|
||||||
|
try {
|
||||||
|
final Uri uri = Uri.parse(url);
|
||||||
|
await launchUrl(
|
||||||
|
uri,
|
||||||
|
mode: LaunchMode.externalApplication,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
print(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
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/config/brand_theme.dart';
|
import 'package:selfprivacy/illustrations/stray_deer.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/app_config_dependent/authentication_dependend_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/app_config_dependent/authentication_dependend_cubit.dart';
|
||||||
|
import 'package:selfprivacy/logic/cubit/app_settings/app_settings_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/models/server_provider_location.dart';
|
import 'package:selfprivacy/logic/models/server_provider_location.dart';
|
||||||
import 'package:selfprivacy/logic/models/server_type.dart';
|
import 'package:selfprivacy/logic/models/server_type.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/info_box/info_box.dart';
|
||||||
|
|
||||||
class ServerTypePicker extends StatefulWidget {
|
class ServerTypePicker extends StatefulWidget {
|
||||||
const ServerTypePicker({
|
const ServerTypePicker({
|
||||||
|
@ -68,11 +70,22 @@ class SelectLocationPage extends StatelessWidget {
|
||||||
if ((snapshot.data as List<ServerProviderLocation>).isEmpty) {
|
if ((snapshot.data as List<ServerProviderLocation>).isEmpty) {
|
||||||
return Text('initializing.no_locations_found'.tr());
|
return Text('initializing.no_locations_found'.tr());
|
||||||
}
|
}
|
||||||
return ListView(
|
return Column(
|
||||||
padding: paddingH15V0,
|
|
||||||
children: [
|
children: [
|
||||||
|
Text(
|
||||||
|
'initializing.choose_location_type'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.headlineSmall,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
'initializing.choose_location_type_text'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
...(snapshot.data! as List<ServerProviderLocation>).map(
|
...(snapshot.data! as List<ServerProviderLocation>).map(
|
||||||
(final location) => InkWell(
|
(final location) => SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
callback(location);
|
callback(location);
|
||||||
},
|
},
|
||||||
|
@ -82,18 +95,23 @@ class SelectLocationPage extends StatelessWidget {
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
if (location.flag != null) Text(location.flag!),
|
Text(
|
||||||
const SizedBox(height: 8),
|
'${location.flag ?? ''} ${location.title}',
|
||||||
Text(location.title),
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
if (location.description != null)
|
if (location.description != null)
|
||||||
Text(location.description!),
|
Text(
|
||||||
|
location.description!,
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
@ -126,11 +144,33 @@ class SelectTypePage extends StatelessWidget {
|
||||||
if (snapshot.hasData) {
|
if (snapshot.hasData) {
|
||||||
if ((snapshot.data as List<ServerType>).isEmpty) {
|
if ((snapshot.data as List<ServerType>).isEmpty) {
|
||||||
return Column(
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'initializing.no_server_types_found'.tr(),
|
'initializing.locations_not_found'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.headlineSmall,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
'initializing.locations_not_found_text'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
LayoutBuilder(
|
||||||
|
builder: (final context, final constraints) => CustomPaint(
|
||||||
|
size: Size(
|
||||||
|
constraints.maxWidth,
|
||||||
|
(constraints.maxWidth * 1).toDouble(),
|
||||||
|
),
|
||||||
|
painter: StrayDeerPainter(
|
||||||
|
colorScheme: Theme.of(context).colorScheme,
|
||||||
|
colorPalette: context
|
||||||
|
.read<AppSettingsCubit>()
|
||||||
|
.state
|
||||||
|
.corePaletteOrDefault,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
BrandButton.rised(
|
BrandButton.rised(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
backToLocationPickingCallback();
|
backToLocationPickingCallback();
|
||||||
|
@ -140,11 +180,23 @@ class SelectTypePage extends StatelessWidget {
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return ListView(
|
return Column(
|
||||||
padding: paddingH15V0,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
Text(
|
||||||
|
'initializing.choose_server_type'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.headlineSmall,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
'initializing.choose_server_type_text'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
...(snapshot.data! as List<ServerType>).map(
|
...(snapshot.data! as List<ServerType>).map(
|
||||||
(final type) => InkWell(
|
(final type) => SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
serverInstallationCubit.setServerType(type);
|
serverInstallationCubit.setServerType(type);
|
||||||
},
|
},
|
||||||
|
@ -156,27 +208,80 @@ class SelectTypePage extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
type.title,
|
type.title,
|
||||||
style: Theme.of(context).textTheme.bodyMedium,
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.memory_outlined,
|
||||||
|
color:
|
||||||
|
Theme.of(context).colorScheme.onSurface,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
Text(
|
Text(
|
||||||
'cores: ${type.cores.toString()}',
|
'server.core_count'.plural(type.cores),
|
||||||
style: Theme.of(context).textTheme.bodySmall,
|
style:
|
||||||
|
Theme.of(context).textTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.memory_outlined,
|
||||||
|
color:
|
||||||
|
Theme.of(context).colorScheme.onSurface,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
Text(
|
Text(
|
||||||
'ram: ${type.ram.toString()}',
|
'initializing.choose_server_type_ram'
|
||||||
style: Theme.of(context).textTheme.bodySmall,
|
.tr(args: [type.ram.toString()]),
|
||||||
|
style:
|
||||||
|
Theme.of(context).textTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.sd_card_outlined,
|
||||||
|
color:
|
||||||
|
Theme.of(context).colorScheme.onSurface,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
Text(
|
Text(
|
||||||
'disk: ${type.disk.gibibyte.toString()}',
|
'initializing.choose_server_type_storage'
|
||||||
style: Theme.of(context).textTheme.bodySmall,
|
.tr(args: [
|
||||||
|
type.disk.gibibyte.toString()
|
||||||
|
]),
|
||||||
|
style:
|
||||||
|
Theme.of(context).textTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
|
const Divider(height: 8),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.payments_outlined,
|
||||||
|
color:
|
||||||
|
Theme.of(context).colorScheme.onSurface,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
Text(
|
Text(
|
||||||
'price: ${type.price.value.toString()} ${type.price.currency}',
|
'initializing.choose_server_type_payment_per_month'
|
||||||
style: Theme.of(context).textTheme.bodySmall,
|
.tr(args: [
|
||||||
|
'${type.price.value.toString()} ${type.price.currency}'
|
||||||
|
]),
|
||||||
|
style:
|
||||||
|
Theme.of(context).textTheme.bodyLarge,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -184,7 +289,9 @@ class SelectTypePage extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
InfoBox(text: 'initializing.choose_server_type_notice'.tr()),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue