feat(mobile): sqlite asset viewer (#19552)

* add full image provider and refactor thumb providers

* photo_view updates

* wip: asset-viewer

* fix controller dispose on page change

* wip: bottom sheet

* fix interactions

* more bottomsheet changes

* generate schema

* PR feedback

* refactor asset viewer

* never rotate and fix background on page change

* use photoview as the loading builder

* precache after delay

* claude: optimizing rebuild of image provider

* claude: optimizing image decoding and caching

* use proper cache for new full size image providers

* chore: load local HEIC fullsize for iOS

* make controller callbacks nullable

* remove imageprovider cache

* do not handle drag gestures when zoomed

* use loadOriginal setting for HEIC / larger images

* preload assets outside timer

* never use same controllers in photo-view gallery

* fix: cannot scroll down once swipe with bottom sheet

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
This commit is contained in:
shenlong
2025-07-02 23:54:37 +05:30
committed by GitHub
parent ec603a008c
commit 7855974a29
47 changed files with 1867 additions and 490 deletions
@@ -11,6 +11,7 @@ class ImageWrapper extends StatefulWidget {
required this.imageProvider,
required this.loadingBuilder,
required this.backgroundDecoration,
required this.semanticLabel,
required this.gaplessPlayback,
required this.heroAttributes,
required this.scaleStateChangedCallback,
@@ -34,6 +35,7 @@ class ImageWrapper extends StatefulWidget {
required this.tightMode,
required this.filterQuality,
required this.disableGestures,
this.disableScaleGestures,
required this.errorBuilder,
required this.enablePanAlways,
required this.index,
@@ -43,6 +45,7 @@ class ImageWrapper extends StatefulWidget {
final LoadingBuilder? loadingBuilder;
final ImageErrorWidgetBuilder? errorBuilder;
final BoxDecoration backgroundDecoration;
final String? semanticLabel;
final bool gaplessPlayback;
final PhotoViewHeroAttributes? heroAttributes;
final ValueChanged<PhotoViewScaleState>? scaleStateChangedCallback;
@@ -66,6 +69,7 @@ class ImageWrapper extends StatefulWidget {
final bool? tightMode;
final FilterQuality? filterQuality;
final bool? disableGestures;
final bool? disableScaleGestures;
final bool? enablePanAlways;
final int index;
@@ -193,6 +197,7 @@ class _ImageWrapperState extends State<ImageWrapper> {
return PhotoViewCore(
imageProvider: widget.imageProvider,
backgroundDecoration: widget.backgroundDecoration,
semanticLabel: widget.semanticLabel,
gaplessPlayback: widget.gaplessPlayback,
enableRotation: widget.enableRotation,
heroAttributes: widget.heroAttributes,
@@ -212,6 +217,7 @@ class _ImageWrapperState extends State<ImageWrapper> {
tightMode: widget.tightMode ?? false,
filterQuality: widget.filterQuality ?? FilterQuality.none,
disableGestures: widget.disableGestures ?? false,
disableScaleGestures: widget.disableScaleGestures ?? false,
enablePanAlways: widget.enablePanAlways ?? false,
);
}
@@ -266,6 +272,7 @@ class CustomChildWrapper extends StatelessWidget {
required this.tightMode,
required this.filterQuality,
required this.disableGestures,
this.disableScaleGestures,
required this.enablePanAlways,
});
@@ -296,6 +303,7 @@ class CustomChildWrapper extends StatelessWidget {
final HitTestBehavior? gestureDetectorBehavior;
final bool? tightMode;
final FilterQuality? filterQuality;
final bool? disableScaleGestures;
final bool? disableGestures;
final bool? enablePanAlways;
@@ -330,6 +338,7 @@ class CustomChildWrapper extends StatelessWidget {
tightMode: tightMode ?? false,
filterQuality: filterQuality ?? FilterQuality.none,
disableGestures: disableGestures ?? false,
disableScaleGestures: disableScaleGestures ?? false,
enablePanAlways: enablePanAlways ?? false,
);
}