import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.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_settings/app_settings_cubit.dart'; import 'package:selfprivacy/logic/models/server_provider_location.dart'; import 'package:selfprivacy/logic/models/server_type.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 { const ServerTypePicker({ required this.serverInstallationCubit, super.key, }); final ServerInstallationCubit serverInstallationCubit; @override State createState() => _ServerTypePickerState(); } class _ServerTypePickerState extends State { ServerProviderLocation? serverProviderLocation; ServerType? serverType; void setServerProviderLocation(final ServerProviderLocation? location) { setState(() { serverProviderLocation = location; }); } @override Widget build(final BuildContext context) { if (serverProviderLocation == null) { return SelectLocationPage( serverInstallationCubit: widget.serverInstallationCubit, callback: setServerProviderLocation, ); } return SelectTypePage( location: serverProviderLocation!, serverInstallationCubit: widget.serverInstallationCubit, backToLocationPickingCallback: () { setServerProviderLocation(null); }, ); } } class SelectLocationPage extends StatelessWidget { const SelectLocationPage({ required this.serverInstallationCubit, required this.callback, super.key, }); final Function callback; final ServerInstallationCubit serverInstallationCubit; @override Widget build(final BuildContext context) => FutureBuilder( future: serverInstallationCubit.fetchAvailableLocations(), builder: ( final BuildContext context, final AsyncSnapshot snapshot, ) { if (snapshot.hasData) { if ((snapshot.data as List).isEmpty) { return Text('initializing.no_locations_found'.tr()); } return Column( 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).map( (final location) => SizedBox( width: double.infinity, child: InkWell( onTap: () { callback(location); }, child: Card( child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '${location.flag ?? ''} ${location.title}', style: Theme.of(context).textTheme.titleMedium, ), const SizedBox(height: 8), if (location.description != null) Text( location.description!, style: Theme.of(context).textTheme.bodyMedium, ), ], ), ), ), ), ), ), const SizedBox(height: 24), ], ); } else { return const Center(child: CircularProgressIndicator()); } }, ); } class SelectTypePage extends StatelessWidget { const SelectTypePage({ required this.backToLocationPickingCallback, required this.location, required this.serverInstallationCubit, super.key, }); final ServerProviderLocation location; final ServerInstallationCubit serverInstallationCubit; final Function backToLocationPickingCallback; @override Widget build(final BuildContext context) => FutureBuilder( future: serverInstallationCubit.fetchAvailableTypesByLocation(location), builder: ( final BuildContext context, final AsyncSnapshot snapshot, ) { if (snapshot.hasData) { if ((snapshot.data as List).isEmpty) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'initializing.locations_not_found'.tr(), style: Theme.of(context).textTheme.headlineSmall, ), 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() .state .corePaletteOrDefault, ), ), ), const SizedBox(height: 16), BrandButton.rised( onPressed: () { backToLocationPickingCallback(); }, text: 'initializing.back_to_locations'.tr(), ), ], ); } return Column( crossAxisAlignment: CrossAxisAlignment.start, 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).map( (final type) => SizedBox( width: double.infinity, child: InkWell( onTap: () { serverInstallationCubit.setServerType(type); }, child: Card( child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( type.title, style: Theme.of(context).textTheme.titleMedium, ), const SizedBox(height: 8), Row( children: [ Icon( Icons.memory_outlined, color: Theme.of(context).colorScheme.onSurface, ), const SizedBox(width: 8), Text( 'server.core_count'.plural(type.cores), style: Theme.of(context).textTheme.bodyMedium, ), ], ), const SizedBox(height: 8), Row( children: [ Icon( Icons.memory_outlined, color: Theme.of(context).colorScheme.onSurface, ), const SizedBox(width: 8), Text( 'initializing.choose_server_type_ram' .tr(args: [type.ram.toString()]), style: Theme.of(context).textTheme.bodyMedium, ), ], ), const SizedBox(height: 8), Row( children: [ Icon( Icons.sd_card_outlined, color: Theme.of(context).colorScheme.onSurface, ), const SizedBox(width: 8), Text( 'initializing.choose_server_type_storage' .tr( args: [type.disk.gibibyte.toString()], ), style: Theme.of(context).textTheme.bodyMedium, ), ], ), 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( 'initializing.choose_server_type_payment_per_month' .tr( args: [ '${type.price.value.toString()} ${type.price.currency}' ], ), style: Theme.of(context).textTheme.bodyLarge, ), ], ), ], ), ), ), ), ), ), const SizedBox(height: 16), InfoBox(text: 'initializing.choose_server_type_notice'.tr()), ], ); } else { return const Center(child: CircularProgressIndicator()); } }, ); }