Update events view, add responsiveness, switch to dark mode
This commit is contained in:
parent
973d9c61cf
commit
34a0ae7dbf
@ -158,7 +158,7 @@ class _Corners {
|
||||
class _Sizes {
|
||||
double get maxContentWidth1 => 800;
|
||||
double get maxContentWidth2 => 600;
|
||||
double get maxContentWidth3 => 400;
|
||||
double get maxContentWidth3 => 500;
|
||||
final Size minAppSize = Size(450, 600);
|
||||
}
|
||||
|
||||
|
@ -1,21 +1,26 @@
|
||||
import 'package:wonders/common_libs.dart';
|
||||
import 'package:wonders/logic/common/string_utils.dart';
|
||||
import 'package:wonders/ui/common/themed_text.dart';
|
||||
|
||||
class TimelineEventCard extends StatelessWidget {
|
||||
const TimelineEventCard({Key? key, required this.year, required this.text}) : super(key: key);
|
||||
const TimelineEventCard({Key? key, required this.year, required this.text, this.darkMode = false}) : super(key: key);
|
||||
final int year;
|
||||
final String text;
|
||||
final bool darkMode;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MergeSemantics(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(bottom: $styles.insets.sm),
|
||||
child: DefaultTextColor(
|
||||
color: darkMode ? Colors.white : Colors.black,
|
||||
child: Container(
|
||||
color: $styles.colors.offWhite,
|
||||
color: darkMode ? $styles.colors.greyStrong : $styles.colors.offWhite,
|
||||
padding: EdgeInsets.all($styles.insets.sm),
|
||||
child: Row(
|
||||
children: [
|
||||
/// Date
|
||||
SizedBox(
|
||||
width: 75,
|
||||
child: Column(
|
||||
@ -26,8 +31,12 @@ class TimelineEventCard extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
),
|
||||
Center(child: Container(width: 1, height: 50, color: $styles.colors.black)),
|
||||
|
||||
/// Divider
|
||||
Center(child: Container(width: 1, height: 50, color: darkMode ? Colors.white : $styles.colors.black)),
|
||||
Gap($styles.insets.sm),
|
||||
|
||||
/// Text content
|
||||
Expanded(
|
||||
child: Text(text, style: $styles.text.bodySmall),
|
||||
),
|
||||
@ -35,6 +44,7 @@ class TimelineEventCard extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,19 @@
|
||||
part of '../wonder_events.dart';
|
||||
|
||||
class _EventsList extends StatefulWidget {
|
||||
const _EventsList({Key? key, required this.data}) : super(key: key);
|
||||
const _EventsList(
|
||||
{Key? key,
|
||||
required this.data,
|
||||
this.topHeight = 0,
|
||||
this.blurOnScroll = false,
|
||||
this.showTopGradient = true,
|
||||
this.showBottomGradient = true})
|
||||
: super(key: key);
|
||||
final WonderData data;
|
||||
final double topHeight;
|
||||
final bool blurOnScroll;
|
||||
final bool showTopGradient;
|
||||
final bool showBottomGradient;
|
||||
|
||||
@override
|
||||
State<_EventsList> createState() => _EventsListState();
|
||||
@ -16,8 +27,6 @@ class _EventsListState extends State<_EventsList> {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _handleGlobalTimelinePressed() => context.push(ScreenPaths.timeline(widget.data.type));
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return PopRouterOnOverScroll(
|
||||
@ -28,9 +37,9 @@ class _EventsListState extends State<_EventsList> {
|
||||
AnimatedBuilder(
|
||||
animation: _scroller,
|
||||
builder: (_, __) {
|
||||
bool showBackdrop = true;
|
||||
bool showBackdrop = widget.blurOnScroll;
|
||||
double backdropAmt = 0;
|
||||
if (_scroller.hasClients) {
|
||||
if (_scroller.hasClients && showBackdrop) {
|
||||
double blurStart = 50;
|
||||
double maxScroll = 150;
|
||||
double scrollPx = _scroller.position.pixels - blurStart;
|
||||
@ -77,20 +86,22 @@ class _EventsListState extends State<_EventsList> {
|
||||
for (var e in events.entries) {
|
||||
final delay = 100.ms + (100 * listItems.length).ms;
|
||||
listItems.add(
|
||||
TimelineEventCard(year: e.key, text: e.value)
|
||||
TimelineEventCard(year: e.key, text: e.value, darkMode: true)
|
||||
.animate()
|
||||
.fade(delay: delay, duration: $styles.times.med * 1.5)
|
||||
.slide(begin: Offset(0, 1), curve: Curves.easeOutBack),
|
||||
);
|
||||
}
|
||||
return SingleChildScrollView(
|
||||
return Stack(
|
||||
children: [
|
||||
SingleChildScrollView(
|
||||
controller: _scroller,
|
||||
child: Column(
|
||||
children: [
|
||||
IgnorePointer(child: Gap(WonderEvents._topHeight)),
|
||||
IgnorePointer(child: Gap(widget.topHeight)),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: $styles.colors.white,
|
||||
color: $styles.colors.black,
|
||||
borderRadius: BorderRadius.circular($styles.corners.md),
|
||||
),
|
||||
padding: EdgeInsets.symmetric(horizontal: $styles.insets.md),
|
||||
@ -100,16 +111,7 @@ class _EventsListState extends State<_EventsList> {
|
||||
buildHandle(),
|
||||
Gap($styles.insets.sm),
|
||||
...listItems,
|
||||
Gap($styles.insets.lg),
|
||||
AppBtn.from(
|
||||
text: $strings.eventsListButtonOpenGlobal,
|
||||
expand: true,
|
||||
onPressed: _handleGlobalTimelinePressed,
|
||||
semanticLabel: $strings.eventsListButtonOpenGlobal,
|
||||
),
|
||||
Gap($styles.insets.xl),
|
||||
CompassDivider(isExpanded: true),
|
||||
Gap($styles.insets.md),
|
||||
HiddenCollectible(widget.data.type, index: 2, size: 150),
|
||||
Gap(150),
|
||||
],
|
||||
@ -117,6 +119,22 @@ class _EventsListState extends State<_EventsList> {
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
/// Vertical gradient on btm
|
||||
if (widget.showBottomGradient)
|
||||
Positioned.fill(
|
||||
child: BottomCenter(
|
||||
child: ListOverscollGradient(bottomUp: true, size: 100),
|
||||
),
|
||||
),
|
||||
if (widget.showTopGradient)
|
||||
Positioned.fill(
|
||||
child: TopCenter(
|
||||
child: ListOverscollGradient(size: 100),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
20
lib/ui/screens/wonder_events/widgets/_timeline_btn.dart
Normal file
20
lib/ui/screens/wonder_events/widgets/_timeline_btn.dart
Normal file
@ -0,0 +1,20 @@
|
||||
part of '../wonder_events.dart';
|
||||
|
||||
class _TimelineBtn extends StatelessWidget {
|
||||
const _TimelineBtn({Key? key, required this.type}) : super(key: key);
|
||||
final WonderType type;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
void handleBtnPressed() => context.push(ScreenPaths.timeline(type));
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: $styles.insets.md),
|
||||
child: AppBtn.from(
|
||||
text: $strings.eventsListButtonOpenGlobal,
|
||||
expand: true,
|
||||
onPressed: handleBtnPressed,
|
||||
semanticLabel: $strings.eventsListButtonOpenGlobal,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,11 +1,12 @@
|
||||
part of '../wonder_events.dart';
|
||||
|
||||
class _TopContent extends StatelessWidget {
|
||||
const _TopContent({Key? key, required this.data}) : super(key: key);
|
||||
class _WonderImageWithTimeline extends StatelessWidget {
|
||||
const _WonderImageWithTimeline({Key? key, required this.data, required this.height}) : super(key: key);
|
||||
final WonderData data;
|
||||
final double height;
|
||||
|
||||
Color _fixLuminence(Color color, [double luminence = 0.35]) {
|
||||
double d = luminence - color.computeLuminance();
|
||||
Color _fixLuminance(Color color, [double luminance = 0.35]) {
|
||||
double d = luminance - color.computeLuminance();
|
||||
if (d <= 0) return color;
|
||||
int r = color.red, g = color.green, b = color.blue;
|
||||
return Color.fromARGB(255, (r + (255 - r) * d).toInt(), (g + (255 - g) * d).toInt(), (b + (255 - b) * d).toInt());
|
||||
@ -14,7 +15,7 @@ class _TopContent extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
height: WonderEvents._topHeight,
|
||||
height: height,
|
||||
child: MergeSemantics(
|
||||
child: LightText(
|
||||
child: SeparatedColumn(
|
||||
@ -45,7 +46,7 @@ class _TopContent extends StatelessWidget {
|
||||
timelineBuilder: (_, data, isSelected) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected ? _fixLuminence(data.type.fgColor) : Colors.transparent,
|
||||
color: isSelected ? _fixLuminance(data.type.fgColor) : Colors.transparent,
|
||||
border: Border.all(color: $styles.colors.greyMedium),
|
||||
borderRadius: BorderRadius.circular($styles.corners.md),
|
||||
),
|
@ -2,7 +2,7 @@ import 'package:wonders/common_libs.dart';
|
||||
import 'package:wonders/logic/common/string_utils.dart';
|
||||
import 'package:wonders/logic/data/wonder_data.dart';
|
||||
import 'package:wonders/ui/common/app_backdrop.dart';
|
||||
import 'package:wonders/ui/common/compass_divider.dart';
|
||||
import 'package:wonders/ui/common/app_icons.dart';
|
||||
import 'package:wonders/ui/common/curved_clippers.dart';
|
||||
import 'package:wonders/ui/common/hidden_collectible.dart';
|
||||
import 'package:wonders/ui/common/list_gradient.dart';
|
||||
@ -13,34 +13,103 @@ import 'package:wonders/ui/common/wonders_timeline_builder.dart';
|
||||
import 'package:wonders/ui/wonder_illustrations/common/wonder_title_text.dart';
|
||||
|
||||
part 'widgets/_events_list.dart';
|
||||
part 'widgets/_top_content.dart';
|
||||
part 'widgets/_timeline_btn.dart';
|
||||
part 'widgets/_wonder_image_with_timeline.dart';
|
||||
|
||||
class WonderEvents extends StatelessWidget {
|
||||
static const double _topHeight = 450;
|
||||
WonderEvents({Key? key, required this.type}) : super(key: key);
|
||||
final WonderType type;
|
||||
late final _data = wondersLogic.getData(type);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LayoutBuilder(builder: (_, constraints) {
|
||||
void handleTimelineBtnPressed() => context.push(ScreenPaths.timeline(type));
|
||||
return LayoutBuilder(builder: (context, constraints) {
|
||||
return Container(
|
||||
color: $styles.colors.black,
|
||||
child: SafeArea(
|
||||
bottom: false,
|
||||
child: Center(
|
||||
child: SizedBox(
|
||||
width: $styles.sizes.maxContentWidth1,
|
||||
child: Stack(
|
||||
children: [
|
||||
/// Top content, sits underneath scrolling list
|
||||
_TopContent(data: _data),
|
||||
|
||||
/// Scrolling Events list, takes up the full view
|
||||
_EventsList(data: _data),
|
||||
Positioned.fill(
|
||||
top: $styles.insets.lg,
|
||||
child: context.isLandscape ? _buildLandscape() : _buildPortrait(),
|
||||
),
|
||||
Positioned(
|
||||
right: $styles.insets.lg,
|
||||
top: $styles.insets.lg,
|
||||
child: CircleIconBtn(
|
||||
icon: AppIcons.timeline,
|
||||
onPressed: handleTimelineBtnPressed,
|
||||
semanticLabel: $strings.eventsListButtonOpenGlobal)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/// Landscape layout is a row, with the WonderImage on left and events on the right
|
||||
Widget _buildLandscape() {
|
||||
return Row(
|
||||
children: [
|
||||
/// WonderImage w/ Timeline btn sits on the left
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: SizedBox(
|
||||
width: $styles.sizes.maxContentWidth3,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Gap($styles.insets.lg),
|
||||
Expanded(child: Center(child: _WonderImageWithTimeline(data: _data, height: 500))),
|
||||
Gap($styles.insets.lg),
|
||||
SizedBox(width: 300, child: _TimelineBtn(type: type)),
|
||||
Gap($styles.insets.xl),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
/// Scrolling event list
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: SizedBox(
|
||||
width: $styles.sizes.maxContentWidth1,
|
||||
child: _EventsList(data: _data, topHeight: 100, blurOnScroll: false),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// Portrait layout is a stack with the list scrolling overtop of the WonderImage
|
||||
Widget _buildPortrait() {
|
||||
return LayoutBuilder(builder: (_, constraints) {
|
||||
double topHeight = max(constraints.maxHeight * .55, 200);
|
||||
return Center(
|
||||
child: SizedBox(
|
||||
width: $styles.sizes.maxContentWidth3,
|
||||
child: Stack(
|
||||
children: [
|
||||
/// Top content, sits underneath scrolling list
|
||||
_WonderImageWithTimeline(height: topHeight, data: _data),
|
||||
|
||||
/// Scrolling Events list, takes up the full view
|
||||
Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: _EventsList(data: _data, topHeight: topHeight, blurOnScroll: true, showTopGradient: false),
|
||||
),
|
||||
Gap($styles.insets.lg),
|
||||
SizedBox(width: $styles.sizes.maxContentWidth3, child: _TimelineBtn(type: _data.type)),
|
||||
Gap($styles.insets.xl),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -297,7 +297,7 @@ packages:
|
||||
name: flutter_inappwebview
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.4.3+7"
|
||||
version: "5.7.1"
|
||||
flutter_lints:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
|
Loading…
x
Reference in New Issue
Block a user