Update collectibles

This commit is contained in:
Shawn 2022-11-14 09:14:08 -07:00
parent b72118c56c
commit 973d9c61cf
8 changed files with 74 additions and 56 deletions

View File

@ -10,7 +10,13 @@ class CollectiblesLogic with ThrottledSaveLoadMixin {
final List<CollectibleData> all = collectiblesData; final List<CollectibleData> all = collectiblesData;
/// Current state for each collectible /// Current state for each collectible
final statesById = ValueNotifier<Map<String, int>>({}); late final statesById = ValueNotifier<Map<String, int>>({})..addListener(_updateCounts);
int _discoveredCount = 0;
int get discoveredCount => _discoveredCount;
int _exploredCount = 0;
int get exploredCount => _exploredCount;
CollectibleData? fromId(String? id) => id == null ? null : all.firstWhereOrNull((o) => o.id == id); CollectibleData? fromId(String? id) => id == null ? null : all.firstWhereOrNull((o) => o.id == id);
@ -18,13 +24,35 @@ class CollectiblesLogic with ThrottledSaveLoadMixin {
return all.where((o) => o.wonder == wonder).toList(growable: false); return all.where((o) => o.wonder == wonder).toList(growable: false);
} }
void updateState(String id, int state) { void setState(String id, int state) {
Map<String, int> states = Map.of(statesById.value); Map<String, int> states = Map.of(statesById.value);
states[id] = state; states[id] = state;
statesById.value = states; statesById.value = states;
scheduleSave(); scheduleSave();
} }
void _updateCounts() {
_discoveredCount = _exploredCount = 0;
statesById.value.forEach((_, state) {
if (state == CollectibleState.discovered) _discoveredCount++;
if (state == CollectibleState.explored) _exploredCount++;
});
}
/// Get a discovered item, sorted by the order of wondersLogic.all
CollectibleData? getFirstDiscoveredOrNull() {
List<CollectibleData> discovered = [];
statesById.value.forEach((key, value) {
if (value == CollectibleState.discovered) discovered.add(fromId(key)!);
});
for (var w in wondersLogic.all) {
for (var d in discovered) {
if (d.wonder == w.type) return d;
}
}
return null;
}
bool isLost(WonderType wonderType, int i) { bool isLost(WonderType wonderType, int i) {
final datas = forWonder(wonderType); final datas = forWonder(wonderType);
final states = statesById.value; final states = statesById.value;

View File

@ -23,7 +23,7 @@ class CollectibleItem extends StatelessWidget with GetItMixin {
// wait to update the state, to ensure the hero works properly: // wait to update the state, to ensure the hero works properly:
await Future.delayed($styles.times.pageTransition); await Future.delayed($styles.times.pageTransition);
collectiblesLogic.updateState(collectible.id, CollectibleState.discovered); collectiblesLogic.setState(collectible.id, CollectibleState.discovered);
} }
@override @override

View File

@ -6,14 +6,13 @@ import 'package:wonders/logic/common/string_utils.dart';
import 'package:wonders/logic/data/collectible_data.dart'; import 'package:wonders/logic/data/collectible_data.dart';
import 'package:wonders/logic/data/wonder_data.dart'; import 'package:wonders/logic/data/wonder_data.dart';
import 'package:wonders/ui/common/controls/simple_header.dart'; import 'package:wonders/ui/common/controls/simple_header.dart';
import 'package:wonders/ui/common/gradient_container.dart';
import 'package:wonders/ui/common/modals/app_modals.dart'; import 'package:wonders/ui/common/modals/app_modals.dart';
part 'widgets/_collectible_image.dart'; part 'widgets/_collectible_image.dart';
part 'widgets/_newly_discovered_items_btn.dart'; part 'widgets/_collection_footer.dart';
part 'widgets/_collection_list.dart'; part 'widgets/_collection_list.dart';
part 'widgets/_collection_list_card.dart'; part 'widgets/_collection_list_card.dart';
part 'widgets/_collection_footer.dart'; part 'widgets/_newly_discovered_items_btn.dart';
class CollectionScreen extends StatefulWidget with GetItStatefulWidgetMixin { class CollectionScreen extends StatefulWidget with GetItStatefulWidgetMixin {
CollectionScreen({required this.fromId, Key? key}) : super(key: key); CollectionScreen({required this.fromId, Key? key}) : super(key: key);
@ -25,13 +24,13 @@ class CollectionScreen extends StatefulWidget with GetItStatefulWidgetMixin {
} }
class _CollectionScreenState extends State<CollectionScreen> with GetItStateMixin { class _CollectionScreenState extends State<CollectionScreen> with GetItStateMixin {
Map<String, int> _states = collectiblesLogic.statesById.value;
final GlobalKey _scrollKey = GlobalKey(); final GlobalKey _scrollKey = GlobalKey();
@override @override
void initState() { void initState() {
super.initState(); super.initState();
if (widget.fromId.isNotEmpty && _states[widget.fromId] == CollectibleState.discovered) { final states = collectiblesLogic.statesById.value;
if (widget.fromId.isNotEmpty && states[widget.fromId] == CollectibleState.discovered) {
scheduleMicrotask(() => _scrollToTarget(false)); scheduleMicrotask(() => _scrollToTarget(false));
} }
} }
@ -52,12 +51,11 @@ class _CollectionScreenState extends State<CollectionScreen> with GetItStateMixi
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
_states = watchX((CollectiblesLogic o) => o.statesById); // Rebuild when collectible states change
int discovered = 0, explored = 0, total = collectiblesLogic.all.length; watchX((CollectiblesLogic o) => o.statesById);
_states.forEach((_, state) { int discovered = collectiblesLogic.discoveredCount;
if (state == CollectibleState.discovered) discovered++; int explored = collectiblesLogic.exploredCount;
if (state == CollectibleState.explored) explored++; int total = collectiblesLogic.all.length;
});
return ColoredBox( return ColoredBox(
color: $styles.colors.greyStrong, color: $styles.colors.greyStrong,
@ -69,7 +67,6 @@ class _CollectionScreenState extends State<CollectionScreen> with GetItStateMixi
_NewlyDiscoveredItemsBtn(count: discovered, onPressed: _scrollToTarget), _NewlyDiscoveredItemsBtn(count: discovered, onPressed: _scrollToTarget),
Flexible( Flexible(
child: _CollectionList( child: _CollectionList(
states: _states,
fromId: widget.fromId, fromId: widget.fromId,
scrollKey: _scrollKey, scrollKey: _scrollKey,
onReset: discovered + explored > 0 ? _handleReset : null, onReset: discovered + explored > 0 ? _handleReset : null,

View File

@ -1,30 +1,31 @@
part of '../collection_screen.dart'; part of '../collection_screen.dart';
@immutable @immutable
class _CollectionList extends StatelessWidget { class _CollectionList extends StatelessWidget with GetItMixin {
const _CollectionList({ _CollectionList({
Key? key, Key? key,
required this.states,
this.onReset, this.onReset,
this.fromId, required this.fromId,
this.scrollKey, this.scrollKey,
}) : super(key: key); }) : super(key: key);
final Map<String, int> states;
final VoidCallback? onReset; final VoidCallback? onReset;
final Key? scrollKey; final Key? scrollKey;
final String? fromId; final String fromId;
WonderType? get scrollTargetWonder { WonderType? get scrollTargetWonder {
String? id = fromId; CollectibleData? item;
if (states[id] != CollectibleState.discovered) { if (fromId.isEmpty) {
id = states.keys.firstWhereOrNull((id) => states[id] == CollectibleState.discovered); item = collectiblesLogic.getFirstDiscoveredOrNull();
} else {
item = collectiblesLogic.fromId(fromId);
} }
return collectiblesLogic.fromId(id)?.wonder; return item?.wonder;
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
watchX((CollectiblesLogic o) => o.statesById);
List<WonderData> wonders = wondersLogic.all; List<WonderData> wonders = wondersLogic.all;
bool vtMode = context.isLandscape == false; bool vtMode = context.isLandscape == false;
final scrollWonder = scrollTargetWonder; final scrollWonder = scrollTargetWonder;
@ -36,7 +37,6 @@ class _CollectionList extends StatelessWidget {
height: vtMode ? 300 : 400, height: vtMode ? 300 : 400,
width: vtMode ? null : 600, width: vtMode ? null : 600,
fromId: fromId, fromId: fromId,
states: states,
data: d, data: d,
); );
}).toList() }).toList()
@ -46,17 +46,12 @@ class _CollectionList extends StatelessWidget {
scrollDirection: vtMode ? Axis.vertical : Axis.horizontal, scrollDirection: vtMode ? Axis.vertical : Axis.horizontal,
child: Padding( child: Padding(
padding: EdgeInsets.all($styles.insets.lg), padding: EdgeInsets.all($styles.insets.lg),
child: vtMode child: SeparatedFlex(
? SeparatedColumn( direction: vtMode ? Axis.vertical : Axis.horizontal,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
separatorBuilder: () => Gap($styles.insets.lg), separatorBuilder: () => Gap($styles.insets.lg),
children: collections, children: collections,
) ),
: SeparatedRow(
separatorBuilder: () => Gap($styles.insets.xl * 2),
mainAxisSize: MainAxisSize.min,
children: collections,
),
), ),
); );
} }

View File

@ -1,23 +1,21 @@
part of '../collection_screen.dart'; part of '../collection_screen.dart';
class _CollectionListCard extends StatelessWidget { class _CollectionListCard extends StatelessWidget with GetItMixin {
const _CollectionListCard( _CollectionListCard({Key? key, this.width, this.height, required this.data, required this.fromId}) : super(key: key);
{Key? key, this.width, this.height, required this.data, required this.fromId, required this.states})
: super(key: key);
final double? width; final double? width;
final double? height; final double? height;
final WonderData data; final WonderData data;
final String? fromId; final String fromId;
final Map<String, int> states;
void _showDetails(BuildContext context, CollectibleData collectible) { void _showDetails(BuildContext context, CollectibleData collectible) {
context.push(ScreenPaths.artifact(collectible.artifactId)); context.push(ScreenPaths.artifact(collectible.artifactId));
Future.delayed(300.ms).then((_) => collectiblesLogic.updateState(collectible.id, CollectibleState.explored)); Future.delayed(300.ms).then((_) => collectiblesLogic.setState(collectible.id, CollectibleState.explored));
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final states = watchX((CollectiblesLogic o) => o.statesById);
List<CollectibleData> collectibles = collectiblesLogic.forWonder(data.type); List<CollectibleData> collectibles = collectiblesLogic.forWonder(data.type);
return Center( return Center(
child: SizedBox( child: SizedBox(

View File

@ -7,11 +7,13 @@ class _AnimatedArrowButton extends StatelessWidget {
final String semanticTitle; final String semanticTitle;
final VoidCallback onTap; final VoidCallback onTap;
// Fades to 0 and back to 1
final _fadeOutIn = TweenSequence<double>([ final _fadeOutIn = TweenSequence<double>([
TweenSequenceItem(tween: Tween(begin: 1, end: 0), weight: .5), TweenSequenceItem(tween: Tween(begin: 1, end: 0), weight: .5),
TweenSequenceItem(tween: Tween(begin: 0, end: 1), weight: .5), TweenSequenceItem(tween: Tween(begin: 0, end: 1), weight: .5),
]); ]);
// Holds top alignment for first half, then jumps down and slides back up
final _slideDown = TweenSequence<double>([ final _slideDown = TweenSequence<double>([
TweenSequenceItem(tween: Tween(begin: 1, end: 1), weight: .5), TweenSequenceItem(tween: Tween(begin: 1, end: 1), weight: .5),
TweenSequenceItem(tween: Tween(begin: -1, end: 1), weight: .5) TweenSequenceItem(tween: Tween(begin: -1, end: 1), weight: .5)
@ -20,11 +22,9 @@ class _AnimatedArrowButton extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final Duration duration = $styles.times.med; final Duration duration = $styles.times.med;
final btnLbl = StringUtils.supplant($strings.animatedArrowSemanticSwipe, {'{title}': semanticTitle});
return AppBtn.basic( return AppBtn.basic(
semanticLabel: StringUtils.supplant( semanticLabel: btnLbl,
$strings.animatedArrowSemanticSwipe,
{'{title}': semanticTitle},
),
onPressed: onTap, onPressed: onTap,
child: SizedBox( child: SizedBox(
height: 80, height: 80,

View File

@ -1,10 +1,10 @@
// This is a generated file; do not edit or check into version control. // This is a generated file; do not edit or check into version control.
FLUTTER_ROOT=/Users/shawn/Dev/flutter FLUTTER_ROOT=C:\_dev\sdks\flutter
FLUTTER_APPLICATION_PATH=/Users/shawn/Dev/gskinner/flutter-wonders-app FLUTTER_APPLICATION_PATH=C:\_dev\gskinner\flutter_wonders_app
COCOAPODS_PARALLEL_CODE_SIGN=true COCOAPODS_PARALLEL_CODE_SIGN=true
FLUTTER_BUILD_DIR=build FLUTTER_BUILD_DIR=build
FLUTTER_BUILD_NAME=1.9.6 FLUTTER_BUILD_NAME=1.9.7
FLUTTER_BUILD_NUMBER=1.9.6 FLUTTER_BUILD_NUMBER=1.9.7
DART_OBFUSCATION=false DART_OBFUSCATION=false
TRACK_WIDGET_CREATION=true TRACK_WIDGET_CREATION=true
TREE_SHAKE_ICONS=false TREE_SHAKE_ICONS=false

View File

@ -1,11 +1,11 @@
#!/bin/sh #!/bin/sh
# This is a generated file; do not edit or check into version control. # This is a generated file; do not edit or check into version control.
export "FLUTTER_ROOT=/Users/shawn/Dev/flutter" export "FLUTTER_ROOT=C:\_dev\sdks\flutter"
export "FLUTTER_APPLICATION_PATH=/Users/shawn/Dev/gskinner/flutter-wonders-app" export "FLUTTER_APPLICATION_PATH=C:\_dev\gskinner\flutter_wonders_app"
export "COCOAPODS_PARALLEL_CODE_SIGN=true" export "COCOAPODS_PARALLEL_CODE_SIGN=true"
export "FLUTTER_BUILD_DIR=build" export "FLUTTER_BUILD_DIR=build"
export "FLUTTER_BUILD_NAME=1.9.6" export "FLUTTER_BUILD_NAME=1.9.7"
export "FLUTTER_BUILD_NUMBER=1.9.6" export "FLUTTER_BUILD_NUMBER=1.9.7"
export "DART_OBFUSCATION=false" export "DART_OBFUSCATION=false"
export "TRACK_WIDGET_CREATION=true" export "TRACK_WIDGET_CREATION=true"
export "TREE_SHAKE_ICONS=false" export "TREE_SHAKE_ICONS=false"