carousel WIP, added trailing
param to SimpleHeader
This commit is contained in:
parent
34f99c1fe5
commit
e9ae67bff5
@ -1,8 +1,9 @@
|
|||||||
import 'package:wonders/common_libs.dart';
|
import 'package:wonders/common_libs.dart';
|
||||||
|
import 'package:wonders/ui/common/app_icons.dart';
|
||||||
|
|
||||||
/// Shared methods across button types
|
/// Shared methods across button types
|
||||||
Widget _buildIcon(BuildContext context, IconData icon, {required bool isSecondary, required double? size}) =>
|
Widget _buildIcon(BuildContext context, AppIcons icon, {required bool isSecondary, required double? size}) =>
|
||||||
Icon(icon, color: isSecondary ? $styles.colors.black : $styles.colors.offWhite, size: size ?? 18);
|
AppIcon(icon, color: isSecondary ? $styles.colors.black : $styles.colors.offWhite, size: size ?? 18);
|
||||||
|
|
||||||
/// The core button that drives all other buttons.
|
/// The core button that drives all other buttons.
|
||||||
class AppBtn extends StatelessWidget {
|
class AppBtn extends StatelessWidget {
|
||||||
@ -37,7 +38,7 @@ class AppBtn extends StatelessWidget {
|
|||||||
this.border,
|
this.border,
|
||||||
String? semanticLabel,
|
String? semanticLabel,
|
||||||
String? text,
|
String? text,
|
||||||
IconData? icon,
|
AppIcons? icon,
|
||||||
double? iconSize,
|
double? iconSize,
|
||||||
}) : child = null,
|
}) : child = null,
|
||||||
circular = false,
|
circular = false,
|
||||||
|
@ -2,14 +2,14 @@ import 'package:wonders/common_libs.dart';
|
|||||||
|
|
||||||
class SimpleHeader extends StatelessWidget {
|
class SimpleHeader extends StatelessWidget {
|
||||||
const SimpleHeader(this.title,
|
const SimpleHeader(this.title,
|
||||||
{Key? key, this.subtitle, this.child, this.showBackBtn = true, this.isTransparent = false, this.onBack})
|
{Key? key, this.subtitle, this.showBackBtn = true, this.isTransparent = false, this.onBack, this.trailing})
|
||||||
: super(key: key);
|
: super(key: key);
|
||||||
final String title;
|
final String title;
|
||||||
final String? subtitle;
|
final String? subtitle;
|
||||||
final Widget? child;
|
|
||||||
final bool showBackBtn;
|
final bool showBackBtn;
|
||||||
final bool isTransparent;
|
final bool isTransparent;
|
||||||
final VoidCallback? onBack;
|
final VoidCallback? onBack;
|
||||||
|
final Widget Function(BuildContext context)? trailing;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -17,14 +17,28 @@ class SimpleHeader extends StatelessWidget {
|
|||||||
color: isTransparent ? Colors.transparent : $styles.colors.black,
|
color: isTransparent ? Colors.transparent : $styles.colors.black,
|
||||||
child: SafeArea(
|
child: SafeArea(
|
||||||
bottom: false,
|
bottom: false,
|
||||||
|
child: SizedBox(
|
||||||
|
height: 64,
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
Positioned.fill(
|
||||||
|
child: Center(
|
||||||
child: Row(children: [
|
child: Row(children: [
|
||||||
if (showBackBtn) BackBtn(onPressed: onBack).safe(),
|
Gap($styles.insets.sm),
|
||||||
Flexible(
|
if (showBackBtn) BackBtn(onPressed: onBack),
|
||||||
fit: FlexFit.tight,
|
Spacer(),
|
||||||
child: MergeSemantics(
|
if (trailing != null) trailing!.call(context),
|
||||||
|
Gap($styles.insets.sm),
|
||||||
|
//if (showBackBtn) Container(width: $styles.insets.lg * 2, alignment: Alignment.centerLeft, child: child),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
MergeSemantics(
|
||||||
child: Semantics(
|
child: Semantics(
|
||||||
header: true,
|
header: true,
|
||||||
|
child: Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
if (!showBackBtn) Gap($styles.insets.xs),
|
if (!showBackBtn) Gap($styles.insets.xs),
|
||||||
Text(
|
Text(
|
||||||
@ -43,9 +57,10 @@ class SimpleHeader extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
if (showBackBtn) Container(width: $styles.insets.lg * 2, alignment: Alignment.centerLeft, child: child),
|
|
||||||
]),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ import 'dart:ui';
|
|||||||
|
|
||||||
import 'package:wonders/common_libs.dart';
|
import 'package:wonders/common_libs.dart';
|
||||||
import 'package:wonders/logic/data/highlight_data.dart';
|
import 'package:wonders/logic/data/highlight_data.dart';
|
||||||
|
import 'package:wonders/ui/common/app_icons.dart';
|
||||||
import 'package:wonders/ui/common/controls/app_page_indicator.dart';
|
import 'package:wonders/ui/common/controls/app_page_indicator.dart';
|
||||||
import 'package:wonders/ui/common/controls/simple_header.dart';
|
import 'package:wonders/ui/common/controls/simple_header.dart';
|
||||||
import 'package:wonders/ui/common/static_text_scale.dart';
|
import 'package:wonders/ui/common/static_text_scale.dart';
|
||||||
@ -10,6 +11,20 @@ import 'package:wonders/ui/common/static_text_scale.dart';
|
|||||||
part 'widgets/_blurred_image_bg.dart';
|
part 'widgets/_blurred_image_bg.dart';
|
||||||
part 'widgets/_carousel_item.dart';
|
part 'widgets/_carousel_item.dart';
|
||||||
|
|
||||||
|
class GreyBox extends StatelessWidget {
|
||||||
|
const GreyBox(this.lbl, {Key? key, this.strength = .5}) : super(key: key);
|
||||||
|
final String lbl;
|
||||||
|
final double strength;
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => ColoredBox(
|
||||||
|
color: Colors.white,
|
||||||
|
child: Container(
|
||||||
|
color: Colors.grey.shade800.withOpacity(strength),
|
||||||
|
child: Center(child: Text(lbl, style: $styles.text.h3)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
class ArtifactCarouselScreen extends StatefulWidget {
|
class ArtifactCarouselScreen extends StatefulWidget {
|
||||||
final WonderType type;
|
final WonderType type;
|
||||||
const ArtifactCarouselScreen({Key? key, required this.type}) : super(key: key);
|
const ArtifactCarouselScreen({Key? key, required this.type}) : super(key: key);
|
||||||
@ -19,6 +34,252 @@ class ArtifactCarouselScreen extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _ArtifactScreenState extends State<ArtifactCarouselScreen> {
|
class _ArtifactScreenState extends State<ArtifactCarouselScreen> {
|
||||||
|
PageController? _pageController;
|
||||||
|
final _currentPage = ValueNotifier<double>(9999);
|
||||||
|
|
||||||
|
late final List<HighlightData> _artifacts = HighlightData.forWonder(widget.type);
|
||||||
|
late final _currentArtifactIndex = ValueNotifier<int>(0);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_handlePageChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handlePageChanged() {
|
||||||
|
_currentPage.value = _pageController?.page ?? 0;
|
||||||
|
_currentArtifactIndex.value = _currentPage.value.round() % _artifacts.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
bool shortMode = context.heightPx < 800;
|
||||||
|
final double bottomHeight = shortMode ? 190 : 310;
|
||||||
|
// Allow objects to become wider as the screen becomes tall, this allows
|
||||||
|
// them to grow taller as well, filling the available space better.
|
||||||
|
//double itemWidth = 150 + max(context.heightPx - 600, 0) / 600 * 150;
|
||||||
|
double itemHeight = context.heightPx - 150 - bottomHeight;
|
||||||
|
double itemWidth = itemHeight * .666;
|
||||||
|
// TODO: This could be optimized to only run if the size has changed...is it worth it?
|
||||||
|
_pageController?.dispose();
|
||||||
|
_pageController = PageController(
|
||||||
|
viewportFraction: itemWidth / context.widthPx,
|
||||||
|
initialPage: _currentPage.value.round(),
|
||||||
|
);
|
||||||
|
_pageController?.addListener(_handlePageChanged);
|
||||||
|
final pages = [
|
||||||
|
GreyBox('item1', strength: .5),
|
||||||
|
GreyBox('item2', strength: .5),
|
||||||
|
GreyBox('item3', strength: .5),
|
||||||
|
GreyBox('item4', strength: .5),
|
||||||
|
GreyBox('item5', strength: .5),
|
||||||
|
].map((e) => Padding(padding: EdgeInsets.all(10), child: e)).toList();
|
||||||
|
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
/// Background
|
||||||
|
Positioned.fill(
|
||||||
|
child: ValueListenableBuilder<int>(
|
||||||
|
valueListenable: _currentArtifactIndex,
|
||||||
|
builder: (_, value, __) {
|
||||||
|
return _BlurredImageBg(url: _artifacts[value].imageUrl);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
|
||||||
|
/// Bottom Text w/ Circle
|
||||||
|
BottomCenter(
|
||||||
|
child: ValueListenableBuilder<int>(
|
||||||
|
valueListenable: _currentArtifactIndex,
|
||||||
|
builder: (_, value, __) => _CarouselBottomTextWithCircle(
|
||||||
|
artifact: _artifacts[value],
|
||||||
|
height: bottomHeight,
|
||||||
|
shortMode: shortMode,
|
||||||
|
state: this,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
/// Carousel Items
|
||||||
|
PageView.builder(
|
||||||
|
controller: _pageController,
|
||||||
|
itemBuilder: (_, index) {
|
||||||
|
final child = pages[index % pages.length];
|
||||||
|
return ValueListenableBuilder<double>(
|
||||||
|
valueListenable: _currentPage,
|
||||||
|
builder: (_, value, __) {
|
||||||
|
final int offset = (value.round() - index).abs();
|
||||||
|
return CollapsingCarouselListItem(
|
||||||
|
width: itemWidth,
|
||||||
|
bottom: bottomHeight,
|
||||||
|
indexOffset: min(3, offset),
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
|
||||||
|
/// header
|
||||||
|
SimpleHeader(
|
||||||
|
$strings.artifactsTitleArtifacts,
|
||||||
|
showBackBtn: true,
|
||||||
|
isTransparent: true,
|
||||||
|
trailing: (context) => CircleBtn(
|
||||||
|
semanticLabel: $strings.artifactsButtonBrowse,
|
||||||
|
onPressed: () {},
|
||||||
|
child: AppIcon(AppIcons.search),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handles the carousel specific logic, like setting the height and vertical alignment of each item.
|
||||||
|
/// This lets the child simply render it's contents
|
||||||
|
class CollapsingCarouselListItem extends StatelessWidget {
|
||||||
|
const CollapsingCarouselListItem(
|
||||||
|
{Key? key, required this.child, required this.indexOffset, required this.width, required this.bottom})
|
||||||
|
: super(key: key);
|
||||||
|
final Widget child;
|
||||||
|
final int indexOffset;
|
||||||
|
final double width;
|
||||||
|
final double bottom;
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
// Calculate offset, this will be subtracted from the bottom padding moving the element downwards
|
||||||
|
double vtOffset = indexOffset * 30;
|
||||||
|
return AppBtn.basic(
|
||||||
|
onPressed: () => print('todo'),
|
||||||
|
semanticLabel: 'TODO',
|
||||||
|
child: AnimatedOpacity(
|
||||||
|
duration: $styles.times.fast,
|
||||||
|
opacity: indexOffset.abs() <= 2 ? 1 : 0,
|
||||||
|
child: AnimatedPadding(
|
||||||
|
duration: $styles.times.fast,
|
||||||
|
padding: EdgeInsets.only(bottom: bottom),
|
||||||
|
child: BottomCenter(
|
||||||
|
child: AnimatedContainer(
|
||||||
|
duration: $styles.times.fast,
|
||||||
|
// Center item is portrait, the others are square
|
||||||
|
height: indexOffset == 0 ? width * 1.3 : width,
|
||||||
|
child: Placeholder(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CarouselBottomTextWithCircle extends StatelessWidget {
|
||||||
|
const _CarouselBottomTextWithCircle(
|
||||||
|
{Key? key, required this.artifact, required this.height, required this.state, required this.shortMode})
|
||||||
|
: super(key: key);
|
||||||
|
|
||||||
|
final HighlightData artifact;
|
||||||
|
final double height;
|
||||||
|
final _ArtifactScreenState state;
|
||||||
|
final bool shortMode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
width: $styles.sizes.maxContentWidth2,
|
||||||
|
height: height,
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: $styles.insets.md),
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
/// BgCircle
|
||||||
|
_buildBgCircle(),
|
||||||
|
|
||||||
|
/// Text
|
||||||
|
Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Gap($styles.insets.md),
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
IgnorePointer(
|
||||||
|
ignoringSemantics: false,
|
||||||
|
child: Semantics(
|
||||||
|
button: true,
|
||||||
|
// TODO: FIX
|
||||||
|
// onIncrease: () => _handleArtifactTap(_currentOffset.round() + 1),
|
||||||
|
// onDecrease: () => _handleArtifactTap(_currentOffset.round() - 1),
|
||||||
|
// onTap: () => _handleArtifactTap(_currentOffset.round()),
|
||||||
|
liveRegion: true,
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// Force column to stretch horizontally so text is centered
|
||||||
|
SizedBox(width: double.infinity),
|
||||||
|
// Stop text from scaling to make layout a little easier, it's already quite large
|
||||||
|
StaticTextScale(
|
||||||
|
child: Text(
|
||||||
|
artifact.title,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: $styles.text.h2.copyWith(color: $styles.colors.black, height: 1.2, fontSize: 32),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
maxLines: 2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (!shortMode) ...[
|
||||||
|
Gap($styles.insets.xxs),
|
||||||
|
Text(
|
||||||
|
artifact.date.isEmpty ? '--' : artifact.date,
|
||||||
|
style: $styles.text.body,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
).animate(key: ValueKey(artifact.artifactId)).fadeIn(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Gap($styles.insets.sm),
|
||||||
|
if (!shortMode)
|
||||||
|
AppPageIndicator(
|
||||||
|
count: state._artifacts.length,
|
||||||
|
controller: state._pageController!,
|
||||||
|
semanticPageTitle: $strings.artifactsSemanticArtifact,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Gap($styles.insets.md),
|
||||||
|
Spacer(),
|
||||||
|
AppBtn.from(
|
||||||
|
text: $strings.artifactsButtonBrowse,
|
||||||
|
icon: AppIcons.search,
|
||||||
|
expand: true,
|
||||||
|
onPressed: () {}, //_handleSearchTap,
|
||||||
|
),
|
||||||
|
Gap($styles.insets.lg),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
OverflowBox _buildBgCircle() {
|
||||||
|
return OverflowBox(
|
||||||
|
maxWidth: 2000,
|
||||||
|
maxHeight: 2000,
|
||||||
|
child: Transform.translate(
|
||||||
|
offset: Offset(0, 1000 - height * .7),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: $styles.colors.offWhite.withOpacity(0.8),
|
||||||
|
borderRadius: BorderRadius.vertical(top: Radius.circular(999)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ArtifactScreenState2 extends State<ArtifactCarouselScreen> {
|
||||||
// Used to cap white background dimensions.
|
// Used to cap white background dimensions.
|
||||||
static const double _maxElementWidth = 440;
|
static const double _maxElementWidth = 440;
|
||||||
static const double _partialElementWidth = 0.9;
|
static const double _partialElementWidth = 0.9;
|
||||||
@ -199,7 +460,7 @@ class _ArtifactScreenState extends State<ArtifactCarouselScreen> {
|
|||||||
Gap(_small ? $styles.insets.sm : $styles.insets.md),
|
Gap(_small ? $styles.insets.sm : $styles.insets.md),
|
||||||
AppBtn.from(
|
AppBtn.from(
|
||||||
text: $strings.artifactsButtonBrowse,
|
text: $strings.artifactsButtonBrowse,
|
||||||
icon: Icons.search,
|
icon: AppIcons.search,
|
||||||
expand: true,
|
expand: true,
|
||||||
onPressed: _handleSearchTap,
|
onPressed: _handleSearchTap,
|
||||||
),
|
),
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'package:wonders/common_libs.dart';
|
import 'package:wonders/common_libs.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/cards/opening_card.dart';
|
import 'package:wonders/ui/common/cards/opening_card.dart';
|
||||||
import 'package:wonders/ui/common/wonders_timeline_builder.dart';
|
import 'package:wonders/ui/common/wonders_timeline_builder.dart';
|
||||||
import 'package:wonders/ui/screens/artifact/artifact_search/artifact_search_screen.dart';
|
import 'package:wonders/ui/screens/artifact/artifact_search/artifact_search_screen.dart';
|
||||||
@ -193,7 +194,7 @@ class _OpenedTimeRange extends StatelessWidget {
|
|||||||
onPressed: onClose,
|
onPressed: onClose,
|
||||||
semanticLabel: $strings.expandingTimeSelectorSemanticSelector,
|
semanticLabel: $strings.expandingTimeSelectorSemanticSelector,
|
||||||
enableFeedback: false, // handled when panelController changes.
|
enableFeedback: false, // handled when panelController changes.
|
||||||
icon: Icons.close,
|
icon: AppIcons.close,
|
||||||
iconSize: 20,
|
iconSize: 20,
|
||||||
padding: EdgeInsets.symmetric(vertical: $styles.insets.xxs),
|
padding: EdgeInsets.symmetric(vertical: $styles.insets.xxs),
|
||||||
bgColor: Colors.transparent,
|
bgColor: Colors.transparent,
|
||||||
|
@ -78,11 +78,13 @@ class _WonderEditorialScreenState extends State<WonderEditorialScreen> {
|
|||||||
children: [
|
children: [
|
||||||
/// Background
|
/// Background
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: ValueListenableBuilder(
|
child: ValueListenableBuilder<double>(
|
||||||
valueListenable: _scrollPos,
|
valueListenable: _scrollPos,
|
||||||
builder: (_, value, __) {
|
builder: (_, value, __) {
|
||||||
return Container(
|
bool showBg = value < 700;
|
||||||
color: widget.data.type.bgColor.withOpacity(1),
|
return AnimatedContainer(
|
||||||
|
duration: $styles.times.fast,
|
||||||
|
color: widget.data.type.bgColor.withOpacity(showBg ? 1 : 0),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -74,10 +74,9 @@ class _AppBar extends StatelessWidget {
|
|||||||
|
|
||||||
/// Colored overlay
|
/// Colored overlay
|
||||||
if (showOverlay) ...[
|
if (showOverlay) ...[
|
||||||
ClipRect(
|
AnimatedContainer(
|
||||||
child: ColoredBox(
|
duration: $styles.times.slow,
|
||||||
color: wonderType.bgColor.withOpacity(.8),
|
color: wonderType.bgColor.withOpacity(showOverlay ? .8 : 0),
|
||||||
).animate().fade(duration: $styles.times.fast),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -10,15 +10,16 @@ class _CollapsingPullQuoteImage extends StatelessWidget {
|
|||||||
// Start transitioning when we are halfway up the screen
|
// Start transitioning when we are halfway up the screen
|
||||||
final collapseStartPx = context.heightPx * 1;
|
final collapseStartPx = context.heightPx * 1;
|
||||||
final collapseEndPx = context.heightPx * .15;
|
final collapseEndPx = context.heightPx * .15;
|
||||||
const double imgHeight = 430;
|
const double imgHeight = 500;
|
||||||
const double outerPadding = 100;
|
const double outerPadding = 100;
|
||||||
|
|
||||||
/// A single piece of quote text, this widget has one on top, and one on bottom
|
/// A single piece of quote text, this widget has one on top, and one on bottom
|
||||||
Widget buildText(String value, double collapseAmt, {required bool top, bool isAuthor = false}) {
|
Widget buildText(String value, double collapseAmt, {required bool top, bool isAuthor = false}) {
|
||||||
var quoteStyle = $styles.text.quote1;
|
/// Use a fixed font-size for this for consistent scaling
|
||||||
|
var quoteStyle = $styles.text.quote1.copyWith(fontSize: 32);
|
||||||
quoteStyle = quoteStyle.copyWith(color: $styles.colors.caption);
|
quoteStyle = quoteStyle.copyWith(color: $styles.colors.caption);
|
||||||
if (isAuthor) {
|
if (isAuthor) {
|
||||||
quoteStyle = quoteStyle.copyWith(fontSize: 20 * $styles.scale, fontWeight: FontWeight.w600);
|
quoteStyle = quoteStyle.copyWith(fontSize: 20, fontWeight: FontWeight.w600);
|
||||||
}
|
}
|
||||||
double offsetY = (imgHeight / 2 + outerPadding * .25) * (1 - collapseAmt);
|
double offsetY = (imgHeight / 2 + outerPadding * .25) * (1 - collapseAmt);
|
||||||
if (top) offsetY *= -1; // flip?
|
if (top) offsetY *= -1; // flip?
|
||||||
@ -44,7 +45,7 @@ class _CollapsingPullQuoteImage extends StatelessWidget {
|
|||||||
return MergeSemantics(
|
return MergeSemantics(
|
||||||
child: CenteredBox(
|
child: CenteredBox(
|
||||||
padding: EdgeInsets.symmetric(vertical: outerPadding),
|
padding: EdgeInsets.symmetric(vertical: outerPadding),
|
||||||
width: 450,
|
width: imgHeight * .66,
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
|
@ -112,6 +112,7 @@ class _AnimatedCloudsState extends State<AnimatedClouds> with SingleTickerProvid
|
|||||||
|
|
||||||
List<_Cloud> _getClouds() {
|
List<_Cloud> _getClouds() {
|
||||||
Size size = ContextUtils.getSize(context) ?? Size(context.widthPx, 400);
|
Size size = ContextUtils.getSize(context) ?? Size(context.widthPx, 400);
|
||||||
|
|
||||||
rndSeed = _getCloudSeed(widget.wonderType);
|
rndSeed = _getCloudSeed(widget.wonderType);
|
||||||
return List<_Cloud>.generate(3, (index) {
|
return List<_Cloud>.generate(3, (index) {
|
||||||
return _Cloud(
|
return _Cloud(
|
||||||
@ -141,7 +142,7 @@ class _Cloud extends StatelessWidget {
|
|||||||
child: Image.asset(
|
child: Image.asset(
|
||||||
ImagePaths.cloud,
|
ImagePaths.cloud,
|
||||||
opacity: AlwaysStoppedAnimation(.4 * opacity),
|
opacity: AlwaysStoppedAnimation(.4 * opacity),
|
||||||
width: context.widthPx * .65 * scale,
|
width: 400 * scale,
|
||||||
fit: BoxFit.fitWidth,
|
fit: BoxFit.fitWidth,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user