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 63d976b9..14583f32 100644 --- a/lib/ui/screens/artifact/artifact_carousel/artifact_carousel_screen.dart +++ b/lib/ui/screens/artifact/artifact_carousel/artifact_carousel_screen.dart @@ -12,8 +12,9 @@ part 'widgets/_bottom_text_content.dart'; part 'widgets/_collapsing_carousel_item.dart'; class ArtifactCarouselScreen extends StatefulWidget { + const ArtifactCarouselScreen({Key? key, required this.type, this.contentPadding = EdgeInsets.zero}) : super(key: key); final WonderType type; - const ArtifactCarouselScreen({Key? key, required this.type}) : super(key: key); + final EdgeInsets contentPadding; @override State createState() => _ArtifactScreenState(); @@ -82,55 +83,61 @@ class _ArtifactScreenState extends State { }), ), - /// BgCircle - _buildBgCircle(bottomHeight), + Padding( + padding: widget.contentPadding, + child: Stack( + children: [ + /// BgCircle + _buildBgCircle(bottomHeight), - /// Carousel Items - PageView.builder( - controller: _pageController, - itemBuilder: (_, index) { - final wrappedIndex = index % pages.length; - final child = pages[wrappedIndex]; - return ValueListenableBuilder( - valueListenable: _currentPage, - builder: (_, value, __) { - final int offset = (value.round() - index).abs(); - return _CollapsingCarouselItem( - width: itemWidth, - indexOffset: min(3, offset), - onPressed: () => _handleArtifactTap(index), - title: _artifacts[wrappedIndex].title, - child: child, - ); - }, - ); - }, - ), + /// Carousel Items + PageView.builder( + controller: _pageController, + itemBuilder: (_, index) { + final wrappedIndex = index % pages.length; + final child = pages[wrappedIndex]; + return ValueListenableBuilder( + valueListenable: _currentPage, + builder: (_, value, __) { + final int offset = (value.round() - index).abs(); + return _CollapsingCarouselItem( + width: itemWidth, + indexOffset: min(3, offset), + onPressed: () => _handleArtifactTap(index), + title: _artifacts[wrappedIndex].title, + child: child, + ); + }, + ); + }, + ), - /// Bottom Text - BottomCenter( - child: ValueListenableBuilder( - valueListenable: _currentArtifactIndex, - builder: (_, value, __) => _BottomTextContent( - artifact: _artifacts[value], - height: bottomHeight, - shortMode: shortMode, - state: this, - ), - ), - ), + /// Bottom Text + BottomCenter( + child: ValueListenableBuilder( + valueListenable: _currentArtifactIndex, + builder: (_, value, __) => _BottomTextContent( + artifact: _artifacts[value], + height: bottomHeight, + shortMode: shortMode, + state: this, + ), + ), + ), - /// Header - AppHeader( - title: $strings.artifactsTitleArtifacts, - showBackBtn: false, - isTransparent: true, - trailing: (context) => CircleBtn( - semanticLabel: $strings.artifactsButtonBrowse, - onPressed: _handleSearchTap, - child: AppIcon(AppIcons.search), - ), - ), + /// Header + AppHeader( + title: $strings.artifactsTitleArtifacts, + showBackBtn: false, + isTransparent: true, + trailing: (context) => CircleBtn( + semanticLabel: $strings.artifactsButtonBrowse, + onPressed: _handleSearchTap, + child: AppIcon(AppIcons.search), + ), + ), + ], + )) ], ); } diff --git a/lib/ui/screens/editorial/editorial_screen.dart b/lib/ui/screens/editorial/editorial_screen.dart index b9f45e84..b2f342e2 100644 --- a/lib/ui/screens/editorial/editorial_screen.dart +++ b/lib/ui/screens/editorial/editorial_screen.dart @@ -38,9 +38,11 @@ part 'widgets/_title_text.dart'; part 'widgets/_top_illustration.dart'; class WonderEditorialScreen extends StatefulWidget { - const WonderEditorialScreen(this.data, {Key? key, required this.onScroll}) : super(key: key); + const WonderEditorialScreen(this.data, {Key? key, required this.onScroll, required this.contentPadding}) + : super(key: key); final WonderData data; final void Function(double scrollPos) onScroll; + final EdgeInsets contentPadding; @override State createState() => _WonderEditorialScreenState(); @@ -95,62 +97,71 @@ class _WonderEditorialScreenState extends State { 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)), + 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), + )), ), ), /// Scrolling content - Includes an invisible gap at the top, and then scrolls over the illustration TopCenter( - child: SizedBox( - child: FocusTraversalGroup( - child: CustomScrollView( - primary: false, - 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), - ), - - /// 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), + child: Padding( + padding: widget.contentPadding, + child: SizedBox( + child: FocusTraversalGroup( + child: CustomScrollView( + primary: false, + 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), + ], + ), ), ), ), diff --git a/lib/ui/screens/editorial/widgets/_top_illustration.dart b/lib/ui/screens/editorial/widgets/_top_illustration.dart index 2f59a197..0be48094 100644 --- a/lib/ui/screens/editorial/widgets/_top_illustration.dart +++ b/lib/ui/screens/editorial/widgets/_top_illustration.dart @@ -1,8 +1,9 @@ part of '../editorial_screen.dart'; class _TopIllustration extends StatelessWidget { - const _TopIllustration(this.type, {Key? key}) : super(key: key); + const _TopIllustration(this.type, {Key? key, this.fgOffset = Offset.zero}) : super(key: key); final WonderType type; + final Offset fgOffset; @override Widget build(BuildContext context) { @@ -11,7 +12,7 @@ class _TopIllustration extends StatelessWidget { WonderIllustration(type, config: WonderIllustrationConfig.bg(enableAnims: false, shortMode: true)), Transform.translate( // Small bump down to make sure we cover the edge between the editorial page and the sky. - offset: Offset(0, 10), + offset: fgOffset + Offset(0, 10), child: WonderIllustration( type, config: WonderIllustrationConfig.mg(enableAnims: false, shortMode: true), diff --git a/lib/ui/screens/wonder_details/wonder_details_tab_menu.dart b/lib/ui/screens/wonder_details/wonder_details_tab_menu.dart index 537a8319..4a3c79a9 100644 --- a/lib/ui/screens/wonder_details/wonder_details_tab_menu.dart +++ b/lib/ui/screens/wonder_details/wonder_details_tab_menu.dart @@ -36,7 +36,12 @@ class WonderDetailsTabMenu extends StatelessWidget { top: isVertical ? context.mq.viewPadding.top : buttonInset, right: isVertical ? buttonInset : 0, ), - child: ColoredBox(color: $styles.colors.offWhite), + child: Container( + decoration: BoxDecoration( + color: $styles.colors.offWhite, + borderRadius: isVertical ? BorderRadius.only(topRight: Radius.circular(32)) : null, + ), + ), ), ), ), diff --git a/lib/ui/screens/wonder_details/wonders_details_screen.dart b/lib/ui/screens/wonder_details/wonders_details_screen.dart index d3660777..2abe0c49 100644 --- a/lib/ui/screens/wonder_details/wonders_details_screen.dart +++ b/lib/ui/screens/wonder_details/wonders_details_screen.dart @@ -57,7 +57,6 @@ class _WonderDetailsScreenState extends State bool showTabBarBg = tabIndex != 1; final tabBarSize = _tabBarSize ?? 0; final menuPadding = _useNavRail ? EdgeInsets.only(left: tabBarSize) : EdgeInsets.only(bottom: tabBarSize); - return ColoredBox( color: Colors.black, child: Stack( @@ -66,19 +65,10 @@ class _WonderDetailsScreenState extends State LazyIndexedStack( index: _tabController.index, children: [ - Padding( - padding: menuPadding, - child: WonderEditorialScreen(wonder, onScroll: _handleDetailsScrolled), - ), + WonderEditorialScreen(wonder, contentPadding: menuPadding, onScroll: _handleDetailsScrolled), PhotoGallery(collectionId: wonder.unsplashCollectionId, wonderType: wonder.type), - Padding( - padding: menuPadding, - child: ArtifactCarouselScreen(type: wonder.type), - ), - Padding( - padding: menuPadding, - child: WonderEvents(type: widget.type), - ), + ArtifactCarouselScreen(type: wonder.type, contentPadding: menuPadding), + WonderEvents(type: widget.type, contentPadding: menuPadding), ], ), diff --git a/lib/ui/screens/wonder_events/wonder_events.dart b/lib/ui/screens/wonder_events/wonder_events.dart index 17a64582..ace39e62 100644 --- a/lib/ui/screens/wonder_events/wonder_events.dart +++ b/lib/ui/screens/wonder_events/wonder_events.dart @@ -19,9 +19,9 @@ part 'widgets/_timeline_btn.dart'; part 'widgets/_wonder_image_with_timeline.dart'; class WonderEvents extends StatefulWidget { - const WonderEvents({Key? key, required this.type}) : super(key: key); + const WonderEvents({Key? key, required this.type, this.contentPadding = EdgeInsets.zero}) : super(key: key); final WonderType type; - + final EdgeInsets contentPadding; @override State createState() => _WonderEventsState(); } @@ -51,7 +51,10 @@ class _WonderEventsState extends State { /// Main view Positioned.fill( top: $styles.insets.sm, - child: useTwoColumnLayout ? _buildTwoColumn(context) : _buildSingleColumn(), + child: Padding( + padding: widget.contentPadding, + child: useTwoColumnLayout ? _buildTwoColumn(context) : _buildSingleColumn(), + ), ), /// Header w/ TimelineBtn