improved welcome screen photo switching; improvements & bugfixes

This commit is contained in:
Myzel394 2022-08-19 22:00:37 +02:00
parent 6a5d50d1ba
commit b226908383
6 changed files with 170 additions and 59 deletions

View File

@ -136,7 +136,7 @@
"emptyScreenTitle": "Houston, we have a problem", "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! :)", "emptyScreenDescription": "To view your timeline you need to create some memories first! :)",
"emptyScreenCreateMemory": "Create a Memory", "emptyScreenCreateMemory": "Create a Memory",

View File

@ -3,7 +3,6 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
import 'package:lottie/lottie.dart'; import 'package:lottie/lottie.dart';
import 'package:quid_faciam_hodie/constants/spacing.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 'package:quid_faciam_hodie/utils/theme.dart';
import '../widgets/icon_button_child.dart'; import '../widgets/icon_button_child.dart';
@ -56,8 +55,7 @@ class EmptyScreen extends StatelessWidget {
label: Text(localizations.emptyScreenCreateMemory), label: Text(localizations.emptyScreenCreateMemory),
), ),
onPressed: () { onPressed: () {
Navigator.pushNamedAndRemoveUntil( Navigator.pop(context);
context, MainScreen.ID, (_) => false);
}, },
), ),
], ],

View File

@ -1,11 +1,15 @@
import 'dart:math';
import 'package:flutter/material.dart'; 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:flutter_platform_widgets/flutter_platform_widgets.dart';
import 'package:quid_faciam_hodie/constants/spacing.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/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/get_started_page.dart';
import 'welcome_screen/pages/guide_page.dart';
import 'welcome_screen/pages/initial_page.dart'; import 'welcome_screen/pages/initial_page.dart';
class WelcomeScreen extends StatefulWidget { class WelcomeScreen extends StatefulWidget {
@ -18,6 +22,7 @@ class WelcomeScreen extends StatefulWidget {
} }
class _WelcomeScreenState extends State<WelcomeScreen> { class _WelcomeScreenState extends State<WelcomeScreen> {
NetworkImage? _initialImageForPhotoSwitching;
final controller = PageController(); final controller = PageController();
@override @override
@ -25,6 +30,7 @@ class _WelcomeScreenState extends State<WelcomeScreen> {
super.initState(); super.initState();
UserHelpSheetsManager.deleteAll(); UserHelpSheetsManager.deleteAll();
getInitialImageForPhotoSwitching();
} }
@override @override
@ -34,6 +40,20 @@ class _WelcomeScreenState extends State<WelcomeScreen> {
super.dispose(); 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() { void nextPage() {
controller.animateToPage( controller.animateToPage(
(controller.page! + 1).toInt(), (controller.page! + 1).toInt(),
@ -44,8 +64,6 @@ class _WelcomeScreenState extends State<WelcomeScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final localizations = AppLocalizations.of(context)!;
return PlatformScaffold( return PlatformScaffold(
body: Padding( body: Padding(
padding: const EdgeInsets.symmetric(vertical: MEDIUM_SPACE), padding: const EdgeInsets.symmetric(vertical: MEDIUM_SPACE),
@ -53,19 +71,11 @@ class _WelcomeScreenState extends State<WelcomeScreen> {
child: PageView( child: PageView(
controller: controller, controller: controller,
children: <Widget>[ children: <Widget>[
InitialPage( InitialPage(onNextPage: nextPage),
CreateMemoriesPage(onNextPage: nextPage),
ViewMemoriesPage(
onNextPage: nextPage, onNextPage: nextPage,
), initialImage: _initialImageForPhotoSwitching,
GuidePage(
onNextPage: nextPage,
description:
localizations.welcomeScreenCreateMemoriesGuideDescription,
picture: 'assets/images/live_photo.svg',
),
GuidePage(
onNextPage: nextPage,
description:
localizations.welcomeScreenViewMemoriesGuideDescription,
), ),
const GetStartedPage(), const GetStartedPage(),
], ],

View File

@ -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: <Widget>[
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),
],
),
),
);
}
}

View File

@ -1,41 +1,39 @@
import 'package:flutter/material.dart'; 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/constants/spacing.dart';
import 'package:quid_faciam_hodie/screens/welcome_screen/crabs/next_button.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/screens/welcome_screen/photo_switching.dart';
import 'package:quid_faciam_hodie/utils/theme.dart'; import 'package:quid_faciam_hodie/utils/theme.dart';
class GuidePage extends StatelessWidget { class ViewMemoriesPage extends StatelessWidget {
final String? picture;
final String description;
final VoidCallback onNextPage; final VoidCallback onNextPage;
final NetworkImage? initialImage;
const GuidePage({ const ViewMemoriesPage({
Key? key, Key? key,
required this.description,
required this.onNextPage, required this.onNextPage,
this.picture, this.initialImage,
}) : super(key: key); }) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final localizations = AppLocalizations.of(context)!;
return Center( return Center(
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: MEDIUM_SPACE), padding: const EdgeInsets.symmetric(horizontal: MEDIUM_SPACE),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ children: <Widget>[
picture == null Expanded(
? const Expanded( child: Padding(
child: Padding( padding: const EdgeInsets.only(top: LARGE_SPACE),
padding: EdgeInsets.only(top: LARGE_SPACE), child: PhotoSwitching(initialImage: initialImage),
child: PhotoSwitching(), ),
), ),
)
: SvgPicture.asset(picture!, height: 400),
const SizedBox(height: LARGE_SPACE), const SizedBox(height: LARGE_SPACE),
Text( Text(
description, localizations.welcomeScreenViewMemoriesGuideDescription,
style: getBodyTextTextStyle(context), style: getBodyTextTextStyle(context),
), ),
const SizedBox(height: LARGE_SPACE), const SizedBox(height: LARGE_SPACE),

View File

@ -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/spacing.dart';
import 'package:quid_faciam_hodie/constants/values.dart'; import 'package:quid_faciam_hodie/constants/values.dart';
import 'package:quid_faciam_hodie/managers/photo_manager.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'; import 'package:quid_faciam_hodie/widgets/status.dart';
class PhotoSwitching extends StatefulWidget { class PhotoSwitching extends StatefulWidget {
const PhotoSwitching({Key? key}) : super(key: key); final NetworkImage? initialImage;
const PhotoSwitching({
Key? key,
this.initialImage,
}) : super(key: key);
@override @override
State<PhotoSwitching> createState() => _PhotoSwitchingState(); State<PhotoSwitching> createState() => _PhotoSwitchingState();
} }
class _PhotoSwitchingState extends State<PhotoSwitching> with Loadable { class _PhotoSwitchingState extends State<PhotoSwitching> {
String photoURL = ''; // 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<NetworkImage> images;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
callWithLoading(getNextPhoto); if (widget.initialImage != null) {
images = [widget.initialImage!];
getInitialPhoto();
}
} }
Future<void> getNextPhoto() async { @override
void didUpdateWidget(PhotoSwitching oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.initialImage != null) {
images = [widget.initialImage!];
getInitialPhoto();
}
}
Future<void> getInitialPhoto() async {
final query = WELCOME_SCREEN_PHOTOS_QUERIES[ final query = WELCOME_SCREEN_PHOTOS_QUERIES[
Random().nextInt(WELCOME_SCREEN_PHOTOS_QUERIES.length)]; Random().nextInt(WELCOME_SCREEN_PHOTOS_QUERIES.length)];
final url = await PhotoManager.getRandomPhoto(query); final url = await PhotoManager.getRandomPhoto(query);
final nextPhotoFuture = PhotoManager.getRandomPhoto(query);
if (!mounted) { if (!mounted) {
return; return;
} }
setState(() { 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<void> 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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (isLoading) { if (widget.initialImage == null) {
return Center( return Center(
child: PlatformCircularProgressIndicator(), child: PlatformCircularProgressIndicator(),
); );
@ -49,22 +120,17 @@ class _PhotoSwitchingState extends State<PhotoSwitching> with Loadable {
return ClipRRect( return ClipRRect(
borderRadius: BorderRadius.circular(MEDIUM_SPACE), borderRadius: BorderRadius.circular(MEDIUM_SPACE),
child: Image.network( child: Status(
photoURL, key: Key(images.toString()),
loadingBuilder: (context, child, loadingProgress) { autoStart: true,
if (loadingProgress == null) { onEnd: () async {
return Status( getNextPhoto();
autoStart: true,
onEnd: () async {
getNextPhoto();
},
duration: const Duration(seconds: 3),
child: child,
);
}
return const SizedBox.expand();
}, },
fit: BoxFit.cover, duration: const Duration(seconds: 3),
child: Image(
image: images[0],
fit: BoxFit.cover,
),
), ),
); );
} }