import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:rra_app/pages/map/tiles/hive_tile_cache.dart'; class HiveTileImage extends StatefulWidget { const HiveTileImage({required this.url, this.onLoaded, super.key}); final String url; final ValueChanged? onLoaded; @override State createState() => _HiveTileImageState(); } class _HiveTileImageState extends State { Uint8List? _bytes; String? _loadingUrl; bool _reportedLoaded = false; @override void initState() { super.initState(); _bytes = HiveTileCache.peek(widget.url); if (_bytes != null && _bytes!.isNotEmpty) { _reportLoaded(); } else { _load(widget.url); } } @override void didUpdateWidget(covariant HiveTileImage oldWidget) { super.didUpdateWidget(oldWidget); if (oldWidget.url != widget.url) { _reportedLoaded = false; _bytes = HiveTileCache.peek(widget.url); if (_bytes != null && _bytes!.isNotEmpty) { _reportLoaded(); } else { _load(widget.url); } } } Future _load(String url) async { _loadingUrl = url; final bytes = await HiveTileCache.getOrFetch(url); if (!mounted || _loadingUrl != url) return; if (bytes != null && bytes.isNotEmpty) { setState(() { _bytes = bytes; }); _reportLoaded(); } } void _reportLoaded() { if (_reportedLoaded) return; _reportedLoaded = true; widget.onLoaded?.call(widget.url); } @override Widget build(BuildContext context) { final bytes = _bytes; if (bytes == null || bytes.isEmpty) { return const ColoredBox(color: Colors.transparent); } _reportLoaded(); return Image.memory( bytes, scale: widget.url.contains('@2x') ? 2.0 : 1.0, fit: BoxFit.cover, gaplessPlayback: true, filterQuality: FilterQuality.medium, ); } }