diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 38dfe3e2..07d9c9f1 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -17,7 +17,7 @@ 297F6FD12AD06E0F00FF159E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 297F6FD02AD06E0F00FF159E /* Assets.xcassets */; }; 297F6FD32AD06E0F00FF159E /* WonderousWidget.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 297F6FCF2AD06E0D00FF159E /* WonderousWidget.intentdefinition */; }; 297F6FD42AD06E0F00FF159E /* WonderousWidget.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 297F6FCF2AD06E0D00FF159E /* WonderousWidget.intentdefinition */; }; - 297F6FD72AD06E0F00FF159E /* Wonderous WidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 297F6FC52AD06E0D00FF159E /* Wonderous WidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 297F6FD72AD06E0F00FF159E /* WonderousWidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 297F6FC52AD06E0D00FF159E /* WonderousWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 297FD5742AE18011008D8BFE /* WonderousWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 297FD5732AE18011008D8BFE /* WonderousWidgetView.swift */; }; 297FD5762AE19BD9008D8BFE /* WonderWidgetViewComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 297FD5752AE19BD9008D8BFE /* WonderWidgetViewComponents.swift */; }; 323DE3CFA8490EAB3C4E249C /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4A44ACC5DE81A9C3E5BDA151 /* Pods_Runner.framework */; }; @@ -52,7 +52,7 @@ dstPath = ""; dstSubfolderSpec = 13; files = ( - 297F6FD72AD06E0F00FF159E /* Wonderous WidgetExtension.appex in Embed Foundation Extensions */, + 297F6FD72AD06E0F00FF159E /* WonderousWidgetExtension.appex in Embed Foundation Extensions */, ); name = "Embed Foundation Extensions"; runOnlyForDeploymentPostprocessing = 0; @@ -75,7 +75,7 @@ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 296251242AE7410D00D574FF /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = ""; }; 2978ECDC2B62D00C00E36CE8 /* FlutterAssets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlutterAssets.swift; sourceTree = ""; }; - 297F6FC52AD06E0D00FF159E /* Wonderous WidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; name = "Wonderous WidgetExtension.appex"; path = WonderousWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + 297F6FC52AD06E0D00FF159E /* WonderousWidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; name = "WonderousWidgetExtension.appex"; path = WonderousWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 297F6FC62AD06E0D00FF159E /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; }; 297F6FC82AD06E0D00FF159E /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; }; 297F6FCB2AD06E0D00FF159E /* WonderousWidgetBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WonderousWidgetBundle.swift; sourceTree = ""; }; @@ -187,7 +187,7 @@ children = ( 97C146EE1CF9000F007C117D /* Runner.app */, E214FC8227C5A18D005F78FB /* wondersUITests.xctest */, - 297F6FC52AD06E0D00FF159E /* Wonderous WidgetExtension.appex */, + 297F6FC52AD06E0D00FF159E /* WonderousWidgetExtension.appex */, ); name = Products; sourceTree = ""; @@ -235,7 +235,7 @@ ); name = WonderousWidgetExtension; productName = WonderousWidgetExtension; - productReference = 297F6FC52AD06E0D00FF159E /* Wonderous WidgetExtension.appex */; + productReference = 297F6FC52AD06E0D00FF159E /* WonderousWidgetExtension.appex */; productType = "com.apple.product-type.app-extension"; }; 97C146ED1CF9000F007C117D /* Runner */ = { @@ -612,7 +612,7 @@ GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = WonderousWidget/Info.plist; - INFOPLIST_KEY_CFBundleDisplayName = "Wonderous Widget"; + INFOPLIST_KEY_CFBundleDisplayName = "WonderousWidget"; INFOPLIST_KEY_NSHumanReadableCopyright = ""; IPHONEOS_DEPLOYMENT_TARGET = 16.4; LD_RUNPATH_SEARCH_PATHS = ( @@ -652,7 +652,7 @@ GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = WonderousWidget/Info.plist; - INFOPLIST_KEY_CFBundleDisplayName = "Wonderous Widget"; + INFOPLIST_KEY_CFBundleDisplayName = "WonderousWidget"; INFOPLIST_KEY_NSHumanReadableCopyright = ""; IPHONEOS_DEPLOYMENT_TARGET = 16.4; LD_RUNPATH_SEARCH_PATHS = ( @@ -681,15 +681,15 @@ CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_ENTITLEMENTS = "Wonderous WidgetExtension.entitlements"; + CODE_SIGN_ENTITLEMENTS = "WonderousWidgetExtension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = S3TL5AY6Y3; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = "Wonderous Widget/Info.plist"; - INFOPLIST_KEY_CFBundleDisplayName = "Wonderous Widget"; + INFOPLIST_FILE = "WonderousWidget/Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = "WonderousWidget"; INFOPLIST_KEY_NSHumanReadableCopyright = ""; IPHONEOS_DEPLOYMENT_TARGET = 16.4; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/ios/WonderousWidget/FlutterUtils.swift b/ios/WonderousWidget/FlutterUtils.swift index bf69dc15..695f7369 100644 --- a/ios/WonderousWidget/FlutterUtils.swift +++ b/ios/WonderousWidget/FlutterUtils.swift @@ -1,6 +1,6 @@ // // FlutterUtils.swift -// Wonderous WidgetExtension +// WonderousWidgetExtension // // Created by Shawn on 2023-10-19. // diff --git a/lib/logic/common/animate_utils.dart b/lib/logic/common/animate_utils.dart new file mode 100644 index 00000000..f286e06c --- /dev/null +++ b/lib/logic/common/animate_utils.dart @@ -0,0 +1,45 @@ +import 'package:wonders/common_libs.dart'; + +// ignore: must_be_immutable +class NeverAnimate extends Animate { + NeverAnimate({super.key, super.child}); + + @override + State createState() => _NeverAnimateState(); +} + +class _NeverAnimateState extends State { + @override + Widget build(BuildContext context) => widget.child; +} + +extension MaybeAnimateExtension on Widget { + Animate maybeAnimate({ + Key? key, + List? effects, + AnimateCallback? onInit, + AnimateCallback? onPlay, + AnimateCallback? onComplete, + bool? autoPlay, + Duration? delay, + AnimationController? controller, + Adapter? adapter, + double? target, + double? value, + }) => $styles.disableAnimations + ? NeverAnimate(child: this) + : Animate( + key: key, + effects: effects, + onInit: onInit, + onPlay: onPlay, + onComplete: onComplete, + autoPlay: autoPlay, + delay: delay, + controller: controller, + adapter: adapter, + target: target, + value: value, + child: this, + ); +} \ No newline at end of file diff --git a/lib/router.dart b/lib/router.dart index 2573b547..368647a1 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -42,24 +42,20 @@ class ScreenPaths { // Routes that are used multiple times AppRoute get _artifactRoute => AppRoute( - 'artifact/:artifactId', - (s) => ArtifactDetailsScreen(artifactId: s.pathParameters['artifactId']!), - ); + 'artifact/:artifactId', + (s) => ArtifactDetailsScreen(artifactId: s.pathParameters['artifactId']!), +); -AppRoute get _timelineRoute { - return AppRoute( - 'timeline', - (s) => TimelineScreen(type: _tryParseWonderType(s.uri.queryParameters['type']!)), - ); -} +AppRoute get _timelineRoute => AppRoute( + 'timeline', + (s) => TimelineScreen(type: _tryParseWonderType(s.uri.queryParameters['type']!)), +); -AppRoute get _collectionRoute { - return AppRoute( - 'collection', - (s) => CollectionScreen(fromId: s.uri.queryParameters['id'] ?? ''), - routes: [_artifactRoute], - ); -} +AppRoute get _collectionRoute => AppRoute( + 'collection', + (s) => CollectionScreen(fromId: s.uri.queryParameters['id'] ?? ''), + routes: [_artifactRoute], +); /// Routing table, matches string paths to UI Screens, optionally parses params from the paths final appRouter = GoRouter( @@ -132,7 +128,7 @@ class AppRoute extends GoRoute { body: builder(state), resizeToAvoidBottomInset: false, ); - if (useFade) { + if (useFade || $styles.disableAnimations) { return CustomTransitionPage( key: state.pageKey, child: pageContent, diff --git a/lib/styles/styles.dart b/lib/styles/styles.dart index 03eaf412..f8b6dd10 100644 --- a/lib/styles/styles.dart +++ b/lib/styles/styles.dart @@ -1,12 +1,13 @@ // ignore_for_file: library_private_types_in_public_api import 'package:wonders/common_libs.dart'; +import 'package:wonders/ui/common/utils/duration_utils.dart'; export 'colors.dart'; @immutable class AppStyle { - AppStyle({Size? screenSize}) { + AppStyle({Size? screenSize, this.disableAnimations = false}) { if (screenSize == null) { scale = 1; return; @@ -24,6 +25,7 @@ class AppStyle { } late final double scale; + late final bool disableAnimations; /// The current theme colors for the app final AppColors colors = AppColors(); @@ -40,7 +42,7 @@ class AppStyle { late final _Text text = _Text(scale); /// Animation Durations - final _Times times = _Times(); + late final _Times times = _Times(); /// Shared sizes late final _Sizes sizes = _Sizes(); @@ -133,10 +135,12 @@ class _Text { @immutable class _Times { - final Duration fast = Duration(milliseconds: 300); - final Duration med = Duration(milliseconds: 600); - final Duration slow = Duration(milliseconds: 900); - final Duration pageTransition = Duration(milliseconds: 200); + _Times(); + late final Duration fast = 300.animateMs; + late final Duration med = 600.animateMs; + late final Duration slow = 900.animateMs; + late final Duration extraSlow = 1300.animateMs; + late final Duration pageTransition = 200.animateMs; } @immutable diff --git a/lib/ui/app_scaffold.dart b/lib/ui/app_scaffold.dart index 8b62a778..a795840e 100644 --- a/lib/ui/app_scaffold.dart +++ b/lib/ui/app_scaffold.dart @@ -15,7 +15,7 @@ class WondersAppScaffold extends StatelessWidget { // Set default timing for animations in the app Animate.defaultDuration = _style.times.fast; // Create a style object that will be passed down the widget tree - _style = AppStyle(screenSize: context.sizePx); + _style = AppStyle(screenSize: context.sizePx, disableAnimations: mq.disableAnimations); return KeyedSubtree( key: ValueKey($styles.scale), child: Theme( diff --git a/lib/ui/common/collectible_item.dart b/lib/ui/common/collectible_item.dart index 64464203..7d8f366e 100644 --- a/lib/ui/common/collectible_item.dart +++ b/lib/ui/common/collectible_item.dart @@ -1,8 +1,10 @@ import 'package:wonders/common_libs.dart'; import 'package:wonders/logic/collectibles_logic.dart'; +import 'package:wonders/logic/common/animate_utils.dart'; import 'package:wonders/logic/data/collectible_data.dart'; import 'package:wonders/ui/common/opening_card.dart'; import 'package:wonders/ui/common/utils/app_haptics.dart'; +import 'package:wonders/ui/common/utils/duration_utils.dart'; import 'package:wonders/ui/screens/collectible_found/collectible_found_screen.dart'; class CollectibleItem extends StatelessWidget with GetItMixin { @@ -53,8 +55,8 @@ class CollectibleItem extends StatelessWidget with GetItMixin { fit: BoxFit.contain, ), ) - .animate(onPlay: (controller) => controller.repeat()) - .shimmer(delay: 4000.ms, duration: $styles.times.med * 3) + .maybeAnimate(onPlay: (controller) => controller.repeat()) + .shimmer(delay: 4000.delayMs, duration: $styles.times.med * 3) .shake(curve: Curves.easeInOutCubic, hz: 4) .scale(begin: Offset(1.0, 1.0), end: Offset(1.1, 1.1), duration: $styles.times.med) .then(delay: $styles.times.med) diff --git a/lib/ui/common/compass_divider.dart b/lib/ui/common/compass_divider.dart index d19958b8..06429e99 100644 --- a/lib/ui/common/compass_divider.dart +++ b/lib/ui/common/compass_divider.dart @@ -1,5 +1,6 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:wonders/common_libs.dart'; +import 'package:wonders/ui/common/utils/duration_utils.dart'; class CompassDivider extends StatelessWidget { const CompassDivider({super.key, required this.isExpanded, this.duration, this.linesColor, this.compassColor}); @@ -10,7 +11,7 @@ class CompassDivider extends StatelessWidget { @override Widget build(BuildContext context) { - Duration duration = this.duration ?? 1500.ms; + Duration duration = this.duration ?? 1500.animateMs; Widget buildHzAnimatedDivider({bool alignLeft = false}) { return TweenAnimationBuilder( duration: duration, diff --git a/lib/ui/common/modals/fullscreen_url_img_viewer.dart b/lib/ui/common/modals/fullscreen_url_img_viewer.dart index 1c88ddf7..d014d107 100644 --- a/lib/ui/common/modals/fullscreen_url_img_viewer.dart +++ b/lib/ui/common/modals/fullscreen_url_img_viewer.dart @@ -53,7 +53,7 @@ class _FullscreenUrlImgViewerState extends State { void _animateToPage(int page) { if (page >= 0 || page < widget.urls.length) { - _controller.animateToPage(page, duration: 300.ms, curve: Curves.easeOut); + _controller.animateToPage(page, duration: $styles.times.fast, curve: Curves.easeOut); } } diff --git a/lib/ui/common/utils/duration_utils.dart b/lib/ui/common/utils/duration_utils.dart new file mode 100644 index 00000000..57d44428 --- /dev/null +++ b/lib/ui/common/utils/duration_utils.dart @@ -0,0 +1,6 @@ +import 'package:wonders/common_libs.dart'; + +extension DurationExtensions on int { + Duration get delayMs => $styles.disableAnimations ? 0.ms : Duration(milliseconds: this); + Duration get animateMs => $styles.disableAnimations ? 1.ms : Duration(milliseconds: this); +} \ No newline at end of file diff --git a/lib/ui/screens/artifact/artifact_carousel/artifact_carousel_screen.dart b/lib/ui/screens/artifact/artifact_carousel/artifact_carousel_screen.dart index b3ce0234..8313bc4b 100644 --- a/lib/ui/screens/artifact/artifact_carousel/artifact_carousel_screen.dart +++ b/lib/ui/screens/artifact/artifact_carousel/artifact_carousel_screen.dart @@ -1,6 +1,7 @@ import 'dart:ui'; import 'package:wonders/common_libs.dart'; +import 'package:wonders/logic/common/animate_utils.dart'; import 'package:wonders/logic/data/highlight_data.dart'; import 'package:wonders/ui/common/app_icons.dart'; import 'package:wonders/ui/common/controls/app_header.dart'; diff --git a/lib/ui/screens/artifact/artifact_carousel/widgets/_bottom_text_content.dart b/lib/ui/screens/artifact/artifact_carousel/widgets/_bottom_text_content.dart index a47db96a..ebafe135 100644 --- a/lib/ui/screens/artifact/artifact_carousel/widgets/_bottom_text_content.dart +++ b/lib/ui/screens/artifact/artifact_carousel/widgets/_bottom_text_content.dart @@ -57,7 +57,7 @@ class _BottomTextContent extends StatelessWidget { ), ] ], - ).animate(key: ValueKey(artifact.artifactId)).fadeIn(), + ).maybeAnimate(key: ValueKey(artifact.artifactId)).fadeIn(), ), ), ], diff --git a/lib/ui/screens/artifact/artifact_details/artifact_details_screen.dart b/lib/ui/screens/artifact/artifact_details/artifact_details_screen.dart index 446c5b06..006daa8b 100644 --- a/lib/ui/screens/artifact/artifact_details/artifact_details_screen.dart +++ b/lib/ui/screens/artifact/artifact_details/artifact_details_screen.dart @@ -1,10 +1,12 @@ import 'package:wonders/common_libs.dart'; +import 'package:wonders/logic/common/animate_utils.dart'; import 'package:wonders/logic/data/artifact_data.dart'; import 'package:wonders/ui/common/compass_divider.dart'; import 'package:wonders/ui/common/controls/app_header.dart'; import 'package:wonders/ui/common/controls/app_loading_indicator.dart'; import 'package:wonders/ui/common/gradient_container.dart'; import 'package:wonders/ui/common/modals/fullscreen_url_img_viewer.dart'; +import 'package:wonders/ui/common/utils/duration_utils.dart'; part 'widgets/_artifact_image_btn.dart'; part 'widgets/_info_column.dart'; @@ -85,6 +87,6 @@ class _ArtifactDetailsScreenState extends State { ), ), ], - ).animate().fadeIn(); + ).maybeAnimate().fadeIn(); } } diff --git a/lib/ui/screens/artifact/artifact_details/widgets/_info_column.dart b/lib/ui/screens/artifact/artifact_details/widgets/_info_column.dart index eeffb437..f837847e 100644 --- a/lib/ui/screens/artifact/artifact_details/widgets/_info_column.dart +++ b/lib/ui/screens/artifact/artifact_details/widgets/_info_column.dart @@ -18,7 +18,7 @@ class _InfoColumn extends StatelessWidget { Text( data.culture.toUpperCase(), style: $styles.text.titleFont.copyWith(color: $styles.colors.accent1), - ).animate().fade(delay: 150.ms, duration: 600.ms), + ).maybeAnimate().fade(delay: 150.delayMs, duration: 600.animateMs), Gap($styles.insets.xs), ], Semantics( @@ -29,11 +29,11 @@ class _InfoColumn extends StatelessWidget { style: $styles.text.h2.copyWith(color: $styles.colors.offWhite, height: 1.2), maxLines: 5, overflow: TextOverflow.ellipsis, - ).animate().fade(delay: 250.ms, duration: 600.ms), + ).maybeAnimate().fade(delay: 250.delayMs, duration: 600.animateMs), ), Gap($styles.insets.lg), Animate().toggle( - delay: 500.ms, + delay: 500.delayMs, builder: (_, value, __) { return CompassDivider(isExpanded: !value, duration: $styles.times.med); }), @@ -49,8 +49,8 @@ class _InfoColumn extends StatelessWidget { _InfoRow($strings.artifactDetailsLabelDimension, data.dimension), _InfoRow($strings.artifactDetailsLabelClassification, data.classification), ] - .animate(interval: 100.ms) - .fadeIn(delay: 600.ms, duration: $styles.times.med) + .animate(interval: 100.delayMs) + .fadeIn(delay: 600.delayMs, duration: $styles.times.med) .slide(begin: Offset(0.2, 0), curve: Curves.easeOut), ], ), @@ -58,7 +58,7 @@ class _InfoColumn extends StatelessWidget { Text( $strings.homeMenuAboutMet, style: $styles.text.caption.copyWith(color: $styles.colors.accent2), - ).animate(delay: 1.5.seconds).fadeIn().slide(begin: Offset(0.2, 0), curve: Curves.easeOut), + ).maybeAnimate(delay: 1500.delayMs).fadeIn().slide(begin: Offset(0.2, 0), curve: Curves.easeOut), Gap($styles.insets.offset), ], ), diff --git a/lib/ui/screens/collectible_found/collectible_found_screen.dart b/lib/ui/screens/collectible_found/collectible_found_screen.dart index 0868bf26..7974853c 100644 --- a/lib/ui/screens/collectible_found/collectible_found_screen.dart +++ b/lib/ui/screens/collectible_found/collectible_found_screen.dart @@ -1,10 +1,12 @@ import 'package:particle_field/particle_field.dart'; import 'package:wonders/common_libs.dart'; +import 'package:wonders/logic/common/animate_utils.dart'; import 'package:wonders/logic/data/collectible_data.dart'; import 'package:wonders/ui/common/app_backdrop.dart'; import 'package:wonders/ui/common/centered_box.dart'; import 'package:wonders/ui/common/controls/app_header.dart'; import 'package:wonders/ui/common/pop_navigator_underlay.dart'; +import 'package:wonders/ui/common/utils/duration_utils.dart'; part 'widgets/_animated_ribbon.dart'; part 'widgets/_celebration_particles.dart'; @@ -21,7 +23,7 @@ class CollectibleFoundScreen extends StatelessWidget { Widget build(BuildContext context) { return RepaintBoundary( child: _buildIntro(context).animate().swap( - delay: $styles.times.fast * 3.5, + delay: 1050.animateMs, builder: (_, __) => _buildDetail(context), ), ); diff --git a/lib/ui/screens/collectible_found/widgets/_animated_ribbon.dart b/lib/ui/screens/collectible_found/widgets/_animated_ribbon.dart index b03c897f..2f49b733 100644 --- a/lib/ui/screens/collectible_found/widgets/_animated_ribbon.dart +++ b/lib/ui/screens/collectible_found/widgets/_animated_ribbon.dart @@ -38,7 +38,7 @@ class _AnimatedRibbon extends StatelessWidget { if (flip) end = Transform.scale(scaleX: -1, child: end); double m = flip ? 1 : -1; return end - .animate() - .move(begin: Offset(m * 8, 2), end: Offset(m * 32, 10), duration: 400.ms, curve: Curves.easeOut); + .maybeAnimate() + .move(begin: Offset(m * 8, 2), end: Offset(m * 32, 10), duration: 400.animateMs, curve: Curves.easeOut); } } diff --git a/lib/ui/screens/collection/collection_screen.dart b/lib/ui/screens/collection/collection_screen.dart index 4fb3b942..fadce9e2 100644 --- a/lib/ui/screens/collection/collection_screen.dart +++ b/lib/ui/screens/collection/collection_screen.dart @@ -3,11 +3,13 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:wonders/common_libs.dart'; import 'package:wonders/logic/collectibles_logic.dart'; +import 'package:wonders/logic/common/animate_utils.dart'; import 'package:wonders/logic/data/collectible_data.dart'; import 'package:wonders/logic/data/wonder_data.dart'; import 'package:wonders/ui/common/centered_box.dart'; import 'package:wonders/ui/common/controls/app_header.dart'; import 'package:wonders/ui/common/modals/app_modals.dart'; +import 'package:wonders/ui/common/utils/duration_utils.dart'; part 'widgets/_collectible_image.dart'; part 'widgets/_collection_footer.dart'; @@ -38,7 +40,7 @@ class _CollectionScreenState extends State with GetItStateMixi void _scrollToTarget([bool animate = true]) { if (_scrollKey.currentContext != null) { - Scrollable.ensureVisible(_scrollKey.currentContext!, alignment: 0.15, duration: animate ? 300.ms : 0.ms); + Scrollable.ensureVisible(_scrollKey.currentContext!, alignment: 0.15, duration: (animate ? 300 : 0).animateMs); } } diff --git a/lib/ui/screens/collection/widgets/_collection_footer.dart b/lib/ui/screens/collection/widgets/_collection_footer.dart index 8e2a6e68..a784a236 100644 --- a/lib/ui/screens/collection/widgets/_collection_footer.dart +++ b/lib/ui/screens/collection/widgets/_collection_footer.dart @@ -69,7 +69,7 @@ class _CollectionFooter extends StatelessWidget { color: $styles.colors.accent1, borderRadius: BorderRadius.circular(1000), ), - ).animate().fade(duration: 1500.ms, curve: Curves.easeOutExpo).custom( + ).maybeAnimate().fade(duration: 1500.animateMs, curve: Curves.easeOutExpo).custom( builder: (_, m, child) => FractionallySizedBox( alignment: Alignment.centerLeft, widthFactor: m * count / total, diff --git a/lib/ui/screens/collection/widgets/_collection_list_card.dart b/lib/ui/screens/collection/widgets/_collection_list_card.dart index 189f286f..7c52b871 100644 --- a/lib/ui/screens/collection/widgets/_collection_list_card.dart +++ b/lib/ui/screens/collection/widgets/_collection_list_card.dart @@ -10,7 +10,7 @@ class _CollectionListCard extends StatelessWidget with GetItMixin { void _showDetails(BuildContext context, CollectibleData collectible) { context.go(ScreenPaths.artifact(collectible.artifactId)); - Future.delayed(300.ms).then((_) => collectiblesLogic.setState(collectible.id, CollectibleState.explored)); + Future.delayed(300.delayMs).then((_) => collectiblesLogic.setState(collectible.id, CollectibleState.explored)); } @override diff --git a/lib/ui/screens/editorial/editorial_screen.dart b/lib/ui/screens/editorial/editorial_screen.dart index 9aa4c5e4..721be97a 100644 --- a/lib/ui/screens/editorial/editorial_screen.dart +++ b/lib/ui/screens/editorial/editorial_screen.dart @@ -5,6 +5,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_circular_text/circular_text.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:wonders/common_libs.dart'; +import 'package:wonders/logic/common/animate_utils.dart'; import 'package:wonders/logic/common/platform_info.dart'; import 'package:wonders/logic/common/string_utils.dart'; import 'package:wonders/logic/data/wonder_data.dart'; @@ -24,6 +25,7 @@ import 'package:wonders/ui/common/scaling_list_item.dart'; import 'package:wonders/ui/common/static_text_scale.dart'; import 'package:wonders/ui/common/themed_text.dart'; import 'package:wonders/ui/common/utils/context_utils.dart'; +import 'package:wonders/ui/common/utils/duration_utils.dart'; import 'package:wonders/ui/wonder_illustrations/common/wonder_illustration.dart'; import 'package:wonders/ui/wonder_illustrations/common/wonder_illustration_config.dart'; import 'package:wonders/ui/wonder_illustrations/common/wonder_title_text.dart'; diff --git a/lib/ui/screens/editorial/widgets/_app_bar.dart b/lib/ui/screens/editorial/widgets/_app_bar.dart index 48b5eba2..a98f57d6 100644 --- a/lib/ui/screens/editorial/widgets/_app_bar.dart +++ b/lib/ui/screens/editorial/widgets/_app_bar.dart @@ -67,7 +67,7 @@ class _AppBar extends StatelessWidget { ); }, ), - ).animate(delay: $styles.times.pageTransition + 500.ms).fadeIn(duration: $styles.times.slow), + ).maybeAnimate(delay: $styles.times.pageTransition + 500.delayMs).fadeIn(duration: $styles.times.slow), ), ), ), diff --git a/lib/ui/screens/editorial/widgets/_circular_title_bar.dart b/lib/ui/screens/editorial/widgets/_circular_title_bar.dart index 2e0360cd..ec9b3c17 100644 --- a/lib/ui/screens/editorial/widgets/_circular_title_bar.dart +++ b/lib/ui/screens/editorial/widgets/_circular_title_bar.dart @@ -34,7 +34,7 @@ class _CircularTitleBar extends StatelessWidget { BottomCenter( child: Padding( padding: EdgeInsets.only(bottom: 20), - child: Image.asset('${ImagePaths.common}/${icons[index]}').animate(key: ValueKey(index)).fade().scale( + child: Image.asset('${ImagePaths.common}/${icons[index]}').maybeAnimate(key: ValueKey(index)).fade().scale( begin: Offset(.5, .5), end: Offset(1, 1), curve: Curves.easeOutBack, duration: $styles.times.med), ), ), diff --git a/lib/ui/screens/editorial/widgets/_scrolling_content.dart b/lib/ui/screens/editorial/widgets/_scrolling_content.dart index 4cac7de1..cd3d4e05 100644 --- a/lib/ui/screens/editorial/widgets/_scrolling_content.dart +++ b/lib/ui/screens/editorial/widgets/_scrolling_content.dart @@ -31,7 +31,7 @@ class _ScrollingContent extends StatelessWidget { label: value, child: ExcludeSemantics( child: skipCaps - ? Text(_fixNewlines(value), style: bodyStyle) + ? Text(_fixNewlines(value), style: bodyStyle ) : DropCapText( _fixNewlines(value).substring(1), dropCap: DropCap( diff --git a/lib/ui/screens/editorial/widgets/_title_text.dart b/lib/ui/screens/editorial/widgets/_title_text.dart index 2d325c63..b5ebca40 100644 --- a/lib/ui/screens/editorial/widgets/_title_text.dart +++ b/lib/ui/screens/editorial/widgets/_title_text.dart @@ -27,7 +27,7 @@ class _TitleText extends StatelessWidget { Expanded( child: Divider( color: data.type.fgColor, - ).animate().scale(curve: Curves.easeOut, delay: 500.ms), + ).maybeAnimate().scale(curve: Curves.easeOut, delay: 500.delayMs), ), Semantics( header: true, @@ -35,12 +35,12 @@ class _TitleText extends StatelessWidget { child: Text( data.subTitle.toUpperCase(), style: $styles.text.title2, - ).animate().fade(delay: 100.ms), + ).maybeAnimate().fade(delay: 100.delayMs), ), Expanded( child: Divider( color: data.type.fgColor, - ).animate().scale(curve: Curves.easeOut, delay: 500.ms), + ).maybeAnimate().scale(curve: Curves.easeOut, delay: 500.delayMs), ), ], ), diff --git a/lib/ui/screens/home/_vertical_swipe_controller.dart b/lib/ui/screens/home/_vertical_swipe_controller.dart index 63d688d5..85df0514 100644 --- a/lib/ui/screens/home/_vertical_swipe_controller.dart +++ b/lib/ui/screens/home/_vertical_swipe_controller.dart @@ -17,7 +17,7 @@ class _VerticalSwipeController { void handleTapCancelled() => isPointerDown.value = false; void handleVerticalSwipeCancelled() { - swipeReleaseAnim.duration = swipeAmt.value.seconds * .5; + swipeReleaseAnim.duration = $styles.disableAnimations ? 1.ms : swipeAmt.value.seconds * .5; swipeReleaseAnim.reverse(from: swipeAmt.value); isPointerDown.value = false; } diff --git a/lib/ui/screens/home/wonders_home_screen.dart b/lib/ui/screens/home/wonders_home_screen.dart index 84a7c7de..9cc77ab7 100644 --- a/lib/ui/screens/home/wonders_home_screen.dart +++ b/lib/ui/screens/home/wonders_home_screen.dart @@ -1,4 +1,5 @@ import 'package:wonders/common_libs.dart'; +import 'package:wonders/logic/common/animate_utils.dart'; import 'package:wonders/logic/data/wonder_data.dart'; import 'package:wonders/ui/common/app_icons.dart'; import 'package:wonders/ui/common/controls/app_header.dart'; @@ -9,6 +10,7 @@ import 'package:wonders/ui/common/ignore_pointer.dart'; import 'package:wonders/ui/common/previous_next_navigation.dart'; import 'package:wonders/ui/common/themed_text.dart'; import 'package:wonders/ui/common/utils/app_haptics.dart'; +import 'package:wonders/ui/common/utils/duration_utils.dart'; import 'package:wonders/ui/screens/home_menu/home_menu.dart'; import 'package:wonders/ui/wonder_illustrations/common/animated_clouds.dart'; import 'package:wonders/ui/wonder_illustrations/common/wonder_illustration.dart'; @@ -113,7 +115,7 @@ class _HomeScreenState extends State with SingleTickerProviderStateM void _showDetailsPage() async { _swipeOverride = _swipeController.swipeAmt.value; context.go(ScreenPaths.wonderDetails(currentWonder.type, tabIndex: 0)); - await Future.delayed(100.ms); + await Future.delayed(100.delayMs); _swipeOverride = null; _fadeInOnNextBuild = true; } @@ -123,7 +125,7 @@ class _HomeScreenState extends State with SingleTickerProviderStateM for (var a in _fadeAnims) { a.value = 0; } - await Future.delayed(300.ms); + await Future.delayed(300.delayMs); for (var a in _fadeAnims) { a.forward(); } @@ -168,7 +170,7 @@ class _HomeScreenState extends State with SingleTickerProviderStateM /// Controls that float on top of the various illustrations _buildFloatingUi(), ], - ).animate().fadeIn(), + ).maybeAnimate().fadeIn(), ), ), )); diff --git a/lib/ui/screens/home_menu/home_menu.dart b/lib/ui/screens/home_menu/home_menu.dart index 164b4ca7..2bb3d55c 100644 --- a/lib/ui/screens/home_menu/home_menu.dart +++ b/lib/ui/screens/home_menu/home_menu.dart @@ -1,12 +1,14 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:wonders/common_libs.dart'; +import 'package:wonders/logic/common/animate_utils.dart'; import 'package:wonders/logic/data/wonder_data.dart'; import 'package:wonders/ui/common/app_backdrop.dart'; import 'package:wonders/ui/common/app_icons.dart'; import 'package:wonders/ui/common/controls/app_header.dart'; import 'package:wonders/ui/common/controls/locale_switcher.dart'; import 'package:wonders/ui/common/pop_navigator_underlay.dart'; +import 'package:wonders/ui/common/utils/duration_utils.dart'; import 'package:wonders/ui/common/wonderous_logo.dart'; import 'package:wonders/ui/screens/home_menu/about_dialog_content.dart'; @@ -68,7 +70,7 @@ class _HomeMenuState extends State { Gap(50), Gap($styles.insets.md), _buildIconGrid(context) - .animate() + .maybeAnimate() .fade(duration: $styles.times.fast) .scale(begin: Offset(.8, .8), curve: Curves.easeOut), Gap($styles.insets.lg), @@ -127,9 +129,9 @@ class _HomeMenuState extends State { valueListenable: settingsLogic.currentLocale, builder: (_, __, ___) { return SeparatedColumn( - separatorBuilder: () => Divider(thickness: 1.5, height: 1).animate().scale( + separatorBuilder: () => Divider(thickness: 1.5, height: 1).maybeAnimate().scale( duration: $styles.times.slow, - delay: $styles.times.pageTransition + 200.ms, + delay: $styles.times.pageTransition + 200.delayMs, curve: Curves.easeOutBack, ), children: [ @@ -147,8 +149,8 @@ class _HomeMenuState extends State { onPressed: () => _handleAboutPressed(context), ), ] - .animate(interval: 50.ms) - .fade(delay: $styles.times.pageTransition + 50.ms) + .animate(interval: 50.delayMs) + .fade(delay: $styles.times.pageTransition + 50.delayMs) .slide(begin: Offset(0, .1), curve: Curves.easeOut), ); }); diff --git a/lib/ui/screens/intro/intro_screen.dart b/lib/ui/screens/intro/intro_screen.dart index 2cb8e1ac..3994f1bd 100644 --- a/lib/ui/screens/intro/intro_screen.dart +++ b/lib/ui/screens/intro/intro_screen.dart @@ -9,6 +9,7 @@ import 'package:wonders/ui/common/previous_next_navigation.dart'; import 'package:wonders/ui/common/static_text_scale.dart'; import 'package:wonders/ui/common/themed_text.dart'; import 'package:wonders/ui/common/utils/app_haptics.dart'; +import 'package:wonders/ui/common/utils/duration_utils.dart'; class IntroScreen extends StatefulWidget { const IntroScreen({super.key}); @@ -60,7 +61,7 @@ class _IntroScreenState extends State { final int current = _pageController.page!.round(); if (_isOnLastPage && dir > 0) return; if (_isOnFirstPage && dir < 0) return; - _pageController.animateToPage(current + dir, duration: 250.ms, curve: Curves.easeIn); + _pageController.animateToPage(current + dir, duration: $styles.times.fast, curve: Curves.easeIn); } @override @@ -85,7 +86,7 @@ class _IntroScreenState extends State { color: $styles.colors.black, child: SafeArea( child: Animate( - delay: 500.ms, + delay: 500.delayMs, effects: const [FadeEffect()], child: PreviousNextNavigation( maxWidth: 600, diff --git a/lib/ui/screens/photo_gallery/photo_gallery.dart b/lib/ui/screens/photo_gallery/photo_gallery.dart index 521314e9..2b234b1a 100644 --- a/lib/ui/screens/photo_gallery/photo_gallery.dart +++ b/lib/ui/screens/photo_gallery/photo_gallery.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:wonders/common_libs.dart'; +import 'package:wonders/logic/common/animate_utils.dart'; import 'package:wonders/logic/data/unsplash_photo_data.dart'; import 'package:wonders/ui/common/controls/app_loading_indicator.dart'; import 'package:wonders/ui/common/controls/eight_way_swipe_detector.dart'; @@ -259,7 +260,7 @@ class _PhotoGalleryState extends State { imgUrl, fit: BoxFit.cover, size: UnsplashPhotoSize.large, - ).animate().fade(), + ).maybeAnimate().fade(), ); return MergeSemantics( diff --git a/lib/ui/screens/timeline/timeline_screen.dart b/lib/ui/screens/timeline/timeline_screen.dart index 6030ad76..589be041 100644 --- a/lib/ui/screens/timeline/timeline_screen.dart +++ b/lib/ui/screens/timeline/timeline_screen.dart @@ -3,6 +3,7 @@ import 'dart:ui'; import 'package:flutter/foundation.dart'; import 'package:wonders/common_libs.dart'; +import 'package:wonders/logic/common/animate_utils.dart'; import 'package:wonders/logic/common/debouncer.dart'; import 'package:wonders/logic/common/string_utils.dart'; import 'package:wonders/logic/data/timeline_data.dart'; @@ -15,6 +16,7 @@ import 'package:wonders/ui/common/ignore_pointer.dart'; import 'package:wonders/ui/common/list_gradient.dart'; import 'package:wonders/ui/common/timeline_event_card.dart'; import 'package:wonders/ui/common/utils/app_haptics.dart'; +import 'package:wonders/ui/common/utils/duration_utils.dart'; import 'package:wonders/ui/common/wonders_timeline_builder.dart'; part 'widgets/_animated_era_text.dart'; diff --git a/lib/ui/screens/timeline/widgets/_animated_era_text.dart b/lib/ui/screens/timeline/widgets/_animated_era_text.dart index 2563305b..e561fc76 100644 --- a/lib/ui/screens/timeline/widgets/_animated_era_text.dart +++ b/lib/ui/screens/timeline/widgets/_animated_era_text.dart @@ -11,6 +11,6 @@ class _AnimatedEraText extends StatelessWidget { return Semantics( liveRegion: true, child: Text(era, style: style), - ).animate(key: ValueKey(era)).fadeIn().slide(begin: Offset(0, .2)); + ).maybeAnimate(key: ValueKey(era)).fadeIn().slide(begin: Offset(0, .2)); } } diff --git a/lib/ui/screens/timeline/widgets/_event_popups.dart b/lib/ui/screens/timeline/widgets/_event_popups.dart index 21a6add7..71d03682 100644 --- a/lib/ui/screens/timeline/widgets/_event_popups.dart +++ b/lib/ui/screens/timeline/widgets/_event_popups.dart @@ -9,7 +9,7 @@ class _EventPopups extends StatefulWidget { } class _EventPopupsState extends State<_EventPopups> { - final _debouncer = Debouncer(500.ms); + final _debouncer = Debouncer(500.animateMs); TimelineEvent? _eventToShow; @override diff --git a/lib/ui/screens/timeline/widgets/_scrolling_viewport.dart b/lib/ui/screens/timeline/widgets/_scrolling_viewport.dart index 21cdea32..eaabbffd 100644 --- a/lib/ui/screens/timeline/widgets/_scrolling_viewport.dart +++ b/lib/ui/screens/timeline/widgets/_scrolling_viewport.dart @@ -66,7 +66,7 @@ class _ScalingViewportState extends State<_ScrollingViewport> { child: Stack( children: [ // Main content area - _buildScrollingArea(context).animate().fadeIn(), + _buildScrollingArea(context).maybeAnimate().fadeIn(), // Dashed line with a year that changes as we scroll IgnorePointerWithSemantics( diff --git a/lib/ui/screens/timeline/widgets/_scrolling_viewport_controller.dart b/lib/ui/screens/timeline/widgets/_scrolling_viewport_controller.dart index 83fa776b..5c244106 100644 --- a/lib/ui/screens/timeline/widgets/_scrolling_viewport_controller.dart +++ b/lib/ui/screens/timeline/widgets/_scrolling_viewport_controller.dart @@ -25,7 +25,7 @@ class _ScrollingViewportController extends ChangeNotifier { final data = wondersLogic.getData(w); final pos = calculateScrollPosFromYear(data.startYr); scroller.jumpTo(pos - 200); - scroller.animateTo(pos, duration: 1.35.seconds, curve: Curves.easeOutCubic); + scroller.animateTo(pos, duration: $styles.times.extraSlow, curve: Curves.easeOutCubic); scroller.addListener(_updateCurrentYear); } }); diff --git a/lib/ui/screens/wonder_events/widgets/_events_list.dart b/lib/ui/screens/wonder_events/widgets/_events_list.dart index 995b39f4..d27c32d6 100644 --- a/lib/ui/screens/wonder_events/widgets/_events_list.dart +++ b/lib/ui/screens/wonder_events/widgets/_events_list.dart @@ -49,11 +49,11 @@ class _EventsListState extends State<_EventsList> { final listItems = []; for (var e in events.entries) { - final delay = 100.ms + (100 * listItems.length).ms; + final delay = (100 + (100 * listItems.length)).delayMs; listItems.add( TimelineEventCard(year: e.key, text: e.value, darkMode: true) - .animate() - .fade(delay: delay, duration: $styles.times.med * 1.5) + .maybeAnimate() + .fade(delay: delay, duration: $styles.times.slow) .slide(begin: Offset(0, 1), curve: Curves.easeOutBack), ); } diff --git a/lib/ui/screens/wonder_events/widgets/_wonder_image_with_timeline.dart b/lib/ui/screens/wonder_events/widgets/_wonder_image_with_timeline.dart index 9d9bb780..08712638 100644 --- a/lib/ui/screens/wonder_events/widgets/_wonder_image_with_timeline.dart +++ b/lib/ui/screens/wonder_events/widgets/_wonder_image_with_timeline.dart @@ -108,7 +108,7 @@ class _WonderImageWithTimeline extends StatelessWidget { _buildDot(context), Text(StringUtils.getEra(data.startYr), style: textStyle), ], - ).animate().fade(delay: $styles.times.pageTransition); + ).maybeAnimate().fade(delay: $styles.times.pageTransition); } Widget _buildDot(BuildContext context) { diff --git a/lib/ui/screens/wonder_events/wonder_events.dart b/lib/ui/screens/wonder_events/wonder_events.dart index 3c3007f0..6deb4a39 100644 --- a/lib/ui/screens/wonder_events/wonder_events.dart +++ b/lib/ui/screens/wonder_events/wonder_events.dart @@ -1,4 +1,5 @@ import 'package:wonders/common_libs.dart'; +import 'package:wonders/logic/common/animate_utils.dart'; import 'package:wonders/logic/common/platform_info.dart'; import 'package:wonders/logic/common/string_utils.dart'; import 'package:wonders/logic/data/wonder_data.dart'; @@ -12,6 +13,7 @@ import 'package:wonders/ui/common/ignore_pointer.dart'; import 'package:wonders/ui/common/list_gradient.dart'; import 'package:wonders/ui/common/themed_text.dart'; import 'package:wonders/ui/common/timeline_event_card.dart'; +import 'package:wonders/ui/common/utils/duration_utils.dart'; import 'package:wonders/ui/common/wonders_timeline_builder.dart'; import 'package:wonders/ui/wonder_illustrations/common/wonder_title_text.dart'; diff --git a/lib/ui/wonder_illustrations/common/animated_clouds.dart b/lib/ui/wonder_illustrations/common/animated_clouds.dart index ea3ff5f2..64c67f0b 100644 --- a/lib/ui/wonder_illustrations/common/animated_clouds.dart +++ b/lib/ui/wonder_illustrations/common/animated_clouds.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:wonders/common_libs.dart'; import 'package:wonders/ui/common/utils/context_utils.dart'; +import 'package:wonders/ui/common/utils/duration_utils.dart'; // TODO: Clouds should fade in and out // Shows a set of clouds that animated onto stage. @@ -21,7 +22,7 @@ class AnimatedClouds extends StatefulWidget with GetItStatefulWidgetMixin { class _AnimatedCloudsState extends State with SingleTickerProviderStateMixin, GetItStateMixin { late List<_Cloud> _clouds = []; List<_Cloud> _oldClouds = []; - late final AnimationController _anim = AnimationController(vsync: this, duration: 1500.ms); + late final AnimationController _anim = AnimationController(vsync: this, duration: 1500.animateMs); @override void initState() { diff --git a/lib/ui/wonder_illustrations/common/illustration_piece.dart b/lib/ui/wonder_illustrations/common/illustration_piece.dart index 7997673f..cfc1fefb 100644 --- a/lib/ui/wonder_illustrations/common/illustration_piece.dart +++ b/lib/ui/wonder_illustrations/common/illustration_piece.dart @@ -136,7 +136,7 @@ class _IllustrationPieceState extends State { children: [ if (widget.bottom != null) Positioned.fill(child: widget.bottom!.call(context)), if (uiImage != null) ...[ - widget.enableHero ? Hero(tag: '$type-${widget.fileName}', child: content!) : content!, + widget.enableHero && !$styles.disableAnimations ? Hero(tag: '$type-${widget.fileName}', child: content!) : content!, ], if (widget.top != null) Positioned.fill(child: widget.top!.call(context)), ], diff --git a/web/manifest.json b/web/manifest.json index c7dd1164..237d3248 100644 --- a/web/manifest.json +++ b/web/manifest.json @@ -31,5 +31,63 @@ "type": "image/png", "purpose": "maskable" } + ], + "screenshots": [ + { + "src": "screenshots/screen1.png", + "sizes": "800x600", + "type": "image/png", + "form_factor": "wide", + "label": "Wonderous Welcome Screen" + }, + { + "src": "screenshots/screen2.png", + "sizes": "800x600", + "type": "image/png", + "form_factor": "wide", + "label": "Read about 8 amazing man-made wonders" + }, + { + "src": "screenshots/screen3.png", + "sizes": "800x600", + "type": "image/png", + "form_factor": "wide", + "label": "Enjoy photos and videos from all around the world" + }, + { + "src": "screenshots/screen4.png", + "sizes": "800x600", + "type": "image/png", + "form_factor": "wide", + "label": "Explore artifacts and relics from the past" + }, + { + "src": "screenshots/mobile1.png", + "sizes": "864x1872", + "type": "image/png", + "form_factor": "narrow", + "label": "Wonderous Welcome Screen" + }, + { + "src": "screenshots/mobile2.png", + "sizes": "864x1872", + "type": "image/png", + "form_factor": "narrow", + "label": "Read about 8 amazing man-made wonders" + }, + { + "src": "screenshots/mobile3.png", + "sizes": "864x1872", + "type": "image/png", + "form_factor": "narrow", + "label": "Enjoy photos and videos from all around the world" + }, + { + "src": "screenshots/mobile4.png", + "sizes": "864x1872", + "type": "image/png", + "form_factor": "narrow", + "label": "Explore artifacts and relics from the past" + } ] } diff --git a/web/screenshots/mobile1.png b/web/screenshots/mobile1.png new file mode 100644 index 00000000..fe6ef527 Binary files /dev/null and b/web/screenshots/mobile1.png differ diff --git a/web/screenshots/mobile2.png b/web/screenshots/mobile2.png new file mode 100644 index 00000000..7129fdd4 Binary files /dev/null and b/web/screenshots/mobile2.png differ diff --git a/web/screenshots/mobile3.png b/web/screenshots/mobile3.png new file mode 100644 index 00000000..794fb9e3 Binary files /dev/null and b/web/screenshots/mobile3.png differ diff --git a/web/screenshots/mobile4.png b/web/screenshots/mobile4.png new file mode 100644 index 00000000..b3cf753d Binary files /dev/null and b/web/screenshots/mobile4.png differ diff --git a/web/screenshots/screen1.png b/web/screenshots/screen1.png new file mode 100644 index 00000000..85e1e761 Binary files /dev/null and b/web/screenshots/screen1.png differ diff --git a/web/screenshots/screen2.png b/web/screenshots/screen2.png new file mode 100644 index 00000000..0f3e6745 Binary files /dev/null and b/web/screenshots/screen2.png differ diff --git a/web/screenshots/screen3.png b/web/screenshots/screen3.png new file mode 100644 index 00000000..3c8a6d60 Binary files /dev/null and b/web/screenshots/screen3.png differ diff --git a/web/screenshots/screen4.png b/web/screenshots/screen4.png new file mode 100644 index 00000000..8be39e8c Binary files /dev/null and b/web/screenshots/screen4.png differ