Finish first pass of home illustrations
This commit is contained in:
parent
859f76d8ce
commit
be4e3c1ea4
@ -21,7 +21,7 @@ class AppScrollBehavior extends ScrollBehavior {
|
||||
// TODO: Finalize scrollbar strategy (Do we use them at all? Where specifically?)
|
||||
@override
|
||||
Widget buildScrollbar(BuildContext context, Widget child, ScrollableDetails details) {
|
||||
return child;
|
||||
//return child;
|
||||
return PlatformInfo.isAndroid
|
||||
? RawScrollbar(controller: details.controller, child: child)
|
||||
: CupertinoScrollbar(controller: details.controller, child: child);
|
||||
|
@ -180,37 +180,3 @@ class _ButtonPressEffectState extends State<_ButtonPressEffect> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this is currently unused, and can probably be removed:
|
||||
// This is a very simple button for elements that don't require button UI (states, focus, etc)
|
||||
// For example panel backgrounds.
|
||||
class BasicBtn extends StatelessWidget {
|
||||
const BasicBtn({
|
||||
required this.onPressed,
|
||||
required this.semanticLabel,
|
||||
this.behavior = HitTestBehavior.opaque,
|
||||
this.enableFeedback = true,
|
||||
this.child,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
final VoidCallback onPressed;
|
||||
final String? semanticLabel;
|
||||
final HitTestBehavior behavior;
|
||||
final bool enableFeedback;
|
||||
final Widget? child;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget button = GestureDetector(
|
||||
excludeFromSemantics: true,
|
||||
onTap: enableFeedback ? Feedback.wrapForTap(onPressed, context) : onPressed,
|
||||
behavior: behavior,
|
||||
child: child,
|
||||
);
|
||||
|
||||
if (semanticLabel != null) button = Semantics(label: semanticLabel, button: true, container: true, child: button);
|
||||
|
||||
return button;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'package:wonders/common_libs.dart';
|
||||
import 'package:wonders/ui/common/fade_color_transition.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/illustration_piece.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/paint_textures.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/wonder_hero.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/wonder_illustration_builder.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/wonder_illustration_config.dart';
|
||||
|
||||
@ -12,7 +12,13 @@ class ChichenItzaIllustration extends StatelessWidget {
|
||||
final fgColor = WonderType.chichenItza.fgColor;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return WonderIllustrationBuilder(config: config, bgBuilder: _buildBg, mgBuilder: _buildMg, fgBuilder: _buildFg);
|
||||
return WonderIllustrationBuilder(
|
||||
config: config,
|
||||
bgBuilder: _buildBg,
|
||||
mgBuilder: _buildMg,
|
||||
fgBuilder: _buildFg,
|
||||
wonderType: WonderType.chichenItza,
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _buildBg(BuildContext context, Animation<double> anim) {
|
||||
@ -26,21 +32,13 @@ class ChichenItzaIllustration extends StatelessWidget {
|
||||
flipY: true,
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment(config.shortMode ? .25 : .5, config.shortMode ? 1 : -.15),
|
||||
child: WonderHero(
|
||||
config,
|
||||
'chichen-sun',
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(0, -.2 * anim.value),
|
||||
child: Image.asset(
|
||||
'$assetPath/sun.png',
|
||||
width: config.shortMode ? 100 : 200,
|
||||
cacheWidth: context.widthPx.round() * 2,
|
||||
opacity: anim,
|
||||
),
|
||||
),
|
||||
),
|
||||
IllustrationPiece(
|
||||
fileName: 'sun.png',
|
||||
initialOffset: Offset(0, 20),
|
||||
enableHero: true,
|
||||
heightFactor: .25,
|
||||
minHeight: 200,
|
||||
fractionalOffset: Offset(1, config.shortMode ? 0 : -.5),
|
||||
),
|
||||
];
|
||||
}
|
||||
@ -48,90 +46,126 @@ class ChichenItzaIllustration extends StatelessWidget {
|
||||
List<Widget> _buildMg(BuildContext context, Animation<double> anim) {
|
||||
// We want to size to the shortest side
|
||||
return [
|
||||
Align(
|
||||
alignment: Alignment(0, config.shortMode ? 1 : 0),
|
||||
child: Transform.translate(
|
||||
offset: Offset(0, config.shortMode ? 30 : 0),
|
||||
child: FractionallySizedBox(
|
||||
heightFactor: config.shortMode ? 1 : .6,
|
||||
child: WonderHero(
|
||||
config,
|
||||
'chichen-mg',
|
||||
child: Image.asset('$assetPath/chichen.png', opacity: anim, fit: BoxFit.cover),
|
||||
),
|
||||
),
|
||||
Transform.translate(
|
||||
offset: Offset(0, 20),
|
||||
child: IllustrationPiece(
|
||||
fileName: 'chichen.png',
|
||||
heightFactor: .55,
|
||||
minHeight: 400,
|
||||
zoomAmt: .05,
|
||||
enableHero: true,
|
||||
),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
List<Widget> _buildFg(BuildContext context, Animation<double> anim) {
|
||||
final curvedAnim = Curves.easeOut.transform(anim.value);
|
||||
return [
|
||||
Stack(
|
||||
children: [
|
||||
Transform.scale(
|
||||
scale: 1 + config.zoom * .05,
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(-.2 * (1 - curvedAnim), 0),
|
||||
child: BottomLeft(
|
||||
child: SizedBox(
|
||||
height: 500,
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(-.4, .15),
|
||||
child: Image.asset('$assetPath/foreground-left.png', opacity: anim, fit: BoxFit.cover),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Transform.scale(
|
||||
scale: 1 + config.zoom * .03,
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(.2 * (1 - curvedAnim), 0),
|
||||
child: BottomRight(
|
||||
child: SizedBox(
|
||||
height: 350,
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(.35, .2),
|
||||
child: Image.asset('$assetPath/foreground-right.png', opacity: anim, fit: BoxFit.cover),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Transform.scale(
|
||||
scale: 1 + config.zoom * .25,
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(-.2 * (1 - curvedAnim), 0),
|
||||
child: TopLeft(
|
||||
child: SizedBox(
|
||||
height: 600,
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(-.3, -.45),
|
||||
child: Image.asset('$assetPath/top-left.png', opacity: anim, fit: BoxFit.cover),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Transform.scale(
|
||||
scale: 1 + config.zoom * .2,
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(.2 * (1 - curvedAnim), 0),
|
||||
child: TopRight(
|
||||
child: SizedBox(
|
||||
height: 700,
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(.2, -.35),
|
||||
child: Image.asset('$assetPath/top-right.png', opacity: anim, fit: BoxFit.cover),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
IllustrationPiece(
|
||||
fileName: 'foreground-left.png',
|
||||
alignment: Alignment.bottomCenter,
|
||||
initialScale: .9,
|
||||
initialOffset: Offset(-40, 60),
|
||||
heightFactor: .65,
|
||||
fractionalOffset: Offset(-.4, .2),
|
||||
zoomAmt: .25,
|
||||
dynamicHzOffset: -250,
|
||||
),
|
||||
IllustrationPiece(
|
||||
fileName: 'foreground-right.png',
|
||||
alignment: Alignment.bottomCenter,
|
||||
initialOffset: Offset(20, 40),
|
||||
initialScale: .95,
|
||||
heightFactor: .6,
|
||||
fractionalOffset: Offset(.4, .2),
|
||||
zoomAmt: .1,
|
||||
dynamicHzOffset: 250,
|
||||
),
|
||||
IllustrationPiece(
|
||||
fileName: 'top-left.png',
|
||||
alignment: Alignment.topLeft,
|
||||
initialScale: .9,
|
||||
initialOffset: Offset(-40, 60),
|
||||
heightFactor: .75,
|
||||
fractionalOffset: Offset(-.5, -.3),
|
||||
zoomAmt: .25,
|
||||
dynamicHzOffset: 100,
|
||||
),
|
||||
IllustrationPiece(
|
||||
fileName: 'top-right.png',
|
||||
alignment: Alignment.topRight,
|
||||
initialOffset: Offset(20, 40),
|
||||
initialScale: .95,
|
||||
heightFactor: .85,
|
||||
fractionalOffset: Offset(.4, -.4),
|
||||
zoomAmt: .1,
|
||||
dynamicHzOffset: -100,
|
||||
),
|
||||
|
||||
// Stack(
|
||||
// children: [
|
||||
// Transform.scale(
|
||||
// scale: 1 + config.zoom * .05,
|
||||
// child: FractionalTranslation(
|
||||
// translation: Offset(-.2 * (1 - curvedAnim), 0),
|
||||
// child: BottomLeft(
|
||||
// child: SizedBox(
|
||||
// height: 500,
|
||||
// child: FractionalTranslation(
|
||||
// translation: Offset(-.4, .15),
|
||||
// child: Image.asset('$assetPath/foreground-left.png', opacity: anim, fit: BoxFit.cover),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// Transform.scale(
|
||||
// scale: 1 + config.zoom * .03,
|
||||
// child: FractionalTranslation(
|
||||
// translation: Offset(.2 * (1 - curvedAnim), 0),
|
||||
// child: BottomRight(
|
||||
// child: SizedBox(
|
||||
// height: 350,
|
||||
// child: FractionalTranslation(
|
||||
// translation: Offset(.35, .2),
|
||||
// child: Image.asset('$assetPath/foreground-right.png', opacity: anim, fit: BoxFit.cover),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// Transform.scale(
|
||||
// scale: 1 + config.zoom * .25,
|
||||
// child: FractionalTranslation(
|
||||
// translation: Offset(-.2 * (1 - curvedAnim), 0),
|
||||
// child: TopLeft(
|
||||
// child: SizedBox(
|
||||
// height: 600,
|
||||
// child: FractionalTranslation(
|
||||
// translation: Offset(-.3, -.45),
|
||||
// child: Image.asset('$assetPath/top-left.png', opacity: anim, fit: BoxFit.cover),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// Transform.scale(
|
||||
// scale: 1 + config.zoom * .2,
|
||||
// child: FractionalTranslation(
|
||||
// translation: Offset(.2 * (1 - curvedAnim), 0),
|
||||
// child: TopRight(
|
||||
// child: SizedBox(
|
||||
// height: 700,
|
||||
// child: FractionalTranslation(
|
||||
// translation: Offset(.2, -.35),
|
||||
// child: Image.asset('$assetPath/top-right.png', opacity: anim, fit: BoxFit.cover),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'package:wonders/common_libs.dart';
|
||||
import 'package:wonders/ui/common/fade_color_transition.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/illustration_piece.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/paint_textures.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/wonder_hero.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/wonder_illustration_builder.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/wonder_illustration_config.dart';
|
||||
|
||||
@ -18,6 +18,7 @@ class ChristRedeemerIllustration extends StatelessWidget {
|
||||
bgBuilder: _buildBg,
|
||||
mgBuilder: _buildMg,
|
||||
fgBuilder: _buildFg,
|
||||
wonderType: WonderType.christRedeemer,
|
||||
);
|
||||
}
|
||||
|
||||
@ -32,90 +33,52 @@ class ChristRedeemerIllustration extends StatelessWidget {
|
||||
opacity: anim.drive(Tween(begin: 0, end: .4)),
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: config.shortMode ? Alignment(.5, -1.5) : Alignment(.5, -.75),
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(0, .5 * anim.value),
|
||||
child: WonderHero(
|
||||
config,
|
||||
'christ-sun',
|
||||
child: Transform.scale(
|
||||
scale: config.shortMode ? 1.4 : 1.6,
|
||||
child: Image.asset(
|
||||
'$assetPath/sun.png',
|
||||
cacheWidth: context.widthPx.round() * 2,
|
||||
opacity: anim,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
IllustrationPiece(
|
||||
fileName: 'sun.png',
|
||||
initialOffset: Offset(0, 20),
|
||||
enableHero: true,
|
||||
heightFactor: .2,
|
||||
minHeight: 120,
|
||||
fractionalOffset: Offset(.5, -1),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
List<Widget> _buildMg(BuildContext context, Animation<double> anim) {
|
||||
return [
|
||||
ClipRect(
|
||||
child: Transform.scale(
|
||||
scale: 1 + config.zoom * .2,
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(0, config.shortMode ? .5 : .2),
|
||||
child: BottomCenter(
|
||||
child: FractionallySizedBox(
|
||||
heightFactor: config.shortMode ? 1.5 : 1.2,
|
||||
child: WonderHero(
|
||||
config,
|
||||
'christ-mg',
|
||||
child: Image.asset(
|
||||
'$assetPath/redeemer.png',
|
||||
opacity: anim,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
IllustrationPiece(
|
||||
fileName: 'redeemer.png',
|
||||
enableHero: true,
|
||||
heightFactor: 1,
|
||||
alignment: Alignment.bottomCenter,
|
||||
fractionalOffset: Offset(0, .1),
|
||||
zoomAmt: .1,
|
||||
)
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
List<Widget> _buildFg(BuildContext context, Animation<double> anim) {
|
||||
final curvedAnim = Curves.easeOut.transform(anim.value);
|
||||
return [
|
||||
Stack(
|
||||
children: [
|
||||
Transform.scale(
|
||||
scale: 1 + config.zoom * .15,
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(-.2 * (1 - curvedAnim), 0),
|
||||
child: BottomLeft(
|
||||
child: FractionallySizedBox(
|
||||
widthFactor: 1.5,
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(-.25, .03),
|
||||
child: Image.asset('$assetPath/foreground-left.png', opacity: anim, fit: BoxFit.cover),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Transform.scale(
|
||||
scale: 1 + config.zoom * .3,
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(.2 * (1 - curvedAnim), 0),
|
||||
child: BottomRight(
|
||||
child: FractionallySizedBox(
|
||||
widthFactor: 1.5,
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(.3, .2),
|
||||
child: Image.asset('$assetPath/foreground-right.png', opacity: anim, fit: BoxFit.cover),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
IllustrationPiece(
|
||||
fileName: 'foreground-left.png',
|
||||
alignment: Alignment.bottomCenter,
|
||||
initialScale: .9,
|
||||
initialOffset: Offset(-40, 60),
|
||||
heightFactor: .55,
|
||||
fractionalOffset: Offset(-.25, 0),
|
||||
zoomAmt: .25,
|
||||
dynamicHzOffset: -100,
|
||||
),
|
||||
IllustrationPiece(
|
||||
fileName: 'foreground-right.png',
|
||||
alignment: Alignment.bottomCenter,
|
||||
initialOffset: Offset(20, 40),
|
||||
initialScale: .95,
|
||||
heightFactor: .65,
|
||||
fractionalOffset: Offset(.2, 0),
|
||||
zoomAmt: .1,
|
||||
dynamicHzOffset: 100,
|
||||
),
|
||||
];
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:wonders/common_libs.dart';
|
||||
import 'package:wonders/ui/common/fade_color_transition.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/illustration_piece.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/paint_textures.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/wonder_hero.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/wonder_illustration_builder.dart';
|
||||
@ -18,6 +19,7 @@ class ColosseumIllustration extends StatelessWidget {
|
||||
bgBuilder: _buildBg,
|
||||
mgBuilder: _buildMg,
|
||||
fgBuilder: _buildFg,
|
||||
wonderType: WonderType.colosseum,
|
||||
);
|
||||
}
|
||||
|
||||
@ -55,25 +57,12 @@ class ColosseumIllustration extends StatelessWidget {
|
||||
List<Widget> _buildMg(BuildContext context, Animation<double> anim) {
|
||||
return [
|
||||
Stack(
|
||||
children: [
|
||||
if (config.shortMode) ...[
|
||||
FractionalTranslation(
|
||||
translation: Offset(0, .9),
|
||||
child: Container(color: bgColor),
|
||||
)
|
||||
],
|
||||
Center(
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(0, config.shortMode ? .1 : -.15),
|
||||
child: Transform.scale(
|
||||
scale: config.shortMode ? .85 : 1.55 + config.zoom * .2,
|
||||
child: WonderHero(
|
||||
config,
|
||||
'colosseum-mg',
|
||||
child: Image.asset('$assetPath/colosseum.png', opacity: anim, fit: BoxFit.cover),
|
||||
),
|
||||
),
|
||||
),
|
||||
children: const [
|
||||
IllustrationPiece(
|
||||
fileName: 'colosseum.png',
|
||||
heightFactor: .55,
|
||||
minHeight: 400,
|
||||
zoomAmt: .15,
|
||||
),
|
||||
],
|
||||
)
|
||||
@ -81,40 +70,27 @@ class ColosseumIllustration extends StatelessWidget {
|
||||
}
|
||||
|
||||
List<Widget> _buildFg(BuildContext context, Animation<double> anim) {
|
||||
final curvedAnim = Curves.easeOut.transform(anim.value);
|
||||
return [
|
||||
Stack(children: [
|
||||
BottomLeft(
|
||||
child: FractionallySizedBox(
|
||||
heightFactor: .56,
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(-.2 * (1 - curvedAnim), 0),
|
||||
child: Transform.scale(
|
||||
scale: 1 + config.zoom * .3,
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(-.1, .1),
|
||||
child: Image.asset('$assetPath/foreground-left.png', opacity: anim, fit: BoxFit.cover),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
BottomRight(
|
||||
child: FractionallySizedBox(
|
||||
heightFactor: .56,
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(.2 * (1 - curvedAnim), 0),
|
||||
child: Transform.scale(
|
||||
scale: 1 + config.zoom * .3,
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(.3, .2),
|
||||
child: Image.asset('$assetPath/foreground-right.png', opacity: anim, fit: BoxFit.cover),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
])
|
||||
IllustrationPiece(
|
||||
fileName: 'foreground-left.png',
|
||||
alignment: Alignment.bottomCenter,
|
||||
initialScale: .9,
|
||||
initialOffset: Offset(-40, 60),
|
||||
heightFactor: .65,
|
||||
fractionalOffset: Offset(-.5, .1),
|
||||
zoomAmt: .25,
|
||||
dynamicHzOffset: -150,
|
||||
),
|
||||
IllustrationPiece(
|
||||
fileName: 'foreground-right.png',
|
||||
alignment: Alignment.bottomCenter,
|
||||
initialOffset: Offset(20, 40),
|
||||
initialScale: .95,
|
||||
heightFactor: .75,
|
||||
fractionalOffset: Offset(.5, .25),
|
||||
zoomAmt: .1,
|
||||
dynamicHzOffset: 150,
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -1,145 +0,0 @@
|
||||
import 'package:wonders/common_libs.dart';
|
||||
|
||||
/// Combines [Align], [FractionalBoxWithMinSize], [Image] and [Transform.translate]
|
||||
/// to standardize behavior across the various wonder illustrations
|
||||
class IllustrationPiece extends StatelessWidget {
|
||||
const IllustrationPiece({
|
||||
Key? key,
|
||||
required this.type,
|
||||
required this.anim,
|
||||
required this.fileName,
|
||||
required this.heightFactor,
|
||||
this.alignment = Alignment.center,
|
||||
this.minHeight,
|
||||
this.translation,
|
||||
}) : super(key: key);
|
||||
|
||||
final WonderType type;
|
||||
final Animation<double> anim;
|
||||
final double heightFactor;
|
||||
final String fileName;
|
||||
final Offset? translation;
|
||||
final Alignment alignment;
|
||||
final double? minHeight;
|
||||
final BoxFit boxFit = BoxFit.cover;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Align(
|
||||
alignment: alignment,
|
||||
child: Transform.translate(
|
||||
offset: translation ?? Offset.zero,
|
||||
child: FractionalBoxWithMinSize(
|
||||
heightFactor: heightFactor,
|
||||
minHeight: minHeight ?? 0,
|
||||
child: Image.asset('${type.assetPath}/$fileName', opacity: anim, fit: boxFit),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
//
|
||||
// class IllustrationPieceStack extends StatelessWidget {
|
||||
// const IllustrationPieceStack({Key? key, required this.pieces}) : super(key: key);
|
||||
// final List<IllustrationPiece> pieces;
|
||||
//
|
||||
// @override
|
||||
// Widget build(BuildContext context) {
|
||||
// return Stack(
|
||||
// children: pieces,
|
||||
// // [
|
||||
// // BottomCenter(
|
||||
// // child: Transform.translate(
|
||||
// // offset: Offset(context.widthPx * .05, 0),
|
||||
// // child: FractionalBoxWithMinSize(
|
||||
// // heightFactor: backHeightFactor,
|
||||
// // minHeight: 300,
|
||||
// // child: Image.asset(
|
||||
// // '${type.assetPath}/foreground-back.png',
|
||||
// // opacity: anim,
|
||||
// // fit: BoxFit.cover,
|
||||
// // ),
|
||||
// // ),
|
||||
// // ),
|
||||
// // ),
|
||||
// // BottomCenter(
|
||||
// // child: Transform.translate(
|
||||
// // offset: Offset(-context.widthPx * .1, 0),
|
||||
// // child: FractionalBoxWithMinSize(
|
||||
// // heightFactor: frontHeightFactor,
|
||||
// // minHeight: 300,
|
||||
// // child: Image.asset(
|
||||
// // '${type.assetPath}/foreground-front.png',
|
||||
// // opacity: anim,
|
||||
// // fit: BoxFit.cover,
|
||||
// // ),
|
||||
// // ),
|
||||
// // ),
|
||||
// // )
|
||||
//
|
||||
// // BottomCenter(
|
||||
// // child: Transform.scale(
|
||||
// // scale: 1 + config.zoom * .05,
|
||||
// // child: FractionallySizedBox(
|
||||
// // heightFactor: backHeightFactor,
|
||||
// // child: FractionalTranslation(
|
||||
// // translation: Offset(.1, 0),
|
||||
// // child: Image.asset('${type.assetPath}/foreground-back.png', opacity: anim, fit: BoxFit.cover)),
|
||||
// // ),
|
||||
// // ),
|
||||
// // ),
|
||||
// // BottomCenter(
|
||||
// // child: Transform.scale(
|
||||
// // scale: 1 + config.zoom * .2,
|
||||
// // child: FractionallySizedBox(
|
||||
// // heightFactor: frontHeightFactor,
|
||||
// // child: FractionalTranslation(
|
||||
// // translation: Offset(-.2, 0),
|
||||
// // child: Image.asset('${type.assetPath}/foreground-front.png', opacity: anim, fit: BoxFit.cover)),
|
||||
// // ),
|
||||
// // ),
|
||||
// // ),
|
||||
// // ],
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
/// Encapsulates a common behavior where
|
||||
/// - we want something to be fractionally sized, down to a pt...
|
||||
/// - when we hit a minSize, stop reducing in size...
|
||||
/// - until available space is less < minSize, then allow piece to reduce
|
||||
/// eg, Take a piece with 50% height, and 500px minHeight. As available height is reduced it will attempt to use 50% height,
|
||||
/// At 200px it it will stop reducing itself in height and ignore the fractional sizing.
|
||||
/// One the available height is < 200px, the piece will then reduce itself so it still
|
||||
/// fits on screen without being clipped.
|
||||
class FractionalBoxWithMinSize extends StatelessWidget {
|
||||
const FractionalBoxWithMinSize(
|
||||
{Key? key, this.minWidth, this.minHeight, this.widthFactor, this.heightFactor, required this.child})
|
||||
: super(key: key);
|
||||
|
||||
final double? widthFactor;
|
||||
final double? heightFactor;
|
||||
final double? minWidth;
|
||||
final double? minHeight;
|
||||
final Widget child;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
assert((widthFactor == null && minWidth == null) || (widthFactor != null && minWidth != null),
|
||||
'widthFactor and minWidth must be provided together');
|
||||
assert((heightFactor == null && minHeight == null) || (heightFactor != null && minHeight != null),
|
||||
'heightFactor and minWidth must be provided together');
|
||||
return LayoutBuilder(builder: (context, constraints) {
|
||||
var c = child;
|
||||
if (widthFactor != null) {
|
||||
double size = max(minWidth!, widthFactor! * constraints.maxWidth);
|
||||
c = SizedBox(width: size, child: c);
|
||||
}
|
||||
if (heightFactor != null) {
|
||||
double size = max(minHeight!, heightFactor! * constraints.maxHeight);
|
||||
c = SizedBox(height: size, child: c);
|
||||
}
|
||||
return c;
|
||||
});
|
||||
}
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
import 'package:wonders/common_libs.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/wonder_hero.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/wonder_illustration_config.dart';
|
||||
|
||||
/// TODO: This can just be an IllustrrationPiece
|
||||
/// TODO: Add counter scaling to illustration piece like this
|
||||
/// TODO: Add hero support to [IllustrationPiece]? Or at least use [FractionalBoxWithMinSize]
|
||||
class IllustrationMg extends StatelessWidget {
|
||||
const IllustrationMg(
|
||||
this.imagePath, {
|
||||
Key? key,
|
||||
required this.config,
|
||||
required this.anim,
|
||||
required this.type,
|
||||
required this.heightFraction,
|
||||
this.maxHeight = 700,
|
||||
}) : super(key: key);
|
||||
|
||||
final String imagePath;
|
||||
final WonderIllustrationConfig config;
|
||||
final Animation<double> anim;
|
||||
final WonderType type;
|
||||
final double maxHeight;
|
||||
final double heightFraction;
|
||||
String get assetPath => type.assetPath;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(top: $styles.insets.sm),
|
||||
child: LayoutBuilder(builder: (_, constraints) {
|
||||
final height = min(maxHeight, constraints.maxHeight) * heightFraction;
|
||||
return Center(
|
||||
child: WonderHero(
|
||||
config,
|
||||
'$imagePath-hero',
|
||||
child: Transform.scale(
|
||||
scale: 4 + config.zoom * .5,
|
||||
child: Image.asset(
|
||||
'$assetPath/$imagePath',
|
||||
opacity: anim,
|
||||
height: height * .25,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
144
lib/ui/wonder_illustrations/common/illustration_piece.dart
Normal file
144
lib/ui/wonder_illustrations/common/illustration_piece.dart
Normal file
@ -0,0 +1,144 @@
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:wonders/common_libs.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/wonder_illustration_builder.dart';
|
||||
|
||||
/// Combines [Align], [FractionalBoxWithMinSize], [Image] and [Transform.translate]
|
||||
/// to standardize behavior across the various wonder illustrations
|
||||
class IllustrationPiece extends StatefulWidget {
|
||||
const IllustrationPiece({
|
||||
Key? key,
|
||||
required this.fileName,
|
||||
required this.heightFactor,
|
||||
this.alignment = Alignment.center,
|
||||
this.minHeight,
|
||||
this.offset = Offset.zero,
|
||||
this.fractionalOffset,
|
||||
this.zoomAmt = 0,
|
||||
this.initialOffset = Offset.zero,
|
||||
this.boxFit = BoxFit.fitHeight,
|
||||
this.overflow = true,
|
||||
this.enableHero = false,
|
||||
this.initialScale = 1,
|
||||
this.dynamicHzOffset = 0,
|
||||
this.top,
|
||||
this.bottom,
|
||||
}) : super(key: key);
|
||||
|
||||
final String fileName;
|
||||
|
||||
final Alignment alignment;
|
||||
|
||||
/// Will animate from this position to Offset.zero, eg is value is Offset(0, 100), the piece will slide up vertically 100px as it enters the screen
|
||||
final Offset initialOffset;
|
||||
|
||||
/// Will animate from this scale to 1, eg if scale is .7, the piece will scale from .7 to 1.0 as it enters the screen.
|
||||
final double initialScale;
|
||||
|
||||
/// % height, will be overridden by minHeight
|
||||
final double heightFactor;
|
||||
|
||||
/// min height in pixels, piece will not be allowed to go below this height in px, unless it has to (available height is too small)
|
||||
final double? minHeight;
|
||||
|
||||
/// px offset for this piece
|
||||
final Offset offset;
|
||||
|
||||
/// offset based on a fraction of the piece size
|
||||
final Offset? fractionalOffset;
|
||||
|
||||
/// The % amount that this object should scale up as the user drags their finger up the screen
|
||||
final double zoomAmt;
|
||||
|
||||
/// Applied to the underlying image in the piece, defaults to [BoxFit.cover]
|
||||
final BoxFit boxFit;
|
||||
|
||||
/// Whether or not this piece can overflow it's parent on the horizontal bounds
|
||||
final bool overflow;
|
||||
|
||||
/// Adds a hero tag to this piece, made from wonderType + fileName
|
||||
final bool enableHero;
|
||||
|
||||
/// Max px offset of the piece as the screen size grows horizontally
|
||||
final double dynamicHzOffset;
|
||||
|
||||
final Widget Function(BuildContext context)? top;
|
||||
final Widget Function(BuildContext context)? bottom;
|
||||
|
||||
@override
|
||||
State<IllustrationPiece> createState() => _IllustrationPieceState();
|
||||
}
|
||||
|
||||
class _IllustrationPieceState extends State<IllustrationPiece> {
|
||||
double? aspectRatio;
|
||||
ui.Image? uiImage;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final wonderBuilder = context.watch<WonderIllustrationBuilderState>();
|
||||
final type = wonderBuilder.widget.wonderType;
|
||||
final imgPath = '${type.assetPath}/${widget.fileName}';
|
||||
if (aspectRatio == null) {
|
||||
aspectRatio == 0; // indicates load has started, so we don't run twice
|
||||
rootBundle.load(imgPath).then((img) async {
|
||||
uiImage = await decodeImageFromList(img.buffer.asUint8List());
|
||||
if (!mounted) return;
|
||||
setState(() => aspectRatio = uiImage!.width / uiImage!.height);
|
||||
});
|
||||
}
|
||||
return Align(
|
||||
alignment: widget.alignment,
|
||||
child: LayoutBuilder(
|
||||
key: ValueKey(aspectRatio),
|
||||
builder: (_, constraints) {
|
||||
final anim = wonderBuilder.anim;
|
||||
final curvedAnim = Curves.easeOut.transform(anim.value);
|
||||
final config = wonderBuilder.widget.config;
|
||||
Widget img = Image.asset(imgPath, opacity: anim, fit: widget.boxFit);
|
||||
if (widget.overflow) {
|
||||
img = OverflowBox(maxWidth: 2000, child: img);
|
||||
}
|
||||
final double introZoom = (widget.initialScale - 1) * (1 - curvedAnim);
|
||||
|
||||
/// Determine target height
|
||||
final double height = max(widget.minHeight ?? 0, constraints.maxHeight * widget.heightFactor);
|
||||
|
||||
/// Combine all the translations, initial + offset + dynamicHzOffset + fractionalOffset
|
||||
Offset finalTranslation = widget.offset;
|
||||
// Initial
|
||||
if (widget.initialOffset != Offset.zero) {
|
||||
finalTranslation += widget.initialOffset * (1 - curvedAnim);
|
||||
}
|
||||
// Dynamic
|
||||
final dynamicOffsetAmt = min(context.widthPx / 1500, 1);
|
||||
finalTranslation += Offset(dynamicOffsetAmt * widget.dynamicHzOffset, 0);
|
||||
// Fractional
|
||||
final width = height * (aspectRatio ?? 0);
|
||||
if (widget.fractionalOffset != null) {
|
||||
finalTranslation += Offset(
|
||||
widget.fractionalOffset!.dx * width,
|
||||
height * widget.fractionalOffset!.dy,
|
||||
);
|
||||
}
|
||||
return Stack(
|
||||
children: [
|
||||
if (widget.bottom != null) Positioned.fill(child: widget.bottom!.call(context)),
|
||||
if (uiImage != null) ...[
|
||||
Transform.translate(
|
||||
offset: finalTranslation,
|
||||
child: Transform.scale(
|
||||
scale: 1 + (widget.zoomAmt * config.zoom) + introZoom,
|
||||
child: SizedBox(
|
||||
height: height,
|
||||
width: height * aspectRatio!,
|
||||
child: !widget.enableHero ? img : Hero(tag: '$type-${widget.fileName}', child: img),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
if (widget.top != null) Positioned.fill(child: widget.top!.call(context)),
|
||||
],
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,8 +1,7 @@
|
||||
import 'package:wonders/common_libs.dart';
|
||||
import 'package:wonders/ui/common/fade_color_transition.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/illustration_mg.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/illustration_piece.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/paint_textures.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/wonder_hero.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/wonder_illustration_builder.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/wonder_illustration_config.dart';
|
||||
|
||||
@ -20,6 +19,7 @@ class GreatWallIllustration extends StatelessWidget {
|
||||
bgBuilder: _buildBg,
|
||||
mgBuilder: _buildMg,
|
||||
fgBuilder: _buildFg,
|
||||
wonderType: WonderType.greatWall,
|
||||
);
|
||||
}
|
||||
|
||||
@ -34,104 +34,51 @@ class GreatWallIllustration extends StatelessWidget {
|
||||
opacity: anim.drive(Tween(begin: 0, end: .5)),
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: config.shortMode ? Alignment(-.5, -.5) : Alignment(-.45, -.63),
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(0, -.5 * anim.value),
|
||||
child: WonderHero(
|
||||
config,
|
||||
'great-wall-sun',
|
||||
child: Image.asset(
|
||||
'$assetPath/sun.png',
|
||||
cacheWidth: context.widthPx.round() * 2,
|
||||
width: config.shortMode ? 100 : 150,
|
||||
opacity: anim,
|
||||
),
|
||||
),
|
||||
),
|
||||
IllustrationPiece(
|
||||
fileName: 'sun.png',
|
||||
initialOffset: Offset(0, 20),
|
||||
enableHero: true,
|
||||
heightFactor: .15,
|
||||
minHeight: 150,
|
||||
offset: config.shortMode ? Offset(-70, context.heightPx * -.05) : Offset(-150, context.heightPx * -.25),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
List<Widget> _buildMg(BuildContext context, Animation<double> anim) {
|
||||
return [
|
||||
IllustrationMg(
|
||||
'great-wall.png',
|
||||
type: WonderType.greatWall,
|
||||
anim: anim,
|
||||
config: config,
|
||||
maxHeight: 800,
|
||||
heightFraction: .85,
|
||||
IllustrationPiece(
|
||||
fileName: 'great-wall.png',
|
||||
heightFactor: .55,
|
||||
minHeight: 600,
|
||||
zoomAmt: .05,
|
||||
enableHero: true,
|
||||
),
|
||||
];
|
||||
return [
|
||||
Center(
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(0, config.shortMode ? .1 * anim.value : 0),
|
||||
child: FractionallySizedBox(
|
||||
widthFactor: config.shortMode ? null : 1.3,
|
||||
child: WonderHero(
|
||||
config,
|
||||
'great-wall-mg',
|
||||
child: Image.asset(
|
||||
'$assetPath/great-wall.png',
|
||||
opacity: anim,
|
||||
width: config.shortMode ? 300 : 500,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// child: FractionalTranslation(
|
||||
// translation: Offset(0, 0),
|
||||
// child: Transform.scale(
|
||||
// scale: 1, //config.shortMode ? .95 : 1.4 + config.zoom * .2,
|
||||
// child: WonderHero(
|
||||
// config,
|
||||
// 'great-wall-mg',
|
||||
// child: Image.asset(
|
||||
// '$assetPath/great-wall.png',
|
||||
// opacity: anim,
|
||||
// width: 700,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
List<Widget> _buildFg(BuildContext context, Animation<double> anim) {
|
||||
final curvedAnim = Curves.easeOut.transform(anim.value);
|
||||
return [
|
||||
Stack(children: [
|
||||
BottomRight(
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(.2 * (1 - curvedAnim), 0),
|
||||
child: Transform.scale(
|
||||
scale: 1.5 + config.zoom * .1,
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(.46, -.22),
|
||||
child: Image.asset('$assetPath/foreground-right.png',
|
||||
opacity: anim, cacheWidth: context.widthPx.round() * 3),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
BottomLeft(
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(-.2 * (1 - curvedAnim), 0),
|
||||
child: Transform.scale(
|
||||
scale: 1 + config.zoom * .3,
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(-.3, -.01),
|
||||
child: Image.asset('$assetPath/foreground-left.png',
|
||||
opacity: anim, cacheWidth: context.widthPx.round() * 3),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
])
|
||||
IllustrationPiece(
|
||||
fileName: 'foreground-left.png',
|
||||
alignment: Alignment.bottomCenter,
|
||||
initialScale: .9,
|
||||
initialOffset: Offset(-40, 60),
|
||||
heightFactor: .75,
|
||||
fractionalOffset: Offset(-.4, .45),
|
||||
zoomAmt: .25,
|
||||
dynamicHzOffset: -150,
|
||||
),
|
||||
IllustrationPiece(
|
||||
fileName: 'foreground-right.png',
|
||||
alignment: Alignment.bottomCenter,
|
||||
initialOffset: Offset(20, 40),
|
||||
initialScale: .95,
|
||||
heightFactor: .85,
|
||||
fractionalOffset: Offset(.4, .25),
|
||||
zoomAmt: .1,
|
||||
dynamicHzOffset: 150,
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'package:wonders/common_libs.dart';
|
||||
import 'package:wonders/ui/common/fade_color_transition.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/illustration_piece.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/paint_textures.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/wonder_hero.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/wonder_illustration_builder.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/wonder_illustration_config.dart';
|
||||
|
||||
@ -19,6 +19,7 @@ class MachuPicchuIllustration extends StatelessWidget {
|
||||
bgBuilder: _buildBg,
|
||||
mgBuilder: _buildMg,
|
||||
fgBuilder: _buildFg,
|
||||
wonderType: WonderType.machuPicchu,
|
||||
);
|
||||
}
|
||||
|
||||
@ -33,80 +34,49 @@ class MachuPicchuIllustration extends StatelessWidget {
|
||||
opacity: anim.drive(Tween(begin: 0, end: .7)),
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: config.shortMode ? Alignment.center : Alignment(.75, -.6),
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(0, -.5 * anim.value),
|
||||
child: Transform.scale(
|
||||
scale: config.shortMode ? .75 : 1,
|
||||
child: WonderHero(
|
||||
config,
|
||||
'machu-sun',
|
||||
child: Image.asset(
|
||||
'$assetPath/sun.png',
|
||||
cacheWidth: context.widthPx.round() * 2,
|
||||
opacity: anim,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
IllustrationPiece(
|
||||
fileName: 'sun.png',
|
||||
initialOffset: Offset(0, 20),
|
||||
enableHero: true,
|
||||
heightFactor: .15,
|
||||
minHeight: 150,
|
||||
offset: config.shortMode ? Offset(-70, context.heightPx * -.05) : Offset(-150, context.heightPx * -.25),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
List<Widget> _buildMg(BuildContext context, Animation<double> anim) => [
|
||||
Center(
|
||||
child: Transform.scale(
|
||||
scale: config.shortMode ? 1.2 : 2.5 + config.zoom * .2,
|
||||
alignment: Alignment(config.shortMode ? 0 : .15, config.shortMode ? -0.6 : .3),
|
||||
child: WonderHero(
|
||||
config,
|
||||
'machu-mg',
|
||||
child: Image.asset(
|
||||
'$assetPath/machu-picchu.png',
|
||||
fit: BoxFit.contain,
|
||||
opacity: anim,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
IllustrationPiece(
|
||||
fileName: 'machu-picchu.png',
|
||||
heightFactor: .65,
|
||||
minHeight: 500,
|
||||
zoomAmt: .05,
|
||||
enableHero: true,
|
||||
),
|
||||
];
|
||||
|
||||
List<Widget> _buildFg(BuildContext context, Animation<double> anim) {
|
||||
final curvedAnim = Curves.easeOut.transform(anim.value);
|
||||
return [
|
||||
Transform.translate(
|
||||
offset: Offset(0, 20 * (1 - curvedAnim)),
|
||||
child: Stack(children: [
|
||||
BottomRight(
|
||||
child: Transform.scale(
|
||||
scale: 1 + config.zoom * .05,
|
||||
child: FractionallySizedBox(
|
||||
widthFactor: 1.5,
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(0, .1),
|
||||
child: Image.asset('$assetPath/foreground-back.png', opacity: anim),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
BottomLeft(
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(-.2 * (1 - curvedAnim), 0),
|
||||
child: Transform.scale(
|
||||
scale: 1 + config.zoom * .25,
|
||||
child: FractionallySizedBox(
|
||||
widthFactor: 1.5,
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(-.3, .4),
|
||||
child: Image.asset('$assetPath/foreground-front.png', opacity: anim),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
]),
|
||||
)
|
||||
IllustrationPiece(
|
||||
fileName: 'foreground-back.png',
|
||||
alignment: Alignment.bottomCenter,
|
||||
initialScale: .9,
|
||||
initialOffset: Offset(0, 60),
|
||||
heightFactor: .6,
|
||||
fractionalOffset: Offset(0, .3),
|
||||
zoomAmt: .1,
|
||||
dynamicHzOffset: 150,
|
||||
),
|
||||
IllustrationPiece(
|
||||
fileName: 'foreground-front.png',
|
||||
alignment: Alignment.bottomCenter,
|
||||
initialOffset: Offset(20, 40),
|
||||
heightFactor: .5,
|
||||
initialScale: .95,
|
||||
fractionalOffset: Offset(-.25, .25),
|
||||
zoomAmt: .12,
|
||||
dynamicHzOffset: -50,
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'package:wonders/common_libs.dart';
|
||||
import 'package:wonders/ui/common/fade_color_transition.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/illustration_piece.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/paint_textures.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/wonder_hero.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/wonder_illustration_builder.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/wonder_illustration_config.dart';
|
||||
|
||||
@ -19,6 +19,7 @@ class PetraIllustration extends StatelessWidget {
|
||||
bgBuilder: _buildBg,
|
||||
mgBuilder: _buildMg,
|
||||
fgBuilder: _buildFg,
|
||||
wonderType: WonderType.petra,
|
||||
);
|
||||
}
|
||||
|
||||
@ -33,74 +34,69 @@ class PetraIllustration extends StatelessWidget {
|
||||
opacity: anim.drive(Tween(begin: 0, end: .25)),
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment(-.3, config.shortMode ? -1.5 : -1.23),
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(0, .5 * anim.value),
|
||||
child: WonderHero(
|
||||
config,
|
||||
'petra-moon',
|
||||
child: Image.asset(
|
||||
'$assetPath/moon.png',
|
||||
opacity: anim,
|
||||
),
|
||||
),
|
||||
),
|
||||
IllustrationPiece(
|
||||
fileName: 'moon.png',
|
||||
heightFactor: .15,
|
||||
minHeight: 100,
|
||||
alignment: Alignment.topCenter,
|
||||
fractionalOffset: Offset(-.7, 0),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
List<Widget> _buildMg(BuildContext context, Animation<double> anim) => [
|
||||
Center(
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(0, config.shortMode ? 0.05 : -.1),
|
||||
child: FractionallySizedBox(
|
||||
widthFactor: config.shortMode ? 1 : 2,
|
||||
child: WonderHero(
|
||||
config,
|
||||
'petra-mg',
|
||||
child: Image.asset('$assetPath/petra.png', fit: BoxFit.contain, opacity: anim),
|
||||
),
|
||||
),
|
||||
FractionallySizedBox(
|
||||
heightFactor: config.shortMode ? 1 : .8,
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: IllustrationPiece(
|
||||
fileName: 'petra.png',
|
||||
heightFactor: .65,
|
||||
minHeight: 500,
|
||||
zoomAmt: .1,
|
||||
enableHero: true,
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
List<Widget> _buildFg(BuildContext context, Animation<double> anim) {
|
||||
final curvedAnim = Curves.easeOut.transform(anim.value);
|
||||
return [
|
||||
Stack(children: [
|
||||
CenterLeft(
|
||||
child: FractionallySizedBox(
|
||||
widthFactor: .63,
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(-.3 * (1 - curvedAnim), 0),
|
||||
child: Transform.scale(
|
||||
scale: 1.1 + config.zoom * .2,
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(-.35, -.07),
|
||||
child: Image.asset('$assetPath/foreground-left.png', opacity: anim, fit: BoxFit.contain),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
CenterRight(
|
||||
child: FractionallySizedBox(
|
||||
widthFactor: .72,
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(.3 * (1 - curvedAnim), 0),
|
||||
child: Transform.scale(
|
||||
scale: 1 + config.zoom * .4,
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(.4, -.03),
|
||||
child: Image.asset('$assetPath/foreground-right.png', opacity: anim, fit: BoxFit.contain),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
])
|
||||
IllustrationPiece(
|
||||
fileName: 'foreground-left.png',
|
||||
alignment: Alignment.bottomCenter,
|
||||
initialOffset: Offset(-80, 0),
|
||||
heightFactor: 1,
|
||||
fractionalOffset: Offset(-.5, 0),
|
||||
zoomAmt: .1,
|
||||
dynamicHzOffset: -130,
|
||||
bottom: (_) {
|
||||
/// To cover everything behind this piece with a solid color, we scale up a container
|
||||
/// and then offset it in negative space
|
||||
const double scaleX = 5;
|
||||
return FractionalTranslation(
|
||||
translation: Offset(-1 - scaleX / 2, 0),
|
||||
child:
|
||||
Transform.scale(scaleX: 5, child: Container(color: WonderType.petra.fgColor.withOpacity(anim.value))),
|
||||
);
|
||||
},
|
||||
),
|
||||
IllustrationPiece(
|
||||
fileName: 'foreground-right.png',
|
||||
alignment: Alignment.bottomCenter,
|
||||
initialOffset: Offset(80, 00),
|
||||
heightFactor: 1,
|
||||
fractionalOffset: Offset(.5, 0),
|
||||
zoomAmt: .15,
|
||||
dynamicHzOffset: 130,
|
||||
bottom: (_) {
|
||||
/// To cover everything behind this piece with a solid color, we scale up a container and then offset it in negative space
|
||||
const double scaleX = 5;
|
||||
return FractionalTranslation(
|
||||
translation: Offset(1 + scaleX / 2, 0),
|
||||
child:
|
||||
Transform.scale(scaleX: 5, child: Container(color: WonderType.petra.fgColor.withOpacity(anim.value))),
|
||||
);
|
||||
},
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,7 @@
|
||||
import 'package:wonders/common_libs.dart';
|
||||
import 'package:wonders/ui/common/fade_color_transition.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/illustration_fg.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/illustration_mg.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/illustration_piece.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/paint_textures.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/wonder_hero.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/wonder_illustration_builder.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/wonder_illustration_config.dart';
|
||||
|
||||
@ -17,6 +15,7 @@ class PyramidsGizaIllustration extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return WonderIllustrationBuilder(
|
||||
wonderType: WonderType.pyramidsGiza,
|
||||
config: config,
|
||||
bgBuilder: _buildBg,
|
||||
mgBuilder: _buildMg,
|
||||
@ -35,93 +34,54 @@ class PyramidsGizaIllustration extends StatelessWidget {
|
||||
flipY: true,
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment(.75, config.shortMode ? -.2 : -.5),
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(0, -.5 * anim.value),
|
||||
child: WonderHero(
|
||||
config,
|
||||
'pyramids-moon',
|
||||
child: Transform.scale(
|
||||
scale: config.shortMode ? 0.8 : 1.2,
|
||||
child: Image.asset('$assetPath/moon.png', opacity: anim),
|
||||
),
|
||||
),
|
||||
)),
|
||||
IllustrationPiece(
|
||||
fileName: 'moon.png',
|
||||
initialOffset: Offset(0, 20),
|
||||
enableHero: true,
|
||||
heightFactor: .15,
|
||||
minHeight: 100,
|
||||
offset: config.shortMode ? Offset(100, context.heightPx * -.1) : Offset(150, context.heightPx * -.15),
|
||||
zoomAmt: .05,
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
List<Widget> _buildMg(BuildContext context, Animation<double> anim) {
|
||||
return [
|
||||
IllustrationMg(
|
||||
'pyramids.png',
|
||||
type: WonderType.pyramidsGiza,
|
||||
anim: anim,
|
||||
config: config,
|
||||
maxHeight: 600,
|
||||
heightFraction: .85,
|
||||
),
|
||||
|
||||
// Align(
|
||||
// alignment: Alignment(0, config.shortMode ? 0.9 : 0),
|
||||
// child: WonderHero(config, 'pyramids-mg',
|
||||
// child: Transform.scale(
|
||||
// scale: 1 + config.zoom * .1,
|
||||
// child: FractionallySizedBox(
|
||||
// widthFactor: config.shortMode ? 1 : 1.94,
|
||||
// child: Image.asset('$assetPath/pyramids.png', fit: BoxFit.contain, opacity: anim),
|
||||
// ),
|
||||
// )),
|
||||
// ),
|
||||
IllustrationPiece(
|
||||
fileName: 'pyramids.png',
|
||||
enableHero: true,
|
||||
heightFactor: .5,
|
||||
minHeight: 300,
|
||||
zoomAmt: .1,
|
||||
boxFit: BoxFit.contain,
|
||||
overflow: !config.shortMode,
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
List<Widget> _buildFg(BuildContext context, Animation<double> anim) {
|
||||
final curvedAnim = Curves.easeOut.transform(anim.value);
|
||||
return [
|
||||
IllustrationPiece(
|
||||
type: WonderType.pyramidsGiza,
|
||||
anim: anim,
|
||||
fileName: 'foreground-back.png',
|
||||
heightFactor: .5,
|
||||
alignment: Alignment.bottomCenter,
|
||||
initialOffset: Offset(20, 40),
|
||||
initialScale: .95,
|
||||
heightFactor: .55,
|
||||
fractionalOffset: Offset(.1, .06),
|
||||
zoomAmt: .1,
|
||||
dynamicHzOffset: 150,
|
||||
),
|
||||
IllustrationPiece(
|
||||
type: WonderType.pyramidsGiza,
|
||||
anim: anim,
|
||||
fileName: 'foreground-front.png',
|
||||
heightFactor: .5,
|
||||
alignment: Alignment.bottomCenter,
|
||||
)
|
||||
// Transform.scale(
|
||||
// scale: 1 + config.zoom * .2,
|
||||
// child: Transform.translate(
|
||||
// offset: Offset(0, 10 * (1 - curvedAnim)),
|
||||
// child: BottomCenter(
|
||||
// child: FractionallySizedBox(
|
||||
// widthFactor: 1.2,
|
||||
// child: FractionalTranslation(
|
||||
// translation: Offset(0, -1.2),
|
||||
// child: Image.asset('$assetPath/foreground-back.png', opacity: anim, fit: BoxFit.cover)),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// Transform.scale(
|
||||
// scale: 1 + config.zoom * .4,
|
||||
// child: Transform.translate(
|
||||
// offset: Offset(0, 30 * (1 - curvedAnim)),
|
||||
// child: BottomCenter(
|
||||
// child: FractionallySizedBox(
|
||||
// widthFactor: 1.52,
|
||||
// child: FractionalTranslation(
|
||||
// translation: Offset(0, 0.1),
|
||||
// child: Image.asset('$assetPath/foreground-front.png', opacity: anim, fit: BoxFit.cover),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
initialScale: .9,
|
||||
initialOffset: Offset(-40, 60),
|
||||
heightFactor: .55,
|
||||
fractionalOffset: Offset(-.1, .1),
|
||||
zoomAmt: .25,
|
||||
dynamicHzOffset: -150,
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'package:wonders/common_libs.dart';
|
||||
import 'package:wonders/ui/common/fade_color_transition.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/illustration_piece.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/paint_textures.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/wonder_hero.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/wonder_illustration_builder.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/wonder_illustration_config.dart';
|
||||
|
||||
@ -20,11 +20,11 @@ class TajMahalIllustration extends StatelessWidget {
|
||||
bgBuilder: _buildBg,
|
||||
mgBuilder: _buildMg,
|
||||
fgBuilder: _buildFg,
|
||||
wonderType: WonderType.tajMahal,
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _buildBg(BuildContext context, Animation<double> anim) {
|
||||
final curvedAnim = Curves.easeOut.transform(anim.value);
|
||||
return [
|
||||
// Bg color
|
||||
FadeColorTransition(color: fgColor, animation: anim),
|
||||
@ -38,78 +38,69 @@ class TajMahalIllustration extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
// Sun
|
||||
Align(
|
||||
alignment: config.shortMode ? Alignment(-1.25, -2.8) : Alignment(-1.25, -1.15),
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(-.2 + curvedAnim * .2, .4 - curvedAnim * .2),
|
||||
child: WonderHero(config, 'taj-sun', child: Image.asset('$assetPath/sun.png', opacity: anim)),
|
||||
),
|
||||
)
|
||||
IllustrationPiece(
|
||||
fileName: 'sun.png',
|
||||
initialOffset: Offset(0, 20),
|
||||
enableHero: true,
|
||||
heightFactor: .15,
|
||||
minHeight: 140,
|
||||
offset: config.shortMode ? Offset(-100, context.heightPx * -.05) : Offset(-150, context.heightPx * -.15),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
List<Widget> _buildMg(BuildContext context, Animation<double> anim) {
|
||||
return [
|
||||
Transform.scale(
|
||||
scale: 1 + config.zoom * .1,
|
||||
child: Align(
|
||||
alignment: Alignment(0, config.shortMode ? 1 : -.15),
|
||||
child: FractionallySizedBox(
|
||||
widthFactor: config.shortMode ? 1 : 1.7,
|
||||
child: Stack(
|
||||
children: [
|
||||
WonderHero(
|
||||
config,
|
||||
'taj-mg',
|
||||
child: Image.asset('$assetPath/taj-mahal.png', opacity: anim, fit: BoxFit.cover),
|
||||
),
|
||||
if (!config.shortMode)
|
||||
FractionalTranslation(
|
||||
translation: Offset(0, 1.33),
|
||||
child: Image.asset('$assetPath/pool.png', opacity: anim, fit: BoxFit.cover),
|
||||
),
|
||||
],
|
||||
LayoutBuilder(builder: (_, constraints) {
|
||||
const double minHeight = 500, heightFactor = .6, poolScale = 1;
|
||||
return Stack(
|
||||
children: [
|
||||
IllustrationPiece(
|
||||
fileName: 'taj-mahal.png',
|
||||
heightFactor: heightFactor,
|
||||
minHeight: minHeight,
|
||||
zoomAmt: .05,
|
||||
top: config.shortMode
|
||||
? null
|
||||
: (_) => FractionalTranslation(
|
||||
translation: Offset(0, .85),
|
||||
child: IllustrationPiece(
|
||||
fileName: 'pool.png',
|
||||
heightFactor: heightFactor * poolScale,
|
||||
minHeight: minHeight * poolScale,
|
||||
zoomAmt: .05,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
List<Widget> _buildFg(BuildContext context, Animation<double> anim) {
|
||||
final curvedAnim = Curves.easeOut.transform(anim.value);
|
||||
/// Let the mangos scale up as the width of the screen grows
|
||||
final mangoScale = max(context.widthPx - 400, 0) / 1000;
|
||||
return [
|
||||
Transform.scale(
|
||||
scale: 1 + config.zoom * .2,
|
||||
child: Stack(
|
||||
children: [
|
||||
FractionalTranslation(
|
||||
translation: Offset(-.2 * (1 - curvedAnim), 0),
|
||||
child: BottomLeft(
|
||||
child: FractionallySizedBox(
|
||||
heightFactor: .6,
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(-.4, -.04),
|
||||
child: Image.asset('$assetPath/foreground-left.png', opacity: anim, fit: BoxFit.cover),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
FractionalTranslation(
|
||||
translation: Offset(.2 * (1 - curvedAnim), 0),
|
||||
child: BottomRight(
|
||||
child: FractionallySizedBox(
|
||||
heightFactor: .6,
|
||||
child: FractionalTranslation(
|
||||
translation: Offset(.4, -.04),
|
||||
child: Image.asset('$assetPath/foreground-right.png', opacity: anim, fit: BoxFit.cover),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
IllustrationPiece(
|
||||
fileName: 'foreground-right.png',
|
||||
alignment: Alignment.bottomRight,
|
||||
initialOffset: Offset(20, 40),
|
||||
initialScale: .85,
|
||||
heightFactor: .5 + .3 * mangoScale,
|
||||
fractionalOffset: Offset(.3, 0),
|
||||
zoomAmt: .1,
|
||||
),
|
||||
IllustrationPiece(
|
||||
fileName: 'foreground-left.png',
|
||||
alignment: Alignment.bottomLeft,
|
||||
initialScale: .9,
|
||||
initialOffset: Offset(-40, 60),
|
||||
heightFactor: .5 + .3 * mangoScale,
|
||||
fractionalOffset: Offset(-.2, 0),
|
||||
zoomAmt: .25,
|
||||
dynamicHzOffset: 0,
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user