Merge branch 'accessability-pass' into accessability-trackpadfix

This commit is contained in:
Alex Garneau
2025-04-02 14:27:31 -06:00
48 changed files with 213 additions and 81 deletions

View File

@ -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 = "<group>"; };
296251242AE7410D00D574FF /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = "<group>"; };
2978ECDC2B62D00C00E36CE8 /* FlutterAssets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlutterAssets.swift; sourceTree = "<group>"; };
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 = "<group>"; };
@ -187,7 +187,7 @@
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
E214FC8227C5A18D005F78FB /* wondersUITests.xctest */,
297F6FC52AD06E0D00FF159E /* Wonderous WidgetExtension.appex */,
297F6FC52AD06E0D00FF159E /* WonderousWidgetExtension.appex */,
);
name = Products;
sourceTree = "<group>";
@ -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 = (

View File

@ -1,6 +1,6 @@
//
// FlutterUtils.swift
// Wonderous WidgetExtension
// WonderousWidgetExtension
//
// Created by Shawn on 2023-10-19.
//

View File

@ -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<NeverAnimate> createState() => _NeverAnimateState();
}
class _NeverAnimateState extends State<NeverAnimate> {
@override
Widget build(BuildContext context) => widget.child;
}
extension MaybeAnimateExtension on Widget {
Animate maybeAnimate({
Key? key,
List<Effect>? 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,
);
}

View File

@ -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,

View File

@ -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

View File

@ -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(

View File

@ -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)

View File

@ -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<double>(
duration: duration,

View File

@ -53,7 +53,7 @@ class _FullscreenUrlImgViewerState extends State<FullscreenUrlImgViewer> {
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);
}
}

View File

@ -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);
}

View File

@ -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';

View File

@ -57,7 +57,7 @@ class _BottomTextContent extends StatelessWidget {
),
]
],
).animate(key: ValueKey(artifact.artifactId)).fadeIn(),
).maybeAnimate(key: ValueKey(artifact.artifactId)).fadeIn(),
),
),
],

View File

@ -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<ArtifactDetailsScreen> {
),
),
],
).animate().fadeIn();
).maybeAnimate().fadeIn();
}
}

View File

@ -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),
],
),

View File

@ -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),
),
);

View File

@ -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);
}
}

View File

@ -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<CollectionScreen> 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);
}
}

View File

@ -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,

View File

@ -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

View File

@ -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';

View File

@ -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),
),
),
),

View File

@ -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),
),
),

View File

@ -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(

View File

@ -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),
),
],
),

View File

@ -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;
}

View File

@ -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<HomeScreen> 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<HomeScreen> 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<HomeScreen> with SingleTickerProviderStateM
/// Controls that float on top of the various illustrations
_buildFloatingUi(),
],
).animate().fadeIn(),
).maybeAnimate().fadeIn(),
),
),
));

View File

@ -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<HomeMenu> {
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<HomeMenu> {
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<HomeMenu> {
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),
);
});

View File

@ -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<IntroScreen> {
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<IntroScreen> {
color: $styles.colors.black,
child: SafeArea(
child: Animate(
delay: 500.ms,
delay: 500.delayMs,
effects: const [FadeEffect()],
child: PreviousNextNavigation(
maxWidth: 600,

View File

@ -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<PhotoGallery> {
imgUrl,
fit: BoxFit.cover,
size: UnsplashPhotoSize.large,
).animate().fade(),
).maybeAnimate().fade(),
);
return MergeSemantics(

View File

@ -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';

View File

@ -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));
}
}

View File

@ -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

View File

@ -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(

View File

@ -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);
}
});

View File

@ -49,11 +49,11 @@ class _EventsListState extends State<_EventsList> {
final listItems = <Widget>[];
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),
);
}

View File

@ -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) {

View File

@ -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';

View File

@ -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<AnimatedClouds> 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() {

View File

@ -136,7 +136,7 @@ class _IllustrationPieceState extends State<IllustrationPiece> {
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)),
],

View File

@ -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"
}
]
}

BIN
web/screenshots/mobile1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

BIN
web/screenshots/mobile2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 987 KiB

BIN
web/screenshots/mobile3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

BIN
web/screenshots/mobile4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 854 KiB

BIN
web/screenshots/screen1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

BIN
web/screenshots/screen2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

BIN
web/screenshots/screen3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 KiB

BIN
web/screenshots/screen4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 606 KiB