diff --git a/lib/ui/pages/onboarding/onboarding.dart b/lib/ui/pages/onboarding/onboarding.dart index c4075741..44576408 100644 --- a/lib/ui/pages/onboarding/onboarding.dart +++ b/lib/ui/pages/onboarding/onboarding.dart @@ -2,7 +2,7 @@ import 'package:auto_route/auto_route.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:selfprivacy/logic/cubit/app_settings/app_settings_cubit.dart'; -import 'package:selfprivacy/ui/components/buttons/brand_button.dart'; +import 'package:selfprivacy/ui/pages/onboarding/views/views.dart'; import 'package:selfprivacy/ui/router/router.dart'; @RoutePage() @@ -17,152 +17,35 @@ class _OnboardingPageState extends State { PageController pageController = PageController(); @override - void initState() { - super.initState(); + void dispose() { + pageController.dispose(); + super.dispose(); } + Future scrollTo(final int targetView) => pageController.animateToPage( + targetView, + duration: const Duration(milliseconds: 300), + curve: Curves.easeInOutCubicEmphasized, + ); + @override - Widget build(final BuildContext context) => Scaffold( - body: PageView( + Widget build(final BuildContext context) => Material( + child: PageView( controller: pageController, children: [ - _withPadding(firstPage()), - _withPadding(secondPage()), - ], - ), - ); - - Widget _withPadding(final Widget child) => Padding( - padding: const EdgeInsets.symmetric( - horizontal: 15, - ), - child: child, - ); - - Widget firstPage() => ConstrainedBox( - constraints: BoxConstraints( - maxHeight: MediaQuery.of(context).size.height, - ), - child: Column( - children: [ - Expanded( - child: ListView( - children: [ - const SizedBox(height: 30), - Text( - 'onboarding.page1_title'.tr(), - style: Theme.of(context).textTheme.headlineSmall, - ), - const SizedBox(height: 16), - Text( - 'onboarding.page1_text'.tr(), - style: Theme.of(context).textTheme.bodyMedium, - ), - const SizedBox(height: 32), - Center( - child: Image.asset( - _fileName( - context: context, - path: 'assets/images/onboarding', - fileExtention: 'png', - fileName: 'onboarding1', - ), - ), - ), - ], - ), + OnboardingFirstView( + onProceed: () => scrollTo(1), ), - BrandButton.rised( - onPressed: () { - pageController.animateToPage( - 1, - duration: const Duration(milliseconds: 300), - curve: Curves.easeInOutCubicEmphasized, - ); - }, - text: 'basis.next'.tr(), - ), - const SizedBox(height: 30), - ], - ), - ); - - Widget secondPage() => ConstrainedBox( - constraints: BoxConstraints( - maxHeight: MediaQuery.of(context).size.height, - ), - child: Column( - children: [ - Expanded( - child: ListView( - children: [ - const SizedBox(height: 30), - Text( - 'onboarding.page2_title'.tr(), - style: Theme.of(context).textTheme.headlineSmall, - ), - 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, - ), - const SizedBox(height: 16), - Text( - 'onboarding.page2_server_provider_text'.tr(), - style: Theme.of(context).textTheme.bodyMedium, - ), - 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( - onPressed: () { + OnboardingSecondView( + onProceed: () { context.read().turnOffOnboarding(); context.router.replaceAll([ const RootRoute(), const InitializingRoute(), ]); }, - text: 'basis.got_it'.tr(), ), - const SizedBox(height: 30), ], ), ); } - -String _fileName({ - required final BuildContext context, - required final String path, - required final String fileName, - required final String fileExtention, -}) { - final ThemeData theme = Theme.of(context); - final bool isDark = theme.brightness == Brightness.dark; - return '$path/$fileName${isDark ? '-dark' : '-light'}.$fileExtention'; -} diff --git a/lib/ui/pages/onboarding/views/onboarding_first_view.dart b/lib/ui/pages/onboarding/views/onboarding_first_view.dart new file mode 100644 index 00000000..fcef8ec5 --- /dev/null +++ b/lib/ui/pages/onboarding/views/onboarding_first_view.dart @@ -0,0 +1,50 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:gap/gap.dart'; +import 'package:selfprivacy/ui/pages/onboarding/views/onboarding_view.dart'; + +class OnboardingFirstView extends StatelessWidget { + const OnboardingFirstView({ + required this.onProceed, + super.key, + }); + + final VoidCallback onProceed; + + String assetName({ + required final BuildContext context, + required final String path, + required final String fileName, + required final String fileExtension, + }) { + final String suffix = + Theme.of(context).brightness == Brightness.dark ? '-dark' : '-light'; + return '$path/$fileName$suffix.$fileExtension'; + } + + @override + Widget build(final BuildContext context) => OnboardingView( + onProceed: onProceed, + children: [ + Text( + 'onboarding.page1_title'.tr(), + style: Theme.of(context).textTheme.headlineSmall, + ), + const Gap(15), + Text( + 'onboarding.page1_text'.tr(), + style: Theme.of(context).textTheme.bodyMedium, + ), + const Gap(30), + Image.asset( + assetName( + context: context, + path: 'assets/images/onboarding', + fileName: 'onboarding1', + fileExtension: 'png', + ), + fit: BoxFit.fitWidth, + ), + ], + ); +} diff --git a/lib/ui/pages/onboarding/views/onboarding_second_view.dart b/lib/ui/pages/onboarding/views/onboarding_second_view.dart new file mode 100644 index 00000000..8a996349 --- /dev/null +++ b/lib/ui/pages/onboarding/views/onboarding_second_view.dart @@ -0,0 +1,60 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:gap/gap.dart'; +import 'package:selfprivacy/ui/pages/onboarding/views/onboarding_view.dart'; + +class OnboardingSecondView extends StatelessWidget { + const OnboardingSecondView({ + required this.onProceed, + super.key, + }); + + final VoidCallback onProceed; + + @override + Widget build(final BuildContext context) => OnboardingView( + buttonTitle: 'basis.got_it', + onProceed: onProceed, + children: [ + Text( + 'onboarding.page2_title'.tr(), + style: Theme.of(context).textTheme.headlineSmall, + ), + const Gap(16), + Text( + 'onboarding.page2_text'.tr(), + style: Theme.of(context).textTheme.bodyMedium, + ), + const Gap(16), + Text( + 'onboarding.page2_server_provider_title'.tr(), + style: Theme.of(context).textTheme.titleLarge, + ), + const Gap(16), + Text( + 'onboarding.page2_server_provider_text'.tr(), + style: Theme.of(context).textTheme.bodyMedium, + ), + const Gap(16), + Text( + 'onboarding.page2_dns_provider_title'.tr(), + style: Theme.of(context).textTheme.titleLarge, + ), + const Gap(16), + Text( + 'onboarding.page2_dns_provider_text'.tr(), + style: Theme.of(context).textTheme.bodyMedium, + ), + const Gap(16), + Text( + 'onboarding.page2_backup_provider_title'.tr(), + style: Theme.of(context).textTheme.titleLarge, + ), + const Gap(16), + Text( + 'onboarding.page2_backup_provider_text'.tr(), + style: Theme.of(context).textTheme.bodyMedium, + ), + ], + ); +} diff --git a/lib/ui/pages/onboarding/views/onboarding_view.dart b/lib/ui/pages/onboarding/views/onboarding_view.dart new file mode 100644 index 00000000..6cf41b94 --- /dev/null +++ b/lib/ui/pages/onboarding/views/onboarding_view.dart @@ -0,0 +1,53 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:selfprivacy/ui/components/buttons/buttons.dart'; + +// base widget for onboarding view +class OnboardingView extends StatelessWidget { + const OnboardingView({ + required this.onProceed, + required this.children, + this.buttonTitle = 'basis.next', + super.key, + }); + + /// Proceed button title + final String buttonTitle; + + /// Proceed button callback + final VoidCallback onProceed; + + /// Current view content + final List children; + + @override + Widget build(final BuildContext context) => Scaffold( + body: Align( + child: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 480), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Expanded( + child: ListView( + primary: true, + shrinkWrap: true, + padding: const EdgeInsets.all(15) + + const EdgeInsets.only(top: 15), + children: children, + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 15) + + const EdgeInsets.only(bottom: 30), + child: SPBrandButton.text( + title: buttonTitle.tr(), + onPressed: onProceed, + ), + ), + ], + ), + ), + ), + ); +} diff --git a/lib/ui/pages/onboarding/views/views.dart b/lib/ui/pages/onboarding/views/views.dart new file mode 100644 index 00000000..b4ea6ffd --- /dev/null +++ b/lib/ui/pages/onboarding/views/views.dart @@ -0,0 +1,2 @@ +export 'onboarding_first_view.dart'; +export 'onboarding_second_view.dart';