100 lines
3.5 KiB
Dart
100 lines
3.5 KiB
Dart
import 'dart:async';
|
|
import 'dart:ui';
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:wonders/common_libs.dart';
|
|
import 'package:wonders/logic/common/debouncer.dart';
|
|
import 'package:wonders/logic/common/string_utils.dart';
|
|
import 'package:wonders/logic/data/timeline_data.dart';
|
|
import 'package:wonders/logic/data/wonder_data.dart';
|
|
import 'package:wonders/ui/common/blend_mask.dart';
|
|
import 'package:wonders/ui/common/centered_box.dart';
|
|
import 'package:wonders/ui/common/controls/app_header.dart';
|
|
import 'package:wonders/ui/common/dashed_line.dart';
|
|
import 'package:wonders/ui/common/list_gradient.dart';
|
|
import 'package:wonders/ui/common/timeline_event_card.dart';
|
|
import 'package:wonders/ui/common/utils/app_haptics.dart';
|
|
import 'package:wonders/ui/common/wonders_timeline_builder.dart';
|
|
|
|
part 'widgets/_animated_era_text.dart';
|
|
part 'widgets/_bottom_scrubber.dart';
|
|
part 'widgets/_dashed_divider_with_year.dart';
|
|
part 'widgets/_event_markers.dart';
|
|
part 'widgets/_event_popups.dart';
|
|
part 'widgets/_scrolling_viewport.dart';
|
|
part 'widgets/_scrolling_viewport_controller.dart';
|
|
part 'widgets/_timeline_section.dart';
|
|
part 'widgets/_year_markers.dart';
|
|
|
|
class TimelineScreen extends StatefulWidget {
|
|
final WonderType? type;
|
|
|
|
const TimelineScreen({super.key, required this.type});
|
|
|
|
@override
|
|
State<TimelineScreen> createState() => _TimelineScreenState();
|
|
}
|
|
|
|
class _TimelineScreenState extends State<TimelineScreen> {
|
|
/// Create a scroll controller that the top and bottom timelines can share
|
|
final ScrollController _scroller = ScrollController();
|
|
final _year = ValueNotifier<int>(0);
|
|
|
|
void _handleViewportYearChanged(int value) => _year.value = value;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return LayoutBuilder(builder: (_, constraints) {
|
|
// Determine min and max size of the timeline based on the size available to this widget
|
|
const double scrubberSize = 80;
|
|
const double minSize = 1200;
|
|
const double maxSize = 5500;
|
|
return Container(
|
|
color: $styles.colors.black,
|
|
child: Padding(
|
|
padding: EdgeInsets.only(bottom: 0),
|
|
child: Column(
|
|
children: [
|
|
AppHeader(title: $strings.timelineTitleGlobalTimeline),
|
|
|
|
/// Vertically scrolling timeline, manages a ScrollController.
|
|
Expanded(
|
|
child: _ScrollingViewport(
|
|
scroller: _scroller,
|
|
minSize: minSize,
|
|
maxSize: maxSize,
|
|
selectedWonder: widget.type,
|
|
onYearChanged: _handleViewportYearChanged,
|
|
),
|
|
),
|
|
|
|
/// Era Text (classical, modern etc)
|
|
ValueListenableBuilder<int>(
|
|
valueListenable: _year,
|
|
builder: (_, value, __) => _AnimatedEraText(value),
|
|
),
|
|
Gap($styles.insets.xs),
|
|
|
|
/// Mini Horizontal timeline, reacts to the state of the larger scrolling timeline,
|
|
/// and changes the timelines scroll position on Hz drag
|
|
CenteredBox(
|
|
width: $styles.sizes.maxContentWidth1,
|
|
child: Padding(
|
|
padding: EdgeInsets.symmetric(horizontal: $styles.insets.lg),
|
|
child: _BottomScrubber(
|
|
_scroller,
|
|
size: scrubberSize,
|
|
timelineMinSize: minSize,
|
|
selectedWonder: widget.type,
|
|
),
|
|
),
|
|
),
|
|
Gap($styles.insets.lg),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
});
|
|
}
|
|
}
|