import 'package:flutter/widgets.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'page_dimensions_provider.g.dart'; /// Threshold: images with aspect ratio >= this are considered double-page spreads. const double doublePageAspectRatio = 1.0; /// Stores resolved dimensions for a single page image. class PageDimension { final int width; final int height; const PageDimension({required this.width, required this.height}); double get aspectRatio => height > 0 ? width / height : 0; bool get isDoublePage => aspectRatio >= doublePageAspectRatio; } /// Provider that caches page dimensions for a publication. /// Parameterized by publication ID so each publication has its own cache. @riverpod class PageDimensionsNotifier extends _$PageDimensionsNotifier { @override Map build(String publicationId) { return {}; } /// Resolve dimensions for a page from its [imageProvider]. /// Returns immediately if already cached. Otherwise resolves asynchronously /// and updates state when done. void resolvePage(int pageIndex, ImageProvider imageProvider) { if (state.containsKey(pageIndex)) return; final stream = imageProvider.resolve(ImageConfiguration.empty); late ImageStreamListener listener; listener = ImageStreamListener( (ImageInfo info, bool synchronousCall) { final image = info.image; final dim = PageDimension( width: image.width, height: image.height, ); state = {...state, pageIndex: dim}; image.dispose(); stream.removeListener(listener); }, onError: (exception, stackTrace) { // Failed to resolve — leave uncached, will be treated as portrait stream.removeListener(listener); }, ); stream.addListener(listener); } /// Check if a page's dimensions have been resolved. bool hasPage(int pageIndex) => state.containsKey(pageIndex); }