Update collectibles
This commit is contained in:
parent
b72118c56c
commit
973d9c61cf
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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(
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user