mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2025-02-02 14:16:58 +00:00
feat(initializing): Implement server type selection for initialization page
This commit is contained in:
parent
fe820ef5be
commit
72760e7980
|
@ -268,6 +268,8 @@
|
|||
"place_where_data": "A place where your data and SelfPrivacy services will reside:",
|
||||
"how": "How to obtain API token",
|
||||
"provider_bad_key_error": "Provider API key is invalid",
|
||||
"no_locations_found": "No available locations found. Make sure your account is accessible.",
|
||||
"no_server_types_found": "No available server types found. Make sure your account is accessible and try to change your server location.",
|
||||
"cloudflare_bad_key_error": "Cloudflare API key is invalid",
|
||||
"backblaze_bad_key_error": "Backblaze storage information is invalid",
|
||||
"connect_cloudflare": "Connect CloudFlare",
|
||||
|
|
|
@ -267,6 +267,8 @@
|
|||
"place_where_data": "Здесь будут жить ваши данные и SelfPrivacy-сервисы:",
|
||||
"how": "Как получить API Token",
|
||||
"provider_bad_key_error": "API ключ провайдера неверен",
|
||||
"no_locations_found": "Не найдено локаций. Убедитесь, что ваш аккаунт доступен.",
|
||||
"no_server_types_found": "Не удалось получить список серверов. Убедитесь, что ваш аккаунт доступен и попытайтесь сменить локацию сервера.",
|
||||
"cloudflare_bad_key_error": "Cloudflare API ключ неверен",
|
||||
"backblaze_bad_key_error": "Информация о Backblaze хранилище неверна",
|
||||
"connect_cloudflare": "Подключите CloudFlare",
|
||||
|
|
|
@ -90,6 +90,9 @@ class BNames {
|
|||
/// A String field of [serverInstallationBox] box.
|
||||
static String cloudFlareKey = 'cloudFlareKey';
|
||||
|
||||
/// A String field of [serverTypeIdentifier] box.
|
||||
static String serverTypeIdentifier = 'serverTypeIdentifier';
|
||||
|
||||
/// A [User] field of [serverInstallationBox] box.
|
||||
static String rootUser = 'rootUser';
|
||||
|
||||
|
|
|
@ -6,8 +6,6 @@ import 'package:equatable/equatable.dart';
|
|||
import 'package:selfprivacy/config/get_it_config.dart';
|
||||
import 'package:selfprivacy/logic/api_maps/rest_maps/api_factory_creator.dart';
|
||||
import 'package:selfprivacy/logic/api_maps/rest_maps/dns_providers/dns_provider_api_settings.dart';
|
||||
import 'package:selfprivacy/logic/api_maps/rest_maps/dns_providers/dns_provider_factory.dart';
|
||||
import 'package:selfprivacy/logic/api_maps/rest_maps/provider_api_settings.dart';
|
||||
import 'package:selfprivacy/logic/api_maps/rest_maps/server_providers/server_provider_api_settings.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/backblaze_credential.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/server_details.dart';
|
||||
|
@ -82,7 +80,9 @@ class ServerInstallationCubit extends Cubit<ServerInstallationState> {
|
|||
repository.serverProviderApiFactory!
|
||||
.getServerProvider(
|
||||
settings: const ServerProviderApiSettings(
|
||||
region: 'fra1', isWithToken: false),
|
||||
region: 'fra1',
|
||||
isWithToken: false,
|
||||
),
|
||||
)
|
||||
.isApiTokenValid(providerToken);
|
||||
|
||||
|
@ -101,12 +101,25 @@ class ServerInstallationCubit extends Cubit<ServerInstallationState> {
|
|||
}
|
||||
|
||||
return repository.serverProviderApiFactory!
|
||||
.getServerProvider(
|
||||
settings: const ServerProviderApiSettings(region: 'fra1'),
|
||||
)
|
||||
.getAvailableLocations();
|
||||
.getServerProvider(
|
||||
settings: const ServerProviderApiSettings(region: 'fra1'),
|
||||
)
|
||||
.getAvailableLocations();
|
||||
}
|
||||
|
||||
Future<List<ServerType>> fetchAvailableTypesByLocation(
|
||||
final ServerProviderLocation location,
|
||||
) async {
|
||||
if (repository.serverProviderApiFactory == null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return repository.serverProviderApiFactory!
|
||||
.getServerProvider(
|
||||
settings: const ServerProviderApiSettings(region: 'fra1'),
|
||||
)
|
||||
.getServerTypesByLocation(location: location);
|
||||
}
|
||||
|
||||
|
||||
void setServerProviderKey(final String serverProviderKey) async {
|
||||
await repository.saveServerProviderKey(serverProviderKey);
|
||||
|
@ -128,6 +141,16 @@ class ServerInstallationCubit extends Cubit<ServerInstallationState> {
|
|||
);
|
||||
}
|
||||
|
||||
void setServerType(final String serverTypeId) async {
|
||||
await repository.saveServerType(serverTypeId);
|
||||
|
||||
emit(
|
||||
(state as ServerInstallationNotFinished).copyWith(
|
||||
serverTypeIdentificator: serverTypeId,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void setCloudflareKey(final String cloudFlareKey) async {
|
||||
if (state is ServerInstallationRecovery) {
|
||||
setAndValidateCloudflareToken(cloudFlareKey);
|
||||
|
|
|
@ -50,6 +50,7 @@ class ServerInstallationRepository {
|
|||
Future<ServerInstallationState> load() async {
|
||||
final String? providerApiToken = getIt<ApiConfigModel>().serverProviderKey;
|
||||
final String? cloudflareToken = getIt<ApiConfigModel>().cloudFlareKey;
|
||||
final String? serverTypeIdentificator = getIt<ApiConfigModel>().serverType;
|
||||
final ServerDomain? serverDomain = getIt<ApiConfigModel>().serverDomain;
|
||||
final BackblazeCredential? backblazeCredential =
|
||||
getIt<ApiConfigModel>().backblazeCredential;
|
||||
|
@ -73,6 +74,7 @@ class ServerInstallationRepository {
|
|||
if (box.get(BNames.hasFinalChecked, defaultValue: false)) {
|
||||
return ServerInstallationFinished(
|
||||
providerApiToken: providerApiToken!,
|
||||
serverTypeIdentificator: serverTypeIdentificator!,
|
||||
cloudFlareKey: cloudflareToken!,
|
||||
serverDomain: serverDomain!,
|
||||
backblazeCredential: backblazeCredential!,
|
||||
|
@ -697,6 +699,10 @@ class ServerInstallationRepository {
|
|||
await getIt<ApiConfigModel>().storeServerProviderKey(key);
|
||||
}
|
||||
|
||||
Future<void> saveServerType(final String serverType) async {
|
||||
await getIt<ApiConfigModel>().storeServerTypeIdentifier(serverType);
|
||||
}
|
||||
|
||||
Future<void> deleteServerProviderKey() async {
|
||||
await box.delete(BNames.hetznerKey);
|
||||
getIt<ApiConfigModel>().init();
|
||||
|
|
|
@ -3,7 +3,7 @@ part of '../server_installation/server_installation_cubit.dart';
|
|||
abstract class ServerInstallationState extends Equatable {
|
||||
const ServerInstallationState({
|
||||
required this.providerApiToken,
|
||||
required this.serverType,
|
||||
required this.serverTypeIdentificator,
|
||||
required this.cloudFlareKey,
|
||||
required this.backblazeCredential,
|
||||
required this.serverDomain,
|
||||
|
@ -17,6 +17,7 @@ abstract class ServerInstallationState extends Equatable {
|
|||
@override
|
||||
List<Object?> get props => [
|
||||
providerApiToken,
|
||||
serverTypeIdentificator,
|
||||
cloudFlareKey,
|
||||
backblazeCredential,
|
||||
serverDomain,
|
||||
|
@ -28,17 +29,17 @@ abstract class ServerInstallationState extends Equatable {
|
|||
|
||||
final String? providerApiToken;
|
||||
final String? cloudFlareKey;
|
||||
final String? serverTypeIdentificator;
|
||||
final BackblazeCredential? backblazeCredential;
|
||||
final ServerDomain? serverDomain;
|
||||
final User? rootUser;
|
||||
final ServerHostingDetails? serverDetails;
|
||||
final ServerType? serverType;
|
||||
final bool isServerStarted;
|
||||
final bool isServerResetedFirstTime;
|
||||
final bool isServerResetedSecondTime;
|
||||
|
||||
bool get isServerProviderApiKeyFilled => providerApiToken != null;
|
||||
bool get isServerTypeFilled => serverType != null;
|
||||
bool get isServerTypeFilled => serverTypeIdentificator != null;
|
||||
bool get isDnsProviderFilled => cloudFlareKey != null;
|
||||
bool get isBackupsProviderFilled => backblazeCredential != null;
|
||||
bool get isDomainSelected => serverDomain != null;
|
||||
|
@ -85,7 +86,7 @@ class TimerState extends ServerInstallationNotFinished {
|
|||
this.duration,
|
||||
}) : super(
|
||||
providerApiToken: dataState.providerApiToken,
|
||||
serverType: dataState.serverType,
|
||||
serverTypeIdentificator: dataState.serverTypeIdentificator,
|
||||
cloudFlareKey: dataState.cloudFlareKey,
|
||||
backblazeCredential: dataState.backblazeCredential,
|
||||
serverDomain: dataState.serverDomain,
|
||||
|
@ -130,7 +131,7 @@ class ServerInstallationNotFinished extends ServerInstallationState {
|
|||
required this.isLoading,
|
||||
required this.dnsMatches,
|
||||
super.providerApiToken,
|
||||
super.serverType,
|
||||
super.serverTypeIdentificator,
|
||||
super.cloudFlareKey,
|
||||
super.backblazeCredential,
|
||||
super.serverDomain,
|
||||
|
@ -143,7 +144,7 @@ class ServerInstallationNotFinished extends ServerInstallationState {
|
|||
@override
|
||||
List<Object?> get props => [
|
||||
providerApiToken,
|
||||
serverType,
|
||||
serverTypeIdentificator,
|
||||
cloudFlareKey,
|
||||
backblazeCredential,
|
||||
serverDomain,
|
||||
|
@ -157,7 +158,7 @@ class ServerInstallationNotFinished extends ServerInstallationState {
|
|||
|
||||
ServerInstallationNotFinished copyWith({
|
||||
final String? providerApiToken,
|
||||
final ServerType? serverType,
|
||||
final String? serverTypeIdentificator,
|
||||
final String? cloudFlareKey,
|
||||
final BackblazeCredential? backblazeCredential,
|
||||
final ServerDomain? serverDomain,
|
||||
|
@ -171,7 +172,7 @@ class ServerInstallationNotFinished extends ServerInstallationState {
|
|||
}) =>
|
||||
ServerInstallationNotFinished(
|
||||
providerApiToken: providerApiToken ?? this.providerApiToken,
|
||||
serverType: serverType ?? this.serverType,
|
||||
serverTypeIdentificator: serverTypeIdentificator ?? this.serverTypeIdentificator,
|
||||
cloudFlareKey: cloudFlareKey ?? this.cloudFlareKey,
|
||||
backblazeCredential: backblazeCredential ?? this.backblazeCredential,
|
||||
serverDomain: serverDomain ?? this.serverDomain,
|
||||
|
@ -188,7 +189,7 @@ class ServerInstallationNotFinished extends ServerInstallationState {
|
|||
|
||||
ServerInstallationFinished finish() => ServerInstallationFinished(
|
||||
providerApiToken: providerApiToken!,
|
||||
serverType: serverType!,
|
||||
serverTypeIdentificator: serverTypeIdentificator!,
|
||||
cloudFlareKey: cloudFlareKey!,
|
||||
backblazeCredential: backblazeCredential!,
|
||||
serverDomain: serverDomain!,
|
||||
|
@ -204,6 +205,7 @@ class ServerInstallationEmpty extends ServerInstallationNotFinished {
|
|||
const ServerInstallationEmpty()
|
||||
: super(
|
||||
providerApiToken: null,
|
||||
serverTypeIdentificator: null,
|
||||
cloudFlareKey: null,
|
||||
backblazeCredential: null,
|
||||
serverDomain: null,
|
||||
|
@ -220,7 +222,7 @@ class ServerInstallationEmpty extends ServerInstallationNotFinished {
|
|||
class ServerInstallationFinished extends ServerInstallationState {
|
||||
const ServerInstallationFinished({
|
||||
required String super.providerApiToken,
|
||||
required ServerType super.serverType,
|
||||
required String super.serverTypeIdentificator,
|
||||
required String super.cloudFlareKey,
|
||||
required BackblazeCredential super.backblazeCredential,
|
||||
required ServerDomain super.serverDomain,
|
||||
|
@ -234,7 +236,7 @@ class ServerInstallationFinished extends ServerInstallationState {
|
|||
@override
|
||||
List<Object?> get props => [
|
||||
providerApiToken,
|
||||
serverType,
|
||||
serverTypeIdentificator,
|
||||
cloudFlareKey,
|
||||
backblazeCredential,
|
||||
serverDomain,
|
||||
|
@ -273,7 +275,7 @@ class ServerInstallationRecovery extends ServerInstallationState {
|
|||
required this.currentStep,
|
||||
required this.recoveryCapabilities,
|
||||
super.providerApiToken,
|
||||
super.serverType,
|
||||
super.serverTypeIdentificator,
|
||||
super.cloudFlareKey,
|
||||
super.backblazeCredential,
|
||||
super.serverDomain,
|
||||
|
@ -290,7 +292,7 @@ class ServerInstallationRecovery extends ServerInstallationState {
|
|||
@override
|
||||
List<Object?> get props => [
|
||||
providerApiToken,
|
||||
serverType,
|
||||
serverTypeIdentificator,
|
||||
cloudFlareKey,
|
||||
backblazeCredential,
|
||||
serverDomain,
|
||||
|
@ -303,7 +305,7 @@ class ServerInstallationRecovery extends ServerInstallationState {
|
|||
|
||||
ServerInstallationRecovery copyWith({
|
||||
final String? providerApiToken,
|
||||
final ServerType? serverType,
|
||||
final String? serverTypeIdentificator,
|
||||
final String? cloudFlareKey,
|
||||
final BackblazeCredential? backblazeCredential,
|
||||
final ServerDomain? serverDomain,
|
||||
|
@ -314,7 +316,7 @@ class ServerInstallationRecovery extends ServerInstallationState {
|
|||
}) =>
|
||||
ServerInstallationRecovery(
|
||||
providerApiToken: providerApiToken ?? this.providerApiToken,
|
||||
serverType: serverType ?? this.serverType,
|
||||
serverTypeIdentificator: serverTypeIdentificator ?? this.serverTypeIdentificator,
|
||||
cloudFlareKey: cloudFlareKey ?? this.cloudFlareKey,
|
||||
backblazeCredential: backblazeCredential ?? this.backblazeCredential,
|
||||
serverDomain: serverDomain ?? this.serverDomain,
|
||||
|
@ -326,7 +328,7 @@ class ServerInstallationRecovery extends ServerInstallationState {
|
|||
|
||||
ServerInstallationFinished finish() => ServerInstallationFinished(
|
||||
providerApiToken: providerApiToken!,
|
||||
serverType: serverType!,
|
||||
serverTypeIdentificator: serverTypeIdentificator!,
|
||||
cloudFlareKey: cloudFlareKey!,
|
||||
backblazeCredential: backblazeCredential!,
|
||||
serverDomain: serverDomain!,
|
||||
|
|
|
@ -10,6 +10,7 @@ class ApiConfigModel {
|
|||
|
||||
ServerHostingDetails? get serverDetails => _serverDetails;
|
||||
String? get serverProviderKey => _serverProviderKey;
|
||||
String? get serverType => _serverType;
|
||||
String? get cloudFlareKey => _cloudFlareKey;
|
||||
BackblazeCredential? get backblazeCredential => _backblazeCredential;
|
||||
ServerDomain? get serverDomain => _serverDomain;
|
||||
|
@ -17,6 +18,7 @@ class ApiConfigModel {
|
|||
|
||||
String? _serverProviderKey;
|
||||
String? _cloudFlareKey;
|
||||
String? _serverType;
|
||||
ServerHostingDetails? _serverDetails;
|
||||
BackblazeCredential? _backblazeCredential;
|
||||
ServerDomain? _serverDomain;
|
||||
|
@ -32,6 +34,11 @@ class ApiConfigModel {
|
|||
_cloudFlareKey = value;
|
||||
}
|
||||
|
||||
Future<void> storeServerTypeIdentifier(final String typeIdentifier) async {
|
||||
await _box.put(BNames.serverTypeIdentifier, typeIdentifier);
|
||||
_serverType = typeIdentifier;
|
||||
}
|
||||
|
||||
Future<void> storeBackblazeCredential(final BackblazeCredential value) async {
|
||||
await _box.put(BNames.backblazeCredential, value);
|
||||
_backblazeCredential = value;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
|
||||
class DiskSize {
|
||||
const DiskSize({final this.byte = 0});
|
||||
const DiskSize({this.byte = 0});
|
||||
|
||||
DiskSize.fromKibibyte(final double kibibyte)
|
||||
: this(byte: (kibibyte * 1024).round());
|
||||
|
|
|
@ -140,15 +140,17 @@ class InitializingPage extends StatelessWidget {
|
|||
}
|
||||
}
|
||||
|
||||
Widget _stepServerProviderToken(final ServerInstallationCubit serverInstallationCubit) =>
|
||||
Widget _stepServerProviderToken(
|
||||
final ServerInstallationCubit serverInstallationCubit) =>
|
||||
ServerProviderPicker(
|
||||
serverInstallationCubit: serverInstallationCubit,
|
||||
);
|
||||
|
||||
Widget _stepServerType(final ServerInstallationCubit serverInstallationCubit) =>
|
||||
ServerTypePicker(
|
||||
serverInstallationCubit: serverInstallationCubit,
|
||||
);
|
||||
Widget _stepServerType(
|
||||
final ServerInstallationCubit serverInstallationCubit) =>
|
||||
ServerTypePicker(
|
||||
serverInstallationCubit: serverInstallationCubit,
|
||||
);
|
||||
|
||||
void _showModal(final BuildContext context, final Widget widget) {
|
||||
showModalBottomSheet<void>(
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:selfprivacy/config/brand_theme.dart';
|
||||
import 'package:selfprivacy/logic/cubit/app_config_dependent/authentication_dependend_cubit.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/server_details.dart';
|
||||
import 'package:selfprivacy/logic/models/server_provider_location.dart';
|
||||
import 'package:selfprivacy/logic/models/server_type.dart';
|
||||
|
||||
class ServerTypePicker extends StatefulWidget {
|
||||
const ServerTypePicker({
|
||||
|
@ -18,6 +19,7 @@ class ServerTypePicker extends StatefulWidget {
|
|||
|
||||
class _ServerTypePickerState extends State<ServerTypePicker> {
|
||||
ServerProviderLocation? serverProviderLocation;
|
||||
ServerType? serverType;
|
||||
|
||||
void setServerProviderLocation(final ServerProviderLocation location) {
|
||||
setState(() {
|
||||
|
@ -27,92 +29,145 @@ class _ServerTypePickerState extends State<ServerTypePicker> {
|
|||
|
||||
@override
|
||||
Widget build(final BuildContext context) {
|
||||
|
||||
if (serverProviderLocation == null) {
|
||||
return SelectLocationPage(
|
||||
serverInstallationCubit: widget.serverInstallationCubit,
|
||||
callback: setServerProviderLocation,
|
||||
);
|
||||
}
|
||||
|
||||
return SelectTypePage(
|
||||
location: serverProviderLocation!,
|
||||
serverInstallationCubit: widget.serverInstallationCubit,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SelectLocationPage extends StatelessWidget {
|
||||
const SelectLocationPage({
|
||||
required this.serverInstallationCubit,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final ServerInstallationCubit serverInstallationCubit;
|
||||
|
||||
@override
|
||||
Widget build(final BuildContext context) => FutureBuilder(
|
||||
future: serverInstallationCubit.repository.serverProviderApiFactory,
|
||||
builder: (
|
||||
final BuildContext context,
|
||||
final AsyncSnapshot<Object?> snapshot,
|
||||
) {
|
||||
if (snapshot.hasData) {
|
||||
return _KeyDisplay(
|
||||
newDeviceKey: snapshot.data.toString(),
|
||||
);
|
||||
} else {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
},
|
||||
),
|
||||
}
|
||||
|
||||
class ProviderSelectionPage extends StatelessWidget {
|
||||
const ProviderSelectionPage({
|
||||
required this.callback,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final Function callback;
|
||||
final ServerInstallationCubit serverInstallationCubit;
|
||||
|
||||
@override
|
||||
Widget build(final BuildContext context) => Column(
|
||||
children: [
|
||||
Text(
|
||||
'initializing.select_provider'.tr(),
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
'initializing.place_where_data'.tr(),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxWidth: 320,
|
||||
),
|
||||
child: Row(
|
||||
Widget build(final BuildContext context) => FutureBuilder(
|
||||
future: serverInstallationCubit.fetchAvailableLocations(),
|
||||
builder: (
|
||||
final BuildContext context,
|
||||
final AsyncSnapshot<Object?> snapshot,
|
||||
) {
|
||||
if (snapshot.hasData) {
|
||||
if ((snapshot.data as List<ServerProviderLocation>).isEmpty) {
|
||||
return Text('initializing.no_locations_found'.tr());
|
||||
}
|
||||
return ListView(
|
||||
padding: paddingH15V0,
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
context
|
||||
.read<ServerInstallationCubit>()
|
||||
.setServerProviderType(ServerProvider.hetzner);
|
||||
callback(ServerProvider.hetzner);
|
||||
},
|
||||
child: Image.asset(
|
||||
'assets/images/logos/hetzner.png',
|
||||
width: 150,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 20,
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
context
|
||||
.read<ServerInstallationCubit>()
|
||||
.setServerProviderType(ServerProvider.digitalOcean);
|
||||
callback(ServerProvider.digitalOcean);
|
||||
},
|
||||
child: Image.asset(
|
||||
'assets/images/logos/digital_ocean.png',
|
||||
width: 150,
|
||||
...(snapshot.data! as List<ServerProviderLocation>).map(
|
||||
(final location) => InkWell(
|
||||
onTap: () {
|
||||
callback(location);
|
||||
},
|
||||
child: Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
if (location.flag != null) Text(location.flag!),
|
||||
const SizedBox(height: 8),
|
||||
Text(location.title),
|
||||
const SizedBox(height: 8),
|
||||
if (location.description != null)
|
||||
Text(location.description!),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
} else {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
class SelectTypePage extends StatelessWidget {
|
||||
const SelectTypePage({
|
||||
required this.location,
|
||||
required this.serverInstallationCubit,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final ServerProviderLocation location;
|
||||
final ServerInstallationCubit serverInstallationCubit;
|
||||
|
||||
@override
|
||||
Widget build(final BuildContext context) => FutureBuilder(
|
||||
future: serverInstallationCubit.fetchAvailableTypesByLocation(location),
|
||||
builder: (
|
||||
final BuildContext context,
|
||||
final AsyncSnapshot<Object?> snapshot,
|
||||
) {
|
||||
if (snapshot.hasData) {
|
||||
if ((snapshot.data as List<ServerType>).isEmpty) {
|
||||
return Text('initializing.no_server_types_found'.tr());
|
||||
}
|
||||
return ListView(
|
||||
padding: paddingH15V0,
|
||||
children: [
|
||||
...(snapshot.data! as List<ServerType>).map(
|
||||
(final type) => InkWell(
|
||||
onTap: () {
|
||||
serverInstallationCubit.setServerType(type.identifier);
|
||||
},
|
||||
child: Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(type.title),
|
||||
const SizedBox(height: 8),
|
||||
Text('cores: $type.cores'),
|
||||
const SizedBox(height: 8),
|
||||
Text('ram: $type.ram'),
|
||||
const SizedBox(height: 8),
|
||||
Text('disk: $type.disk.gibibyte'),
|
||||
const SizedBox(height: 8),
|
||||
Text('price: $type.price.value $type.price.currency'),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
],
|
||||
);
|
||||
} else {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue