Polish editorial screen

This commit is contained in:
Shawn 2022-11-30 13:30:56 -07:00
parent fd0a044a8f
commit bd3a87edd9
8 changed files with 157 additions and 163 deletions

View File

@ -39,7 +39,7 @@ class ArchPoint {
} }
List<ArchPoint> _getArchPts(Size size, ArchType type) { List<ArchPoint> _getArchPts(Size size, ArchType type) {
double distanceFromTop = 100; double distanceFromTop = size.width / 3;
switch (type) { switch (type) {
case ArchType.pyramid: case ArchType.pyramid:
return [ return [
@ -60,19 +60,19 @@ List<ArchPoint> _getArchPts(Size size, ArchType type) {
case ArchType.arch: case ArchType.arch:
return [ return [
ArchPoint(Offset(0, size.height)), ArchPoint(Offset(0, size.height)),
ArchPoint(Offset(0, distanceFromTop * 2)), ArchPoint(Offset(0, size.width / 2)),
ArchPoint(Offset(size.width / 2, 0), Offset(0, 0)), ArchPoint(Offset(size.width / 2, 0), Offset(0, 0)),
ArchPoint(Offset(size.width, distanceFromTop * 2), Offset(size.width, 0)), ArchPoint(Offset(size.width, size.width / 2), Offset(size.width, 0)),
ArchPoint(Offset(size.width, size.height)), ArchPoint(Offset(size.width, size.height)),
]; ];
case ArchType.wideArch: case ArchType.wideArch:
return [ return [
ArchPoint(Offset(0, size.height)), ArchPoint(Offset(0, size.height)),
ArchPoint(Offset(0, distanceFromTop * 2)), ArchPoint(Offset(0, size.width / 2)),
ArchPoint(Offset(0, distanceFromTop)), ArchPoint(Offset(0, distanceFromTop)),
ArchPoint(Offset(size.width / 2, 0), Offset(0, 0)), ArchPoint(Offset(size.width / 2, 0), Offset(0, 0)),
ArchPoint(Offset(size.width, distanceFromTop), Offset(size.width, 0)), ArchPoint(Offset(size.width, distanceFromTop), Offset(size.width, 0)),
ArchPoint(Offset(size.width, distanceFromTop * 2)), ArchPoint(Offset(size.width, size.width / 2)),
ArchPoint(Offset(size.width, size.height)), ArchPoint(Offset(size.width, size.height)),
]; ];
case ArchType.flatPyramid: case ArchType.flatPyramid:

View File

@ -160,7 +160,6 @@ class CollectibleFoundScreen extends StatelessWidget {
return AppBtn.from( return AppBtn.from(
text: $strings.collectibleFoundButtonViewCollection, text: $strings.collectibleFoundButtonViewCollection,
isSecondary: true, isSecondary: true,
expand: true,
onPressed: () => _handleViewCollectionPressed(context), onPressed: () => _handleViewCollectionPressed(context),
) )
.animate() .animate()

View File

@ -5,6 +5,7 @@ import 'package:flutter/rendering.dart';
import 'package:flutter_circular_text/circular_text.dart'; import 'package:flutter_circular_text/circular_text.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:wonders/common_libs.dart'; import 'package:wonders/common_libs.dart';
import 'package:wonders/logic/common/platform_info.dart';
import 'package:wonders/logic/common/string_utils.dart'; import 'package:wonders/logic/common/string_utils.dart';
import 'package:wonders/logic/data/wonder_data.dart'; import 'package:wonders/logic/data/wonder_data.dart';
import 'package:wonders/ui/common/app_icons.dart'; import 'package:wonders/ui/common/app_icons.dart';
@ -72,7 +73,9 @@ class _WonderEditorialScreenState extends State<WonderEditorialScreen> {
bool shortMode = constraints.biggest.height < 700; bool shortMode = constraints.biggest.height < 700;
double illustrationHeight = shortMode ? 250 : 280; double illustrationHeight = shortMode ? 250 : 280;
double minAppBarHeight = shortMode ? 80 : 120; double minAppBarHeight = shortMode ? 80 : 120;
double maxAppBarHeight = shortMode ? 400 : 500;
/// Attempt to maintain a similar aspect ratio for the image within the app-bar
double maxAppBarHeight = min(context.widthPx, $styles.sizes.maxContentWidth1) * 1.5;
return PopRouterOnOverScroll( return PopRouterOnOverScroll(
controller: _scroller, controller: _scroller,
@ -82,16 +85,7 @@ class _WonderEditorialScreenState extends State<WonderEditorialScreen> {
children: [ children: [
/// Background /// Background
Positioned.fill( Positioned.fill(
child: ValueListenableBuilder<double>( child: ColoredBox(color: widget.data.type.bgColor),
valueListenable: _scrollPos,
builder: (_, value, __) {
bool showBg = value < 700;
return AnimatedContainer(
duration: $styles.times.fast,
color: widget.data.type.bgColor.withOpacity(showBg ? 1 : 0),
);
},
),
), ),
/// Top Illustration - Sits underneath the scrolling content, fades out as it scrolls /// Top Illustration - Sits underneath the scrolling content, fades out as it scrolls
@ -112,7 +106,7 @@ class _WonderEditorialScreenState extends State<WonderEditorialScreen> {
/// Scrolling content - Includes an invisible gap at the top, and then scrolls over the illustration /// Scrolling content - Includes an invisible gap at the top, and then scrolls over the illustration
TopCenter( TopCenter(
child: SizedBox( child: SizedBox(
width: $styles.sizes.maxContentWidth1, //width: $styles.sizes.maxContentWidth1,
child: CustomScrollView( child: CustomScrollView(
primary: false, primary: false,
controller: _scroller, controller: _scroller,

View File

@ -47,28 +47,33 @@ class _AppBar extends StatelessWidget {
fit: StackFit.expand, fit: StackFit.expand,
children: [ children: [
AnimatedSwitcher( AnimatedSwitcher(
duration: $styles.times.fast * .5, duration: $styles.times.med,
child: Stack( child: Stack(
key: ValueKey(showOverlay), key: ValueKey(showOverlay),
fit: StackFit.expand, fit: StackFit.expand,
children: [ children: [
/// Masked image /// Masked image
ClipPath( Center(
// Switch arch type to Rect if we are showing the title bar child: SizedBox(
clipper: showOverlay ? null : ArchClipper(arch), width: showOverlay ? double.infinity : $styles.sizes.maxContentWidth1,
child: ValueListenableBuilder<double>( child: ClipPath(
valueListenable: scrollPos, // Switch arch type to Rect if we are showing the title bar
builder: (_, value, child) { clipper: showOverlay ? null : ArchClipper(arch),
double opacity = (.4 + (value / 1500)).clamp(0, 1); child: ValueListenableBuilder<double>(
return ScalingListItem( valueListenable: scrollPos,
scrollPos: scrollPos, builder: (_, value, child) {
child: Image.asset( double opacity = (.4 + (value / 1500)).clamp(0, 1);
wonderType.photo1, return ScalingListItem(
fit: BoxFit.cover, scrollPos: scrollPos,
opacity: AlwaysStoppedAnimation(opacity), child: Image.asset(
), wonderType.photo1,
); fit: BoxFit.cover,
}, opacity: AlwaysStoppedAnimation(opacity),
),
);
},
),
),
), ),
), ),

View File

@ -89,50 +89,57 @@ class _ScrollingContent extends StatelessWidget {
sliver: SliverPadding( sliver: SliverPadding(
padding: EdgeInsets.symmetric(vertical: $styles.insets.md), padding: EdgeInsets.symmetric(vertical: $styles.insets.md),
sliver: SliverList( sliver: SliverList(
delegate: SliverChildListDelegate([ delegate: SliverChildListDelegate.fixed([
..._contentSection([ Center(
Center(child: buildHiddenCollectible(slot: 0)), child: SizedBox(
width: $styles.sizes.maxContentWidth1,
child: Column(children: [
..._contentSection([
Center(child: buildHiddenCollectible(slot: 0)),
/// History 1 /// History 1
buildDropCapText(data.historyInfo1), buildDropCapText(data.historyInfo1),
/// Quote1 /// Quote1
_CollapsingPullQuoteImage(data: data, scrollPos: scrollPos), _CollapsingPullQuoteImage(data: data, scrollPos: scrollPos),
Center(child: buildHiddenCollectible(slot: 1)), Center(child: buildHiddenCollectible(slot: 1)),
/// Callout1 /// Callout1
_Callout(text: data.callout1), _Callout(text: data.callout1),
/// History 2 /// History 2
buildText(data.historyInfo2), buildText(data.historyInfo2),
_SectionDivider(scrollPos, sectionNotifier, index: 1), _SectionDivider(scrollPos, sectionNotifier, index: 1),
/// Construction 1 /// Construction 1
buildDropCapText(data.constructionInfo1), buildDropCapText(data.constructionInfo1),
Center(child: buildHiddenCollectible(slot: 2)), Center(child: buildHiddenCollectible(slot: 2)),
]), ]),
Gap($styles.insets.md), Gap($styles.insets.md),
_YouTubeThumbnail(id: data.videoId, caption: data.videoCaption), _YouTubeThumbnail(id: data.videoId, caption: data.videoCaption),
Gap($styles.insets.md), Gap($styles.insets.md),
..._contentSection([ ..._contentSection([
/// Callout2 /// Callout2
Gap($styles.insets.xs), Gap($styles.insets.xs),
_Callout(text: data.callout2), _Callout(text: data.callout2),
/// Construction 2 /// Construction 2
buildText(data.constructionInfo2), buildText(data.constructionInfo2),
_SlidingImageStack(scrollPos: scrollPos, type: data.type), _SlidingImageStack(scrollPos: scrollPos, type: data.type),
_SectionDivider(scrollPos, sectionNotifier, index: 2), _SectionDivider(scrollPos, sectionNotifier, index: 2),
/// Location /// Location
buildDropCapText(data.locationInfo1), buildDropCapText(data.locationInfo1),
_LargeSimpleQuote(text: data.pullQuote2, author: data.pullQuote2Author), _LargeSimpleQuote(text: data.pullQuote2, author: data.pullQuote2Author),
buildText(data.locationInfo2), buildText(data.locationInfo2),
]), ]),
Gap($styles.insets.md), Gap($styles.insets.md),
_MapsThumbnail(data, height: 200), _MapsThumbnail(data, height: 200),
Gap($styles.insets.md), Gap($styles.insets.md),
..._contentSection([Center(child: buildHiddenCollectible(slot: 3))]), ..._contentSection([Center(child: buildHiddenCollectible(slot: 3))]),
]),
),
),
]), ]),
), ),
), ),
@ -221,6 +228,7 @@ class _MapsThumbnailState extends State<_MapsThumbnail> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
void handlePressed() => context.push(ScreenPaths.maps(widget.data.type)); void handlePressed() => context.push(ScreenPaths.maps(widget.data.type));
if (PlatformInfo.isDesktop) return Placeholder();
return MergeSemantics( return MergeSemantics(
child: Column( child: Column(
children: [ children: [

View File

@ -11,83 +11,88 @@ class _TitleText extends StatelessWidget {
child: DefaultTextColor( child: DefaultTextColor(
color: $styles.colors.offWhite, color: $styles.colors.offWhite,
child: StaticTextScale( child: StaticTextScale(
child: Column( child: Center(
children: [ child: SizedBox(
Gap($styles.insets.md), width: $styles.sizes.maxContentWidth1,
Gap(30), child: Column(
/// Sub-title row
SeparatedRow(
padding: EdgeInsets.symmetric(horizontal: $styles.insets.sm),
separatorBuilder: () => Gap($styles.insets.sm),
children: [ children: [
Expanded( Gap($styles.insets.md),
child: Divider( Gap(30),
color: data.type.fgColor,
).animate().scale(curve: Curves.easeOut, delay: 500.ms), /// Sub-title row
SeparatedRow(
padding: EdgeInsets.symmetric(horizontal: $styles.insets.sm),
separatorBuilder: () => Gap($styles.insets.sm),
children: [
Expanded(
child: Divider(
color: data.type.fgColor,
).animate().scale(curve: Curves.easeOut, delay: 500.ms),
),
Semantics(
header: true,
sortKey: OrdinalSortKey(1),
child: Text(
data.subTitle.toUpperCase(),
style: $styles.text.title2,
).animate().fade(delay: 100.ms),
),
Expanded(
child: Divider(
color: data.type.fgColor,
).animate().scale(curve: Curves.easeOut, delay: 500.ms),
),
],
), ),
Gap($styles.insets.md),
/// Wonder title text
Semantics( Semantics(
header: true, sortKey: OrdinalSortKey(0),
sortKey: OrdinalSortKey(1), child: ListenableBuilder(
child: Text( listenable: scroller,
data.subTitle.toUpperCase(), builder: (_, __) {
style: $styles.text.title2, final yPos = ContextUtils.getGlobalPos(context)?.dy ?? 0;
).animate().fade(delay: 100.ms), bool enableHero = yPos > -100;
return WonderTitleText(data, enableHero: enableHero);
}),
), ),
Expanded( Gap($styles.insets.xs),
child: Divider(
color: data.type.fgColor, /// Region
).animate().scale(curve: Curves.easeOut, delay: 500.ms), Text(
data.regionTitle.toUpperCase(),
style: $styles.text.title1,
textAlign: TextAlign.center,
), ),
], Gap($styles.insets.md),
),
Gap($styles.insets.md),
/// Wonder title text /// Compass divider
Semantics( ExcludeSemantics(
sortKey: OrdinalSortKey(0), child: Padding(
child: ListenableBuilder( padding: EdgeInsets.symmetric(horizontal: $styles.insets.md),
listenable: scroller, child: ListenableBuilder(
builder: (_, __) { listenable: scroller,
final yPos = ContextUtils.getGlobalPos(context)?.dy ?? 0; builder: (_, __) => CompassDivider(
bool enableHero = yPos > -100; isExpanded: scroller.position.pixels <= 0,
return WonderTitleText(data, enableHero: enableHero); linesColor: data.type.fgColor,
}), compassColor: $styles.colors.offWhite,
), ),
Gap($styles.insets.xs), ),
/// Region
Text(
data.regionTitle.toUpperCase(),
style: $styles.text.title1,
textAlign: TextAlign.center,
),
Gap($styles.insets.md),
/// Compass divider
ExcludeSemantics(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: $styles.insets.md),
child: ListenableBuilder(
listenable: scroller,
builder: (_, __) => CompassDivider(
isExpanded: scroller.position.pixels <= 0,
linesColor: data.type.fgColor,
compassColor: $styles.colors.offWhite,
), ),
), ),
), Gap($styles.insets.sm),
),
Gap($styles.insets.sm),
/// Date /// Date
Text( Text(
$strings.titleLabelDate(StringUtils.formatYr(data.startYr), StringUtils.formatYr(data.endYr)), $strings.titleLabelDate(StringUtils.formatYr(data.startYr), StringUtils.formatYr(data.endYr)),
style: $styles.text.h4, style: $styles.text.h4,
textAlign: TextAlign.center, textAlign: TextAlign.center,
),
Gap($styles.insets.sm),
],
), ),
Gap($styles.insets.sm), ),
],
), ),
), ),
), ),

View File

@ -125,7 +125,7 @@ class _TabBtn extends StatelessWidget {
final iconImgPath = '${ImagePaths.common}/tab-$iconImg${selected ? '-active' : ''}.png'; final iconImgPath = '${ImagePaths.common}/tab-$iconImg${selected ? '-active' : ''}.png';
String tabLabel = localizations.tabLabel(tabIndex: index + 1, tabCount: tabController.length); String tabLabel = localizations.tabLabel(tabIndex: index + 1, tabCount: tabController.length);
tabLabel = '$label: $tabLabel'; tabLabel = '$label: $tabLabel';
final double btnWidth = (context.widthPx / 6).clamp(80, 120); final double btnWidth = (context.widthPx / 6).clamp(70, 120);
return MergeSemantics( return MergeSemantics(
child: Semantics( child: Semantics(
selected: selected, selected: selected,
@ -136,25 +136,8 @@ class _TabBtn extends StatelessWidget {
onPressed: () => tabController.index = index, onPressed: () => tabController.index = index,
semanticLabel: label, semanticLabel: label,
minimumSize: Size(btnWidth, 0), minimumSize: Size(btnWidth, 0),
child: Stack( // Image icon
children: [ child: Image.asset(iconImgPath, height: 32, width: 32, color: selected ? null : color),
/// Image icon
Image.asset(iconImgPath, height: 32, width: 32, color: selected ? null : color),
// if (selected)
// Positioned.fill(
// child: BottomCenter(
// child: Transform.translate(
// offset: Offset(0, $styles.insets.xxs),
// child: Animate().custom(
// curve: Curves.easeOutCubic,
// end: 24,
// builder: (_, v, __) => Container(height: 3, width: v, color: $styles.colors.accent1),
// ),
// ),
// ),
// ),
],
),
), ),
), ),
), ),

View File

@ -1149,10 +1149,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: string_scanner name: string_scanner
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" sha256: "862015c5db1f3f3c4ea3b94dc2490363a84262994b88902315ed74be1155612f"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.0" version: "1.1.1"
sync_http: sync_http:
dependency: transitive dependency: transitive
description: description:
@ -1173,10 +1173,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 sha256: c9aba3b3dbfe8878845dfab5fa096eb8de7b62231baeeb1cea8e3ee81ca8c6d8
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.4.16" version: "0.4.15"
timing: timing:
dependency: transitive dependency: transitive
description: description: