From 346d01f63cb390bc211fccf0e45cdb7e13b04bb4 Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Wed, 19 Feb 2025 01:07:20 -0700 Subject: [PATCH 01/35] Swapped count and total for appPageSemanticSwipe. Renamed count to current. --- lib/l10n/app_en.arb | 4 ++-- lib/l10n/app_zh.arb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index e8be0a2e..0b87c0b6 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -32,8 +32,8 @@ "appModalsButtonOk": "Ok", "appModalsButtonCancel": "Cancel", "appPageDefaultTitlePage": "page", - "appPageSemanticSwipe": "{pageTitle} {count} of {total}.", - "@appPageSemanticSwipe": {"placeholders": {"pageTitle": {}, "total": {}, "count": {}}}, + "appPageSemanticSwipe": "{pageTitle} {current} of {total}.", + "@appPageSemanticSwipe": {"placeholders": {"pageTitle": {}, "current": {}, "total": {}}}, "artifactsTitleArtifacts": "ARTIFACTS", "semanticsPrevious": "Previous {title}", "@semanticsPrevious": {"placeholders": {"title": {}}}, diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index e970ed12..c7a2a366 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -25,7 +25,7 @@ "appModalsButtonOk": "确定", "appModalsButtonCancel": "取消", "appPageDefaultTitlePage": "页", - "appPageSemanticSwipe": "{pageTitle} {total} 之 {count}.", + "appPageSemanticSwipe": "{pageTitle} {total} 之 {current}.", "artifactsTitleArtifacts": "文物", "semanticsPrevious": "之前的文物{title}", "semanticsNext": "下一个文物{title}", From 1b815006078a70d8982bf275c241144b779822af Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Wed, 19 Feb 2025 13:33:24 -0700 Subject: [PATCH 02/35] Modified _scrolling_content.dart to include all text in a Focusable Semantic. _callout.dart also has Focus set. This allows the user to select all the text in the wonders_details_screens. --- .../screens/editorial/widgets/_callout.dart | 30 ++++---- .../editorial/widgets/_scrolling_content.dart | 74 +++++++++---------- 2 files changed, 53 insertions(+), 51 deletions(-) diff --git a/lib/ui/screens/editorial/widgets/_callout.dart b/lib/ui/screens/editorial/widgets/_callout.dart index f682d341..e213deb9 100644 --- a/lib/ui/screens/editorial/widgets/_callout.dart +++ b/lib/ui/screens/editorial/widgets/_callout.dart @@ -6,20 +6,22 @@ class _Callout extends StatelessWidget { const _Callout({super.key, required this.text}); @override Widget build(BuildContext context) { - return IntrinsicHeight( - child: Row( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container(color: $styles.colors.accent1, width: 1), - Gap($styles.insets.sm), - Expanded( - child: Text( - text, - style: $styles.text.callout, - ), - ) - ], - ), + return Focus( + child: IntrinsicHeight( + child: Row( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Container(color: $styles.colors.accent1, width: 1), + Gap($styles.insets.sm), + Expanded( + child: Text( + text, + style: $styles.text.callout, + ), + ) + ], + ), + ) ); } } diff --git a/lib/ui/screens/editorial/widgets/_scrolling_content.dart b/lib/ui/screens/editorial/widgets/_scrolling_content.dart index fea6e796..0564e818 100644 --- a/lib/ui/screens/editorial/widgets/_scrolling_content.dart +++ b/lib/ui/screens/editorial/widgets/_scrolling_content.dart @@ -19,45 +19,45 @@ class _ScrollingContent extends StatelessWidget { @override Widget build(BuildContext context) { - Widget buildText(String value) => Focus(child: Text(_fixNewlines(value), style: $styles.text.body)); - - Widget buildDropCapText(String value) { + Widget buildText(String value, bool useDropCaps) { + final bool skipCaps = !localeLogic.isEnglish || !useDropCaps; final TextStyle dropStyle = $styles.text.dropCase; final TextStyle bodyStyle = $styles.text.body; final String dropChar = value.substring(0, 1); final textScale = MediaQuery.of(context).textScaleFactor; final double dropCapWidth = StringUtils.measure(dropChar, dropStyle).width * textScale; - final bool skipCaps = !localeLogic.isEnglish; - return Semantics( - label: value, - child: ExcludeSemantics( - child: !skipCaps - ? DropCapText( - _fixNewlines(value).substring(1), - dropCap: DropCap( - width: dropCapWidth, - height: $styles.text.body.fontSize! * $styles.text.body.height! * 2, - child: Transform.translate( - offset: Offset(0, bodyStyle.fontSize! * (bodyStyle.height! - 1) - 2), - child: Text( - dropChar, - overflow: TextOverflow.visible, - style: $styles.text.dropCase.copyWith( - color: $styles.colors.accent1, - height: 1, + return Focus( + child: Semantics( + label: value, + child: ExcludeSemantics( + child: skipCaps + ? Text(_fixNewlines(value), style: bodyStyle) + : DropCapText( + _fixNewlines(value).substring(1), + dropCap: DropCap( + width: dropCapWidth, + height: $styles.text.body.fontSize! * $styles.text.body.height! * 2, + child: Transform.translate( + offset: Offset(0, bodyStyle.fontSize! * (bodyStyle.height! - 1) - 2), + child: Text( + dropChar, + overflow: TextOverflow.visible, + style: $styles.text.dropCase.copyWith( + color: $styles.colors.accent1, + height: 1, + ), ), ), ), - ), - style: $styles.text.body, - dropCapPadding: EdgeInsets.only(right: 6), - dropCapStyle: $styles.text.dropCase.copyWith( - color: $styles.colors.accent1, - height: 1, - ), - ) - : Text(value, style: bodyStyle), - ), + style: $styles.text.body, + dropCapPadding: EdgeInsets.only(right: 6), + dropCapStyle: $styles.text.dropCase.copyWith( + color: $styles.colors.accent1, + height: 1, + ), + ) + ), + ) ); } @@ -93,7 +93,7 @@ class _ScrollingContent extends StatelessWidget { Center(child: buildHiddenCollectible(slot: 0)), /// History 1 - buildDropCapText(data.historyInfo1), + buildText(data.historyInfo1, true), /// Quote1 _CollapsingPullQuoteImage(data: data, scrollPos: scrollPos), @@ -103,11 +103,11 @@ class _ScrollingContent extends StatelessWidget { _Callout(text: data.callout1), /// History 2 - buildText(data.historyInfo2), + buildText(data.historyInfo2, false), _SectionDivider(scrollPos, sectionNotifier, index: 1), /// Construction 1 - buildDropCapText(data.constructionInfo1), + buildText(data.constructionInfo1, true), Center(child: buildHiddenCollectible(slot: 2)), ]), Gap($styles.insets.md), @@ -119,14 +119,14 @@ class _ScrollingContent extends StatelessWidget { _Callout(text: data.callout2), /// Construction 2 - buildText(data.constructionInfo2), + buildText(data.constructionInfo2, false), _SlidingImageStack(scrollPos: scrollPos, type: data.type), _SectionDivider(scrollPos, sectionNotifier, index: 2), /// Location - buildDropCapText(data.locationInfo1), + buildText(data.locationInfo1, true), _LargeSimpleQuote(text: data.pullQuote2, author: data.pullQuote2Author), - buildText(data.locationInfo2), + buildText(data.locationInfo2, false), ]), Gap($styles.insets.md), _MapsThumbnail(data), From e14836bc684b062c4303d2f7c0869a44cddaa7a2 Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Wed, 19 Feb 2025 16:25:43 -0700 Subject: [PATCH 03/35] Added focus element to Artifact Info Column so artifact details can be read aloud. --- .../widgets/_info_column.dart | 104 +++++++++--------- 1 file changed, 53 insertions(+), 51 deletions(-) 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 637c5046..eeffb437 100644 --- a/lib/ui/screens/artifact/artifact_details/widgets/_info_column.dart +++ b/lib/ui/screens/artifact/artifact_details/widgets/_info_column.dart @@ -9,59 +9,61 @@ class _InfoColumn extends StatelessWidget { return Padding( padding: EdgeInsets.symmetric(horizontal: $styles.insets.lg), child: SingleChildScrollView( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Gap($styles.insets.xl), - if (data.culture.isNotEmpty) ...[ - Text( - data.culture.toUpperCase(), - style: $styles.text.titleFont.copyWith(color: $styles.colors.accent1), - ).animate().fade(delay: 150.ms, duration: 600.ms), - Gap($styles.insets.xs), - ], - Semantics( - header: true, - child: Text( - data.title, - textAlign: TextAlign.center, - 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), - ), - Gap($styles.insets.lg), - Animate().toggle( - delay: 500.ms, - builder: (_, value, __) { - return CompassDivider(isExpanded: !value, duration: $styles.times.med); - }), - Gap($styles.insets.lg), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ...[ - _InfoRow($strings.artifactDetailsLabelDate, data.date), - _InfoRow($strings.artifactDetailsLabelPeriod, data.period), - _InfoRow($strings.artifactDetailsLabelGeography, data.country), - _InfoRow($strings.artifactDetailsLabelMedium, data.medium), - _InfoRow($strings.artifactDetailsLabelDimension, data.dimension), - _InfoRow($strings.artifactDetailsLabelClassification, data.classification), - ] - .animate(interval: 100.ms) - .fadeIn(delay: 600.ms, duration: $styles.times.med) - .slide(begin: Offset(0.2, 0), curve: Curves.easeOut), + child: Focus( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Gap($styles.insets.xl), + if (data.culture.isNotEmpty) ...[ + Text( + data.culture.toUpperCase(), + style: $styles.text.titleFont.copyWith(color: $styles.colors.accent1), + ).animate().fade(delay: 150.ms, duration: 600.ms), + Gap($styles.insets.xs), ], - ), - Gap($styles.insets.md), - 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), - Gap($styles.insets.offset), - ], + Semantics( + header: true, + child: Text( + data.title, + textAlign: TextAlign.center, + 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), + ), + Gap($styles.insets.lg), + Animate().toggle( + delay: 500.ms, + builder: (_, value, __) { + return CompassDivider(isExpanded: !value, duration: $styles.times.med); + }), + Gap($styles.insets.lg), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ...[ + _InfoRow($strings.artifactDetailsLabelDate, data.date), + _InfoRow($strings.artifactDetailsLabelPeriod, data.period), + _InfoRow($strings.artifactDetailsLabelGeography, data.country), + _InfoRow($strings.artifactDetailsLabelMedium, data.medium), + _InfoRow($strings.artifactDetailsLabelDimension, data.dimension), + _InfoRow($strings.artifactDetailsLabelClassification, data.classification), + ] + .animate(interval: 100.ms) + .fadeIn(delay: 600.ms, duration: $styles.times.med) + .slide(begin: Offset(0.2, 0), curve: Curves.easeOut), + ], + ), + Gap($styles.insets.md), + 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), + Gap($styles.insets.offset), + ], + ), ), - ), + ) ); } } From 398d0581be13033a4eb8f0e665320a5fddfed752 Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Fri, 21 Feb 2025 16:47:33 -0700 Subject: [PATCH 04/35] Replaced deprecated IgnorePointer with custom Flutter docs provided IgnorePointerWithSchematics. --- lib/ui/common/controls/buttons.dart | 3 +- lib/ui/common/controls/scroll_decorator.dart | 3 +- lib/ui/common/gradient_container.dart | 35 ++++++++++--------- lib/ui/common/ignore_pointer.dart | 18 ++++++++++ .../widgets/_bottom_text_content.dart | 3 +- .../screens/editorial/editorial_screen.dart | 1 + .../editorial/widgets/_scrolling_content.dart | 2 +- lib/ui/screens/home/wonders_home_screen.dart | 8 ++--- lib/ui/screens/intro/intro_screen.dart | 4 +-- .../screens/photo_gallery/photo_gallery.dart | 1 + .../widgets/_animated_cutout_overlay.dart | 2 +- lib/ui/screens/timeline/timeline_screen.dart | 1 + .../timeline/widgets/_event_markers.dart | 3 +- .../timeline/widgets/_event_popups.dart | 3 +- .../timeline/widgets/_scrolling_viewport.dart | 3 +- .../timeline/widgets/_timeline_section.dart | 3 +- .../timeline/widgets/_year_markers.dart | 3 +- .../wonder_events/widgets/_events_list.dart | 4 +-- .../screens/wonder_events/wonder_events.dart | 1 + 19 files changed, 61 insertions(+), 40 deletions(-) create mode 100644 lib/ui/common/ignore_pointer.dart diff --git a/lib/ui/common/controls/buttons.dart b/lib/ui/common/controls/buttons.dart index 3ffdd087..ac27907c 100644 --- a/lib/ui/common/controls/buttons.dart +++ b/lib/ui/common/controls/buttons.dart @@ -1,5 +1,6 @@ import 'package:wonders/common_libs.dart'; import 'package:wonders/ui/common/app_icons.dart'; +import 'package:wonders/ui/common/ignore_pointer.dart'; /// Shared methods across button types Widget _buildIcon(BuildContext context, AppIcons icon, {required bool isSecondary, required double? size}) => @@ -154,7 +155,7 @@ class AppBtn extends StatelessWidget { ), if (focus.hasFocus) Positioned.fill( - child: IgnorePointer( + child: IgnorePointerWithSemantics( child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular($styles.corners.md), diff --git a/lib/ui/common/controls/scroll_decorator.dart b/lib/ui/common/controls/scroll_decorator.dart index 1255999d..c0c124b8 100644 --- a/lib/ui/common/controls/scroll_decorator.dart +++ b/lib/ui/common/controls/scroll_decorator.dart @@ -1,4 +1,5 @@ import 'package:wonders/common_libs.dart'; +import 'package:wonders/ui/common/ignore_pointer.dart'; /// Easily add visual decorations to a scrolling widget based on the state of its controller. class ScrollDecorator extends StatefulWidget { @@ -64,7 +65,7 @@ class ScrollDecorator extends StatefulWidget { bgBuilder = null; fgBuilder = (controller) { final double ratio = controller.hasClients ? min(1, controller.position.extentBefore / 60) : 0; - return IgnorePointer( + return IgnorePointerWithSemantics( child: Container( height: 24, decoration: BoxDecoration( diff --git a/lib/ui/common/gradient_container.dart b/lib/ui/common/gradient_container.dart index 44fb789e..869adb44 100644 --- a/lib/ui/common/gradient_container.dart +++ b/lib/ui/common/gradient_container.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:wonders/ui/common/ignore_pointer.dart'; class GradientContainer extends StatelessWidget { const GradientContainer(this.colors, this.stops, @@ -23,24 +24,26 @@ class GradientContainer extends StatelessWidget { final BorderRadius? borderRadius; @override - Widget build(BuildContext context) => IgnorePointer( - child: Container( - width: width, - height: height, - alignment: alignment, - decoration: BoxDecoration( - gradient: LinearGradient( - begin: begin ?? Alignment.centerLeft, - end: end ?? Alignment.centerRight, - colors: colors, - stops: stops, - ), - backgroundBlendMode: blendMode, - borderRadius: borderRadius, + Widget build(BuildContext context) => ExcludeSemantics( + child: IgnorePointerWithSemantics( + child: Container( + width: width, + height: height, + alignment: alignment, + decoration: BoxDecoration( + gradient: LinearGradient( + begin: begin ?? Alignment.centerLeft, + end: end ?? Alignment.centerRight, + colors: colors, + stops: stops, ), - child: child, + backgroundBlendMode: blendMode, + borderRadius: borderRadius, ), - ); + child: child, + ), + ) + ); } class HzGradient extends GradientContainer { diff --git a/lib/ui/common/ignore_pointer.dart b/lib/ui/common/ignore_pointer.dart new file mode 100644 index 00000000..cc27da96 --- /dev/null +++ b/lib/ui/common/ignore_pointer.dart @@ -0,0 +1,18 @@ +import 'package:flutter/rendering.dart'; +import 'package:wonders/common_libs.dart'; + +class IgnorePointerWithSemantics extends SingleChildRenderObjectWidget { + const IgnorePointerWithSemantics({super.key, super.child}); + + @override + RenderIgnorePointerWithSemantics createRenderObject(BuildContext context) { + return RenderIgnorePointerWithSemantics(); + } +} + +class RenderIgnorePointerWithSemantics extends RenderProxyBox { + RenderIgnorePointerWithSemantics(); + + @override + bool hitTest(BoxHitTestResult result, { required Offset position }) => false; +} \ No newline at end of file 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 98e73aaa..a47db96a 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 @@ -26,8 +26,7 @@ class _BottomTextContent extends StatelessWidget { Gap($styles.insets.md), Column( children: [ - IgnorePointer( - ignoringSemantics: false, + IgnorePointerWithSemantics( child: Semantics( button: true, onIncrease: () => state._handleArtifactTap(_currentPage + 1), diff --git a/lib/ui/screens/editorial/editorial_screen.dart b/lib/ui/screens/editorial/editorial_screen.dart index b250bb55..073ff240 100644 --- a/lib/ui/screens/editorial/editorial_screen.dart +++ b/lib/ui/screens/editorial/editorial_screen.dart @@ -17,6 +17,7 @@ import 'package:wonders/ui/common/fullscreen_keyboard_list_scroller.dart'; import 'package:wonders/ui/common/google_maps_marker.dart'; import 'package:wonders/ui/common/gradient_container.dart'; import 'package:wonders/ui/common/hidden_collectible.dart'; +import 'package:wonders/ui/common/ignore_pointer.dart'; import 'package:wonders/ui/common/pop_router_on_over_scroll.dart'; import 'package:wonders/ui/common/scaling_list_item.dart'; import 'package:wonders/ui/common/static_text_scale.dart'; diff --git a/lib/ui/screens/editorial/widgets/_scrolling_content.dart b/lib/ui/screens/editorial/widgets/_scrolling_content.dart index 0564e818..4cac7de1 100644 --- a/lib/ui/screens/editorial/widgets/_scrolling_content.dart +++ b/lib/ui/screens/editorial/widgets/_scrolling_content.dart @@ -242,7 +242,7 @@ class _MapsThumbnailState extends State<_MapsThumbnail> { child: Stack( children: [ Positioned.fill(child: ColoredBox(color: Colors.transparent)), - IgnorePointer( + IgnorePointerWithSemantics( child: GoogleMap( markers: {getMapsMarker(startPos.target)}, zoomControlsEnabled: false, diff --git a/lib/ui/screens/home/wonders_home_screen.dart b/lib/ui/screens/home/wonders_home_screen.dart index f8756cf4..e1172c43 100644 --- a/lib/ui/screens/home/wonders_home_screen.dart +++ b/lib/ui/screens/home/wonders_home_screen.dart @@ -4,6 +4,7 @@ import 'package:wonders/ui/common/app_icons.dart'; import 'package:wonders/ui/common/controls/app_header.dart'; import 'package:wonders/ui/common/controls/app_page_indicator.dart'; import 'package:wonders/ui/common/gradient_container.dart'; +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'; @@ -210,7 +211,7 @@ class _HomeScreenState extends State with SingleTickerProviderStateM Widget _buildFgAndGradients() { Widget buildSwipeableBgGradient(Color fgColor) { return _swipeController.buildListener(builder: (swipeAmt, isPointerDown, _) { - return IgnorePointer( + return IgnorePointerWithSemantics( child: FractionallySizedBox( heightFactor: .6, child: Container( @@ -248,7 +249,7 @@ class _HomeScreenState extends State with SingleTickerProviderStateM return Animate( effects: const [FadeEffect()], onPlay: _handleFadeAnimInit, - child: IgnorePointer(child: WonderIllustration(e.type, config: config))); + child: IgnorePointerWithSemantics(child: WonderIllustration(e.type, config: config))); }); }), @@ -277,8 +278,7 @@ class _HomeScreenState extends State with SingleTickerProviderStateM /// Title Content LightText( - child: IgnorePointer( - ignoringSemantics: false, + child: IgnorePointerWithSemantics( child: Transform.translate( offset: Offset(0, 30), child: Column( diff --git a/lib/ui/screens/intro/intro_screen.dart b/lib/ui/screens/intro/intro_screen.dart index b0c3b151..3095c65e 100644 --- a/lib/ui/screens/intro/intro_screen.dart +++ b/lib/ui/screens/intro/intro_screen.dart @@ -4,6 +4,7 @@ import 'package:wonders/logic/common/platform_info.dart'; import 'package:wonders/ui/common/app_icons.dart'; import 'package:wonders/ui/common/controls/app_page_indicator.dart'; import 'package:wonders/ui/common/gradient_container.dart'; +import 'package:wonders/ui/common/ignore_pointer.dart'; 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'; @@ -112,8 +113,7 @@ class _IntroScreenState extends State { ), ), - IgnorePointer( - ignoringSemantics: false, + IgnorePointerWithSemantics( child: Column(children: [ Spacer(), diff --git a/lib/ui/screens/photo_gallery/photo_gallery.dart b/lib/ui/screens/photo_gallery/photo_gallery.dart index 44329549..731288a7 100644 --- a/lib/ui/screens/photo_gallery/photo_gallery.dart +++ b/lib/ui/screens/photo_gallery/photo_gallery.dart @@ -7,6 +7,7 @@ import 'package:wonders/ui/common/controls/app_loading_indicator.dart'; import 'package:wonders/ui/common/controls/eight_way_swipe_detector.dart'; import 'package:wonders/ui/common/fullscreen_keyboard_listener.dart'; import 'package:wonders/ui/common/hidden_collectible.dart'; +import 'package:wonders/ui/common/ignore_pointer.dart'; import 'package:wonders/ui/common/modals/fullscreen_url_img_viewer.dart'; import 'package:wonders/ui/common/unsplash_photo.dart'; import 'package:wonders/ui/common/utils/app_haptics.dart'; diff --git a/lib/ui/screens/photo_gallery/widgets/_animated_cutout_overlay.dart b/lib/ui/screens/photo_gallery/widgets/_animated_cutout_overlay.dart index 2b0e70ef..9f918d51 100644 --- a/lib/ui/screens/photo_gallery/widgets/_animated_cutout_overlay.dart +++ b/lib/ui/screens/photo_gallery/widgets/_animated_cutout_overlay.dart @@ -31,7 +31,7 @@ class _AnimatedCutoutOverlay extends StatelessWidget { effects: [CustomEffect(builder: _buildAnimatedCutout, curve: Curves.easeOut, duration: duration)], key: animationKey, onComplete: (c) => c.reverse(), - child: IgnorePointer(child: Container(color: Colors.black.withOpacity(opacity))), + child: IgnorePointerWithSemantics(child: Container(color: Colors.black.withOpacity(opacity))), ), ], ); diff --git a/lib/ui/screens/timeline/timeline_screen.dart b/lib/ui/screens/timeline/timeline_screen.dart index d1df1bfe..6030ad76 100644 --- a/lib/ui/screens/timeline/timeline_screen.dart +++ b/lib/ui/screens/timeline/timeline_screen.dart @@ -11,6 +11,7 @@ import 'package:wonders/ui/common/blend_mask.dart'; import 'package:wonders/ui/common/centered_box.dart'; import 'package:wonders/ui/common/controls/app_header.dart'; import 'package:wonders/ui/common/dashed_line.dart'; +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'; diff --git a/lib/ui/screens/timeline/widgets/_event_markers.dart b/lib/ui/screens/timeline/widgets/_event_markers.dart index 1f963ef8..b9107b0e 100644 --- a/lib/ui/screens/timeline/widgets/_event_markers.dart +++ b/lib/ui/screens/timeline/widgets/_event_markers.dart @@ -54,8 +54,7 @@ class _EventMarkersState extends State<_EventMarkers> { @override Widget build(BuildContext context) { - return IgnorePointer( - ignoringSemantics: false, + return IgnorePointerWithSemantics( child: LayoutBuilder(builder: (_, constraints) { /// Figure out which event is "selected" _updateSelectedEvent(constraints.maxHeight); diff --git a/lib/ui/screens/timeline/widgets/_event_popups.dart b/lib/ui/screens/timeline/widgets/_event_popups.dart index bd02ae6c..21a6add7 100644 --- a/lib/ui/screens/timeline/widgets/_event_popups.dart +++ b/lib/ui/screens/timeline/widgets/_event_popups.dart @@ -35,8 +35,7 @@ class _EventPopupsState extends State<_EventPopups> { final evt = _eventToShow; return TopCenter( child: ClipRect( - child: IgnorePointer( - ignoringSemantics: false, + child: IgnorePointerWithSemantics( child: AnimatedSwitcher( duration: $styles.times.fast, child: evt == null diff --git a/lib/ui/screens/timeline/widgets/_scrolling_viewport.dart b/lib/ui/screens/timeline/widgets/_scrolling_viewport.dart index 863b9d9a..21cdea32 100644 --- a/lib/ui/screens/timeline/widgets/_scrolling_viewport.dart +++ b/lib/ui/screens/timeline/widgets/_scrolling_viewport.dart @@ -69,8 +69,7 @@ class _ScalingViewportState extends State<_ScrollingViewport> { _buildScrollingArea(context).animate().fadeIn(), // Dashed line with a year that changes as we scroll - IgnorePointer( - ignoringSemantics: false, + IgnorePointerWithSemantics( child: AnimatedBuilder( animation: controller.scroller, builder: (_, __) { diff --git a/lib/ui/screens/timeline/widgets/_timeline_section.dart b/lib/ui/screens/timeline/widgets/_timeline_section.dart index 99f8841c..c6acb68b 100644 --- a/lib/ui/screens/timeline/widgets/_timeline_section.dart +++ b/lib/ui/screens/timeline/widgets/_timeline_section.dart @@ -20,8 +20,7 @@ class TimelineSection extends StatelessWidget { StringUtils.formatYr(data.startYr), StringUtils.formatYr(data.endYr), )}', - child: IgnorePointer( - ignoringSemantics: false, + child: IgnorePointerWithSemantics( child: Container( alignment: Alignment(0, -1 + fraction * 2), padding: EdgeInsets.all($styles.insets.xs), diff --git a/lib/ui/screens/timeline/widgets/_year_markers.dart b/lib/ui/screens/timeline/widgets/_year_markers.dart index 321c47d9..2d34f98a 100644 --- a/lib/ui/screens/timeline/widgets/_year_markers.dart +++ b/lib/ui/screens/timeline/widgets/_year_markers.dart @@ -13,8 +13,7 @@ class _YearMarkers extends StatelessWidget { @override Widget build(BuildContext context) { - return IgnorePointer( - ignoringSemantics: false, + return IgnorePointerWithSemantics( child: LayoutBuilder(builder: (_, constraints) { int interval = 100; if (constraints.maxHeight < 800) { diff --git a/lib/ui/screens/wonder_events/widgets/_events_list.dart b/lib/ui/screens/wonder_events/widgets/_events_list.dart index 295cf1f6..995b39f4 100644 --- a/lib/ui/screens/wonder_events/widgets/_events_list.dart +++ b/lib/ui/screens/wonder_events/widgets/_events_list.dart @@ -64,7 +64,7 @@ class _EventsListState extends State<_EventsList> { key: PageStorageKey('eventsList'), child: Column( children: [ - IgnorePointer(child: Gap(widget.topHeight)), + IgnorePointerWithSemantics(child: Gap(widget.topHeight)), Container( decoration: BoxDecoration( color: $styles.colors.black, @@ -120,7 +120,7 @@ class _EventsListState extends State<_EventsList> { if (showBackdrop) ...[ AppBackdrop( strength: backdropAmt, - child: IgnorePointer( + child: IgnorePointerWithSemantics( child: Container( color: $styles.colors.black.withOpacity(backdropAmt * .6), ), diff --git a/lib/ui/screens/wonder_events/wonder_events.dart b/lib/ui/screens/wonder_events/wonder_events.dart index 2d902e6d..3c3007f0 100644 --- a/lib/ui/screens/wonder_events/wonder_events.dart +++ b/lib/ui/screens/wonder_events/wonder_events.dart @@ -8,6 +8,7 @@ import 'package:wonders/ui/common/centered_box.dart'; import 'package:wonders/ui/common/controls/app_header.dart'; import 'package:wonders/ui/common/curved_clippers.dart'; import 'package:wonders/ui/common/hidden_collectible.dart'; +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'; From 9973af837ac55088c78c472fffa0984359803719 Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Fri, 21 Feb 2025 17:01:55 -0700 Subject: [PATCH 05/35] Missed one. --- .../artifact/artifact_carousel/artifact_carousel_screen.dart | 1 + 1 file changed, 1 insertion(+) 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 ebc9e030..b3ce0234 100644 --- a/lib/ui/screens/artifact/artifact_carousel/artifact_carousel_screen.dart +++ b/lib/ui/screens/artifact/artifact_carousel/artifact_carousel_screen.dart @@ -5,6 +5,7 @@ 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'; import 'package:wonders/ui/common/controls/app_page_indicator.dart'; +import 'package:wonders/ui/common/ignore_pointer.dart'; import 'package:wonders/ui/common/static_text_scale.dart'; part 'widgets/_blurred_image_bg.dart'; From 526f5877523b8617fd52d9990a576bc8e22b92f5 Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Fri, 21 Feb 2025 20:02:42 -0700 Subject: [PATCH 06/35] Renamed fullscreen image viewer left button to "previous" so they are not both labelled as "next". --- lib/ui/common/modals/fullscreen_url_img_viewer.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ui/common/modals/fullscreen_url_img_viewer.dart b/lib/ui/common/modals/fullscreen_url_img_viewer.dart index 8cb717de..1c88ddf7 100644 --- a/lib/ui/common/modals/fullscreen_url_img_viewer.dart +++ b/lib/ui/common/modals/fullscreen_url_img_viewer.dart @@ -102,7 +102,7 @@ class _FullscreenUrlImgViewerState extends State { CircleIconBtn( icon: AppIcons.prev, onPressed: page == 0 ? null : () => _animateToPage(page - 1), - semanticLabel: $strings.semanticsNext(''), + semanticLabel: $strings.semanticsPrevious(''), ), Gap($styles.insets.xs), CircleIconBtn( From 885554657eec4e2418be9b3f0cc9d4da9c02b91a Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Mon, 24 Feb 2025 09:40:10 -0700 Subject: [PATCH 07/35] Added lang="en" to HTML tag to show app's default language (usually starts on English). --- web/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/index.html b/web/index.html index 8832c744..ee827b5b 100644 --- a/web/index.html +++ b/web/index.html @@ -1,5 +1,5 @@ - + Wonderous From 281b29896755c2f36b8cd95dd3207309ee2a40b1 Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Wed, 26 Feb 2025 11:52:14 -0700 Subject: [PATCH 08/35] Set search input field to a fixed maxWidth. --- .../artifact/artifact_search/widgets/_search_input.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/ui/screens/artifact/artifact_search/widgets/_search_input.dart b/lib/ui/screens/artifact/artifact_search/widgets/_search_input.dart index 23f4c5fb..54044209 100644 --- a/lib/ui/screens/artifact/artifact_search/widgets/_search_input.dart +++ b/lib/ui/screens/artifact/artifact_search/widgets/_search_input.dart @@ -1,6 +1,7 @@ part of '../artifact_search_screen.dart'; /// Autopopulating textfield used for searching for Artifacts by name. +const double _inputWidth = 400; class _SearchInput extends StatelessWidget { const _SearchInput({super.key, required this.onSubmit, required this.wonder}); final void Function(String) onSubmit; @@ -49,6 +50,7 @@ class _SearchInput extends StatelessWidget { child: Container( margin: EdgeInsets.only(top: $styles.insets.xxs), width: constraints.maxWidth, + constraints: BoxConstraints(maxWidth: _inputWidth), decoration: BoxDecoration( boxShadow: [ BoxShadow( @@ -120,6 +122,7 @@ class _SearchInput extends StatelessWidget { Widget _buildInput(BuildContext context, TextEditingController textController, FocusNode focusNode, _) { Color captionColor = $styles.colors.caption; return Container( + constraints: BoxConstraints(maxWidth: _inputWidth), height: $styles.insets.xl, decoration: BoxDecoration( color: $styles.colors.offWhite, @@ -134,7 +137,7 @@ class _SearchInput extends StatelessWidget { onSubmitted: onSubmit, controller: textController, focusNode: focusNode, - style: TextStyle(color: captionColor), + style: TextStyle(color: captionColor, ), textAlignVertical: TextAlignVertical.top, decoration: InputDecoration( isDense: true, From 6469ae10437d958a98b088caaa662fe73e8539cd Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Sat, 1 Mar 2025 02:30:48 -0700 Subject: [PATCH 09/35] Excluded several illustration images from Semantics to prevent VoiceOver from highlighting them unnecessarily. --- lib/ui/common/wonderous_logo.dart | 1 + lib/ui/screens/intro/intro_screen.dart | 2 ++ .../wonder_events/widgets/_wonder_image_with_timeline.dart | 1 + lib/ui/wonder_illustrations/common/animated_clouds.dart | 1 + lib/ui/wonder_illustrations/common/illustration_piece.dart | 7 ++++++- lib/ui/wonder_illustrations/common/paint_textures.dart | 1 + 6 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/ui/common/wonderous_logo.dart b/lib/ui/common/wonderous_logo.dart index fb88e86e..b0e48b28 100644 --- a/lib/ui/common/wonderous_logo.dart +++ b/lib/ui/common/wonderous_logo.dart @@ -9,6 +9,7 @@ class WonderousLogo extends StatelessWidget { @override Widget build(BuildContext context) => Image.asset( ImagePaths.appLogoPlain, + excludeFromSemantics: true, fit: BoxFit.cover, width: width, filterQuality: FilterQuality.high, diff --git a/lib/ui/screens/intro/intro_screen.dart b/lib/ui/screens/intro/intro_screen.dart index 3095c65e..2cb8e1ac 100644 --- a/lib/ui/screens/intro/intro_screen.dart +++ b/lib/ui/screens/intro/intro_screen.dart @@ -325,6 +325,7 @@ class _PageImage extends StatelessWidget { SizedBox.expand( child: Image.asset( '${ImagePaths.common}/intro-${data.img}.jpg', + excludeFromSemantics: true, fit: BoxFit.cover, alignment: Alignment.centerRight, ), @@ -332,6 +333,7 @@ class _PageImage extends StatelessWidget { Positioned.fill( child: Image.asset( '${ImagePaths.common}/intro-mask-${data.mask}.png', + excludeFromSemantics: true, fit: BoxFit.fill, )), ], 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 59544e8f..9d9bb780 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 @@ -73,6 +73,7 @@ class _WonderImageWithTimeline extends StatelessWidget { clipper: CurvedTopClipper(), child: Image.asset( data.type.flattened, + excludeFromSemantics: true, width: 200, fit: BoxFit.cover, alignment: Alignment(0, -.5), diff --git a/lib/ui/wonder_illustrations/common/animated_clouds.dart b/lib/ui/wonder_illustrations/common/animated_clouds.dart index fa3c7dd3..ea3ff5f2 100644 --- a/lib/ui/wonder_illustrations/common/animated_clouds.dart +++ b/lib/ui/wonder_illustrations/common/animated_clouds.dart @@ -138,6 +138,7 @@ class _Cloud extends StatelessWidget { scaleY: scale * (flipY ? -1 : 1), child: Image.asset( ImagePaths.cloud, + excludeFromSemantics: true, opacity: AlwaysStoppedAnimation(.4 * opacity), width: size * scale, fit: BoxFit.fitWidth, diff --git a/lib/ui/wonder_illustrations/common/illustration_piece.dart b/lib/ui/wonder_illustrations/common/illustration_piece.dart index 54d48534..7997673f 100644 --- a/lib/ui/wonder_illustrations/common/illustration_piece.dart +++ b/lib/ui/wonder_illustrations/common/illustration_piece.dart @@ -86,7 +86,12 @@ class _IllustrationPieceState extends State { final anim = wonderBuilder.anim; final curvedAnim = Curves.easeOut.transform(anim.value); final config = wonderBuilder.widget.config; - Widget img = Image.asset(imgPath, opacity: anim, fit: BoxFit.fitHeight); + Widget img = Image.asset( + imgPath, + excludeFromSemantics: true, + opacity: anim, + fit: BoxFit.fitHeight + ); // Add overflow box so image doesn't get clipped as we translate it around img = OverflowBox(maxWidth: 2500, child: img); diff --git a/lib/ui/wonder_illustrations/common/paint_textures.dart b/lib/ui/wonder_illustrations/common/paint_textures.dart index b8348919..a9d26381 100644 --- a/lib/ui/wonder_illustrations/common/paint_textures.dart +++ b/lib/ui/wonder_illustrations/common/paint_textures.dart @@ -18,6 +18,7 @@ class IllustrationTexture extends StatelessWidget { scaleX: scale * (flipX ? -1 : 1), scaleY: scale * (flipY ? -1 : 1), child: Image.asset(path, + excludeFromSemantics: true, repeat: ImageRepeat.repeat, fit: BoxFit.contain, alignment: Alignment.topCenter, From a4a304be39ed757cf3df7b2a591d089a4c41868f Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Mon, 10 Mar 2025 19:11:47 -0600 Subject: [PATCH 10/35] Applying Semantics labelling to Browse Artifacts time slider. --- lib/l10n/app_en.arb | 2 + lib/l10n/app_zh.arb | 1 + .../expanding_time_range_selector.dart | 164 ++++++++++-------- 3 files changed, 92 insertions(+), 75 deletions(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index e8be0a2e..ff618fce 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -70,6 +70,8 @@ "collectionPopupResetConfirm": "Are you sure you want to reset your collection?", "eightWaySemanticSwipeDetector": "eight-way swipe detector", "expandingTimeSelectorSemanticSelector": "time range selector", + "expandingTimeSelectorYears": "from {startYr} {startYrSuffix} to {endYr} {endYrSuffix}", + "@expandingTimeSelectorYears": {"placeholders": {"startYr": {}, "startYrSuffix": {}, "endYr": {}, "endYrSuffix": {}}}, "fullscreenImageViewerSemanticFull": "full screen image, no description available", "homeMenuButtonExplore": "Explore the timeline", "homeMenuButtonView": "View your collection", diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index e970ed12..367e8301 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -58,6 +58,7 @@ "collectionPopupResetConfirm": "您确定要重置您的收藏吗?", "eightWaySemanticSwipeDetector": "八方滑动识别器", "expandingTimeSelectorSemanticSelector": "日期范围选择器", + "expandingTimeSelectorYears": "从{startYrSuffix}{startYr}年到{endYrSuffix}{endYr}年", "fullscreenImageViewerSemanticFull": "全屏图像,没有描述信息", "homeMenuButtonExplore": "探索历史年表", "homeMenuButtonView": "观看您的收藏", diff --git a/lib/ui/screens/artifact/artifact_search/time_range_selector/expanding_time_range_selector.dart b/lib/ui/screens/artifact/artifact_search/time_range_selector/expanding_time_range_selector.dart index 0f36a3a0..2f3323ae 100644 --- a/lib/ui/screens/artifact/artifact_search/time_range_selector/expanding_time_range_selector.dart +++ b/lib/ui/screens/artifact/artifact_search/time_range_selector/expanding_time_range_selector.dart @@ -133,34 +133,44 @@ class _OpenedTimeRange extends StatelessWidget { final TimeRangePainter painter; final void Function() onClose; - List _buildChineseDateLayout(TextStyle headingTextStyle, TextStyle captionTextStyle, int startYr, int endYr) { - return [ - Text(StringUtils.getYrSuffix(startYr), style: captionTextStyle), - Gap($styles.insets.xxs), - Text(startYr.abs().toString(), style: headingTextStyle), - Text($strings.year, style: captionTextStyle), - Gap($styles.insets.xs), - Text('~', style: captionTextStyle), - Gap($styles.insets.xs), - Text(StringUtils.getYrSuffix(endYr.round()), style: captionTextStyle), - Gap($styles.insets.xxs), - Text(endYr.abs().toString(), style: headingTextStyle), - Text($strings.year, style: captionTextStyle), - ]; + Widget _buildChineseDateLayout(TextStyle headingTextStyle, TextStyle captionTextStyle, int startYr, int endYr) { + return Semantics( + label: $strings.expandingTimeSelectorYears(startYr.abs(), StringUtils.getYrSuffix(startYr), endYr.abs(), StringUtils.getYrSuffix(endYr)), + child: Row( + children: [ + Text(StringUtils.getYrSuffix(startYr), style: captionTextStyle), + Gap($styles.insets.xxs), + Text(startYr.abs().toString(), style: headingTextStyle), + Text($strings.year, style: captionTextStyle), + Gap($styles.insets.xs), + Text('~', style: captionTextStyle), + Gap($styles.insets.xs), + Text(StringUtils.getYrSuffix(endYr.round()), style: captionTextStyle), + Gap($styles.insets.xxs), + Text(endYr.abs().toString(), style: headingTextStyle), + Text($strings.year, style: captionTextStyle), + ] + ) + ); } - List _buildDefaultDateLayout(TextStyle headingTextStyle, TextStyle captionTextStyle, int startYr, int endYr) { - return [ - Text(startYr.abs().toString(), style: headingTextStyle), - Gap($styles.insets.xxs), - Text(StringUtils.getYrSuffix(startYr), style: captionTextStyle), - Gap($styles.insets.xs), - Text('—', style: captionTextStyle), - Gap($styles.insets.xs), - Text(endYr.abs().toString(), style: headingTextStyle), - Gap($styles.insets.xxs), - Text(StringUtils.getYrSuffix(endYr.round()), style: captionTextStyle), - ]; + Widget _buildDefaultDateLayout(TextStyle headingTextStyle, TextStyle captionTextStyle, int startYr, int endYr) { + return Semantics( + label: $strings.expandingTimeSelectorYears(startYr.abs(), StringUtils.getYrSuffix(startYr), endYr.abs(), StringUtils.getYrSuffix(endYr)), + child: Row( + children: [ + Text(startYr.abs().toString(), style: headingTextStyle), + Gap($styles.insets.xxs), + Text(StringUtils.getYrSuffix(startYr), style: captionTextStyle), + Gap($styles.insets.xs), + Text('—', style: captionTextStyle), + Gap($styles.insets.xs), + Text(endYr.abs().toString(), style: headingTextStyle), + Gap($styles.insets.xxs), + Text(StringUtils.getYrSuffix(endYr.round()), style: captionTextStyle), + ] + ) + ); } @override @@ -181,16 +191,16 @@ class _OpenedTimeRange extends StatelessWidget { Gap($styles.insets.xl), Spacer(), if (localeLogic.strings.localeName == 'zh') ...{ - ..._buildChineseDateLayout(headingTextStyle, captionTextStyle, startYr, endYr), + _buildChineseDateLayout(headingTextStyle, captionTextStyle, startYr, endYr), } else ...{ - ..._buildDefaultDateLayout(headingTextStyle, captionTextStyle, startYr, endYr), + _buildDefaultDateLayout(headingTextStyle, captionTextStyle, startYr, endYr), }, Spacer(), SizedBox( width: $styles.insets.xl, child: AppBtn.from( onPressed: onClose, - semanticLabel: $strings.expandingTimeSelectorSemanticSelector, + semanticLabel: $strings.circleButtonsSemanticClose, enableFeedback: false, // handled when panelController changes. icon: AppIcons.close, iconSize: 20, @@ -206,60 +216,64 @@ class _OpenedTimeRange extends StatelessWidget { // Timeframe slider SizedBox( height: $styles.insets.lg * 2, - child: Stack(children: [ - // grid lines: - Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular($styles.corners.md), - color: Color.lerp($styles.colors.black, Colors.black, 0.2), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: timelineGrid, - ), - ), - - // results visualization: - Positioned.fill( - child: Padding( - padding: EdgeInsets.symmetric(horizontal: RangeSelector.handleWidth), - child: RepaintBoundary( - child: CustomPaint(painter: painter), + child: Semantics( + label: $strings.expandingTimeSelectorSemanticSelector, + excludeSemantics: true, + child: Stack(children: [ + // grid lines: + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular($styles.corners.md), + color: Color.lerp($styles.colors.black, Colors.black, 0.2), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: timelineGrid, ), ), - ), - // wonder minimap: - Positioned.fill( - child: Padding( - padding: EdgeInsets.symmetric(horizontal: RangeSelector.handleWidth, vertical: 12), - child: WondersTimelineBuilder( - crossAxisGap: 6, - minSize: 16, - selectedWonders: [wonder.type], - timelineBuilder: (_, __, sel) => Container( - decoration: BoxDecoration( - color: $styles.colors.offWhite.withOpacity(sel ? 0.75 : 0.25), - borderRadius: BorderRadius.circular(999), + // results visualization: + Positioned.fill( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: RangeSelector.handleWidth), + child: RepaintBoundary( + child: CustomPaint(painter: painter), + ), + ), + ), + + // wonder minimap: + Positioned.fill( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: RangeSelector.handleWidth, vertical: 12), + child: WondersTimelineBuilder( + crossAxisGap: 6, + minSize: 16, + selectedWonders: [wonder.type], + timelineBuilder: (_, __, sel) => Container( + decoration: BoxDecoration( + color: $styles.colors.offWhite.withOpacity(sel ? 0.75 : 0.25), + borderRadius: BorderRadius.circular(999), + ), ), ), ), ), - ), - // Time slider itself - Positioned.fill( - child: RangeSelector( - key: ValueKey('RangeSelectorIsWonderTime'), - min: wondersLogic.timelineStartYear * 1.0, - max: wondersLogic.timelineEndYear * 1.0, - minDelta: 500, - start: startYear, - end: endYear, - onUpdated: onChange, - ), - ), - ]), + // Time slider itself + Positioned.fill( + child: RangeSelector( + key: ValueKey('RangeSelectorIsWonderTime'), + min: wondersLogic.timelineStartYear * 1.0, + max: wondersLogic.timelineEndYear * 1.0, + minDelta: 500, + start: startYear, + end: endYear, + onUpdated: onChange, + ), + ) + ]), + ) ), Gap(safeBottom), From 29d3d4784bf82e66a73e231b65ca2380a65f3032 Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Tue, 11 Mar 2025 12:06:20 -0600 Subject: [PATCH 11/35] Applied MergeSemantics. Removed the added locale lines; not necessary after all. --- lib/l10n/app_en.arb | 2 - lib/l10n/app_zh.arb | 1 - .../expanding_time_range_selector.dart | 47 ++++++++++--------- 3 files changed, 24 insertions(+), 26 deletions(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 2683daf5..0b87c0b6 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -70,8 +70,6 @@ "collectionPopupResetConfirm": "Are you sure you want to reset your collection?", "eightWaySemanticSwipeDetector": "eight-way swipe detector", "expandingTimeSelectorSemanticSelector": "time range selector", - "expandingTimeSelectorYears": "from {startYr} {startYrSuffix} to {endYr} {endYrSuffix}", - "@expandingTimeSelectorYears": {"placeholders": {"startYr": {}, "startYrSuffix": {}, "endYr": {}, "endYrSuffix": {}}}, "fullscreenImageViewerSemanticFull": "full screen image, no description available", "homeMenuButtonExplore": "Explore the timeline", "homeMenuButtonView": "View your collection", diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 6772d9d6..c7a2a366 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -58,7 +58,6 @@ "collectionPopupResetConfirm": "您确定要重置您的收藏吗?", "eightWaySemanticSwipeDetector": "八方滑动识别器", "expandingTimeSelectorSemanticSelector": "日期范围选择器", - "expandingTimeSelectorYears": "从{startYrSuffix}{startYr}年到{endYrSuffix}{endYr}年", "fullscreenImageViewerSemanticFull": "全屏图像,没有描述信息", "homeMenuButtonExplore": "探索历史年表", "homeMenuButtonView": "观看您的收藏", diff --git a/lib/ui/screens/artifact/artifact_search/time_range_selector/expanding_time_range_selector.dart b/lib/ui/screens/artifact/artifact_search/time_range_selector/expanding_time_range_selector.dart index 2f3323ae..02868a2e 100644 --- a/lib/ui/screens/artifact/artifact_search/time_range_selector/expanding_time_range_selector.dart +++ b/lib/ui/screens/artifact/artifact_search/time_range_selector/expanding_time_range_selector.dart @@ -134,8 +134,7 @@ class _OpenedTimeRange extends StatelessWidget { final void Function() onClose; Widget _buildChineseDateLayout(TextStyle headingTextStyle, TextStyle captionTextStyle, int startYr, int endYr) { - return Semantics( - label: $strings.expandingTimeSelectorYears(startYr.abs(), StringUtils.getYrSuffix(startYr), endYr.abs(), StringUtils.getYrSuffix(endYr)), + return MergeSemantics( child: Row( children: [ Text(StringUtils.getYrSuffix(startYr), style: captionTextStyle), @@ -149,14 +148,13 @@ class _OpenedTimeRange extends StatelessWidget { Gap($styles.insets.xxs), Text(endYr.abs().toString(), style: headingTextStyle), Text($strings.year, style: captionTextStyle), - ] - ) + ], + ), ); } Widget _buildDefaultDateLayout(TextStyle headingTextStyle, TextStyle captionTextStyle, int startYr, int endYr) { - return Semantics( - label: $strings.expandingTimeSelectorYears(startYr.abs(), StringUtils.getYrSuffix(startYr), endYr.abs(), StringUtils.getYrSuffix(endYr)), + return MergeSemantics( child: Row( children: [ Text(startYr.abs().toString(), style: headingTextStyle), @@ -168,8 +166,8 @@ class _OpenedTimeRange extends StatelessWidget { Text(endYr.abs().toString(), style: headingTextStyle), Gap($styles.insets.xxs), Text(StringUtils.getYrSuffix(endYr.round()), style: captionTextStyle), - ] - ) + ], + ), ); } @@ -216,10 +214,8 @@ class _OpenedTimeRange extends StatelessWidget { // Timeframe slider SizedBox( height: $styles.insets.lg * 2, - child: Semantics( - label: $strings.expandingTimeSelectorSemanticSelector, - excludeSemantics: true, - child: Stack(children: [ + child: Stack( + children: [ // grid lines: Container( decoration: BoxDecoration( @@ -262,18 +258,23 @@ class _OpenedTimeRange extends StatelessWidget { // Time slider itself Positioned.fill( - child: RangeSelector( - key: ValueKey('RangeSelectorIsWonderTime'), - min: wondersLogic.timelineStartYear * 1.0, - max: wondersLogic.timelineEndYear * 1.0, - minDelta: 500, - start: startYear, - end: endYear, - onUpdated: onChange, + child: MergeSemantics( + child: Semantics( + label: $strings.bottomScrubberSemanticTimeline, + child: RangeSelector( + key: ValueKey('RangeSelectorIsWonderTime'), + min: wondersLogic.timelineStartYear * 1.0, + max: wondersLogic.timelineEndYear * 1.0, + minDelta: 500, + start: startYear, + end: endYear, + onUpdated: onChange, + ), + ), ), - ) - ]), - ) + ), + ], + ), ), Gap(safeBottom), From 6e0d4e2d926024bd03c0cbe631ab148267a4c420 Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Mon, 17 Mar 2025 18:58:35 -0600 Subject: [PATCH 12/35] Creating a Trackpad reader to cover bases. --- lib/ui/common/controls/trackpad_reader.dart | 74 +++++++++++++++++++ .../screens/photo_gallery/photo_gallery.dart | 16 +++- 2 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 lib/ui/common/controls/trackpad_reader.dart diff --git a/lib/ui/common/controls/trackpad_reader.dart b/lib/ui/common/controls/trackpad_reader.dart new file mode 100644 index 00000000..71fa4b9a --- /dev/null +++ b/lib/ui/common/controls/trackpad_reader.dart @@ -0,0 +1,74 @@ +import 'package:flutter/gestures.dart'; +import 'package:wonders/common_libs.dart'; + +class TrackpadReader extends StatefulWidget { + static const int swipeSensitivity = 15; + static const int scrollSensitivity = 100; + + const TrackpadReader({ + super.key, + required this.child, + this.swipeUp, + this.swipeDown, + this.swipeLeft, + this.swipeRight, + this.scrollUp, + this.scrollDown, + this.scrollLeft, + this.scrollRight, + }); + + final Widget child; + final void Function()? swipeUp; + final void Function()? swipeDown; + final void Function()? swipeLeft; + final void Function()? swipeRight; + final void Function()? scrollUp; + final void Function()? scrollDown; + final void Function()? scrollLeft; + final void Function()? scrollRight; + + @override + State createState() => _TrackpadReaderState(); +} + +class _TrackpadReaderState extends State { + void _handleTrackpadEvent(PointerSignalEvent event) { + GestureBinding.instance.pointerSignalResolver.register(event, (PointerSignalEvent event) { + if (event is PointerScrollEvent && event.kind == PointerDeviceKind.trackpad) { + debugPrint(' - TrackpadReader: ${event}'); + debugPrint(' - TrackpadReader A: ${event.scrollDelta}'); + debugPrint(' - TrackpadReader B: ${event.platformData}'); + debugPrint(' - TrackpadReader C: ${event.buttons}'); + debugPrint(' - TrackpadReader D: ${event.delta}'); + debugPrint(' - TrackpadReader E: ${event.device}'); + debugPrint(' - TrackpadReader F: ${event.kind}'); + debugPrint(' - TrackpadReader G: ${event.timeStamp}'); + debugPrint(' - TrackpadReader H: ${event.size}'); + if (event.scrollDelta.dy > TrackpadReader.swipeSensitivity) { + widget.swipeUp?.call(); + } else if (event.scrollDelta.dy < TrackpadReader.swipeSensitivity) { + widget.swipeDown?.call(); + } + if (event.scrollDelta.dx > TrackpadReader.swipeSensitivity) { + widget.swipeLeft?.call(); + } else if (event.scrollDelta.dx < TrackpadReader.swipeSensitivity) { + widget.swipeRight?.call(); + } + } + }); + } + + @override + Widget build(BuildContext context) { + return Listener( + onPointerPanZoomStart: (event) { + debugPrint(' - TrackpadReader: onPointerPanZoomStart'); + }, + onPointerPanZoomEnd: (event) { + debugPrint(' - TrackpadReader: onPointerPanZoomEnd'); + }, + onPointerSignal: _handleTrackpadEvent, + child: widget.child); + } +} diff --git a/lib/ui/screens/photo_gallery/photo_gallery.dart b/lib/ui/screens/photo_gallery/photo_gallery.dart index 731288a7..df13da46 100644 --- a/lib/ui/screens/photo_gallery/photo_gallery.dart +++ b/lib/ui/screens/photo_gallery/photo_gallery.dart @@ -5,6 +5,7 @@ import 'package:wonders/common_libs.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'; +import 'package:wonders/ui/common/controls/trackpad_reader.dart'; import 'package:wonders/ui/common/fullscreen_keyboard_listener.dart'; import 'package:wonders/ui/common/hidden_collectible.dart'; import 'package:wonders/ui/common/ignore_pointer.dart'; @@ -169,9 +170,14 @@ class _PhotoGalleryState extends State { @override Widget build(BuildContext context) { - return FullscreenKeyboardListener( - onKeyDown: _handleKeyDown, - child: ValueListenableBuilder>( + return TrackpadReader( + swipeLeft: () => _handleSwipe(Offset(-1, 0)), + swipeRight: () => _handleSwipe(Offset(1, 0)), + swipeDown: () => _handleSwipe(Offset(0, -1)), + swipeUp: () => _handleSwipe(Offset(0, 1)), + child: FullscreenKeyboardListener( + onKeyDown: _handleKeyDown, + child: ValueListenableBuilder>( valueListenable: _photoIds, builder: (_, value, __) { if (value.isEmpty) { @@ -227,7 +233,9 @@ class _PhotoGalleryState extends State { ), ), ); - }), + }, + ), + ), ); } From 7d83cdde1efbfc3f8009f0807fca7a654fb00b83 Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Tue, 18 Mar 2025 10:28:06 -0600 Subject: [PATCH 13/35] TrackpadListener functional in Photo Gallery (for testing). Will apply elsewhere. --- ...pad_reader.dart => trackpad_listener.dart} | 27 +++++++------------ .../screens/photo_gallery/photo_gallery.dart | 24 ++++++++++++----- 2 files changed, 27 insertions(+), 24 deletions(-) rename lib/ui/common/controls/{trackpad_reader.dart => trackpad_listener.dart} (59%) diff --git a/lib/ui/common/controls/trackpad_reader.dart b/lib/ui/common/controls/trackpad_listener.dart similarity index 59% rename from lib/ui/common/controls/trackpad_reader.dart rename to lib/ui/common/controls/trackpad_listener.dart index 71fa4b9a..5d02e7bc 100644 --- a/lib/ui/common/controls/trackpad_reader.dart +++ b/lib/ui/common/controls/trackpad_listener.dart @@ -1,11 +1,11 @@ import 'package:flutter/gestures.dart'; import 'package:wonders/common_libs.dart'; -class TrackpadReader extends StatefulWidget { +class TrackpadListener extends StatefulWidget { static const int swipeSensitivity = 15; static const int scrollSensitivity = 100; - const TrackpadReader({ + const TrackpadListener({ super.key, required this.child, this.swipeUp, @@ -29,30 +29,21 @@ class TrackpadReader extends StatefulWidget { final void Function()? scrollRight; @override - State createState() => _TrackpadReaderState(); + State createState() => _TrackpadListenerState(); } -class _TrackpadReaderState extends State { +class _TrackpadListenerState extends State { void _handleTrackpadEvent(PointerSignalEvent event) { GestureBinding.instance.pointerSignalResolver.register(event, (PointerSignalEvent event) { if (event is PointerScrollEvent && event.kind == PointerDeviceKind.trackpad) { - debugPrint(' - TrackpadReader: ${event}'); - debugPrint(' - TrackpadReader A: ${event.scrollDelta}'); - debugPrint(' - TrackpadReader B: ${event.platformData}'); - debugPrint(' - TrackpadReader C: ${event.buttons}'); - debugPrint(' - TrackpadReader D: ${event.delta}'); - debugPrint(' - TrackpadReader E: ${event.device}'); - debugPrint(' - TrackpadReader F: ${event.kind}'); - debugPrint(' - TrackpadReader G: ${event.timeStamp}'); - debugPrint(' - TrackpadReader H: ${event.size}'); - if (event.scrollDelta.dy > TrackpadReader.swipeSensitivity) { - widget.swipeUp?.call(); - } else if (event.scrollDelta.dy < TrackpadReader.swipeSensitivity) { + if (event.scrollDelta.dy > TrackpadListener.swipeSensitivity) { widget.swipeDown?.call(); + } else if (event.scrollDelta.dy < -TrackpadListener.swipeSensitivity) { + widget.swipeUp?.call(); } - if (event.scrollDelta.dx > TrackpadReader.swipeSensitivity) { + if (event.scrollDelta.dx > TrackpadListener.swipeSensitivity) { widget.swipeLeft?.call(); - } else if (event.scrollDelta.dx < TrackpadReader.swipeSensitivity) { + } else if (event.scrollDelta.dx < -TrackpadListener.swipeSensitivity) { widget.swipeRight?.call(); } } diff --git a/lib/ui/screens/photo_gallery/photo_gallery.dart b/lib/ui/screens/photo_gallery/photo_gallery.dart index df13da46..009490e2 100644 --- a/lib/ui/screens/photo_gallery/photo_gallery.dart +++ b/lib/ui/screens/photo_gallery/photo_gallery.dart @@ -5,7 +5,7 @@ import 'package:wonders/common_libs.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'; -import 'package:wonders/ui/common/controls/trackpad_reader.dart'; +import 'package:wonders/ui/common/controls/trackpad_listener.dart'; import 'package:wonders/ui/common/fullscreen_keyboard_listener.dart'; import 'package:wonders/ui/common/hidden_collectible.dart'; import 'package:wonders/ui/common/ignore_pointer.dart'; @@ -170,11 +170,23 @@ class _PhotoGalleryState extends State { @override Widget build(BuildContext context) { - return TrackpadReader( - swipeLeft: () => _handleSwipe(Offset(-1, 0)), - swipeRight: () => _handleSwipe(Offset(1, 0)), - swipeDown: () => _handleSwipe(Offset(0, -1)), - swipeUp: () => _handleSwipe(Offset(0, 1)), + return TrackpadListener( + swipeLeft: () { + debugPrint('LEFT!'); + _handleSwipe(Offset(-1, 0)); + }, + swipeRight: () { + debugPrint('RIGHT!'); + _handleSwipe(Offset(1, 0)); + }, + swipeDown: () { + debugPrint('DOWN!'); + _handleSwipe(Offset(0, -1)); + }, + swipeUp: () { + debugPrint('UP!'); + _handleSwipe(Offset(0, 1)); + }, child: FullscreenKeyboardListener( onKeyDown: _handleKeyDown, child: ValueListenableBuilder>( From 4f4b81e45f317142a27d111a6c2d996d5ae483a0 Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Wed, 19 Mar 2025 16:34:32 -0600 Subject: [PATCH 14/35] Moved TrackpadListener into eight-way-swipe-detector, which no longer reads trackpad events. Added it to editorial screen and wonders home screen for the down/up swipes. Bit more refinement. --- .../controls/eight_way_swipe_detector.dart | 36 +++- lib/ui/common/controls/trackpad_listener.dart | 94 ++++---- .../screens/editorial/editorial_screen.dart | 200 ++++++++++-------- lib/ui/screens/home/wonders_home_screen.dart | 37 ++-- .../screens/photo_gallery/photo_gallery.dart | 127 +++++------ 5 files changed, 263 insertions(+), 231 deletions(-) diff --git a/lib/ui/common/controls/eight_way_swipe_detector.dart b/lib/ui/common/controls/eight_way_swipe_detector.dart index f4a65257..06efebff 100644 --- a/lib/ui/common/controls/eight_way_swipe_detector.dart +++ b/lib/ui/common/controls/eight_way_swipe_detector.dart @@ -1,4 +1,6 @@ +import 'package:flutter/gestures.dart'; import 'package:wonders/common_libs.dart'; +import 'package:wonders/ui/common/controls/trackpad_listener.dart'; class EightWaySwipeDetector extends StatefulWidget { const EightWaySwipeDetector({super.key, required this.child, this.threshold = 50, required this.onSwipe}); @@ -40,12 +42,16 @@ class _EightWaySwipeDetectorState extends State { } } - void _handleSwipeStart(d) { - _isSwiping = true; + void _trackpadSwipe(Offset delta) { + widget.onSwipe?.call(delta); + } + + void _handleSwipeStart(DragStartDetails d) { + _isSwiping = d.kind != null; _startPos = _endPos = d.localPosition; } - void _handleSwipeUpdate(d) { + void _handleSwipeUpdate(DragUpdateDetails d) { _endPos = d.localPosition; _maybeTriggerSwipe(); } @@ -57,12 +63,22 @@ class _EightWaySwipeDetectorState extends State { @override Widget build(BuildContext context) { - return GestureDetector( - behavior: HitTestBehavior.translucent, - onPanStart: _handleSwipeStart, - onPanUpdate: _handleSwipeUpdate, - onPanCancel: _resetSwipe, - onPanEnd: _handleSwipeEnd, - child: widget.child); + return TrackpadListener( + onScroll: _trackpadSwipe, + child: GestureDetector( + behavior: HitTestBehavior.translucent, + onPanStart: _handleSwipeStart, + onPanUpdate: _handleSwipeUpdate, + onPanCancel: _resetSwipe, + onPanEnd: _handleSwipeEnd, + supportedDevices: const { + // Purposely omitting PointerDeviceKind.trackpad. + PointerDeviceKind.mouse, + PointerDeviceKind.stylus, + PointerDeviceKind.touch, + PointerDeviceKind.unknown, + }, + child: widget.child), + ); } } diff --git a/lib/ui/common/controls/trackpad_listener.dart b/lib/ui/common/controls/trackpad_listener.dart index 5d02e7bc..c26d9e89 100644 --- a/lib/ui/common/controls/trackpad_listener.dart +++ b/lib/ui/common/controls/trackpad_listener.dart @@ -1,65 +1,83 @@ +import 'dart:async'; + import 'package:flutter/gestures.dart'; import 'package:wonders/common_libs.dart'; class TrackpadListener extends StatefulWidget { - static const int swipeSensitivity = 15; - static const int scrollSensitivity = 100; + final Widget child; + final double scrollSensitivity; + final void Function()? onScrollUp; + final void Function()? onScrollDown; + final void Function()? onScrollLeft; + final void Function()? onScrollRight; + final void Function(Offset delta)? onScroll; const TrackpadListener({ super.key, required this.child, - this.swipeUp, - this.swipeDown, - this.swipeLeft, - this.swipeRight, - this.scrollUp, - this.scrollDown, - this.scrollLeft, - this.scrollRight, + this.scrollSensitivity = 100, + this.onScrollUp, + this.onScrollDown, + this.onScrollLeft, + this.onScrollRight, + this.onScroll, }); - final Widget child; - final void Function()? swipeUp; - final void Function()? swipeDown; - final void Function()? swipeLeft; - final void Function()? swipeRight; - final void Function()? scrollUp; - final void Function()? scrollDown; - final void Function()? scrollLeft; - final void Function()? scrollRight; - @override State createState() => _TrackpadListenerState(); } class _TrackpadListenerState extends State { + Offset _scrollOffset = Offset.zero; void _handleTrackpadEvent(PointerSignalEvent event) { GestureBinding.instance.pointerSignalResolver.register(event, (PointerSignalEvent event) { if (event is PointerScrollEvent && event.kind == PointerDeviceKind.trackpad) { - if (event.scrollDelta.dy > TrackpadListener.swipeSensitivity) { - widget.swipeDown?.call(); - } else if (event.scrollDelta.dy < -TrackpadListener.swipeSensitivity) { - widget.swipeUp?.call(); - } - if (event.scrollDelta.dx > TrackpadListener.swipeSensitivity) { - widget.swipeLeft?.call(); - } else if (event.scrollDelta.dx < -TrackpadListener.swipeSensitivity) { - widget.swipeRight?.call(); - } + Offset newScroll = _scrollOffset + event.scrollDelta; + newScroll = Offset( + newScroll.dx.clamp(-widget.scrollSensitivity, widget.scrollSensitivity), + newScroll.dy.clamp(-widget.scrollSensitivity, widget.scrollSensitivity), + ); + _update(newScroll); } }); } + void _update(Offset newOffset) { + Offset directionScroll = Offset.zero; + double sensitivity = widget.scrollSensitivity; + while (newOffset.dy >= sensitivity) { + widget.onScrollDown?.call(); + newOffset -= Offset(0.0, sensitivity); + directionScroll -= Offset(0.0, 1.0); + } + while (newOffset.dy <= -sensitivity) { + widget.onScrollUp?.call(); + newOffset += Offset(0.0, sensitivity); + directionScroll += Offset(0.0, 1.0); + } + while (newOffset.dx >= sensitivity) { + widget.onScrollLeft?.call(); + newOffset -= Offset(sensitivity, 0.0); + directionScroll -= Offset(1.0, 0.0); + } + while (newOffset.dx <= -sensitivity) { + widget.onScrollRight?.call(); + newOffset += Offset(sensitivity, 0.0); + directionScroll += Offset(1.0, 0.0); + } + if (directionScroll != Offset.zero) { + widget.onScroll?.call(directionScroll); + } + // Tone it down over time. + newOffset *= 0.9; + setState(() => _scrollOffset = newOffset); + } + @override Widget build(BuildContext context) { return Listener( - onPointerPanZoomStart: (event) { - debugPrint(' - TrackpadReader: onPointerPanZoomStart'); - }, - onPointerPanZoomEnd: (event) { - debugPrint(' - TrackpadReader: onPointerPanZoomEnd'); - }, - onPointerSignal: _handleTrackpadEvent, - child: widget.child); + onPointerSignal: _handleTrackpadEvent, + child: widget.child, + ); } } diff --git a/lib/ui/screens/editorial/editorial_screen.dart b/lib/ui/screens/editorial/editorial_screen.dart index 073ff240..94276a5c 100644 --- a/lib/ui/screens/editorial/editorial_screen.dart +++ b/lib/ui/screens/editorial/editorial_screen.dart @@ -12,6 +12,7 @@ import 'package:wonders/ui/common/app_icons.dart'; import 'package:wonders/ui/common/blend_mask.dart'; import 'package:wonders/ui/common/centered_box.dart'; import 'package:wonders/ui/common/compass_divider.dart'; +import 'package:wonders/ui/common/controls/trackpad_listener.dart'; import 'package:wonders/ui/common/curved_clippers.dart'; import 'package:wonders/ui/common/fullscreen_keyboard_list_scroller.dart'; import 'package:wonders/ui/common/google_maps_marker.dart'; @@ -64,6 +65,13 @@ class _WonderEditorialScreenState extends State { _scrollPos.value = _scroller.position.pixels; } + void _handleSwipeUp() { + // Trackpad swipe up. Return to home if at the top. + if (_scroller.position.pixels == 0) { + _handleBackPressed(); + } + } + void _handleBackPressed() => context.go(ScreenPaths.home); @override @@ -80,115 +88,119 @@ class _WonderEditorialScreenState extends State { controller: _scroller, child: ColoredBox( color: $styles.colors.offWhite, - child: Stack( - children: [ - /// Background - Positioned.fill( - child: ColoredBox(color: widget.data.type.bgColor), - ), - - /// Top Illustration - Sits underneath the scrolling content, fades out as it scrolls - SizedBox( - height: illustrationHeight, - child: ValueListenableBuilder( - valueListenable: _scrollPos, - builder: (_, value, child) { - // get some value between 0 and 1, based on the amt scrolled - double opacity = (1 - value / 700).clamp(0, 1); - return Opacity(opacity: opacity, child: child); - }, - // This is due to a bug: https://github.com/flutter/flutter/issues/101872 - child: RepaintBoundary( - child: _TopIllustration( - widget.data.type, - // Polish: Inject the content padding into the illustration as an offset, so it can center itself relative to the content - // this allows the background to extend underneath the vertical side nav when it has rounded corners. - fgOffset: Offset(widget.contentPadding.left / 2, 0), - )), + child: TrackpadListener( + onScrollUp: _handleSwipeUp, + scrollSensitivity: 120, + child: Stack( + children: [ + /// Background + Positioned.fill( + child: ColoredBox(color: widget.data.type.bgColor), ), - ), - /// Scrolling content - Includes an invisible gap at the top, and then scrolls over the illustration - TopCenter( - child: Padding( - padding: widget.contentPadding, - child: SizedBox( - child: FocusTraversalGroup( - child: FullscreenKeyboardListScroller( - scrollController: _scroller, - child: CustomScrollView( - controller: _scroller, - scrollBehavior: ScrollConfiguration.of(context).copyWith(), - key: PageStorageKey('editorial'), - slivers: [ - /// Invisible padding at the top of the list, so the illustration shows through the btm - SliverToBoxAdapter( - child: SizedBox(height: illustrationHeight), - ), + /// Top Illustration - Sits underneath the scrolling content, fades out as it scrolls + SizedBox( + height: illustrationHeight, + child: ValueListenableBuilder( + valueListenable: _scrollPos, + builder: (_, value, child) { + // get some value between 0 and 1, based on the amt scrolled + double opacity = (1 - value / 700).clamp(0, 1); + return Opacity(opacity: opacity, child: child); + }, + // This is due to a bug: https://github.com/flutter/flutter/issues/101872 + child: RepaintBoundary( + child: _TopIllustration( + widget.data.type, + // Polish: Inject the content padding into the illustration as an offset, so it can center itself relative to the content + // this allows the background to extend underneath the vertical side nav when it has rounded corners. + fgOffset: Offset(widget.contentPadding.left / 2, 0), + )), + ), + ), - /// Text content, animates itself to hide behind the app bar as it scrolls up - SliverToBoxAdapter( - child: ValueListenableBuilder( - valueListenable: _scrollPos, - builder: (_, value, child) { - double offsetAmt = max(0, value * .3); - double opacity = (1 - offsetAmt / 150).clamp(0, 1); - return Transform.translate( - offset: Offset(0, offsetAmt), - child: Opacity(opacity: opacity, child: child), - ); - }, - child: _TitleText(widget.data, scroller: _scroller), + /// Scrolling content - Includes an invisible gap at the top, and then scrolls over the illustration + TopCenter( + child: Padding( + padding: widget.contentPadding, + child: SizedBox( + child: FocusTraversalGroup( + child: FullscreenKeyboardListScroller( + scrollController: _scroller, + child: CustomScrollView( + controller: _scroller, + scrollBehavior: ScrollConfiguration.of(context).copyWith(), + key: PageStorageKey('editorial'), + slivers: [ + /// Invisible padding at the top of the list, so the illustration shows through the btm + SliverToBoxAdapter( + child: SizedBox(height: illustrationHeight), ), - ), - /// Collapsing App bar, pins to the top of the list - SliverAppBar( - pinned: true, - collapsedHeight: minAppBarHeight, - toolbarHeight: minAppBarHeight, - expandedHeight: maxAppBarHeight, - backgroundColor: Colors.transparent, - elevation: 0, - leading: SizedBox.shrink(), - flexibleSpace: SizedBox.expand( - child: _AppBar( - widget.data.type, - scrollPos: _scrollPos, - sectionIndex: _sectionIndex, + /// Text content, animates itself to hide behind the app bar as it scrolls up + SliverToBoxAdapter( + child: ValueListenableBuilder( + valueListenable: _scrollPos, + builder: (_, value, child) { + double offsetAmt = max(0, value * .3); + double opacity = (1 - offsetAmt / 150).clamp(0, 1); + return Transform.translate( + offset: Offset(0, offsetAmt), + child: Opacity(opacity: opacity, child: child), + ); + }, + child: _TitleText(widget.data, scroller: _scroller), ), ), - ), - /// Editorial content (text and images) - _ScrollingContent(widget.data, scrollPos: _scrollPos, sectionNotifier: _sectionIndex), - ], + /// Collapsing App bar, pins to the top of the list + SliverAppBar( + pinned: true, + collapsedHeight: minAppBarHeight, + toolbarHeight: minAppBarHeight, + expandedHeight: maxAppBarHeight, + backgroundColor: Colors.transparent, + elevation: 0, + leading: SizedBox.shrink(), + flexibleSpace: SizedBox.expand( + child: _AppBar( + widget.data.type, + scrollPos: _scrollPos, + sectionIndex: _sectionIndex, + ), + ), + ), + + /// Editorial content (text and images) + _ScrollingContent(widget.data, scrollPos: _scrollPos, sectionNotifier: _sectionIndex), + ], + ), ), ), ), ), ), - ), - /// Home Btn - AnimatedBuilder( - animation: _scroller, - builder: (_, child) { - return AnimatedOpacity( - opacity: _scrollPos.value > 0 ? 0 : 1, - duration: $styles.times.med, - child: child, - ); - }, - child: Align( - alignment: backBtnAlign, - child: Padding( - padding: EdgeInsets.all($styles.insets.sm), - child: BackBtn(icon: AppIcons.north, onPressed: _handleBackPressed), + /// Home Btn + AnimatedBuilder( + animation: _scroller, + builder: (_, child) { + return AnimatedOpacity( + opacity: _scrollPos.value > 0 ? 0 : 1, + duration: $styles.times.med, + child: child, + ); + }, + child: Align( + alignment: backBtnAlign, + child: Padding( + padding: EdgeInsets.all($styles.insets.sm), + child: BackBtn(icon: AppIcons.north, onPressed: _handleBackPressed), + ), ), - ), - ) - ], + ) + ], + ), ), ), ); diff --git a/lib/ui/screens/home/wonders_home_screen.dart b/lib/ui/screens/home/wonders_home_screen.dart index e1172c43..a9abb481 100644 --- a/lib/ui/screens/home/wonders_home_screen.dart +++ b/lib/ui/screens/home/wonders_home_screen.dart @@ -3,6 +3,7 @@ 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'; import 'package:wonders/ui/common/controls/app_page_indicator.dart'; +import 'package:wonders/ui/common/controls/trackpad_listener.dart'; import 'package:wonders/ui/common/gradient_container.dart'; import 'package:wonders/ui/common/ignore_pointer.dart'; import 'package:wonders/ui/common/previous_next_navigation.dart'; @@ -140,25 +141,29 @@ class _HomeScreenState extends State with SingleTickerProviderStateM return _swipeController.wrapGestureDetector(Container( color: $styles.colors.black, - child: PreviousNextNavigation( - listenToMouseWheel: false, - onPreviousPressed: () => _handlePrevNext(-1), - onNextPressed: () => _handlePrevNext(1), - child: Stack( - children: [ - /// Background - ..._buildBgAndClouds(), + child: TrackpadListener( + scrollSensitivity: 60, + onScrollDown: () => _showDetailsPage(), + child: PreviousNextNavigation( + listenToMouseWheel: false, + onPreviousPressed: () => _handlePrevNext(-1), + onNextPressed: () => _handlePrevNext(1), + child: Stack( + children: [ + /// Background + ..._buildBgAndClouds(), - /// Wonders Illustrations (main content) - _buildMgPageView(), + /// Wonders Illustrations (main content) + _buildMgPageView(), - /// Foreground illustrations and gradients - _buildFgAndGradients(), + /// Foreground illustrations and gradients + _buildFgAndGradients(), - /// Controls that float on top of the various illustrations - _buildFloatingUi(), - ], - ).animate().fadeIn(), + /// Controls that float on top of the various illustrations + _buildFloatingUi(), + ], + ).animate().fadeIn(), + ), ), )); } diff --git a/lib/ui/screens/photo_gallery/photo_gallery.dart b/lib/ui/screens/photo_gallery/photo_gallery.dart index 009490e2..521314e9 100644 --- a/lib/ui/screens/photo_gallery/photo_gallery.dart +++ b/lib/ui/screens/photo_gallery/photo_gallery.dart @@ -5,7 +5,6 @@ import 'package:wonders/common_libs.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'; -import 'package:wonders/ui/common/controls/trackpad_listener.dart'; import 'package:wonders/ui/common/fullscreen_keyboard_listener.dart'; import 'package:wonders/ui/common/hidden_collectible.dart'; import 'package:wonders/ui/common/ignore_pointer.dart'; @@ -170,83 +169,65 @@ class _PhotoGalleryState extends State { @override Widget build(BuildContext context) { - return TrackpadListener( - swipeLeft: () { - debugPrint('LEFT!'); - _handleSwipe(Offset(-1, 0)); - }, - swipeRight: () { - debugPrint('RIGHT!'); - _handleSwipe(Offset(1, 0)); - }, - swipeDown: () { - debugPrint('DOWN!'); - _handleSwipe(Offset(0, -1)); - }, - swipeUp: () { - debugPrint('UP!'); - _handleSwipe(Offset(0, 1)); - }, - child: FullscreenKeyboardListener( - onKeyDown: _handleKeyDown, - child: ValueListenableBuilder>( - valueListenable: _photoIds, - builder: (_, value, __) { - if (value.isEmpty) { - return Center(child: AppLoadingIndicator()); - } - Size imgSize = context.isLandscape - ? Size(context.widthPx * .5, context.heightPx * .66) - : Size(context.widthPx * .66, context.heightPx * .5); - imgSize = (widget.imageSize ?? imgSize) * _scale; - // Get transform offset for the current _index - final padding = $styles.insets.md; - var gridOffset = _calculateCurrentOffset(padding, imgSize); - gridOffset += Offset(0, -context.mq.padding.top / 2); - final offsetTweenDuration = _skipNextOffsetTween ? Duration.zero : swipeDuration; - final cutoutTweenDuration = _skipNextOffsetTween ? Duration.zero : swipeDuration * .5; - return _AnimatedCutoutOverlay( - animationKey: ValueKey(_index), - cutoutSize: imgSize, - swipeDir: _lastSwipeDir, - duration: cutoutTweenDuration, - opacity: _scale == 1 ? .7 : .5, - enabled: useClipPathWorkAroundForWeb == false, - child: SafeArea( - bottom: false, - // Place content in overflow box, to allow it to flow outside the parent - child: OverflowBox( - maxWidth: _gridSize * imgSize.width + padding * (_gridSize - 1), - maxHeight: _gridSize * imgSize.height + padding * (_gridSize - 1), - alignment: Alignment.center, - // Detect swipes in order to change index - child: EightWaySwipeDetector( - onSwipe: _handleSwipe, - threshold: 30, - // A tween animation builder moves from image to image based on current offset - child: TweenAnimationBuilder( - tween: Tween(begin: gridOffset, end: gridOffset), - duration: offsetTweenDuration, - curve: Curves.easeOut, - builder: (_, value, child) => Transform.translate(offset: value, child: child), - child: FocusTraversalGroup( - //policy: OrderedTraversalPolicy(), - child: GridView.count( - physics: NeverScrollableScrollPhysics(), - crossAxisCount: _gridSize, - childAspectRatio: imgSize.aspectRatio, - mainAxisSpacing: padding, - crossAxisSpacing: padding, - children: List.generate(_imgCount, (i) => _buildImage(i, swipeDuration, imgSize)), - ), + return FullscreenKeyboardListener( + onKeyDown: _handleKeyDown, + child: ValueListenableBuilder>( + valueListenable: _photoIds, + builder: (_, value, __) { + if (value.isEmpty) { + return Center(child: AppLoadingIndicator()); + } + Size imgSize = context.isLandscape + ? Size(context.widthPx * .5, context.heightPx * .66) + : Size(context.widthPx * .66, context.heightPx * .5); + imgSize = (widget.imageSize ?? imgSize) * _scale; + // Get transform offset for the current _index + final padding = $styles.insets.md; + var gridOffset = _calculateCurrentOffset(padding, imgSize); + gridOffset += Offset(0, -context.mq.padding.top / 2); + final offsetTweenDuration = _skipNextOffsetTween ? Duration.zero : swipeDuration; + final cutoutTweenDuration = _skipNextOffsetTween ? Duration.zero : swipeDuration * .5; + return _AnimatedCutoutOverlay( + animationKey: ValueKey(_index), + cutoutSize: imgSize, + swipeDir: _lastSwipeDir, + duration: cutoutTweenDuration, + opacity: _scale == 1 ? .7 : .5, + enabled: useClipPathWorkAroundForWeb == false, + child: SafeArea( + bottom: false, + // Place content in overflow box, to allow it to flow outside the parent + child: OverflowBox( + maxWidth: _gridSize * imgSize.width + padding * (_gridSize - 1), + maxHeight: _gridSize * imgSize.height + padding * (_gridSize - 1), + alignment: Alignment.center, + // Detect swipes in order to change index + child: EightWaySwipeDetector( + onSwipe: _handleSwipe, + threshold: 30, + // A tween animation builder moves from image to image based on current offset + child: TweenAnimationBuilder( + tween: Tween(begin: gridOffset, end: gridOffset), + duration: offsetTweenDuration, + curve: Curves.easeOut, + builder: (_, value, child) => Transform.translate(offset: value, child: child), + child: FocusTraversalGroup( + //policy: OrderedTraversalPolicy(), + child: GridView.count( + physics: NeverScrollableScrollPhysics(), + crossAxisCount: _gridSize, + childAspectRatio: imgSize.aspectRatio, + mainAxisSpacing: padding, + crossAxisSpacing: padding, + children: List.generate(_imgCount, (i) => _buildImage(i, swipeDuration, imgSize)), ), ), ), ), ), - ); - }, - ), + ), + ); + }, ), ); } From a73b5fb62ab69a4902496f7316e045c2c68dcfe1 Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Thu, 20 Mar 2025 14:40:19 -0600 Subject: [PATCH 15/35] Fair bit of code cleanup. --- .../controls/eight_way_swipe_detector.dart | 28 ++++++----- lib/ui/common/controls/trackpad_listener.dart | 48 ++++++++----------- .../screens/editorial/editorial_screen.dart | 6 +-- lib/ui/screens/home/wonders_home_screen.dart | 8 +++- 4 files changed, 44 insertions(+), 46 deletions(-) diff --git a/lib/ui/common/controls/eight_way_swipe_detector.dart b/lib/ui/common/controls/eight_way_swipe_detector.dart index 06efebff..2017c4ab 100644 --- a/lib/ui/common/controls/eight_way_swipe_detector.dart +++ b/lib/ui/common/controls/eight_way_swipe_detector.dart @@ -64,21 +64,23 @@ class _EightWaySwipeDetectorState extends State { @override Widget build(BuildContext context) { return TrackpadListener( + scrollSensitivity: 70, onScroll: _trackpadSwipe, child: GestureDetector( - behavior: HitTestBehavior.translucent, - onPanStart: _handleSwipeStart, - onPanUpdate: _handleSwipeUpdate, - onPanCancel: _resetSwipe, - onPanEnd: _handleSwipeEnd, - supportedDevices: const { - // Purposely omitting PointerDeviceKind.trackpad. - PointerDeviceKind.mouse, - PointerDeviceKind.stylus, - PointerDeviceKind.touch, - PointerDeviceKind.unknown, - }, - child: widget.child), + behavior: HitTestBehavior.translucent, + onPanStart: _handleSwipeStart, + onPanUpdate: _handleSwipeUpdate, + onPanCancel: _resetSwipe, + onPanEnd: _handleSwipeEnd, + supportedDevices: const { + // Purposely omitting PointerDeviceKind.trackpad. + PointerDeviceKind.mouse, + PointerDeviceKind.stylus, + PointerDeviceKind.touch, + PointerDeviceKind.unknown, + }, + child: widget.child, + ), ); } } diff --git a/lib/ui/common/controls/trackpad_listener.dart b/lib/ui/common/controls/trackpad_listener.dart index c26d9e89..93e1667c 100644 --- a/lib/ui/common/controls/trackpad_listener.dart +++ b/lib/ui/common/controls/trackpad_listener.dart @@ -6,20 +6,12 @@ import 'package:wonders/common_libs.dart'; class TrackpadListener extends StatefulWidget { final Widget child; final double scrollSensitivity; - final void Function()? onScrollUp; - final void Function()? onScrollDown; - final void Function()? onScrollLeft; - final void Function()? onScrollRight; final void Function(Offset delta)? onScroll; const TrackpadListener({ super.key, required this.child, this.scrollSensitivity = 100, - this.onScrollUp, - this.onScrollDown, - this.onScrollLeft, - this.onScrollRight, this.onScroll, }); @@ -29,48 +21,46 @@ class TrackpadListener extends StatefulWidget { class _TrackpadListenerState extends State { Offset _scrollOffset = Offset.zero; + void _handleTrackpadEvent(PointerSignalEvent event) { GestureBinding.instance.pointerSignalResolver.register(event, (PointerSignalEvent event) { + // Only handle trackpad events here. if (event is PointerScrollEvent && event.kind == PointerDeviceKind.trackpad) { Offset newScroll = _scrollOffset + event.scrollDelta; newScroll = Offset( newScroll.dx.clamp(-widget.scrollSensitivity, widget.scrollSensitivity), newScroll.dy.clamp(-widget.scrollSensitivity, widget.scrollSensitivity), ); - _update(newScroll); + _scrollOffset = newScroll; + _update(); } }); } - void _update(Offset newOffset) { + void _update() { Offset directionScroll = Offset.zero; double sensitivity = widget.scrollSensitivity; - while (newOffset.dy >= sensitivity) { - widget.onScrollDown?.call(); - newOffset -= Offset(0.0, sensitivity); - directionScroll -= Offset(0.0, 1.0); - } - while (newOffset.dy <= -sensitivity) { - widget.onScrollUp?.call(); - newOffset += Offset(0.0, sensitivity); + if (_scrollOffset.dy >= sensitivity) { + // Scroll down + _scrollOffset += Offset(0.0, -sensitivity); + directionScroll += Offset(0.0, -1.0); + } else if (_scrollOffset.dy <= -sensitivity) { + // Scroll up + _scrollOffset += Offset(0.0, sensitivity); directionScroll += Offset(0.0, 1.0); } - while (newOffset.dx >= sensitivity) { - widget.onScrollLeft?.call(); - newOffset -= Offset(sensitivity, 0.0); - directionScroll -= Offset(1.0, 0.0); - } - while (newOffset.dx <= -sensitivity) { - widget.onScrollRight?.call(); - newOffset += Offset(sensitivity, 0.0); + if (_scrollOffset.dx >= sensitivity) { + // Scroll left + _scrollOffset += Offset(-sensitivity, 0.0); + directionScroll += Offset(-1.0, 0.0); + } else if (_scrollOffset.dx <= -sensitivity) { + // Scroll right + _scrollOffset += Offset(sensitivity, 0.0); directionScroll += Offset(1.0, 0.0); } if (directionScroll != Offset.zero) { widget.onScroll?.call(directionScroll); } - // Tone it down over time. - newOffset *= 0.9; - setState(() => _scrollOffset = newOffset); } @override diff --git a/lib/ui/screens/editorial/editorial_screen.dart b/lib/ui/screens/editorial/editorial_screen.dart index 94276a5c..9aa4c5e4 100644 --- a/lib/ui/screens/editorial/editorial_screen.dart +++ b/lib/ui/screens/editorial/editorial_screen.dart @@ -65,9 +65,9 @@ class _WonderEditorialScreenState extends State { _scrollPos.value = _scroller.position.pixels; } - void _handleSwipeUp() { + void _handleTrackpadScroll(Offset direction) { // Trackpad swipe up. Return to home if at the top. - if (_scroller.position.pixels == 0) { + if (_scroller.position.pixels == 0 && direction.dy > 0) { _handleBackPressed(); } } @@ -89,7 +89,7 @@ class _WonderEditorialScreenState extends State { child: ColoredBox( color: $styles.colors.offWhite, child: TrackpadListener( - onScrollUp: _handleSwipeUp, + onScroll: _handleTrackpadScroll, scrollSensitivity: 120, child: Stack( children: [ diff --git a/lib/ui/screens/home/wonders_home_screen.dart b/lib/ui/screens/home/wonders_home_screen.dart index a9abb481..84a7c7de 100644 --- a/lib/ui/screens/home/wonders_home_screen.dart +++ b/lib/ui/screens/home/wonders_home_screen.dart @@ -132,6 +132,12 @@ class _HomeScreenState extends State with SingleTickerProviderStateM } } + void _handleTrackpadScroll(Offset direction) { + if (direction.dy < 0) { + _showDetailsPage(); + } + } + @override Widget build(BuildContext context) { if (_fadeInOnNextBuild == true) { @@ -143,7 +149,7 @@ class _HomeScreenState extends State with SingleTickerProviderStateM color: $styles.colors.black, child: TrackpadListener( scrollSensitivity: 60, - onScrollDown: () => _showDetailsPage(), + onScroll: _handleTrackpadScroll, child: PreviousNextNavigation( listenToMouseWheel: false, onPreviousPressed: () => _handlePrevNext(-1), From 8495d160301e64b2584a1c344bc3e4489937657f Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Thu, 20 Mar 2025 18:06:22 -0600 Subject: [PATCH 16/35] Removed debug print. --- lib/logic/app_logic.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/logic/app_logic.dart b/lib/logic/app_logic.dart index 5fa66463..5c92ceb1 100644 --- a/lib/logic/app_logic.dart +++ b/lib/logic/app_logic.dart @@ -128,8 +128,6 @@ class AppLogic { } void precacheWonderImages(BuildContext context) { - debugPrint('Skipping precache, need to figure out why it\'s not working on web.'); - return; precacheImage(AssetImage('images/chichen_itza/chichen.png'), context); precacheImage(AssetImage('images/chichen_itza/foreground-left.png'), context); precacheImage(AssetImage('images/chichen_itza/foreground-right.png'), context); From 9a7f7887d4a26d7c28347299d157dfed29f27ce1 Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Fri, 21 Mar 2025 10:06:18 -0600 Subject: [PATCH 17/35] Revert "Removed debug print." This reverts commit 8495d160301e64b2584a1c344bc3e4489937657f. --- lib/logic/app_logic.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/logic/app_logic.dart b/lib/logic/app_logic.dart index 5c92ceb1..5fa66463 100644 --- a/lib/logic/app_logic.dart +++ b/lib/logic/app_logic.dart @@ -128,6 +128,8 @@ class AppLogic { } void precacheWonderImages(BuildContext context) { + debugPrint('Skipping precache, need to figure out why it\'s not working on web.'); + return; precacheImage(AssetImage('images/chichen_itza/chichen.png'), context); precacheImage(AssetImage('images/chichen_itza/foreground-left.png'), context); precacheImage(AssetImage('images/chichen_itza/foreground-right.png'), context); From 91af2b386dcf18a63330f6ea8e8113c854f12863 Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Thu, 27 Mar 2025 09:36:34 -0600 Subject: [PATCH 18/35] Created animate_utils and applied "maybeAnimate" throughout app. --- lib/logic/common/animate_utils.dart | 74 +++++++++++++++++++ lib/styles/styles.dart | 4 +- lib/ui/app_scaffold.dart | 2 +- lib/ui/common/collectible_item.dart | 3 +- .../artifact_carousel_screen.dart | 1 + .../widgets/_bottom_text_content.dart | 2 +- .../artifact_details_screen.dart | 3 +- .../widgets/_info_column.dart | 8 +- .../collectible_found_screen.dart | 15 ++-- .../widgets/_animated_ribbon.dart | 2 +- .../screens/collection/collection_screen.dart | 1 + .../widgets/_collection_footer.dart | 2 +- .../screens/editorial/editorial_screen.dart | 1 + .../screens/editorial/widgets/_app_bar.dart | 2 +- .../widgets/_circular_title_bar.dart | 2 +- .../editorial/widgets/_scrolling_content.dart | 2 +- .../editorial/widgets/_title_text.dart | 6 +- lib/ui/screens/home/wonders_home_screen.dart | 3 +- lib/ui/screens/home_menu/home_menu.dart | 7 +- .../screens/photo_gallery/photo_gallery.dart | 3 +- lib/ui/screens/timeline/timeline_screen.dart | 1 + .../timeline/widgets/_animated_era_text.dart | 2 +- .../timeline/widgets/_scrolling_viewport.dart | 2 +- .../wonder_events/widgets/_events_list.dart | 2 +- .../widgets/_wonder_image_with_timeline.dart | 2 +- .../screens/wonder_events/wonder_events.dart | 1 + 26 files changed, 120 insertions(+), 33 deletions(-) create mode 100644 lib/logic/common/animate_utils.dart diff --git a/lib/logic/common/animate_utils.dart b/lib/logic/common/animate_utils.dart new file mode 100644 index 00000000..140e271d --- /dev/null +++ b/lib/logic/common/animate_utils.dart @@ -0,0 +1,74 @@ +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, + }) { + debugPrint('Do not animate widget: ${$styles.disableAnimations}'); + return $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, + ); + } +} +extension MaybeAnimateListExtension on List { + AnimateList maybeAnimateList({ + List? effects, + AnimateCallback? onInit, + AnimateCallback? onPlay, + AnimateCallback? onComplete, + bool? autoPlay, + Duration? delay, + Duration? interval + }) { + debugPrint('Do not animate list: ${$styles.disableAnimations}'); + return $styles.disableAnimations ? + AnimateList(children: this) : + AnimateList( + effects: effects, + onInit: onInit, + onPlay: onPlay, + onComplete: onComplete, + autoPlay: autoPlay, + delay: delay, + interval: interval, + children: this + ); + } +} + diff --git a/lib/styles/styles.dart b/lib/styles/styles.dart index 03eaf412..5620b838 100644 --- a/lib/styles/styles.dart +++ b/lib/styles/styles.dart @@ -6,7 +6,8 @@ export 'colors.dart'; @immutable class AppStyle { - AppStyle({Size? screenSize}) { + AppStyle({Size? screenSize, bool? disableAnimations}) { + this.disableAnimations = true; // A43 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(); 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..44c4ff9e 100644 --- a/lib/ui/common/collectible_item.dart +++ b/lib/ui/common/collectible_item.dart @@ -1,5 +1,6 @@ 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'; @@ -53,7 +54,7 @@ class CollectibleItem extends StatelessWidget with GetItMixin { fit: BoxFit.contain, ), ) - .animate(onPlay: (controller) => controller.repeat()) + .maybeAnimate(onPlay: (controller) => controller.repeat()) .shimmer(delay: 4000.ms, 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) 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..19b5dc66 100644 --- a/lib/ui/screens/artifact/artifact_details/artifact_details_screen.dart +++ b/lib/ui/screens/artifact/artifact_details/artifact_details_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/artifact_data.dart'; import 'package:wonders/ui/common/compass_divider.dart'; import 'package:wonders/ui/common/controls/app_header.dart'; @@ -85,6 +86,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..766a71f1 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.ms, duration: 600.ms), Gap($styles.insets.xs), ], Semantics( @@ -29,7 +29,7 @@ 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.ms, duration: 600.ms), ), Gap($styles.insets.lg), Animate().toggle( @@ -49,7 +49,7 @@ class _InfoColumn extends StatelessWidget { _InfoRow($strings.artifactDetailsLabelDimension, data.dimension), _InfoRow($strings.artifactDetailsLabelClassification, data.classification), ] - .animate(interval: 100.ms) + .maybeAnimateList(interval: 100.ms) .fadeIn(delay: 600.ms, 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: 1.5.seconds).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..a3f1c25f 100644 --- a/lib/ui/screens/collectible_found/collectible_found_screen.dart +++ b/lib/ui/screens/collectible_found/collectible_found_screen.dart @@ -1,5 +1,6 @@ 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'; @@ -20,7 +21,7 @@ class CollectibleFoundScreen extends StatelessWidget { @override Widget build(BuildContext context) { return RepaintBoundary( - child: _buildIntro(context).animate().swap( + child: _buildIntro(context).maybeAnimate().swap( delay: $styles.times.fast * 3.5, builder: (_, __) => _buildDetail(context), ), @@ -45,7 +46,7 @@ class CollectibleFoundScreen extends StatelessWidget { ), ), ) - .animate() + .maybeAnimate() .scale(begin: Offset(1.5, 1.5), end: Offset(3, 3), curve: Curves.easeInExpo, delay: t, duration: t * 3) .fadeOut(), ) @@ -59,7 +60,7 @@ class CollectibleFoundScreen extends StatelessWidget { AppBackdrop( strength: .5, child: Container(color: $styles.colors.greyStrong.withOpacity(.96)), - ).animate().fadeIn(), + ).maybeAnimate().fadeIn(), /// Particles _CelebrationParticles(fadeMs: (t * 6).inMilliseconds), @@ -95,7 +96,7 @@ class CollectibleFoundScreen extends StatelessWidget { ), ), ), - AppHeader(isTransparent: true).animate().fade(delay: t * 4, duration: t * 2), + AppHeader(isTransparent: true).maybeAnimate().fade(delay: t * 4, duration: t * 2), ]); } @@ -123,7 +124,7 @@ class CollectibleFoundScreen extends StatelessWidget { Duration t = $styles.times.fast; // build an image with animated shadows and scaling return AppImage(image: imageProvider, scale: 1.0) - .animate() + .maybeAnimate() .custom( duration: t * 6, builder: (_, ratio, child) => Container( @@ -149,7 +150,7 @@ class CollectibleFoundScreen extends StatelessWidget { Widget _buildRibbon(BuildContext context) { Duration t = $styles.times.fast; return _AnimatedRibbon($strings.collectibleFoundTitleArtifactDiscovered.toUpperCase()) - .animate() + .maybeAnimate() .scale(begin: Offset(0.3, 0.3), duration: t * 2, curve: Curves.easeOutExpo, alignment: Alignment(0, -1)); } @@ -178,7 +179,7 @@ class CollectibleFoundScreen extends StatelessWidget { text: $strings.collectibleFoundButtonViewCollection, isSecondary: true, onPressed: () => _handleViewCollectionPressed(context), - ).animate().fadeIn(delay: t).move( + ).maybeAnimate().fadeIn(delay: t).move( begin: Offset(0, 50), duration: t, curve: Curves.easeOutCubic, diff --git a/lib/ui/screens/collectible_found/widgets/_animated_ribbon.dart b/lib/ui/screens/collectible_found/widgets/_animated_ribbon.dart index b03c897f..4e645c84 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() + .maybeAnimate() .move(begin: Offset(m * 8, 2), end: Offset(m * 32, 10), duration: 400.ms, curve: Curves.easeOut); } } diff --git a/lib/ui/screens/collection/collection_screen.dart b/lib/ui/screens/collection/collection_screen.dart index 4fb3b942..0f5d2cdb 100644 --- a/lib/ui/screens/collection/collection_screen.dart +++ b/lib/ui/screens/collection/collection_screen.dart @@ -3,6 +3,7 @@ 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'; diff --git a/lib/ui/screens/collection/widgets/_collection_footer.dart b/lib/ui/screens/collection/widgets/_collection_footer.dart index 8e2a6e68..996f2af5 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.ms, curve: Curves.easeOutExpo).custom( builder: (_, m, child) => FractionallySizedBox( alignment: Alignment.centerLeft, widthFactor: m * count / total, diff --git a/lib/ui/screens/editorial/editorial_screen.dart b/lib/ui/screens/editorial/editorial_screen.dart index 073ff240..e0b97b1f 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'; diff --git a/lib/ui/screens/editorial/widgets/_app_bar.dart b/lib/ui/screens/editorial/widgets/_app_bar.dart index 48b5eba2..bacab4fe 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.ms).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..9cd39b1a 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.ms), ), 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.ms), ), Expanded( child: Divider( color: data.type.fgColor, - ).animate().scale(curve: Curves.easeOut, delay: 500.ms), + ).maybeAnimate().scale(curve: Curves.easeOut, delay: 500.ms), ), ], ), diff --git a/lib/ui/screens/home/wonders_home_screen.dart b/lib/ui/screens/home/wonders_home_screen.dart index e1172c43..9051be80 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'; @@ -158,7 +159,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..1ea6b3bb 100644 --- a/lib/ui/screens/home_menu/home_menu.dart +++ b/lib/ui/screens/home_menu/home_menu.dart @@ -1,6 +1,7 @@ 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'; @@ -68,7 +69,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,7 +128,7 @@ 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, curve: Curves.easeOutBack, @@ -147,7 +148,7 @@ class _HomeMenuState extends State { onPressed: () => _handleAboutPressed(context), ), ] - .animate(interval: 50.ms) + .maybeAnimateList(interval: 50.ms) .fade(delay: $styles.times.pageTransition + 50.ms) .slide(begin: Offset(0, .1), curve: Curves.easeOut), ); diff --git a/lib/ui/screens/photo_gallery/photo_gallery.dart b/lib/ui/screens/photo_gallery/photo_gallery.dart index 731288a7..b89751db 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'; @@ -258,7 +259,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..b9c92bca 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'; 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/_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/wonder_events/widgets/_events_list.dart b/lib/ui/screens/wonder_events/widgets/_events_list.dart index 995b39f4..118ccaf9 100644 --- a/lib/ui/screens/wonder_events/widgets/_events_list.dart +++ b/lib/ui/screens/wonder_events/widgets/_events_list.dart @@ -52,7 +52,7 @@ class _EventsListState extends State<_EventsList> { final delay = 100.ms + (100 * listItems.length).ms; listItems.add( TimelineEventCard(year: e.key, text: e.value, darkMode: true) - .animate() + .maybeAnimate() .fade(delay: delay, duration: $styles.times.med * 1.5) .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..ac810174 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'; From e109b8ee64df36b080efac2704a724e688cfc1cd Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Thu, 27 Mar 2025 10:11:28 -0600 Subject: [PATCH 19/35] Reimplemented _Times disabled state and implemented in scroll/page controller animations. --- lib/styles/styles.dart | 14 +++++++++----- .../common/modals/fullscreen_url_img_viewer.dart | 2 +- lib/ui/screens/intro/intro_screen.dart | 2 +- .../widgets/_scrolling_viewport_controller.dart | 2 +- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/lib/styles/styles.dart b/lib/styles/styles.dart index 5620b838..7ec3f643 100644 --- a/lib/styles/styles.dart +++ b/lib/styles/styles.dart @@ -42,7 +42,8 @@ class AppStyle { late final _Text text = _Text(scale); /// Animation Durations - final _Times times = _Times(); + late final _Times times = _Times(disableAnimations); + late final _CustomTime customTime = _CustomTime(disableAnimations); /// Shared sizes late final _Sizes sizes = _Sizes(); @@ -135,10 +136,13 @@ 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(this.disabled); + final bool disabled; + late final Duration fast = Duration(milliseconds: disabled ? 1 : 300); + late final Duration med = Duration(milliseconds: disabled ? 1 : 600); + late final Duration slow = Duration(milliseconds: disabled ? 1 : 900); + late final Duration extraSlow = Duration(milliseconds: disabled ? 1 : 1300); + late final Duration pageTransition = Duration(milliseconds: disabled ? 1 : 200); } @immutable 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/screens/intro/intro_screen.dart b/lib/ui/screens/intro/intro_screen.dart index 2cb8e1ac..cdbb838d 100644 --- a/lib/ui/screens/intro/intro_screen.dart +++ b/lib/ui/screens/intro/intro_screen.dart @@ -60,7 +60,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 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); } }); From 2d32965ae95a3584240a27d1fe7f907b7a2bba7b Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Thu, 27 Mar 2025 10:19:07 -0600 Subject: [PATCH 20/35] Missed a spot. --- lib/styles/styles.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/styles/styles.dart b/lib/styles/styles.dart index 7ec3f643..9c1c7c62 100644 --- a/lib/styles/styles.dart +++ b/lib/styles/styles.dart @@ -43,7 +43,6 @@ class AppStyle { /// Animation Durations late final _Times times = _Times(disableAnimations); - late final _CustomTime customTime = _CustomTime(disableAnimations); /// Shared sizes late final _Sizes sizes = _Sizes(); From 98e1ed87175066d5790f752bf8d48438b8fe4f70 Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Thu, 27 Mar 2025 10:37:34 -0600 Subject: [PATCH 21/35] Simplified maybeAnimate to match list and simplified things. Removed debug stuff. --- lib/logic/common/animate_utils.dart | 75 +++++++++++------------------ lib/styles/styles.dart | 3 +- 2 files changed, 29 insertions(+), 49 deletions(-) diff --git a/lib/logic/common/animate_utils.dart b/lib/logic/common/animate_utils.dart index 140e271d..e8d97a54 100644 --- a/lib/logic/common/animate_utils.dart +++ b/lib/logic/common/animate_utils.dart @@ -1,18 +1,5 @@ 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, @@ -26,25 +13,22 @@ extension MaybeAnimateExtension on Widget { Adapter? adapter, double? target, double? value, - }) { - debugPrint('Do not animate widget: ${$styles.disableAnimations}'); - return $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, - ); - } + }) => $styles.disableAnimations + ? Animate(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, + ); } extension MaybeAnimateListExtension on List { AnimateList maybeAnimateList({ @@ -55,20 +39,17 @@ extension MaybeAnimateListExtension on List { bool? autoPlay, Duration? delay, Duration? interval - }) { - debugPrint('Do not animate list: ${$styles.disableAnimations}'); - return $styles.disableAnimations ? - AnimateList(children: this) : - AnimateList( - effects: effects, - onInit: onInit, - onPlay: onPlay, - onComplete: onComplete, - autoPlay: autoPlay, - delay: delay, - interval: interval, - children: this - ); - } + }) => $styles.disableAnimations ? + AnimateList(children: this) : + AnimateList( + effects: effects, + onInit: onInit, + onPlay: onPlay, + onComplete: onComplete, + autoPlay: autoPlay, + delay: delay, + interval: interval, + children: this + ); } diff --git a/lib/styles/styles.dart b/lib/styles/styles.dart index 9c1c7c62..59fedf07 100644 --- a/lib/styles/styles.dart +++ b/lib/styles/styles.dart @@ -6,8 +6,7 @@ export 'colors.dart'; @immutable class AppStyle { - AppStyle({Size? screenSize, bool? disableAnimations}) { - this.disableAnimations = true; // A43 disableAnimations ?? false; + AppStyle({Size? screenSize, this.disableAnimations = false}) { if (screenSize == null) { scale = 1; return; From a737b5e275545911198234ce41c32eeeda2e6af2 Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Thu, 27 Mar 2025 17:01:19 -0600 Subject: [PATCH 22/35] Trimmed back down to working stuff. --- lib/logic/common/animate_utils.dart | 40 +++++++------------ .../widgets/_info_column.dart | 2 +- lib/ui/screens/home_menu/home_menu.dart | 2 +- 3 files changed, 17 insertions(+), 27 deletions(-) diff --git a/lib/logic/common/animate_utils.dart b/lib/logic/common/animate_utils.dart index e8d97a54..f286e06c 100644 --- a/lib/logic/common/animate_utils.dart +++ b/lib/logic/common/animate_utils.dart @@ -1,5 +1,18 @@ 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, @@ -14,7 +27,7 @@ extension MaybeAnimateExtension on Widget { double? target, double? value, }) => $styles.disableAnimations - ? Animate(child: this) + ? NeverAnimate(child: this) : Animate( key: key, effects: effects, @@ -29,27 +42,4 @@ extension MaybeAnimateExtension on Widget { value: value, child: this, ); -} -extension MaybeAnimateListExtension on List { - AnimateList maybeAnimateList({ - List? effects, - AnimateCallback? onInit, - AnimateCallback? onPlay, - AnimateCallback? onComplete, - bool? autoPlay, - Duration? delay, - Duration? interval - }) => $styles.disableAnimations ? - AnimateList(children: this) : - AnimateList( - effects: effects, - onInit: onInit, - onPlay: onPlay, - onComplete: onComplete, - autoPlay: autoPlay, - delay: delay, - interval: interval, - children: this - ); -} - +} \ No newline at end of file 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 766a71f1..e60a14f2 100644 --- a/lib/ui/screens/artifact/artifact_details/widgets/_info_column.dart +++ b/lib/ui/screens/artifact/artifact_details/widgets/_info_column.dart @@ -49,7 +49,7 @@ class _InfoColumn extends StatelessWidget { _InfoRow($strings.artifactDetailsLabelDimension, data.dimension), _InfoRow($strings.artifactDetailsLabelClassification, data.classification), ] - .maybeAnimateList(interval: 100.ms) + .animate(interval: 100.ms) .fadeIn(delay: 600.ms, duration: $styles.times.med) .slide(begin: Offset(0.2, 0), curve: Curves.easeOut), ], diff --git a/lib/ui/screens/home_menu/home_menu.dart b/lib/ui/screens/home_menu/home_menu.dart index 1ea6b3bb..7901a889 100644 --- a/lib/ui/screens/home_menu/home_menu.dart +++ b/lib/ui/screens/home_menu/home_menu.dart @@ -148,7 +148,7 @@ class _HomeMenuState extends State { onPressed: () => _handleAboutPressed(context), ), ] - .maybeAnimateList(interval: 50.ms) + .animate(interval: 50.ms) .fade(delay: $styles.times.pageTransition + 50.ms) .slide(begin: Offset(0, .1), curve: Curves.easeOut), ); From f6fbfa55c8ea9846fb3dcb591b89bf607b92f2bc Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Fri, 28 Mar 2025 10:41:47 -0600 Subject: [PATCH 23/35] Restored custom time. Added $styles.times to cloud animation. --- lib/styles/styles.dart | 9 +++++++++ lib/ui/wonder_illustrations/common/animated_clouds.dart | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/styles/styles.dart b/lib/styles/styles.dart index 59fedf07..91507f56 100644 --- a/lib/styles/styles.dart +++ b/lib/styles/styles.dart @@ -43,6 +43,9 @@ class AppStyle { /// Animation Durations late final _Times times = _Times(disableAnimations); + // Custom durations / delays + late final _CustomTime customTime = _CustomTime(disableAnimations); + /// Shared sizes late final _Sizes sizes = _Sizes(); } @@ -143,6 +146,12 @@ class _Times { late final Duration pageTransition = Duration(milliseconds: disabled ? 1 : 200); } +class _CustomTime { + _CustomTime(this.disabled); + final bool disabled; + Duration ms(int ms) => Duration(milliseconds: disabled ? 1 : ms); +} + @immutable class _Corners { late final double sm = 4; diff --git a/lib/ui/wonder_illustrations/common/animated_clouds.dart b/lib/ui/wonder_illustrations/common/animated_clouds.dart index ea3ff5f2..368021d2 100644 --- a/lib/ui/wonder_illustrations/common/animated_clouds.dart +++ b/lib/ui/wonder_illustrations/common/animated_clouds.dart @@ -21,7 +21,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: $styles.customTime.ms(1500)); @override void initState() { From cfa0f4794bc3bb32c6ff5fc82bc0604e1d90858e Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Tue, 1 Apr 2025 15:10:20 -0600 Subject: [PATCH 24/35] Created duration_utils to apply a cleaner version of the CustomTime code. --- lib/styles/styles.dart | 25 ++++++------------- lib/ui/common/collectible_item.dart | 3 ++- lib/ui/common/compass_divider.dart | 3 ++- lib/ui/common/utils/duration_utils.dart | 6 +++++ .../artifact_details_screen.dart | 1 + .../widgets/_info_column.dart | 10 ++++---- .../collectible_found_screen.dart | 1 + .../widgets/_animated_ribbon.dart | 2 +- .../screens/collection/collection_screen.dart | 3 ++- .../widgets/_collection_footer.dart | 2 +- .../widgets/_collection_list_card.dart | 2 +- .../screens/editorial/editorial_screen.dart | 1 + .../screens/editorial/widgets/_app_bar.dart | 2 +- .../editorial/widgets/_title_text.dart | 6 ++--- lib/ui/screens/home/wonders_home_screen.dart | 5 ++-- lib/ui/screens/home_menu/home_menu.dart | 7 +++--- lib/ui/screens/intro/intro_screen.dart | 3 ++- lib/ui/screens/timeline/timeline_screen.dart | 1 + .../timeline/widgets/_event_popups.dart | 2 +- .../wonder_events/widgets/_events_list.dart | 2 +- .../screens/wonder_events/wonder_events.dart | 1 + .../common/animated_clouds.dart | 3 ++- 22 files changed, 50 insertions(+), 41 deletions(-) create mode 100644 lib/ui/common/utils/duration_utils.dart diff --git a/lib/styles/styles.dart b/lib/styles/styles.dart index 91507f56..f8b6dd10 100644 --- a/lib/styles/styles.dart +++ b/lib/styles/styles.dart @@ -1,6 +1,7 @@ // 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'; @@ -41,10 +42,7 @@ class AppStyle { late final _Text text = _Text(scale); /// Animation Durations - late final _Times times = _Times(disableAnimations); - - // Custom durations / delays - late final _CustomTime customTime = _CustomTime(disableAnimations); + late final _Times times = _Times(); /// Shared sizes late final _Sizes sizes = _Sizes(); @@ -137,19 +135,12 @@ class _Text { @immutable class _Times { - _Times(this.disabled); - final bool disabled; - late final Duration fast = Duration(milliseconds: disabled ? 1 : 300); - late final Duration med = Duration(milliseconds: disabled ? 1 : 600); - late final Duration slow = Duration(milliseconds: disabled ? 1 : 900); - late final Duration extraSlow = Duration(milliseconds: disabled ? 1 : 1300); - late final Duration pageTransition = Duration(milliseconds: disabled ? 1 : 200); -} - -class _CustomTime { - _CustomTime(this.disabled); - final bool disabled; - Duration ms(int ms) => Duration(milliseconds: disabled ? 1 : ms); + _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/common/collectible_item.dart b/lib/ui/common/collectible_item.dart index 44c4ff9e..7d8f366e 100644 --- a/lib/ui/common/collectible_item.dart +++ b/lib/ui/common/collectible_item.dart @@ -4,6 +4,7 @@ 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 { @@ -55,7 +56,7 @@ class CollectibleItem extends StatelessWidget with GetItMixin { ), ) .maybeAnimate(onPlay: (controller) => controller.repeat()) - .shimmer(delay: 4000.ms, duration: $styles.times.med * 3) + .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/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_details/artifact_details_screen.dart b/lib/ui/screens/artifact/artifact_details/artifact_details_screen.dart index 19b5dc66..006daa8b 100644 --- a/lib/ui/screens/artifact/artifact_details/artifact_details_screen.dart +++ b/lib/ui/screens/artifact/artifact_details/artifact_details_screen.dart @@ -6,6 +6,7 @@ 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'; 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 e60a14f2..b8d14b79 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), - ).maybeAnimate().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, - ).maybeAnimate().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), ], ), diff --git a/lib/ui/screens/collectible_found/collectible_found_screen.dart b/lib/ui/screens/collectible_found/collectible_found_screen.dart index a3f1c25f..18b0dfe2 100644 --- a/lib/ui/screens/collectible_found/collectible_found_screen.dart +++ b/lib/ui/screens/collectible_found/collectible_found_screen.dart @@ -6,6 +6,7 @@ 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'; diff --git a/lib/ui/screens/collectible_found/widgets/_animated_ribbon.dart b/lib/ui/screens/collectible_found/widgets/_animated_ribbon.dart index 4e645c84..2f49b733 100644 --- a/lib/ui/screens/collectible_found/widgets/_animated_ribbon.dart +++ b/lib/ui/screens/collectible_found/widgets/_animated_ribbon.dart @@ -39,6 +39,6 @@ class _AnimatedRibbon extends StatelessWidget { double m = flip ? 1 : -1; return end .maybeAnimate() - .move(begin: Offset(m * 8, 2), end: Offset(m * 32, 10), duration: 400.ms, curve: Curves.easeOut); + .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 0f5d2cdb..fadce9e2 100644 --- a/lib/ui/screens/collection/collection_screen.dart +++ b/lib/ui/screens/collection/collection_screen.dart @@ -9,6 +9,7 @@ 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'; @@ -39,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 996f2af5..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), ), - ).maybeAnimate().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 e0b97b1f..c6eb00f7 100644 --- a/lib/ui/screens/editorial/editorial_screen.dart +++ b/lib/ui/screens/editorial/editorial_screen.dart @@ -24,6 +24,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 bacab4fe..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 { ); }, ), - ).maybeAnimate(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/_title_text.dart b/lib/ui/screens/editorial/widgets/_title_text.dart index 9cd39b1a..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, - ).maybeAnimate().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, - ).maybeAnimate().fade(delay: 100.ms), + ).maybeAnimate().fade(delay: 100.delayMs), ), Expanded( child: Divider( color: data.type.fgColor, - ).maybeAnimate().scale(curve: Curves.easeOut, delay: 500.ms), + ).maybeAnimate().scale(curve: Curves.easeOut, delay: 500.delayMs), ), ], ), diff --git a/lib/ui/screens/home/wonders_home_screen.dart b/lib/ui/screens/home/wonders_home_screen.dart index 9051be80..65b4d43c 100644 --- a/lib/ui/screens/home/wonders_home_screen.dart +++ b/lib/ui/screens/home/wonders_home_screen.dart @@ -9,6 +9,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 +114,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 +124,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(); } diff --git a/lib/ui/screens/home_menu/home_menu.dart b/lib/ui/screens/home_menu/home_menu.dart index 7901a889..2bb3d55c 100644 --- a/lib/ui/screens/home_menu/home_menu.dart +++ b/lib/ui/screens/home_menu/home_menu.dart @@ -8,6 +8,7 @@ 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'; @@ -130,7 +131,7 @@ class _HomeMenuState extends State { return SeparatedColumn( 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: [ @@ -148,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 cdbb838d..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}); @@ -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/timeline/timeline_screen.dart b/lib/ui/screens/timeline/timeline_screen.dart index b9c92bca..589be041 100644 --- a/lib/ui/screens/timeline/timeline_screen.dart +++ b/lib/ui/screens/timeline/timeline_screen.dart @@ -16,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/_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/wonder_events/widgets/_events_list.dart b/lib/ui/screens/wonder_events/widgets/_events_list.dart index 118ccaf9..26032098 100644 --- a/lib/ui/screens/wonder_events/widgets/_events_list.dart +++ b/lib/ui/screens/wonder_events/widgets/_events_list.dart @@ -49,7 +49,7 @@ 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) .maybeAnimate() diff --git a/lib/ui/screens/wonder_events/wonder_events.dart b/lib/ui/screens/wonder_events/wonder_events.dart index ac810174..6deb4a39 100644 --- a/lib/ui/screens/wonder_events/wonder_events.dart +++ b/lib/ui/screens/wonder_events/wonder_events.dart @@ -13,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 368021d2..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: $styles.customTime.ms(1500)); + late final AnimationController _anim = AnimationController(vsync: this, duration: 1500.animateMs); @override void initState() { From 16ffd1b09eb6f3b73a2f417ae90aa2c86595b65f Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Tue, 1 Apr 2025 18:04:53 -0600 Subject: [PATCH 25/35] Additional tweaks. --- .../screens/artifact/artifact_details/widgets/_info_column.dart | 2 +- lib/ui/screens/home/_vertical_swipe_controller.dart | 2 +- lib/ui/screens/wonder_events/widgets/_events_list.dart | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) 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 b8d14b79..f837847e 100644 --- a/lib/ui/screens/artifact/artifact_details/widgets/_info_column.dart +++ b/lib/ui/screens/artifact/artifact_details/widgets/_info_column.dart @@ -58,7 +58,7 @@ class _InfoColumn extends StatelessWidget { Text( $strings.homeMenuAboutMet, style: $styles.text.caption.copyWith(color: $styles.colors.accent2), - ).maybeAnimate(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/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/wonder_events/widgets/_events_list.dart b/lib/ui/screens/wonder_events/widgets/_events_list.dart index 26032098..d27c32d6 100644 --- a/lib/ui/screens/wonder_events/widgets/_events_list.dart +++ b/lib/ui/screens/wonder_events/widgets/_events_list.dart @@ -53,7 +53,7 @@ class _EventsListState extends State<_EventsList> { listItems.add( TimelineEventCard(year: e.key, text: e.value, darkMode: true) .maybeAnimate() - .fade(delay: delay, duration: $styles.times.med * 1.5) + .fade(delay: delay, duration: $styles.times.slow) .slide(begin: Offset(0, 1), curve: Curves.easeOutBack), ); } From 123fafa502d794c1b8393adda17da0be3ada029a Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Wed, 2 Apr 2025 10:57:02 -0600 Subject: [PATCH 26/35] Fixed collectable softlock and quelled animated hero screen. --- .../collectible_found_screen.dart | 16 ++++++++-------- .../common/illustration_piece.dart | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/ui/screens/collectible_found/collectible_found_screen.dart b/lib/ui/screens/collectible_found/collectible_found_screen.dart index 18b0dfe2..7974853c 100644 --- a/lib/ui/screens/collectible_found/collectible_found_screen.dart +++ b/lib/ui/screens/collectible_found/collectible_found_screen.dart @@ -22,8 +22,8 @@ class CollectibleFoundScreen extends StatelessWidget { @override Widget build(BuildContext context) { return RepaintBoundary( - child: _buildIntro(context).maybeAnimate().swap( - delay: $styles.times.fast * 3.5, + child: _buildIntro(context).animate().swap( + delay: 1050.animateMs, builder: (_, __) => _buildDetail(context), ), ); @@ -47,7 +47,7 @@ class CollectibleFoundScreen extends StatelessWidget { ), ), ) - .maybeAnimate() + .animate() .scale(begin: Offset(1.5, 1.5), end: Offset(3, 3), curve: Curves.easeInExpo, delay: t, duration: t * 3) .fadeOut(), ) @@ -61,7 +61,7 @@ class CollectibleFoundScreen extends StatelessWidget { AppBackdrop( strength: .5, child: Container(color: $styles.colors.greyStrong.withOpacity(.96)), - ).maybeAnimate().fadeIn(), + ).animate().fadeIn(), /// Particles _CelebrationParticles(fadeMs: (t * 6).inMilliseconds), @@ -97,7 +97,7 @@ class CollectibleFoundScreen extends StatelessWidget { ), ), ), - AppHeader(isTransparent: true).maybeAnimate().fade(delay: t * 4, duration: t * 2), + AppHeader(isTransparent: true).animate().fade(delay: t * 4, duration: t * 2), ]); } @@ -125,7 +125,7 @@ class CollectibleFoundScreen extends StatelessWidget { Duration t = $styles.times.fast; // build an image with animated shadows and scaling return AppImage(image: imageProvider, scale: 1.0) - .maybeAnimate() + .animate() .custom( duration: t * 6, builder: (_, ratio, child) => Container( @@ -151,7 +151,7 @@ class CollectibleFoundScreen extends StatelessWidget { Widget _buildRibbon(BuildContext context) { Duration t = $styles.times.fast; return _AnimatedRibbon($strings.collectibleFoundTitleArtifactDiscovered.toUpperCase()) - .maybeAnimate() + .animate() .scale(begin: Offset(0.3, 0.3), duration: t * 2, curve: Curves.easeOutExpo, alignment: Alignment(0, -1)); } @@ -180,7 +180,7 @@ class CollectibleFoundScreen extends StatelessWidget { text: $strings.collectibleFoundButtonViewCollection, isSecondary: true, onPressed: () => _handleViewCollectionPressed(context), - ).maybeAnimate().fadeIn(delay: t).move( + ).animate().fadeIn(delay: t).move( begin: Offset(0, 50), duration: t, curve: Curves.easeOutCubic, 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)), ], From 34b881978b0d05bb0a2bd1dae30954b9ddfc7124 Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Wed, 2 Apr 2025 11:27:23 -0600 Subject: [PATCH 27/35] Disabled Cupertino page translations when animations disabled in Router. Also cleaned it a bit. --- lib/router.dart | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) 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, From bf909fe669406d40424c2e45b62e2fbbd3b7f2e2 Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Thu, 3 Apr 2025 11:13:35 -0600 Subject: [PATCH 28/35] Added highContrast bool to styles for future use. --- lib/styles/styles.dart | 3 ++- lib/ui/app_scaffold.dart | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/styles/styles.dart b/lib/styles/styles.dart index f8b6dd10..9c1ada8c 100644 --- a/lib/styles/styles.dart +++ b/lib/styles/styles.dart @@ -7,7 +7,7 @@ export 'colors.dart'; @immutable class AppStyle { - AppStyle({Size? screenSize, this.disableAnimations = false}) { + AppStyle({Size? screenSize, this.disableAnimations = false, this.highContrast = false}) { if (screenSize == null) { scale = 1; return; @@ -26,6 +26,7 @@ class AppStyle { late final double scale; late final bool disableAnimations; + late final bool highContrast; /// The current theme colors for the app final AppColors colors = AppColors(); diff --git a/lib/ui/app_scaffold.dart b/lib/ui/app_scaffold.dart index a795840e..46080d92 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, disableAnimations: mq.disableAnimations); + _style = AppStyle(screenSize: context.sizePx, disableAnimations: mq.disableAnimations, highContrast: mq.highContrast); return KeyedSubtree( key: ValueKey($styles.scale), child: Theme( From a2bccce1d6aded6a717c35aa5db4feec756d4aa8 Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Fri, 4 Apr 2025 13:23:26 -0600 Subject: [PATCH 29/35] Photo Gallery's opacity eases off in high contrast mode. --- lib/ui/screens/photo_gallery/photo_gallery.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ui/screens/photo_gallery/photo_gallery.dart b/lib/ui/screens/photo_gallery/photo_gallery.dart index b89751db..3e611a01 100644 --- a/lib/ui/screens/photo_gallery/photo_gallery.dart +++ b/lib/ui/screens/photo_gallery/photo_gallery.dart @@ -292,7 +292,7 @@ class _PhotoGalleryState extends State { Positioned.fill( child: AnimatedOpacity( duration: $styles.times.med, - opacity: isSelected ? 0 : .7, + opacity: isSelected ? 0 : ($styles.highContrast ? 0.4 : 0.7), child: ColoredBox(color: $styles.colors.black), ), ), From 7afbd2db13a7624734e2e35ccd7582272a03a483 Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Fri, 4 Apr 2025 16:42:23 -0600 Subject: [PATCH 30/35] Added darker accent3 to deal with existing text contrast issues. --- lib/styles/colors.dart | 1 + lib/ui/screens/editorial/widgets/_circular_title_bar.dart | 2 +- lib/ui/screens/editorial/widgets/_large_simple_quote.dart | 4 ++-- lib/ui/screens/editorial/widgets/_scrolling_content.dart | 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/styles/colors.dart b/lib/styles/colors.dart index 428644fc..c8de2dfd 100644 --- a/lib/styles/colors.dart +++ b/lib/styles/colors.dart @@ -7,6 +7,7 @@ class AppColors { /// Common final Color accent1 = Color(0xFFE4935D); final Color accent2 = Color(0xFFBEABA1); + final Color accent3 = Color(0xFFC47642); final Color offWhite = Color(0xFFF8ECE5); final Color caption = const Color(0xFF7D7873); final Color body = const Color(0xFF514F4D); diff --git a/lib/ui/screens/editorial/widgets/_circular_title_bar.dart b/lib/ui/screens/editorial/widgets/_circular_title_bar.dart index ec9b3c17..c22eaf31 100644 --- a/lib/ui/screens/editorial/widgets/_circular_title_bar.dart +++ b/lib/ui/screens/editorial/widgets/_circular_title_bar.dart @@ -133,7 +133,7 @@ class _AnimatedCircleWithTextState extends State<_AnimatedCircleWithText> with S Widget _buildCircularText(String title) { final textStyle = $styles.text.monoTitleFont.copyWith( fontSize: 22 * $styles.scale, - color: $styles.colors.accent1, + color: $styles.colors.accent3, ); return CircularText( position: CircularTextPosition.inside, diff --git a/lib/ui/screens/editorial/widgets/_large_simple_quote.dart b/lib/ui/screens/editorial/widgets/_large_simple_quote.dart index b449ebe8..19a0d4d3 100644 --- a/lib/ui/screens/editorial/widgets/_large_simple_quote.dart +++ b/lib/ui/screens/editorial/widgets/_large_simple_quote.dart @@ -18,7 +18,7 @@ class _LargeSimpleQuote extends StatelessWidget { child: Text( '“', style: $styles.text.quote1.copyWith( - color: $styles.colors.accent1, + color: $styles.colors.accent3, fontSize: 90 * $styles.scale, height: .7, ), @@ -32,7 +32,7 @@ class _LargeSimpleQuote extends StatelessWidget { Gap($styles.insets.md), Text( '- $author', - style: $styles.text.quote2Sub.copyWith(color: $styles.colors.accent1), + style: $styles.text.quote2Sub.copyWith(color: $styles.colors.accent3), ), ], ), diff --git a/lib/ui/screens/editorial/widgets/_scrolling_content.dart b/lib/ui/screens/editorial/widgets/_scrolling_content.dart index cd3d4e05..c4e31f3d 100644 --- a/lib/ui/screens/editorial/widgets/_scrolling_content.dart +++ b/lib/ui/screens/editorial/widgets/_scrolling_content.dart @@ -43,7 +43,7 @@ class _ScrollingContent extends StatelessWidget { dropChar, overflow: TextOverflow.visible, style: $styles.text.dropCase.copyWith( - color: $styles.colors.accent1, + color: $styles.colors.accent3, height: 1, ), ), @@ -52,7 +52,7 @@ class _ScrollingContent extends StatelessWidget { style: $styles.text.body, dropCapPadding: EdgeInsets.only(right: 6), dropCapStyle: $styles.text.dropCase.copyWith( - color: $styles.colors.accent1, + color: $styles.colors.accent3, height: 1, ), ) From 907aad0bde1a910417e2a3f1c042bf7295ecaec2 Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Mon, 7 Apr 2025 09:56:40 -0600 Subject: [PATCH 31/35] Removed GestureBinding call; supposedly not needed. --- lib/ui/common/controls/trackpad_listener.dart | 32 ++++++++----------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/lib/ui/common/controls/trackpad_listener.dart b/lib/ui/common/controls/trackpad_listener.dart index 93e1667c..8dab79be 100644 --- a/lib/ui/common/controls/trackpad_listener.dart +++ b/lib/ui/common/controls/trackpad_listener.dart @@ -1,16 +1,14 @@ -import 'dart:async'; - import 'package:flutter/gestures.dart'; -import 'package:wonders/common_libs.dart'; +import 'package:flutter/material.dart'; class TrackpadListener extends StatefulWidget { - final Widget child; + final Widget? child; final double scrollSensitivity; - final void Function(Offset delta)? onScroll; + final ValueChanged? onScroll; const TrackpadListener({ super.key, - required this.child, + this.child, this.scrollSensitivity = 100, this.onScroll, }); @@ -23,18 +21,16 @@ class _TrackpadListenerState extends State { Offset _scrollOffset = Offset.zero; void _handleTrackpadEvent(PointerSignalEvent event) { - GestureBinding.instance.pointerSignalResolver.register(event, (PointerSignalEvent event) { - // Only handle trackpad events here. - if (event is PointerScrollEvent && event.kind == PointerDeviceKind.trackpad) { - Offset newScroll = _scrollOffset + event.scrollDelta; - newScroll = Offset( - newScroll.dx.clamp(-widget.scrollSensitivity, widget.scrollSensitivity), - newScroll.dy.clamp(-widget.scrollSensitivity, widget.scrollSensitivity), - ); - _scrollOffset = newScroll; - _update(); - } - }); + // Directly process the event here. + if (event is PointerScrollEvent && event.kind == PointerDeviceKind.trackpad) { + Offset newScroll = _scrollOffset + event.scrollDelta; + newScroll = Offset( + newScroll.dx.clamp(-widget.scrollSensitivity, widget.scrollSensitivity), + newScroll.dy.clamp(-widget.scrollSensitivity, widget.scrollSensitivity), + ); + _scrollOffset = newScroll; + _update(); + } } void _update() { From dd031a68bc7f2301d973058681f4f94c96e73d82 Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Mon, 7 Apr 2025 11:03:36 -0600 Subject: [PATCH 32/35] Updated the search bar text and hint colors to be darker. --- .../artifact/artifact_search/widgets/_search_input.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ui/screens/artifact/artifact_search/widgets/_search_input.dart b/lib/ui/screens/artifact/artifact_search/widgets/_search_input.dart index 54044209..238ec7ef 100644 --- a/lib/ui/screens/artifact/artifact_search/widgets/_search_input.dart +++ b/lib/ui/screens/artifact/artifact_search/widgets/_search_input.dart @@ -131,19 +131,19 @@ class _SearchInput extends StatelessWidget { child: Row( children: [ Gap($styles.insets.xs * 1.5), - Icon(Icons.search, color: $styles.colors.caption), + Icon(Icons.search, color: captionColor), Expanded( child: TextField( onSubmitted: onSubmit, controller: textController, focusNode: focusNode, - style: TextStyle(color: captionColor, ), + style: TextStyle(color: $styles.colors.greyStrong), textAlignVertical: TextAlignVertical.top, decoration: InputDecoration( isDense: true, contentPadding: EdgeInsets.all($styles.insets.xs), labelStyle: TextStyle(color: captionColor), - hintStyle: TextStyle(color: captionColor.withOpacity(0.5)), + hintStyle: TextStyle(color: $styles.colors.body), prefixStyle: TextStyle(color: captionColor), focusedBorder: OutlineInputBorder(borderSide: BorderSide.none), enabledBorder: UnderlineInputBorder(borderSide: BorderSide.none), From e7541892f4fd7cb16847ba3ccb86981db76e9f9a Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Mon, 7 Apr 2025 11:34:51 -0600 Subject: [PATCH 33/35] Renamed IgnorePointerWithSemantics and split them to both true and false versions. --- lib/ui/common/controls/buttons.dart | 2 +- lib/ui/common/controls/scroll_decorator.dart | 2 +- lib/ui/common/gradient_container.dart | 32 +++++++++---------- lib/ui/common/ignore_pointer.dart | 26 +++++++++++---- .../widgets/_bottom_text_content.dart | 2 +- .../editorial/widgets/_scrolling_content.dart | 2 +- lib/ui/screens/home/wonders_home_screen.dart | 6 ++-- lib/ui/screens/intro/intro_screen.dart | 2 +- .../widgets/_animated_cutout_overlay.dart | 2 +- .../timeline/widgets/_event_markers.dart | 2 +- .../timeline/widgets/_event_popups.dart | 2 +- .../timeline/widgets/_scrolling_viewport.dart | 2 +- .../timeline/widgets/_timeline_section.dart | 2 +- .../timeline/widgets/_year_markers.dart | 2 +- .../wonder_events/widgets/_events_list.dart | 4 +-- 15 files changed, 51 insertions(+), 39 deletions(-) diff --git a/lib/ui/common/controls/buttons.dart b/lib/ui/common/controls/buttons.dart index ac27907c..8fca67d3 100644 --- a/lib/ui/common/controls/buttons.dart +++ b/lib/ui/common/controls/buttons.dart @@ -155,7 +155,7 @@ class AppBtn extends StatelessWidget { ), if (focus.hasFocus) Positioned.fill( - child: IgnorePointerWithSemantics( + child: IgnorePointerKeepSemantics( child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular($styles.corners.md), diff --git a/lib/ui/common/controls/scroll_decorator.dart b/lib/ui/common/controls/scroll_decorator.dart index c0c124b8..580c11b3 100644 --- a/lib/ui/common/controls/scroll_decorator.dart +++ b/lib/ui/common/controls/scroll_decorator.dart @@ -65,7 +65,7 @@ class ScrollDecorator extends StatefulWidget { bgBuilder = null; fgBuilder = (controller) { final double ratio = controller.hasClients ? min(1, controller.position.extentBefore / 60) : 0; - return IgnorePointerWithSemantics( + return IgnorePointerKeepSemantics( child: Container( height: 24, decoration: BoxDecoration( diff --git a/lib/ui/common/gradient_container.dart b/lib/ui/common/gradient_container.dart index 869adb44..230a822b 100644 --- a/lib/ui/common/gradient_container.dart +++ b/lib/ui/common/gradient_container.dart @@ -24,25 +24,23 @@ class GradientContainer extends StatelessWidget { final BorderRadius? borderRadius; @override - Widget build(BuildContext context) => ExcludeSemantics( - child: IgnorePointerWithSemantics( - child: Container( - width: width, - height: height, - alignment: alignment, - decoration: BoxDecoration( - gradient: LinearGradient( - begin: begin ?? Alignment.centerLeft, - end: end ?? Alignment.centerRight, - colors: colors, - stops: stops, - ), - backgroundBlendMode: blendMode, - borderRadius: borderRadius, + Widget build(BuildContext context) => IgnorePointerAndSemantics( + child: Container( + width: width, + height: height, + alignment: alignment, + decoration: BoxDecoration( + gradient: LinearGradient( + begin: begin ?? Alignment.centerLeft, + end: end ?? Alignment.centerRight, + colors: colors, + stops: stops, ), - child: child, + backgroundBlendMode: blendMode, + borderRadius: borderRadius, ), - ) + child: child, + ), ); } diff --git a/lib/ui/common/ignore_pointer.dart b/lib/ui/common/ignore_pointer.dart index cc27da96..b53ad555 100644 --- a/lib/ui/common/ignore_pointer.dart +++ b/lib/ui/common/ignore_pointer.dart @@ -1,18 +1,32 @@ import 'package:flutter/rendering.dart'; import 'package:wonders/common_libs.dart'; -class IgnorePointerWithSemantics extends SingleChildRenderObjectWidget { - const IgnorePointerWithSemantics({super.key, super.child}); +class IgnorePointerKeepSemantics extends SingleChildRenderObjectWidget { + const IgnorePointerKeepSemantics({super.key, super.child}); @override - RenderIgnorePointerWithSemantics createRenderObject(BuildContext context) { - return RenderIgnorePointerWithSemantics(); + RenderIgnorePointerKeepSemantics createRenderObject(BuildContext context) { + return RenderIgnorePointerKeepSemantics(); } } -class RenderIgnorePointerWithSemantics extends RenderProxyBox { - RenderIgnorePointerWithSemantics(); +class RenderIgnorePointerKeepSemantics extends RenderProxyBox { + RenderIgnorePointerKeepSemantics(); @override bool hitTest(BoxHitTestResult result, { required Offset position }) => false; +} + +class IgnorePointerAndSemantics extends StatelessWidget { + final Widget child; + const IgnorePointerAndSemantics({super.key, required this.child}); + + @override + Widget build(BuildContext context) { + return ExcludeSemantics( + child: IgnorePointer( + child: child + ) + ); + } } \ No newline at end of file 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 ebafe135..cd723c91 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 @@ -26,7 +26,7 @@ class _BottomTextContent extends StatelessWidget { Gap($styles.insets.md), Column( children: [ - IgnorePointerWithSemantics( + IgnorePointerKeepSemantics( child: Semantics( button: true, onIncrease: () => state._handleArtifactTap(_currentPage + 1), diff --git a/lib/ui/screens/editorial/widgets/_scrolling_content.dart b/lib/ui/screens/editorial/widgets/_scrolling_content.dart index c4e31f3d..a08a1b1c 100644 --- a/lib/ui/screens/editorial/widgets/_scrolling_content.dart +++ b/lib/ui/screens/editorial/widgets/_scrolling_content.dart @@ -242,7 +242,7 @@ class _MapsThumbnailState extends State<_MapsThumbnail> { child: Stack( children: [ Positioned.fill(child: ColoredBox(color: Colors.transparent)), - IgnorePointerWithSemantics( + IgnorePointerKeepSemantics( child: GoogleMap( markers: {getMapsMarker(startPos.target)}, zoomControlsEnabled: false, diff --git a/lib/ui/screens/home/wonders_home_screen.dart b/lib/ui/screens/home/wonders_home_screen.dart index 65b4d43c..1ab8309e 100644 --- a/lib/ui/screens/home/wonders_home_screen.dart +++ b/lib/ui/screens/home/wonders_home_screen.dart @@ -213,7 +213,7 @@ class _HomeScreenState extends State with SingleTickerProviderStateM Widget _buildFgAndGradients() { Widget buildSwipeableBgGradient(Color fgColor) { return _swipeController.buildListener(builder: (swipeAmt, isPointerDown, _) { - return IgnorePointerWithSemantics( + return IgnorePointerKeepSemantics( child: FractionallySizedBox( heightFactor: .6, child: Container( @@ -251,7 +251,7 @@ class _HomeScreenState extends State with SingleTickerProviderStateM return Animate( effects: const [FadeEffect()], onPlay: _handleFadeAnimInit, - child: IgnorePointerWithSemantics(child: WonderIllustration(e.type, config: config))); + child: IgnorePointerKeepSemantics(child: WonderIllustration(e.type, config: config))); }); }), @@ -280,7 +280,7 @@ class _HomeScreenState extends State with SingleTickerProviderStateM /// Title Content LightText( - child: IgnorePointerWithSemantics( + child: IgnorePointerKeepSemantics( child: Transform.translate( offset: Offset(0, 30), child: Column( diff --git a/lib/ui/screens/intro/intro_screen.dart b/lib/ui/screens/intro/intro_screen.dart index 3994f1bd..43798a57 100644 --- a/lib/ui/screens/intro/intro_screen.dart +++ b/lib/ui/screens/intro/intro_screen.dart @@ -114,7 +114,7 @@ class _IntroScreenState extends State { ), ), - IgnorePointerWithSemantics( + IgnorePointerKeepSemantics( child: Column(children: [ Spacer(), diff --git a/lib/ui/screens/photo_gallery/widgets/_animated_cutout_overlay.dart b/lib/ui/screens/photo_gallery/widgets/_animated_cutout_overlay.dart index 9f918d51..572dea45 100644 --- a/lib/ui/screens/photo_gallery/widgets/_animated_cutout_overlay.dart +++ b/lib/ui/screens/photo_gallery/widgets/_animated_cutout_overlay.dart @@ -31,7 +31,7 @@ class _AnimatedCutoutOverlay extends StatelessWidget { effects: [CustomEffect(builder: _buildAnimatedCutout, curve: Curves.easeOut, duration: duration)], key: animationKey, onComplete: (c) => c.reverse(), - child: IgnorePointerWithSemantics(child: Container(color: Colors.black.withOpacity(opacity))), + child: IgnorePointerKeepSemantics(child: Container(color: Colors.black.withOpacity(opacity))), ), ], ); diff --git a/lib/ui/screens/timeline/widgets/_event_markers.dart b/lib/ui/screens/timeline/widgets/_event_markers.dart index b9107b0e..5f0c2a0b 100644 --- a/lib/ui/screens/timeline/widgets/_event_markers.dart +++ b/lib/ui/screens/timeline/widgets/_event_markers.dart @@ -54,7 +54,7 @@ class _EventMarkersState extends State<_EventMarkers> { @override Widget build(BuildContext context) { - return IgnorePointerWithSemantics( + return IgnorePointerKeepSemantics( child: LayoutBuilder(builder: (_, constraints) { /// Figure out which event is "selected" _updateSelectedEvent(constraints.maxHeight); diff --git a/lib/ui/screens/timeline/widgets/_event_popups.dart b/lib/ui/screens/timeline/widgets/_event_popups.dart index 71d03682..d09fed11 100644 --- a/lib/ui/screens/timeline/widgets/_event_popups.dart +++ b/lib/ui/screens/timeline/widgets/_event_popups.dart @@ -35,7 +35,7 @@ class _EventPopupsState extends State<_EventPopups> { final evt = _eventToShow; return TopCenter( child: ClipRect( - child: IgnorePointerWithSemantics( + child: IgnorePointerKeepSemantics( child: AnimatedSwitcher( duration: $styles.times.fast, child: evt == null diff --git a/lib/ui/screens/timeline/widgets/_scrolling_viewport.dart b/lib/ui/screens/timeline/widgets/_scrolling_viewport.dart index eaabbffd..802b9f34 100644 --- a/lib/ui/screens/timeline/widgets/_scrolling_viewport.dart +++ b/lib/ui/screens/timeline/widgets/_scrolling_viewport.dart @@ -69,7 +69,7 @@ class _ScalingViewportState extends State<_ScrollingViewport> { _buildScrollingArea(context).maybeAnimate().fadeIn(), // Dashed line with a year that changes as we scroll - IgnorePointerWithSemantics( + IgnorePointerKeepSemantics( child: AnimatedBuilder( animation: controller.scroller, builder: (_, __) { diff --git a/lib/ui/screens/timeline/widgets/_timeline_section.dart b/lib/ui/screens/timeline/widgets/_timeline_section.dart index c6acb68b..ef6c53ef 100644 --- a/lib/ui/screens/timeline/widgets/_timeline_section.dart +++ b/lib/ui/screens/timeline/widgets/_timeline_section.dart @@ -20,7 +20,7 @@ class TimelineSection extends StatelessWidget { StringUtils.formatYr(data.startYr), StringUtils.formatYr(data.endYr), )}', - child: IgnorePointerWithSemantics( + child: IgnorePointerKeepSemantics( child: Container( alignment: Alignment(0, -1 + fraction * 2), padding: EdgeInsets.all($styles.insets.xs), diff --git a/lib/ui/screens/timeline/widgets/_year_markers.dart b/lib/ui/screens/timeline/widgets/_year_markers.dart index 2d34f98a..8468fe8e 100644 --- a/lib/ui/screens/timeline/widgets/_year_markers.dart +++ b/lib/ui/screens/timeline/widgets/_year_markers.dart @@ -13,7 +13,7 @@ class _YearMarkers extends StatelessWidget { @override Widget build(BuildContext context) { - return IgnorePointerWithSemantics( + return IgnorePointerKeepSemantics( child: LayoutBuilder(builder: (_, constraints) { int interval = 100; if (constraints.maxHeight < 800) { diff --git a/lib/ui/screens/wonder_events/widgets/_events_list.dart b/lib/ui/screens/wonder_events/widgets/_events_list.dart index d27c32d6..4b8f8205 100644 --- a/lib/ui/screens/wonder_events/widgets/_events_list.dart +++ b/lib/ui/screens/wonder_events/widgets/_events_list.dart @@ -64,7 +64,7 @@ class _EventsListState extends State<_EventsList> { key: PageStorageKey('eventsList'), child: Column( children: [ - IgnorePointerWithSemantics(child: Gap(widget.topHeight)), + IgnorePointerKeepSemantics(child: Gap(widget.topHeight)), Container( decoration: BoxDecoration( color: $styles.colors.black, @@ -120,7 +120,7 @@ class _EventsListState extends State<_EventsList> { if (showBackdrop) ...[ AppBackdrop( strength: backdropAmt, - child: IgnorePointerWithSemantics( + child: IgnorePointerKeepSemantics( child: Container( color: $styles.colors.black.withOpacity(backdropAmt * .6), ), From 6095ff3337e47aec118f4add91b16a38116528fb Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Mon, 7 Apr 2025 14:45:03 -0600 Subject: [PATCH 34/35] IgnorePointer's ignoringSemantics defaulted to true, so swapped out all things (without readable children) to IgnorePointerAndSemantics. Left the ones that were set to false. --- lib/ui/common/controls/buttons.dart | 2 +- lib/ui/common/controls/scroll_decorator.dart | 2 +- lib/ui/screens/editorial/widgets/_scrolling_content.dart | 2 +- lib/ui/screens/home/wonders_home_screen.dart | 4 ++-- .../photo_gallery/widgets/_animated_cutout_overlay.dart | 2 +- lib/ui/screens/wonder_events/widgets/_events_list.dart | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/ui/common/controls/buttons.dart b/lib/ui/common/controls/buttons.dart index 8fca67d3..587da2ab 100644 --- a/lib/ui/common/controls/buttons.dart +++ b/lib/ui/common/controls/buttons.dart @@ -155,7 +155,7 @@ class AppBtn extends StatelessWidget { ), if (focus.hasFocus) Positioned.fill( - child: IgnorePointerKeepSemantics( + child: IgnorePointerAndSemantics( child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular($styles.corners.md), diff --git a/lib/ui/common/controls/scroll_decorator.dart b/lib/ui/common/controls/scroll_decorator.dart index 580c11b3..fd80aeeb 100644 --- a/lib/ui/common/controls/scroll_decorator.dart +++ b/lib/ui/common/controls/scroll_decorator.dart @@ -65,7 +65,7 @@ class ScrollDecorator extends StatefulWidget { bgBuilder = null; fgBuilder = (controller) { final double ratio = controller.hasClients ? min(1, controller.position.extentBefore / 60) : 0; - return IgnorePointerKeepSemantics( + return IgnorePointerAndSemantics( child: Container( height: 24, decoration: BoxDecoration( diff --git a/lib/ui/screens/editorial/widgets/_scrolling_content.dart b/lib/ui/screens/editorial/widgets/_scrolling_content.dart index a08a1b1c..455c628a 100644 --- a/lib/ui/screens/editorial/widgets/_scrolling_content.dart +++ b/lib/ui/screens/editorial/widgets/_scrolling_content.dart @@ -242,7 +242,7 @@ class _MapsThumbnailState extends State<_MapsThumbnail> { child: Stack( children: [ Positioned.fill(child: ColoredBox(color: Colors.transparent)), - IgnorePointerKeepSemantics( + IgnorePointerAndSemantics( child: GoogleMap( markers: {getMapsMarker(startPos.target)}, zoomControlsEnabled: false, diff --git a/lib/ui/screens/home/wonders_home_screen.dart b/lib/ui/screens/home/wonders_home_screen.dart index 105c65aa..a489eb65 100644 --- a/lib/ui/screens/home/wonders_home_screen.dart +++ b/lib/ui/screens/home/wonders_home_screen.dart @@ -224,7 +224,7 @@ class _HomeScreenState extends State with SingleTickerProviderStateM Widget _buildFgAndGradients() { Widget buildSwipeableBgGradient(Color fgColor) { return _swipeController.buildListener(builder: (swipeAmt, isPointerDown, _) { - return IgnorePointerKeepSemantics( + return IgnorePointerAndSemantics( child: FractionallySizedBox( heightFactor: .6, child: Container( @@ -262,7 +262,7 @@ class _HomeScreenState extends State with SingleTickerProviderStateM return Animate( effects: const [FadeEffect()], onPlay: _handleFadeAnimInit, - child: IgnorePointerKeepSemantics(child: WonderIllustration(e.type, config: config))); + child: IgnorePointerAndSemantics(child: WonderIllustration(e.type, config: config))); }); }), diff --git a/lib/ui/screens/photo_gallery/widgets/_animated_cutout_overlay.dart b/lib/ui/screens/photo_gallery/widgets/_animated_cutout_overlay.dart index 572dea45..69c95a10 100644 --- a/lib/ui/screens/photo_gallery/widgets/_animated_cutout_overlay.dart +++ b/lib/ui/screens/photo_gallery/widgets/_animated_cutout_overlay.dart @@ -31,7 +31,7 @@ class _AnimatedCutoutOverlay extends StatelessWidget { effects: [CustomEffect(builder: _buildAnimatedCutout, curve: Curves.easeOut, duration: duration)], key: animationKey, onComplete: (c) => c.reverse(), - child: IgnorePointerKeepSemantics(child: Container(color: Colors.black.withOpacity(opacity))), + child: IgnorePointerAndSemantics(child: Container(color: Colors.black.withOpacity(opacity))), ), ], ); diff --git a/lib/ui/screens/wonder_events/widgets/_events_list.dart b/lib/ui/screens/wonder_events/widgets/_events_list.dart index 4b8f8205..fca45509 100644 --- a/lib/ui/screens/wonder_events/widgets/_events_list.dart +++ b/lib/ui/screens/wonder_events/widgets/_events_list.dart @@ -64,7 +64,7 @@ class _EventsListState extends State<_EventsList> { key: PageStorageKey('eventsList'), child: Column( children: [ - IgnorePointerKeepSemantics(child: Gap(widget.topHeight)), + IgnorePointerAndSemantics(child: Gap(widget.topHeight)), Container( decoration: BoxDecoration( color: $styles.colors.black, @@ -120,7 +120,7 @@ class _EventsListState extends State<_EventsList> { if (showBackdrop) ...[ AppBackdrop( strength: backdropAmt, - child: IgnorePointerKeepSemantics( + child: IgnorePointerAndSemantics( child: Container( color: $styles.colors.black.withOpacity(backdropAmt * .6), ), From 4512eb7a58000b930b43ab2c9e2115f7a02f48a8 Mon Sep 17 00:00:00 2001 From: Alex Garneau Date: Tue, 8 Apr 2025 14:49:40 -0600 Subject: [PATCH 35/35] Revised some of the IgnorePointers so they're the bare-bones version. --- lib/ui/common/gradient_container.dart | 2 +- lib/ui/screens/editorial/widgets/_scrolling_content.dart | 2 +- .../photo_gallery/widgets/_animated_cutout_overlay.dart | 2 +- lib/ui/screens/wonder_events/widgets/_events_list.dart | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/ui/common/gradient_container.dart b/lib/ui/common/gradient_container.dart index 230a822b..31d85825 100644 --- a/lib/ui/common/gradient_container.dart +++ b/lib/ui/common/gradient_container.dart @@ -24,7 +24,7 @@ class GradientContainer extends StatelessWidget { final BorderRadius? borderRadius; @override - Widget build(BuildContext context) => IgnorePointerAndSemantics( + Widget build(BuildContext context) => IgnorePointer( child: Container( width: width, height: height, diff --git a/lib/ui/screens/editorial/widgets/_scrolling_content.dart b/lib/ui/screens/editorial/widgets/_scrolling_content.dart index 455c628a..4f6438ea 100644 --- a/lib/ui/screens/editorial/widgets/_scrolling_content.dart +++ b/lib/ui/screens/editorial/widgets/_scrolling_content.dart @@ -242,7 +242,7 @@ class _MapsThumbnailState extends State<_MapsThumbnail> { child: Stack( children: [ Positioned.fill(child: ColoredBox(color: Colors.transparent)), - IgnorePointerAndSemantics( + IgnorePointer( child: GoogleMap( markers: {getMapsMarker(startPos.target)}, zoomControlsEnabled: false, diff --git a/lib/ui/screens/photo_gallery/widgets/_animated_cutout_overlay.dart b/lib/ui/screens/photo_gallery/widgets/_animated_cutout_overlay.dart index 69c95a10..2b0e70ef 100644 --- a/lib/ui/screens/photo_gallery/widgets/_animated_cutout_overlay.dart +++ b/lib/ui/screens/photo_gallery/widgets/_animated_cutout_overlay.dart @@ -31,7 +31,7 @@ class _AnimatedCutoutOverlay extends StatelessWidget { effects: [CustomEffect(builder: _buildAnimatedCutout, curve: Curves.easeOut, duration: duration)], key: animationKey, onComplete: (c) => c.reverse(), - child: IgnorePointerAndSemantics(child: Container(color: Colors.black.withOpacity(opacity))), + child: IgnorePointer(child: Container(color: Colors.black.withOpacity(opacity))), ), ], ); diff --git a/lib/ui/screens/wonder_events/widgets/_events_list.dart b/lib/ui/screens/wonder_events/widgets/_events_list.dart index fca45509..b37a1bf9 100644 --- a/lib/ui/screens/wonder_events/widgets/_events_list.dart +++ b/lib/ui/screens/wonder_events/widgets/_events_list.dart @@ -64,7 +64,7 @@ class _EventsListState extends State<_EventsList> { key: PageStorageKey('eventsList'), child: Column( children: [ - IgnorePointerAndSemantics(child: Gap(widget.topHeight)), + IgnorePointer(child: Gap(widget.topHeight)), Container( decoration: BoxDecoration( color: $styles.colors.black, @@ -120,7 +120,7 @@ class _EventsListState extends State<_EventsList> { if (showBackdrop) ...[ AppBackdrop( strength: backdropAmt, - child: IgnorePointerAndSemantics( + child: IgnorePointer( child: Container( color: $styles.colors.black.withOpacity(backdropAmt * .6), ),