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;
/// 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);
@ -18,13 +24,35 @@ class CollectiblesLogic with ThrottledSaveLoadMixin {
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);
states[id] = state;
statesById.value = states;
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) {
final datas = forWonder(wonderType);
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:
await Future.delayed($styles.times.pageTransition);
collectiblesLogic.updateState(collectible.id, CollectibleState.discovered);
collectiblesLogic.setState(collectible.id, CollectibleState.discovered);
}
@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/wonder_data.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';
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_card.dart';
part 'widgets/_collection_footer.dart';
part 'widgets/_newly_discovered_items_btn.dart';
class CollectionScreen extends StatefulWidget with GetItStatefulWidgetMixin {
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 {
Map<String, int> _states = collectiblesLogic.statesById.value;
final GlobalKey _scrollKey = GlobalKey();
@override
void 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));
}
}
@ -52,12 +51,11 @@ class _CollectionScreenState extends State<CollectionScreen> with GetItStateMixi
@override
Widget build(BuildContext context) {
_states = watchX((CollectiblesLogic o) => o.statesById);
int discovered = 0, explored = 0, total = collectiblesLogic.all.length;
_states.forEach((_, state) {
if (state == CollectibleState.discovered) discovered++;
if (state == CollectibleState.explored) explored++;
});
// Rebuild when collectible states change
watchX((CollectiblesLogic o) => o.statesById);
int discovered = collectiblesLogic.discoveredCount;
int explored = collectiblesLogic.exploredCount;
int total = collectiblesLogic.all.length;
return ColoredBox(
color: $styles.colors.greyStrong,
@ -69,7 +67,6 @@ class _CollectionScreenState extends State<CollectionScreen> with GetItStateMixi
_NewlyDiscoveredItemsBtn(count: discovered, onPressed: _scrollToTarget),
Flexible(
child: _CollectionList(
states: _states,
fromId: widget.fromId,
scrollKey: _scrollKey,
onReset: discovered + explored > 0 ? _handleReset : null,

View File

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

View File

@ -1,23 +1,21 @@
part of '../collection_screen.dart';
class _CollectionListCard extends StatelessWidget {
const _CollectionListCard(
{Key? key, this.width, this.height, required this.data, required this.fromId, required this.states})
: super(key: key);
class _CollectionListCard extends StatelessWidget with GetItMixin {
_CollectionListCard({Key? key, this.width, this.height, required this.data, required this.fromId}) : super(key: key);
final double? width;
final double? height;
final WonderData data;
final String? fromId;
final Map<String, int> states;
final String fromId;
void _showDetails(BuildContext context, CollectibleData collectible) {
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
Widget build(BuildContext context) {
final states = watchX((CollectiblesLogic o) => o.statesById);
List<CollectibleData> collectibles = collectiblesLogic.forWonder(data.type);
return Center(
child: SizedBox(

View File

@ -7,11 +7,13 @@ class _AnimatedArrowButton extends StatelessWidget {
final String semanticTitle;
final VoidCallback onTap;
// Fades to 0 and back to 1
final _fadeOutIn = TweenSequence<double>([
TweenSequenceItem(tween: Tween(begin: 1, end: 0), 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>([
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
Widget build(BuildContext context) {
final Duration duration = $styles.times.med;
final btnLbl = StringUtils.supplant($strings.animatedArrowSemanticSwipe, {'{title}': semanticTitle});
return AppBtn.basic(
semanticLabel: StringUtils.supplant(
$strings.animatedArrowSemanticSwipe,
{'{title}': semanticTitle},
),
semanticLabel: btnLbl,
onPressed: onTap,
child: SizedBox(
height: 80,

View File

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

View File

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