refactor(router): Use GoRouter instead of Navigator

Please note that Recovery flow is not refactored yet.

Also:
- Merged two "About" pages
- DiskStatus now has a getVolumeByName function
This commit is contained in:
inexcode 2022-11-08 12:18:34 +03:00
parent 6eb49fa8f1
commit f07f2e803c
26 changed files with 299 additions and 354 deletions

View File

@ -119,4 +119,13 @@ class DiskStatus {
bool get isDiskOkay => diskVolumes.every((final volume) => volume.isDiskOkay);
List<DiskVolume> diskVolumes = [];
DiskVolume getVolumeByName(final String name) {
for (final DiskVolume volume in diskVolumes) {
if (volume.name == name) {
return volume;
}
}
throw Exception('Volume $name not found');
}
}

View File

@ -2,20 +2,17 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:selfprivacy/config/brand_colors.dart';
import 'package:selfprivacy/config/hive_config.dart';
import 'package:selfprivacy/theming/factory/app_theme_factory.dart';
import 'package:selfprivacy/ui/pages/setup/initializing/initializing.dart';
import 'package:selfprivacy/ui/pages/onboarding/onboarding.dart';
import 'package:selfprivacy/ui/pages/root_route.dart';
import 'package:wakelock/wakelock.dart';
import 'package:timezone/data/latest.dart' as tz;
import 'package:selfprivacy/config/bloc_config.dart';
import 'package:selfprivacy/config/bloc_observer.dart';
import 'package:selfprivacy/config/brand_colors.dart';
import 'package:selfprivacy/config/get_it_config.dart';
import 'package:selfprivacy/config/hive_config.dart';
import 'package:selfprivacy/config/localization.dart';
import 'package:selfprivacy/logic/cubit/app_settings/app_settings_cubit.dart';
import 'package:selfprivacy/router.dart';
import 'package:selfprivacy/theming/factory/app_theme_factory.dart';
import 'package:timezone/data/latest.dart' as tz;
import 'package:wakelock/wakelock.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
@ -76,10 +73,10 @@ class MyApp extends StatelessWidget {
final BuildContext context,
final AppSettingsState appSettings,
) =>
MaterialApp(
MaterialApp.router(
scaffoldMessengerKey:
getIt.get<NavigationService>().scaffoldMessengerKey,
navigatorKey: getIt.get<NavigationService>().navigatorKey,
// navigatorKey: getIt.get<NavigationService>().navigatorKey,
localizationsDelegates: context.localizationDelegates,
supportedLocales: context.supportedLocales,
locale: context.locale,
@ -89,9 +86,8 @@ class MyApp extends StatelessWidget {
darkTheme: darkThemeData,
themeMode:
appSettings.isDarkModeOn ? ThemeMode.dark : ThemeMode.light,
home: appSettings.isOnboardingShowing
? const OnboardingPage(nextPage: InitializingPage())
: const RootPage(),
routerConfig: router,
// home: appSettings.isOnboardingShowing ? const OnboardingPage(nextPage: InitializingPage()) : const RootPage(),
builder: (final BuildContext context, final Widget? widget) {
Widget error = const Text('...rendering error...');
if (widget is Scaffold || widget is Navigator) {

139
lib/router.dart Normal file
View File

@ -0,0 +1,139 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
import 'package:selfprivacy/logic/cubit/server_volumes/server_volume_cubit.dart';
import 'package:selfprivacy/logic/models/service.dart';
import 'package:selfprivacy/ui/pages/backup_details/backup_details.dart';
import 'package:selfprivacy/ui/pages/devices/devices.dart';
import 'package:selfprivacy/ui/pages/devices/new_device.dart';
import 'package:selfprivacy/ui/pages/dns_details/dns_details.dart';
import 'package:selfprivacy/ui/pages/more/about_application.dart';
import 'package:selfprivacy/ui/pages/more/app_settings/app_setting.dart';
import 'package:selfprivacy/ui/pages/more/console.dart';
import 'package:selfprivacy/ui/pages/onboarding/onboarding.dart';
import 'package:selfprivacy/ui/pages/recovery_key/recovery_key.dart';
import 'package:selfprivacy/ui/pages/recovery_key/recovery_key_receiving.dart';
import 'package:selfprivacy/ui/pages/root_route.dart';
import 'package:selfprivacy/ui/pages/server_details/server_details_screen.dart';
import 'package:selfprivacy/ui/pages/server_storage/binds_migration/services_migration.dart';
import 'package:selfprivacy/ui/pages/server_storage/extending_volume.dart';
import 'package:selfprivacy/ui/pages/server_storage/server_storage.dart';
import 'package:selfprivacy/ui/pages/services/service_page.dart';
import 'package:selfprivacy/ui/pages/setup/initializing/initializing.dart';
import 'package:selfprivacy/ui/pages/setup/recovering/recovery_routing.dart';
import 'package:selfprivacy/ui/pages/users/users.dart';
final GoRouter router = GoRouter(
routes: [
GoRoute(
path: '/',
builder: (final _, final __) => const RootPage(),
),
GoRoute(
path: '/server',
builder: (final _, final __) => const ServerDetailsScreen(),
routes: [
GoRoute(
path: 'storage',
builder: (final _, final __) => const ServerStoragePage(),
routes: [
GoRoute(
path: 'extend/:volumeName',
builder: (final context, final state) => ExtendingVolumePage(
diskVolumeToResize: context
.read<ApiServerVolumeCubit>()
.state
.diskStatus
.getVolumeByName(state.params['volumeName']!),
),
),
],
),
GoRoute(
path: 'settings/timezone',
builder: (final _, final __) => const SelectTimezone(),
),
],
),
GoRoute(
path: '/dns',
builder: (final _, final __) => const DnsDetailsPage(),
),
GoRoute(
path: '/backups',
builder: (final _, final __) => const BackupDetails(),
),
GoRoute(
path: '/services/:serviceId',
builder: (final context, final state) => ServicePage(
serviceId: state.params['serviceId']!,
),
routes: [
GoRoute(
path: 'move',
builder: (final context, final state) => ServicesMigrationPage(
services: state.extra! as List<Service>,
isMigration: false,
),
),
],
),
GoRoute(
path: '/users/:userId',
builder: (final context, final state) =>
UserDetails(login: state.params['userId']!),
),
GoRoute(
path: '/migrations/binds',
builder: (final context, final state) => ServicesMigrationPage(
services: state.extra! as List<Service>,
isMigration: true,
),
),
GoRoute(
path: '/initial-setup',
builder: (final _, final __) => const InitializingPage(),
),
GoRoute(
path: '/recover-access',
builder: (final _, final __) => const RecoveryRouting(),
),
GoRoute(
path: '/recovery-key',
builder: (final _, final __) => const RecoveryKeyPage(),
routes: [
GoRoute(
path: 'new',
builder: (final context, final state) => RecoveryKeyReceiving(
recoveryKey: state.extra! as String,
),
),
],
),
GoRoute(
path: '/devices',
builder: (final _, final __) => const DevicesScreen(),
routes: [
GoRoute(
path: 'new',
builder: (final _, final __) => const NewDeviceScreen(),
),
],
),
GoRoute(
path: '/settings',
builder: (final _, final __) => const AppSettingsPage(),
),
GoRoute(
path: '/about',
builder: (final _, final __) => const AboutPage(),
),
GoRoute(
path: '/onboarding',
builder: (final _, final __) => const OnboardingPage(),
),
GoRoute(
path: '/console',
builder: (final _, final __) => const ConsolePage(),
)
],
);

View File

@ -1,9 +1,8 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:selfprivacy/config/brand_colors.dart';
import 'package:selfprivacy/config/text_themes.dart';
import 'package:selfprivacy/ui/pages/setup/initializing/initializing.dart';
import 'package:selfprivacy/utils/route_transitions/basic.dart';
import 'package:easy_localization/easy_localization.dart';
class NotReadyCard extends StatelessWidget {
const NotReadyCard({super.key});
@ -26,11 +25,7 @@ class NotReadyCard extends StatelessWidget {
child: Padding(
padding: const EdgeInsets.only(bottom: 0.5),
child: GestureDetector(
onTap: () => Navigator.of(context).push(
materialRoute(
const InitializingPage(),
),
),
onTap: () => context.go('/initial-setup'),
child: Text(
'not_ready_card.insertion'.tr(),
style: body1Style.copyWith(

View File

@ -1,14 +1,13 @@
import 'package:cubit_form/cubit_form.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:selfprivacy/logic/common_enum/common_enum.dart';
import 'package:selfprivacy/logic/cubit/devices/devices_cubit.dart';
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
import 'package:selfprivacy/logic/models/json/api_token.dart';
import 'package:selfprivacy/ui/components/brand_hero_screen/brand_hero_screen.dart';
import 'package:selfprivacy/ui/components/info_box/info_box.dart';
import 'package:selfprivacy/ui/pages/devices/new_device.dart';
import 'package:selfprivacy/utils/route_transitions/basic.dart';
class DevicesScreen extends StatefulWidget {
const DevicesScreen({super.key});
@ -45,8 +44,7 @@ class _DevicesScreenState extends State<DevicesScreen> {
),
const SizedBox(height: 16),
OutlinedButton(
onPressed: () => Navigator.of(context)
.push(materialRoute(const NewDeviceScreen())),
onPressed: () => context.go('/devices/new'),
child: Text('devices.main_screen.authorize_new_device'.tr()),
),
const SizedBox(height: 16),

View File

@ -1,13 +1,14 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:package_info/package_info.dart';
import 'package:selfprivacy/config/brand_theme.dart';
import 'package:selfprivacy/logic/api_maps/graphql_maps/server_api/server.dart';
import 'package:selfprivacy/ui/components/brand_header/brand_header.dart';
import 'package:selfprivacy/ui/components/brand_md/brand_md.dart';
import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
import 'package:package_info/package_info.dart';
import 'package:easy_localization/easy_localization.dart';
class AboutApplicationPage extends StatelessWidget {
const AboutApplicationPage({super.key});
class AboutPage extends StatelessWidget {
const AboutPage({super.key});
@override
Widget build(final BuildContext context) => SafeArea(
@ -22,7 +23,7 @@ class AboutApplicationPage extends StatelessWidget {
body: ListView(
padding: paddingH15V0,
children: [
const SizedBox(height: 10),
const SizedBox(height: 16),
FutureBuilder(
future: _packageVersion(),
builder: (final context, final snapshot) => BrandText.body1(
@ -37,6 +38,10 @@ class AboutApplicationPage extends StatelessWidget {
.tr(args: [snapshot.data.toString()]),
),
),
const SizedBox(height: 16),
const BrandMarkdown(
fileName: 'about',
),
],
),
),

View File

@ -1,30 +0,0 @@
import 'package:flutter/material.dart';
import 'package:selfprivacy/config/brand_theme.dart';
import 'package:selfprivacy/ui/components/brand_header/brand_header.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:selfprivacy/ui/components/brand_md/brand_md.dart';
class AboutUsPage extends StatelessWidget {
const AboutUsPage({super.key});
@override
Widget build(final BuildContext context) => SafeArea(
child: Scaffold(
appBar: PreferredSize(
preferredSize: const Size.fromHeight(52),
child: BrandHeader(
title: 'about_us_page.title'.tr(),
hasBackButton: true,
),
),
body: ListView(
padding: paddingH15V0,
children: const [
BrandMarkdown(
fileName: 'about',
),
],
),
),
);
}

View File

@ -7,14 +7,14 @@ import 'package:selfprivacy/config/get_it_config.dart';
import 'package:selfprivacy/logic/models/message.dart';
import 'package:selfprivacy/ui/components/brand_header/brand_header.dart';
class Console extends StatefulWidget {
const Console({super.key});
class ConsolePage extends StatefulWidget {
const ConsolePage({super.key});
@override
State<Console> createState() => _ConsoleState();
State<ConsolePage> createState() => _ConsolePageState();
}
class _ConsoleState extends State<Console> {
class _ConsolePageState extends State<ConsolePage> {
@override
void initState() {
getIt.get<ConsoleModel>().addListener(update);

View File

@ -1,5 +1,6 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:ionicons/ionicons.dart';
import 'package:selfprivacy/config/brand_theme.dart';
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
@ -8,19 +9,6 @@ import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
import 'package:selfprivacy/ui/components/brand_cards/filled_card.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/pages/devices/devices.dart';
import 'package:selfprivacy/ui/pages/recovery_key/recovery_key.dart';
import 'package:selfprivacy/ui/pages/server_storage/binds_migration/services_migration.dart';
import 'package:selfprivacy/ui/pages/setup/initializing/initializing.dart';
import 'package:selfprivacy/ui/pages/onboarding/onboarding.dart';
import 'package:selfprivacy/ui/pages/root_route.dart';
import 'package:selfprivacy/ui/pages/users/users.dart';
import 'package:selfprivacy/utils/route_transitions/basic.dart';
import 'package:selfprivacy/ui/pages/more/about_us.dart';
import 'package:selfprivacy/ui/pages/more/app_settings/app_setting.dart';
import 'package:selfprivacy/ui/pages/more/console.dart';
import 'package:selfprivacy/ui/pages/more/about_application.dart';
class MorePage extends StatelessWidget {
const MorePage({super.key});
@ -50,26 +38,20 @@ class MorePage extends StatelessWidget {
_MoreMenuItem(
title: 'storage.start_migration_button'.tr(),
iconData: Icons.drive_file_move_outline,
goTo: ServicesMigrationPage(
diskStatus: context
.watch<ApiServerVolumeCubit>()
.state
.diskStatus,
services: context
.read<ServicesCubit>()
.state
.services
.where(
(final service) =>
service.id == 'bitwarden' ||
service.id == 'gitea' ||
service.id == 'pleroma' ||
service.id == 'mailserver' ||
service.id == 'nextcloud',
)
.toList(),
isMigration: true,
),
goToPath: '/migrations/binds',
goToExtra: context
.read<ServicesCubit>()
.state
.services
.where(
(final service) =>
service.id == 'bitwarden' ||
service.id == 'gitea' ||
service.id == 'pleroma' ||
service.id == 'mailserver' ||
service.id == 'nextcloud',
)
.toList(),
subtitle: 'storage.data_migration_notice'.tr(),
accent: true,
),
@ -77,7 +59,7 @@ class MorePage extends StatelessWidget {
_MoreMenuItem(
title: 'more_page.configuration_wizard'.tr(),
iconData: Icons.change_history_outlined,
goTo: const InitializingPage(),
goToPath: '/initial-setup',
subtitle: 'not_ready_card.in_menu'.tr(),
accent: true,
),
@ -85,47 +67,40 @@ class MorePage extends StatelessWidget {
_MoreMenuItem(
title: 'more_page.create_ssh_key'.tr(),
iconData: Ionicons.key_outline,
goTo: const UserDetails(
login: 'root',
),
goToPath: '/users/root',
),
if (isReady)
_MoreMenuItem(
iconData: Icons.password_outlined,
goTo: const RecoveryKey(),
goToPath: '/recovery-key',
title: 'recovery_key.key_main_header'.tr(),
),
if (isReady)
_MoreMenuItem(
iconData: Icons.devices_outlined,
goTo: const DevicesScreen(),
goToPath: '/devices',
title: 'devices.main_screen.header'.tr(),
),
_MoreMenuItem(
title: 'more_page.application_settings'.tr(),
iconData: Icons.settings_outlined,
goTo: const AppSettingsPage(),
),
_MoreMenuItem(
title: 'more_page.about_project'.tr(),
iconData: BrandIcons.engineer,
goTo: const AboutUsPage(),
goToPath: '/settings',
),
_MoreMenuItem(
title: 'more_page.about_application'.tr(),
iconData: BrandIcons.fire,
goTo: const AboutApplicationPage(),
iconData: BrandIcons.engineer,
goToPath: '/about',
),
if (!isReady)
_MoreMenuItem(
title: 'more_page.onboarding'.tr(),
iconData: BrandIcons.start,
goTo: const OnboardingPage(nextPage: RootPage()),
goToPath: '/onboarding',
),
_MoreMenuItem(
title: 'more_page.console'.tr(),
iconData: BrandIcons.terminal,
goTo: const Console(),
goToPath: '/console',
),
],
),
@ -141,13 +116,15 @@ class _MoreMenuItem extends StatelessWidget {
required this.iconData,
required this.title,
this.subtitle,
this.goTo,
this.goToPath,
this.goToExtra,
this.accent = false,
});
final IconData iconData;
final String title;
final Widget? goTo;
final String? goToPath;
final Object? goToExtra;
final String? subtitle;
final bool accent;
@ -160,8 +137,9 @@ class _MoreMenuItem extends StatelessWidget {
tertiary: accent,
child: ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
onTap: goTo != null
? () => Navigator.of(context).push(materialRoute(goTo!))
// onTap: goTo != null ? () => Navigator.of(context).push(materialRoute(goTo!)) : null,
onTap: goToPath != null
? () => context.go(goToPath!, extra: goToExtra)
: null,
leading: Icon(
iconData,

View File

@ -1,14 +1,12 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.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_text/brand_text.dart';
import 'package:selfprivacy/utils/route_transitions/basic.dart';
import 'package:easy_localization/easy_localization.dart';
class OnboardingPage extends StatefulWidget {
const OnboardingPage({required this.nextPage, super.key});
final Widget nextPage;
const OnboardingPage({super.key});
@override
State<OnboardingPage> createState() => _OnboardingPageState();
}
@ -117,10 +115,7 @@ class _OnboardingPageState extends State<OnboardingPage> {
BrandButton.rised(
onPressed: () {
context.read<AppSettingsCubit>().turnOffOnboarding();
Navigator.of(context).pushAndRemoveUntil(
materialRoute(widget.nextPage),
(final route) => false,
);
context.go('/initial-setup');
},
text: 'basis.got_it'.tr(),
),

View File

@ -1,5 +1,6 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:selfprivacy/config/brand_theme.dart';
import 'package:selfprivacy/logic/cubit/backups/backups_cubit.dart';
import 'package:selfprivacy/logic/cubit/dns_records/dns_records_cubit.dart';
@ -10,10 +11,6 @@ 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/icon_status_mask/icon_status_mask.dart';
import 'package:selfprivacy/ui/components/not_ready_card/not_ready_card.dart';
import 'package:selfprivacy/ui/pages/backup_details/backup_details.dart';
import 'package:selfprivacy/ui/pages/dns_details/dns_details.dart';
import 'package:selfprivacy/ui/pages/server_details/server_details_screen.dart';
import 'package:selfprivacy/utils/route_transitions/basic.dart';
GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
@ -81,8 +78,7 @@ class _ProvidersPageState extends State<ProvidersPage> {
subtitle: diskStatus.isDiskOkay
? 'storage.status_ok'.tr()
: 'storage.status_error'.tr(),
onTap: () => Navigator.of(context)
.push(materialRoute(const ServerDetailsScreen())),
onTap: () => context.go('/server'),
),
const SizedBox(height: 16),
_Card(
@ -92,11 +88,7 @@ class _ProvidersPageState extends State<ProvidersPage> {
subtitle: appConfig.isDomainSelected
? appConfig.serverDomain!.domainName
: '',
onTap: () => Navigator.of(context).push(
materialRoute(
const DnsDetailsPage(),
),
),
onTap: () => context.go('/dns'),
),
const SizedBox(height: 16),
// TODO: When backups are fixed, show this card
@ -108,8 +100,7 @@ class _ProvidersPageState extends State<ProvidersPage> {
icon: BrandIcons.save,
title: 'backup.card_title'.tr(),
subtitle: isBackupInitialized ? 'backup.card_subtitle'.tr() : '',
onTap: () => Navigator.of(context)
.push(materialRoute(const BackupDetails())),
onTap: () => context.go('/backups'),
),
],
),

View File

@ -2,6 +2,7 @@ import 'package:cubit_form/cubit_form.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:go_router/go_router.dart';
import 'package:selfprivacy/config/get_it_config.dart';
import 'package:selfprivacy/logic/common_enum/common_enum.dart';
import 'package:selfprivacy/logic/cubit/recovery_key/recovery_key_cubit.dart';
@ -10,17 +11,15 @@ import 'package:selfprivacy/ui/components/brand_button/brand_button.dart';
import 'package:selfprivacy/ui/components/brand_button/filled_button.dart';
import 'package:selfprivacy/ui/components/brand_cards/filled_card.dart';
import 'package:selfprivacy/ui/components/brand_hero_screen/brand_hero_screen.dart';
import 'package:selfprivacy/ui/pages/recovery_key/recovery_key_receiving.dart';
import 'package:selfprivacy/utils/route_transitions/basic.dart';
class RecoveryKey extends StatefulWidget {
const RecoveryKey({super.key});
class RecoveryKeyPage extends StatefulWidget {
const RecoveryKeyPage({super.key});
@override
State<RecoveryKey> createState() => _RecoveryKeyState();
State<RecoveryKeyPage> createState() => _RecoveryKeyPageState();
}
class _RecoveryKeyState extends State<RecoveryKey> {
class _RecoveryKeyPageState extends State<RecoveryKeyPage> {
@override
Widget build(final BuildContext context) {
final RecoveryKeyState keyStatus = context.watch<RecoveryKeyCubit>().state;
@ -240,11 +239,7 @@ class _RecoveryKeyConfigurationState extends State<RecoveryKeyConfiguration> {
setState(() {
_isLoading = false;
});
Navigator.of(context).push(
materialRoute(
RecoveryKeyReceiving(recoveryKey: token), // TO DO
),
);
context.go('/recovery-key/new', extra: token);
} on GenerationError catch (e) {
setState(() {
_isLoading = false;

View File

@ -1,6 +1,7 @@
import 'package:cubit_form/cubit_form.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:selfprivacy/config/brand_colors.dart';
import 'package:selfprivacy/logic/common_enum/common_enum.dart';
import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
@ -23,7 +24,6 @@ import 'package:selfprivacy/ui/pages/server_storage/storage_card.dart';
import 'package:selfprivacy/utils/extensions/duration.dart';
import 'package:selfprivacy/utils/extensions/string_extensions.dart';
import 'package:selfprivacy/utils/named_font_weight.dart';
import 'package:selfprivacy/utils/route_transitions/basic.dart';
import 'package:timezone/timezone.dart';
part 'charts/chart.dart';

View File

@ -85,11 +85,7 @@ class _ServerSettingsState extends State<_ServerSettings> {
context.read<JobsCubit>().addJob(
RebuildServerJob(title: 'jobs.upgrade_server'.tr()),
);
Navigator.of(context).push(
materialRoute(
const SelectTimezone(),
),
);
context.go('/server/settings/timezone');
},
),
],

View File

@ -1,79 +0,0 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:selfprivacy/logic/cubit/server_jobs/server_jobs_cubit.dart';
import 'package:selfprivacy/logic/models/json/server_job.dart';
import 'package:selfprivacy/ui/components/brand_button/filled_button.dart';
import 'package:selfprivacy/ui/components/brand_hero_screen/brand_hero_screen.dart';
import 'package:selfprivacy/ui/components/brand_linear_indicator/brand_linear_indicator.dart';
import 'package:selfprivacy/ui/pages/root_route.dart';
import 'package:selfprivacy/utils/route_transitions/basic.dart';
class MigrationProcessPage extends StatefulWidget {
const MigrationProcessPage({super.key});
@override
State<MigrationProcessPage> createState() => _MigrationProcessPageState();
}
class _MigrationProcessPageState extends State<MigrationProcessPage> {
@override
void initState() {
super.initState();
}
@override
Widget build(final BuildContext context) {
ServerJob? job;
String? subtitle = '';
double value = 0.0;
List<Widget> children = [];
final serverJobsState = context.watch<ServerJobsCubit>().state;
if (serverJobsState.migrationJobUid != null) {
job = context.read<ServerJobsCubit>().getServerJobByUid(
serverJobsState.migrationJobUid!,
);
}
if (job == null) {
subtitle = 'basis.loading'.tr();
} else {
value = job.progress == null ? 0.0 : job.progress! / 100;
subtitle = job.statusText;
children = [
...children,
const SizedBox(height: 16),
if (job.finishedAt != null)
Text(
job.result!,
style: Theme.of(context).textTheme.titleMedium,
),
if (job.finishedAt != null) const SizedBox(height: 16),
if (job.finishedAt != null)
FilledButton(
title: 'storage.migration_done'.tr(),
onPressed: () {
Navigator.of(context).pushAndRemoveUntil(
materialRoute(const RootPage()),
(final predicate) => false,
);
},
),
];
}
return BrandHeroScreen(
hasBackButton: false,
heroTitle: 'storage.migration_process'.tr(),
heroSubtitle: subtitle,
children: [
BrandLinearIndicator(
value: value,
color: Theme.of(context).colorScheme.primary,
backgroundColor: Theme.of(context).colorScheme.surfaceVariant,
height: 4.0,
),
...children,
],
);
}
}

View File

@ -1,30 +1,28 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:selfprivacy/logic/cubit/server_jobs/server_jobs_cubit.dart';
import 'package:selfprivacy/logic/cubit/server_volumes/server_volume_cubit.dart';
import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
import 'package:selfprivacy/logic/models/disk_size.dart';
import 'package:selfprivacy/logic/models/disk_status.dart';
import 'package:selfprivacy/logic/models/service.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_header/brand_header.dart';
import 'package:selfprivacy/ui/components/info_box/info_box.dart';
import 'package:selfprivacy/logic/models/disk_status.dart';
import 'package:selfprivacy/ui/components/jobs_content/jobs_content.dart';
import 'package:selfprivacy/ui/components/storage_list_items/server_storage_list_item.dart';
import 'package:selfprivacy/ui/components/storage_list_items/service_migration_list_item.dart';
import 'package:selfprivacy/ui/helpers/modals.dart';
import 'package:selfprivacy/ui/pages/root_route.dart';
import 'package:selfprivacy/utils/route_transitions/basic.dart';
class ServicesMigrationPage extends StatefulWidget {
const ServicesMigrationPage({
required this.services,
required this.diskStatus,
required this.isMigration,
super.key,
});
final DiskStatus diskStatus;
final List<Service> services;
final bool isMigration;
@ -87,11 +85,13 @@ class _ServicesMigrationPageState extends State<ServicesMigrationPage> {
@override
Widget build(final BuildContext context) {
final DiskStatus diskStatus =
context.watch<ApiServerVolumeCubit>().state.diskStatus;
final Size appBarHeight = Size.fromHeight(
headerHeight +
headerVerticalPadding * 2 +
listItemHeight * widget.diskStatus.diskVolumes.length +
headerVerticalPadding * widget.diskStatus.diskVolumes.length,
listItemHeight * diskStatus.diskVolumes.length +
headerVerticalPadding * diskStatus.diskVolumes.length,
);
return SafeArea(
child: Scaffold(
@ -110,7 +110,7 @@ class _ServicesMigrationPageState extends State<ServicesMigrationPage> {
),
child: Column(
children: [
...widget.diskStatus.diskVolumes
...diskStatus.diskVolumes
.map(
(final volume) => Column(
children: [
@ -145,7 +145,7 @@ class _ServicesMigrationPageState extends State<ServicesMigrationPage> {
const SizedBox(height: 8),
ServiceMigrationListItem(
service: service,
diskStatus: widget.diskStatus,
diskStatus: diskStatus,
selectedVolume: serviceToDisk[service.id]!,
onChange: onChange,
),
@ -180,10 +180,7 @@ class _ServicesMigrationPageState extends State<ServicesMigrationPage> {
}
}
}
Navigator.of(context).pushAndRemoveUntil(
materialRoute(const RootPage()),
(final predicate) => false,
);
context.go('/');
showBrandBottomSheet(
context: context,
builder: (final BuildContext context) =>

View File

@ -1,25 +1,23 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:selfprivacy/logic/cubit/app_config_dependent/authentication_dependend_cubit.dart';
import 'package:selfprivacy/logic/cubit/provider_volumes/provider_volume_cubit.dart';
import 'package:selfprivacy/logic/cubit/server_volumes/server_volume_cubit.dart';
import 'package:selfprivacy/logic/models/disk_size.dart';
import 'package:selfprivacy/logic/models/disk_status.dart';
import 'package:selfprivacy/logic/models/price.dart';
import 'package:selfprivacy/ui/components/brand_button/filled_button.dart';
import 'package:selfprivacy/ui/components/brand_hero_screen/brand_hero_screen.dart';
import 'package:selfprivacy/logic/models/disk_status.dart';
import 'package:selfprivacy/ui/pages/root_route.dart';
import 'package:selfprivacy/utils/route_transitions/basic.dart';
import 'package:selfprivacy/ui/components/info_box/info_box.dart';
class ExtendingVolumePage extends StatefulWidget {
const ExtendingVolumePage({
required this.diskVolumeToResize,
required this.diskStatus,
super.key,
});
final DiskVolume diskVolumeToResize;
final DiskStatus diskStatus;
@override
State<ExtendingVolumePage> createState() => _ExtendingVolumePageState();
@ -156,10 +154,7 @@ class _ExtendingVolumePageState extends State<ExtendingVolumePage> {
DiskSize.fromGibibyte(_currentSliderGbValue),
context.read<ApiServerVolumeCubit>().reload,
);
Navigator.of(context).pushAndRemoveUntil(
materialRoute(const RootPage()),
(final predicate) => false,
);
context.go('/');
},
disabled: _isError || isAlreadyResizing,
),
@ -168,16 +163,10 @@ class _ExtendingVolumePageState extends State<ExtendingVolumePage> {
height: 1.0,
),
const SizedBox(height: 16),
const Align(
alignment: Alignment.centerLeft,
child: Icon(
Icons.info_outlined,
size: 24,
),
InfoBox(
text: 'storage.extending_volume_price_info'.tr(),
),
const SizedBox(height: 16),
Text('storage.extending_volume_price_info'.tr()),
const SizedBox(height: 16),
],
);
},

View File

@ -1,24 +1,21 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:go_router/go_router.dart';
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
import 'package:selfprivacy/logic/cubit/server_volumes/server_volume_cubit.dart';
import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
import 'package:selfprivacy/logic/models/disk_status.dart';
import 'package:selfprivacy/logic/models/service.dart';
import 'package:selfprivacy/ui/components/brand_button/outlined_button.dart';
import 'package:selfprivacy/ui/components/brand_hero_screen/brand_hero_screen.dart';
import 'package:selfprivacy/logic/models/disk_status.dart';
import 'package:selfprivacy/ui/pages/server_storage/extending_volume.dart';
import 'package:selfprivacy/ui/components/storage_list_items/server_storage_list_item.dart';
import 'package:selfprivacy/utils/route_transitions/basic.dart';
class ServerStoragePage extends StatefulWidget {
const ServerStoragePage({
required this.diskStatus,
super.key,
});
final DiskStatus diskStatus;
@override
State<ServerStoragePage> createState() => _ServerStoragePageState();
}
@ -32,6 +29,9 @@ class _ServerStoragePageState extends State<ServerStoragePage> {
final List<Service> services =
context.watch<ServicesCubit>().state.services;
final DiskStatus diskStatus =
context.watch<ApiServerVolumeCubit>().state.diskStatus;
if (!isReady) {
return BrandHeroScreen(
hasBackButton: true,
@ -45,14 +45,14 @@ class _ServerStoragePageState extends State<ServerStoragePage> {
heroTitle: 'storage.card_title'.tr(),
children: [
// ...sections,
...widget.diskStatus.diskVolumes
...diskStatus.diskVolumes
.map(
(final volume) => Column(
mainAxisSize: MainAxisSize.min,
children: [
ServerStorageSection(
volume: volume,
diskStatus: widget.diskStatus,
diskStatus: diskStatus,
services: services
.where(
(final service) =>
@ -105,14 +105,8 @@ class ServerStorageSection extends StatelessWidget {
const SizedBox(height: 16),
BrandOutlinedButton(
title: 'storage.extend_volume_button.title'.tr(),
onPressed: () => Navigator.of(context).push(
materialRoute(
ExtendingVolumePage(
diskVolumeToResize: volume,
diskStatus: diskStatus,
),
),
),
onPressed: () =>
context.go('/server/storage/extend/${volume.name}'),
),
],
],

View File

@ -1,12 +1,11 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:selfprivacy/logic/cubit/app_config_dependent/authentication_dependend_cubit.dart';
import 'package:selfprivacy/logic/cubit/providers/providers_cubit.dart';
import 'package:selfprivacy/ui/components/icon_status_mask/icon_status_mask.dart';
import 'package:selfprivacy/logic/models/disk_status.dart';
import 'package:selfprivacy/ui/pages/server_storage/server_storage.dart';
import 'package:selfprivacy/ui/components/icon_status_mask/icon_status_mask.dart';
import 'package:selfprivacy/ui/components/storage_list_items/server_storage_list_item.dart';
import 'package:selfprivacy/utils/route_transitions/basic.dart';
class StorageCard extends StatelessWidget {
const StorageCard({
@ -45,13 +44,7 @@ class StorageCard extends StatelessWidget {
clipBehavior: Clip.antiAlias,
child: InkResponse(
highlightShape: BoxShape.rectangle,
onTap: () => Navigator.of(context).push(
materialRoute(
ServerStoragePage(
diskStatus: diskStatus,
),
),
),
onTap: () => context.go('/server/storage'),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(

View File

@ -1,6 +1,7 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:go_router/go_router.dart';
import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
import 'package:selfprivacy/logic/cubit/server_volumes/server_volume_cubit.dart';
import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
@ -8,8 +9,6 @@ import 'package:selfprivacy/logic/models/job.dart';
import 'package:selfprivacy/logic/models/service.dart';
import 'package:selfprivacy/ui/components/brand_cards/filled_card.dart';
import 'package:selfprivacy/ui/components/brand_hero_screen/brand_hero_screen.dart';
import 'package:selfprivacy/ui/pages/server_storage/binds_migration/services_migration.dart';
import 'package:selfprivacy/utils/route_transitions/basic.dart';
import 'package:url_launcher/url_launcher.dart';
class ServicePage extends StatefulWidget {
@ -108,15 +107,9 @@ class _ServicePageState extends State<ServicePage> {
ListTile(
iconColor: Theme.of(context).colorScheme.onBackground,
// Open page ServicesMigrationPage
onTap: () => Navigator.of(context).push(
materialRoute(
ServicesMigrationPage(
services: [service],
diskStatus:
context.read<ApiServerVolumeCubit>().state.diskStatus,
isMigration: false,
),
),
onTap: () => context.go(
'/services/${service.id}/migration',
extra: [service],
),
leading: const Icon(Icons.drive_file_move_outlined),
title: Text(

View File

@ -1,10 +1,12 @@
import 'dart:ui';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:go_router/go_router.dart';
import 'package:selfprivacy/config/brand_theme.dart';
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
import 'package:selfprivacy/logic/models/job.dart';
import 'package:selfprivacy/logic/models/service.dart';
@ -15,9 +17,6 @@ import 'package:selfprivacy/ui/components/brand_switch/brand_switch.dart';
import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
import 'package:selfprivacy/ui/components/icon_status_mask/icon_status_mask.dart';
import 'package:selfprivacy/ui/components/not_ready_card/not_ready_card.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:selfprivacy/ui/pages/services/service_page.dart';
import 'package:selfprivacy/utils/route_transitions/basic.dart';
import 'package:selfprivacy/utils/ui_helpers.dart';
import 'package:url_launcher/url_launcher.dart';
@ -119,10 +118,7 @@ class _Card extends StatelessWidget {
final domainName = UiHelpers.getDomainName(config);
return GestureDetector(
onTap: isReady
? () => Navigator.of(context)
.push(materialRoute(ServicePage(serviceId: service.id)))
: null,
onTap: isReady ? () => context.go('/services/${service.id}') : null,
child: BrandCards.big(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,

View File

@ -1,14 +1,15 @@
import 'package:cubit_form/cubit_form.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:selfprivacy/config/brand_theme.dart';
import 'package:selfprivacy/logic/cubit/forms/setup/initializing/provider_form_cubit.dart';
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
import 'package:selfprivacy/logic/cubit/forms/factories/field_cubit_factory.dart';
import 'package:selfprivacy/logic/cubit/forms/setup/initializing/backblaze_form_cubit.dart';
import 'package:selfprivacy/logic/cubit/forms/setup/initializing/dns_provider_form_cubit.dart';
import 'package:selfprivacy/logic/cubit/forms/setup/initializing/domain_setup_cubit.dart';
import 'package:selfprivacy/logic/cubit/forms/setup/initializing/provider_form_cubit.dart';
import 'package:selfprivacy/logic/cubit/forms/setup/initializing/root_user_form_cubit.dart';
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.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_cards/brand_cards.dart';
@ -16,11 +17,9 @@ 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_timer/brand_timer.dart';
import 'package:selfprivacy/ui/components/progress_bar/progress_bar.dart';
import 'package:selfprivacy/ui/pages/root_route.dart';
import 'package:selfprivacy/ui/pages/setup/initializing/server_provider_picker.dart';
import 'package:selfprivacy/ui/pages/setup/initializing/server_type_picker.dart';
import 'package:selfprivacy/ui/pages/setup/recovering/recovery_routing.dart';
import 'package:selfprivacy/utils/route_transitions/basic.dart';
class InitializingPage extends StatelessWidget {
const InitializingPage({super.key});
@ -52,8 +51,7 @@ class InitializingPage extends StatelessWidget {
return BlocListener<ServerInstallationCubit, ServerInstallationState>(
listener: (final context, final state) {
if (cubit.state is ServerInstallationFinished) {
Navigator.of(context)
.pushReplacement(materialRoute(const RootPage()));
context.go('/');
}
},
child: SafeArea(
@ -105,10 +103,7 @@ class InitializingPage extends StatelessWidget {
? 'basis.close'.tr()
: 'basis.later'.tr(),
onPressed: () {
Navigator.of(context).pushAndRemoveUntil(
materialRoute(const RootPage()),
(final predicate) => false,
);
context.go('/');
},
),
),
@ -120,11 +115,7 @@ class InitializingPage extends StatelessWidget {
child: BrandButton.text(
title: 'basis.connect_to_existing'.tr(),
onPressed: () {
Navigator.of(context).push(
materialRoute(
const RecoveryRouting(),
),
);
context.go('/recover-access');
},
),
)

View File

@ -11,9 +11,7 @@ class _User extends StatelessWidget {
@override
Widget build(final BuildContext context) => InkWell(
onTap: () {
Navigator.of(context).push(
materialRoute(UserDetails(login: user.login)),
);
context.go('/users/${user.login}');
},
child: Container(
padding: paddingH15V0,

View File

@ -1,16 +1,17 @@
import 'package:cubit_form/cubit_form.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:selfprivacy/config/brand_colors.dart';
import 'package:selfprivacy/config/brand_theme.dart';
import 'package:selfprivacy/logic/cubit/forms/user/ssh_form_cubit.dart';
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
import 'package:selfprivacy/logic/cubit/forms/factories/field_cubit_factory.dart';
import 'package:selfprivacy/logic/cubit/forms/user/user_form_cubit.dart';
import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
import 'package:selfprivacy/logic/cubit/forms/factories/field_cubit_factory.dart';
import 'package:selfprivacy/logic/cubit/forms/user/ssh_form_cubit.dart';
import 'package:selfprivacy/logic/cubit/forms/user/user_form_cubit.dart';
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
import 'package:selfprivacy/logic/cubit/users/users_cubit.dart';
import 'package:selfprivacy/logic/models/job.dart';
import 'package:selfprivacy/logic/models/hive/user.dart';
import 'package:selfprivacy/logic/models/job.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/outlined_button.dart';
@ -24,14 +25,12 @@ import 'package:selfprivacy/ui/components/list_tiles/list_tile_on_surface_varian
import 'package:selfprivacy/ui/components/not_ready_card/not_ready_card.dart';
import 'package:selfprivacy/utils/ui_helpers.dart';
import 'package:selfprivacy/utils/route_transitions/basic.dart';
part 'add_user_fab.dart';
part 'empty.dart';
part 'new_user.dart';
part 'reset_password.dart';
part 'user.dart';
part 'user_details.dart';
part 'add_user_fab.dart';
part 'reset_password.dart';
class UsersPage extends StatelessWidget {
const UsersPage({super.key});
@ -50,7 +49,6 @@ class UsersPage extends StatelessWidget {
final List<User> users = state.users
.where((final user) => user.type != UserType.root)
.toList();
// final List<User> users = [];
users.sort(
(final User a, final User b) =>
a.login.toLowerCase().compareTo(b.login.toLowerCase()),

View File

@ -35,7 +35,7 @@ packages:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.8.2"
version: "2.9.0"
auto_size_text:
dependency: "direct main"
description:
@ -126,7 +126,7 @@ packages:
name: characters
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
version: "1.2.1"
charcode:
dependency: transitive
description:
@ -147,7 +147,7 @@ packages:
name: clock
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
version: "1.1.1"
code_builder:
dependency: transitive
description:
@ -350,7 +350,7 @@ packages:
name: fake_async
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
version: "1.3.1"
ffi:
dependency: transitive
description:
@ -511,6 +511,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
go_router:
dependency: "direct main"
description:
name: go_router
url: "https://pub.dartlang.org"
source: hosted
version: "5.1.5"
gql:
dependency: "direct main"
description:
@ -762,21 +769,21 @@ packages:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.11"
version: "0.12.12"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.4"
version: "0.1.5"
meta:
dependency: transitive
description:
name: meta
url: "https://pub.dartlang.org"
source: hosted
version: "1.7.0"
version: "1.8.0"
mime:
dependency: transitive
description:
@ -846,7 +853,7 @@ packages:
name: path
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.1"
version: "1.8.2"
path_drawing:
dependency: transitive
description:
@ -1159,7 +1166,7 @@ packages:
name: source_span
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.2"
version: "1.9.0"
stack_trace:
dependency: transitive
description:
@ -1187,7 +1194,7 @@ packages:
name: string_scanner
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
version: "1.1.1"
system_theme:
dependency: "direct main"
description:
@ -1208,28 +1215,28 @@ packages:
name: term_glyph
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
version: "1.2.1"
test:
dependency: transitive
description:
name: test
url: "https://pub.dartlang.org"
source: hosted
version: "1.21.1"
version: "1.21.4"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.9"
version: "0.4.12"
test_core:
dependency: transitive
description:
name: test_core
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.13"
version: "0.4.16"
timezone:
dependency: "direct main"
description:
@ -1414,4 +1421,4 @@ packages:
version: "3.1.1"
sdks:
dart: ">=2.17.0 <3.0.0"
flutter: ">=3.0.0"
flutter: ">=3.3.0"

View File

@ -26,6 +26,7 @@ dependencies:
flutter_secure_storage: ^5.0.2
flutter_svg: ^1.1.4
get_it: ^7.2.0
go_router: ^5.1.5
gql: ^0.13.1
graphql: ^5.1.1
graphql_codegen: ^0.10.2