wonders/lib/ui/common/collectible_item.dart

68 lines
2.9 KiB
Dart

import 'package:wonders/common_libs.dart';
import 'package:wonders/logic/collectibles_logic.dart';
import 'package:wonders/logic/data/collectible_data.dart';
import 'package:wonders/ui/common/opening_card.dart';
import 'package:wonders/ui/common/utils/app_haptics.dart';
import 'package:wonders/ui/screens/collectible_found/collectible_found_screen.dart';
class CollectibleItem extends StatelessWidget with GetItMixin {
CollectibleItem(this.collectible, {this.size = 64.0, super.key, this.focus}) {
// pre-fetch the image, so it's ready if we show the collectible found screen.
_imageProvider = NetworkImage(collectible.imageUrl);
_imageProvider.resolve(ImageConfiguration()).addListener(ImageStreamListener((_, __) {}));
}
final CollectibleData collectible;
final double size;
late final ImageProvider _imageProvider;
final FocusNode? focus;
void _handleTap(BuildContext context) async {
final screen = CollectibleFoundScreen(collectible: collectible, imageProvider: _imageProvider);
appLogic.showFullscreenDialogRoute(context, screen, transparent: true);
AppHaptics.mediumImpact();
// wait to update the state, to ensure the hero works properly:
await Future.delayed($styles.times.pageTransition);
collectiblesLogic.setState(collectible.id, CollectibleState.discovered);
}
@override
Widget build(BuildContext context) {
final states = watchX((CollectiblesLogic c) => c.statesById);
bool isLost = states[collectible.id] == CollectibleState.lost;
// Use an OpeningCard to let the collectible smoothly collapse its size once it has been found
return SizedBox(
height: isLost ? size : null,
child: RepaintBoundary(
child: OpeningCard(
isOpen: isLost,
// Note: In order for the collapse animation to run properly, we must return a non-zero height or width.
closedBuilder: (_) => SizedBox(width: 1, height: 0),
openBuilder: (_) => AppBtn.basic(
focusNode: focus,
semanticLabel: $strings.collectibleItemSemanticCollectible,
onPressed: () => _handleTap(context),
enableFeedback: false,
child: Hero(
tag: 'collectible_icon_${collectible.id}',
child: Image(
image: collectible.icon,
width: size,
height: size,
fit: BoxFit.contain,
),
)
.animate(onPlay: (controller) => controller.repeat())
.shimmer(delay: 4000.ms, duration: $styles.times.med * 3)
.shake(curve: Curves.easeInOutCubic, hz: 4)
.scale(begin: Offset(1.0, 1.0), end: Offset(1.1, 1.1), duration: $styles.times.med)
.then(delay: $styles.times.med)
.scale(begin: Offset(1.0, 1.0), end: Offset(1 / 1.1, 1 / 1.1)),
),
),
),
);
}
}