From b22690838317ec01bc8acd37feca02f97ad724f0 Mon Sep 17 00:00:00 2001 From: Myzel394 <50424412+Myzel394@users.noreply.github.com> Date: Fri, 19 Aug 2022 22:00:37 +0200 Subject: [PATCH] improved welcome screen photo switching; improvements & bugfixes --- lib/locale/l10n/app_en.arb | 2 +- lib/screens/empty_screen.dart | 4 +- lib/screens/welcome_screen.dart | 42 ++++--- .../pages/create_memories_page.dart | 39 ++++++ ...uide_page.dart => view_memories_page.dart} | 30 +++-- .../welcome_screen/photo_switching.dart | 112 ++++++++++++++---- 6 files changed, 170 insertions(+), 59 deletions(-) create mode 100644 lib/screens/welcome_screen/pages/create_memories_page.dart rename lib/screens/welcome_screen/pages/{guide_page.dart => view_memories_page.dart} (63%) diff --git a/lib/locale/l10n/app_en.arb b/lib/locale/l10n/app_en.arb index cc78100..ee538cd 100644 --- a/lib/locale/l10n/app_en.arb +++ b/lib/locale/l10n/app_en.arb @@ -136,7 +136,7 @@ "emptyScreenTitle": "Houston, we have a problem", - "emptyScreenSubtitle": "The user hasn't created any mem ories yet!", + "emptyScreenSubtitle": "The user hasn't created any memories yet!", "emptyScreenDescription": "To view your timeline you need to create some memories first! :)", "emptyScreenCreateMemory": "Create a Memory", diff --git a/lib/screens/empty_screen.dart b/lib/screens/empty_screen.dart index 4af4282..3769151 100644 --- a/lib/screens/empty_screen.dart +++ b/lib/screens/empty_screen.dart @@ -3,7 +3,6 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:lottie/lottie.dart'; import 'package:quid_faciam_hodie/constants/spacing.dart'; -import 'package:quid_faciam_hodie/screens/main_screen.dart'; import 'package:quid_faciam_hodie/utils/theme.dart'; import '../widgets/icon_button_child.dart'; @@ -56,8 +55,7 @@ class EmptyScreen extends StatelessWidget { label: Text(localizations.emptyScreenCreateMemory), ), onPressed: () { - Navigator.pushNamedAndRemoveUntil( - context, MainScreen.ID, (_) => false); + Navigator.pop(context); }, ), ], diff --git a/lib/screens/welcome_screen.dart b/lib/screens/welcome_screen.dart index 56e24e9..a70db12 100644 --- a/lib/screens/welcome_screen.dart +++ b/lib/screens/welcome_screen.dart @@ -1,11 +1,15 @@ +import 'dart:math'; + import 'package:flutter/material.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:quid_faciam_hodie/constants/spacing.dart'; +import 'package:quid_faciam_hodie/constants/values.dart'; +import 'package:quid_faciam_hodie/managers/photo_manager.dart'; import 'package:quid_faciam_hodie/managers/user_help_sheets_manager.dart'; +import 'package:quid_faciam_hodie/screens/welcome_screen/pages/view_memories_page.dart'; +import 'welcome_screen/pages/create_memories_page.dart'; import 'welcome_screen/pages/get_started_page.dart'; -import 'welcome_screen/pages/guide_page.dart'; import 'welcome_screen/pages/initial_page.dart'; class WelcomeScreen extends StatefulWidget { @@ -18,6 +22,7 @@ class WelcomeScreen extends StatefulWidget { } class _WelcomeScreenState extends State { + NetworkImage? _initialImageForPhotoSwitching; final controller = PageController(); @override @@ -25,6 +30,7 @@ class _WelcomeScreenState extends State { super.initState(); UserHelpSheetsManager.deleteAll(); + getInitialImageForPhotoSwitching(); } @override @@ -34,6 +40,20 @@ class _WelcomeScreenState extends State { super.dispose(); } + void getInitialImageForPhotoSwitching() async { + final query = WELCOME_SCREEN_PHOTOS_QUERIES[ + Random().nextInt(WELCOME_SCREEN_PHOTOS_QUERIES.length)]; + final url = await PhotoManager.getRandomPhoto(query); + + if (!mounted) { + return; + } + + setState(() { + _initialImageForPhotoSwitching = NetworkImage(url); + }); + } + void nextPage() { controller.animateToPage( (controller.page! + 1).toInt(), @@ -44,8 +64,6 @@ class _WelcomeScreenState extends State { @override Widget build(BuildContext context) { - final localizations = AppLocalizations.of(context)!; - return PlatformScaffold( body: Padding( padding: const EdgeInsets.symmetric(vertical: MEDIUM_SPACE), @@ -53,19 +71,11 @@ class _WelcomeScreenState extends State { child: PageView( controller: controller, children: [ - InitialPage( + InitialPage(onNextPage: nextPage), + CreateMemoriesPage(onNextPage: nextPage), + ViewMemoriesPage( onNextPage: nextPage, - ), - GuidePage( - onNextPage: nextPage, - description: - localizations.welcomeScreenCreateMemoriesGuideDescription, - picture: 'assets/images/live_photo.svg', - ), - GuidePage( - onNextPage: nextPage, - description: - localizations.welcomeScreenViewMemoriesGuideDescription, + initialImage: _initialImageForPhotoSwitching, ), const GetStartedPage(), ], diff --git a/lib/screens/welcome_screen/pages/create_memories_page.dart b/lib/screens/welcome_screen/pages/create_memories_page.dart new file mode 100644 index 0000000..9454835 --- /dev/null +++ b/lib/screens/welcome_screen/pages/create_memories_page.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:quid_faciam_hodie/constants/spacing.dart'; +import 'package:quid_faciam_hodie/screens/welcome_screen/crabs/next_button.dart'; +import 'package:quid_faciam_hodie/utils/theme.dart'; + +class CreateMemoriesPage extends StatelessWidget { + final VoidCallback onNextPage; + + const CreateMemoriesPage({ + Key? key, + required this.onNextPage, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final localizations = AppLocalizations.of(context)!; + + return Center( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: MEDIUM_SPACE), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SvgPicture.asset('assets/images/live_photo.svg', height: 400), + const SizedBox(height: LARGE_SPACE), + Text( + localizations.welcomeScreenCreateMemoriesGuideDescription, + style: getBodyTextTextStyle(context), + ), + const SizedBox(height: LARGE_SPACE), + CrabNextButton(onPressed: onNextPage), + ], + ), + ), + ); + } +} diff --git a/lib/screens/welcome_screen/pages/guide_page.dart b/lib/screens/welcome_screen/pages/view_memories_page.dart similarity index 63% rename from lib/screens/welcome_screen/pages/guide_page.dart rename to lib/screens/welcome_screen/pages/view_memories_page.dart index cb79ef6..397ca90 100644 --- a/lib/screens/welcome_screen/pages/guide_page.dart +++ b/lib/screens/welcome_screen/pages/view_memories_page.dart @@ -1,41 +1,39 @@ import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:quid_faciam_hodie/constants/spacing.dart'; import 'package:quid_faciam_hodie/screens/welcome_screen/crabs/next_button.dart'; import 'package:quid_faciam_hodie/screens/welcome_screen/photo_switching.dart'; import 'package:quid_faciam_hodie/utils/theme.dart'; -class GuidePage extends StatelessWidget { - final String? picture; - final String description; +class ViewMemoriesPage extends StatelessWidget { final VoidCallback onNextPage; + final NetworkImage? initialImage; - const GuidePage({ + const ViewMemoriesPage({ Key? key, - required this.description, required this.onNextPage, - this.picture, + this.initialImage, }) : super(key: key); @override Widget build(BuildContext context) { + final localizations = AppLocalizations.of(context)!; + return Center( child: Padding( padding: const EdgeInsets.symmetric(horizontal: MEDIUM_SPACE), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - picture == null - ? const Expanded( - child: Padding( - padding: EdgeInsets.only(top: LARGE_SPACE), - child: PhotoSwitching(), - ), - ) - : SvgPicture.asset(picture!, height: 400), + Expanded( + child: Padding( + padding: const EdgeInsets.only(top: LARGE_SPACE), + child: PhotoSwitching(initialImage: initialImage), + ), + ), const SizedBox(height: LARGE_SPACE), Text( - description, + localizations.welcomeScreenViewMemoriesGuideDescription, style: getBodyTextTextStyle(context), ), const SizedBox(height: LARGE_SPACE), diff --git a/lib/screens/welcome_screen/photo_switching.dart b/lib/screens/welcome_screen/photo_switching.dart index 534c816..1459b25 100644 --- a/lib/screens/welcome_screen/photo_switching.dart +++ b/lib/screens/welcome_screen/photo_switching.dart @@ -5,43 +5,114 @@ import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:quid_faciam_hodie/constants/spacing.dart'; import 'package:quid_faciam_hodie/constants/values.dart'; import 'package:quid_faciam_hodie/managers/photo_manager.dart'; -import 'package:quid_faciam_hodie/utils/loadable.dart'; import 'package:quid_faciam_hodie/widgets/status.dart'; class PhotoSwitching extends StatefulWidget { - const PhotoSwitching({Key? key}) : super(key: key); + final NetworkImage? initialImage; + + const PhotoSwitching({ + Key? key, + this.initialImage, + }) : super(key: key); @override State createState() => _PhotoSwitchingState(); } -class _PhotoSwitchingState extends State with Loadable { - String photoURL = ''; +class _PhotoSwitchingState extends State { + // Contains two photos, the first one is the current photo, the second one is the next photo. + // The second one will be precached for faster image switching + late final List images; @override void initState() { super.initState(); - callWithLoading(getNextPhoto); + if (widget.initialImage != null) { + images = [widget.initialImage!]; + getInitialPhoto(); + } } - Future getNextPhoto() async { + @override + void didUpdateWidget(PhotoSwitching oldWidget) { + super.didUpdateWidget(oldWidget); + + if (widget.initialImage != null) { + images = [widget.initialImage!]; + getInitialPhoto(); + } + } + + Future getInitialPhoto() async { final query = WELCOME_SCREEN_PHOTOS_QUERIES[ Random().nextInt(WELCOME_SCREEN_PHOTOS_QUERIES.length)]; final url = await PhotoManager.getRandomPhoto(query); + final nextPhotoFuture = PhotoManager.getRandomPhoto(query); if (!mounted) { return; } setState(() { - photoURL = url; + images.add(NetworkImage(url)); }); + + final nextPhotoURL = await nextPhotoFuture; + + if (!mounted) { + return; + } + + final nextImage = NetworkImage(nextPhotoURL); + precacheImage(nextImage, context); + + setState(() { + images.add(nextImage); + }); + } + + Future getNextPhoto() async { + final query = WELCOME_SCREEN_PHOTOS_QUERIES[ + Random().nextInt(WELCOME_SCREEN_PHOTOS_QUERIES.length)]; + final nextPhotoFuture = PhotoManager.getRandomPhoto(query); + + if (images.length == 1) { + // We need to wait for the next photo to load first + final nextPhotoURL = await nextPhotoFuture; + + if (!mounted) { + return; + } + + final nextImage = NetworkImage(nextPhotoURL); + precacheImage(nextImage, context); + + setState(() { + images[0] = images[1]; + images[1] = nextImage; + }); + } else { + setState(() { + images[0] = images[1]; + }); + + final nextPhotoURL = await nextPhotoFuture; + + if (!mounted) { + return; + } + + final nextImage = NetworkImage(nextPhotoURL); + precacheImage(nextImage, context); + + images[1] = nextImage; + } } @override Widget build(BuildContext context) { - if (isLoading) { + if (widget.initialImage == null) { return Center( child: PlatformCircularProgressIndicator(), ); @@ -49,22 +120,17 @@ class _PhotoSwitchingState extends State with Loadable { return ClipRRect( borderRadius: BorderRadius.circular(MEDIUM_SPACE), - child: Image.network( - photoURL, - loadingBuilder: (context, child, loadingProgress) { - if (loadingProgress == null) { - return Status( - autoStart: true, - onEnd: () async { - getNextPhoto(); - }, - duration: const Duration(seconds: 3), - child: child, - ); - } - return const SizedBox.expand(); + child: Status( + key: Key(images.toString()), + autoStart: true, + onEnd: () async { + getNextPhoto(); }, - fit: BoxFit.cover, + duration: const Duration(seconds: 3), + child: Image( + image: images[0], + fit: BoxFit.cover, + ), ), ); }