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:
@@ -37,6 +37,13 @@ abstract class PhotoViewControllerBase<T extends PhotoViewControllerValue> {
|
||||
/// Closes streams and removes eventual listeners.
|
||||
void dispose();
|
||||
|
||||
void positionAnimationBuilder(void Function(Offset)? value);
|
||||
void scaleAnimationBuilder(void Function(double)? value);
|
||||
void rotationAnimationBuilder(void Function(double)? value);
|
||||
|
||||
/// Animates multiple fields of the state
|
||||
void animateMultiple({Offset? position, double? scale, double? rotation});
|
||||
|
||||
/// Add a listener that will ignore updates made internally
|
||||
///
|
||||
/// Since it is made for internal use, it is not performatic to use more than one
|
||||
@@ -147,12 +154,31 @@ class PhotoViewController
|
||||
|
||||
late StreamController<PhotoViewControllerValue> _outputCtrl;
|
||||
|
||||
late void Function(Offset)? _animatePosition;
|
||||
late void Function(double)? _animateScale;
|
||||
late void Function(double)? _animateRotation;
|
||||
|
||||
@override
|
||||
Stream<PhotoViewControllerValue> get outputStateStream => _outputCtrl.stream;
|
||||
|
||||
@override
|
||||
late PhotoViewControllerValue prevValue;
|
||||
|
||||
@override
|
||||
void positionAnimationBuilder(void Function(Offset)? value) {
|
||||
_animatePosition = value;
|
||||
}
|
||||
|
||||
@override
|
||||
void scaleAnimationBuilder(void Function(double)? value) {
|
||||
_animateScale = value;
|
||||
}
|
||||
|
||||
@override
|
||||
void rotationAnimationBuilder(void Function(double)? value) {
|
||||
_animateRotation = value;
|
||||
}
|
||||
|
||||
@override
|
||||
void reset() {
|
||||
value = initial;
|
||||
@@ -172,6 +198,21 @@ class PhotoViewController
|
||||
_valueNotifier.removeIgnorableListener(callback);
|
||||
}
|
||||
|
||||
@override
|
||||
void animateMultiple({Offset? position, double? scale, double? rotation}) {
|
||||
if (position != null && _animatePosition != null) {
|
||||
_animatePosition!(position);
|
||||
}
|
||||
|
||||
if (scale != null && _animateScale != null) {
|
||||
_animateScale!(scale);
|
||||
}
|
||||
|
||||
if (rotation != null && _animateRotation != null) {
|
||||
_animateRotation!(rotation);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_outputCtrl.close();
|
||||
|
||||
@@ -111,6 +111,16 @@ mixin PhotoViewControllerDelegate on State<PhotoViewCore> {
|
||||
);
|
||||
}
|
||||
|
||||
PhotoViewScaleState getScaleStateFromNewScale(double newScale) {
|
||||
PhotoViewScaleState newScaleState = PhotoViewScaleState.initial;
|
||||
if (scale != scaleBoundaries.initialScale) {
|
||||
newScaleState = (newScale > scaleBoundaries.initialScale)
|
||||
? PhotoViewScaleState.zoomedIn
|
||||
: PhotoViewScaleState.zoomedOut;
|
||||
}
|
||||
return newScaleState;
|
||||
}
|
||||
|
||||
void updateScaleStateFromNewScale(double newScale) {
|
||||
PhotoViewScaleState newScaleState = PhotoViewScaleState.initial;
|
||||
if (scale != scaleBoundaries.initialScale) {
|
||||
|
||||
@@ -26,6 +26,8 @@ class PhotoViewScaleStateController {
|
||||
StreamController<PhotoViewScaleState>.broadcast()
|
||||
..sink.add(PhotoViewScaleState.initial);
|
||||
|
||||
bool _hasZoomedOutManually = false;
|
||||
|
||||
/// The output for state/value updates
|
||||
Stream<PhotoViewScaleState> get outputScaleStateStream =>
|
||||
_outputScaleStateCtrl.stream;
|
||||
@@ -42,10 +44,20 @@ class PhotoViewScaleStateController {
|
||||
return;
|
||||
}
|
||||
|
||||
if (newValue == PhotoViewScaleState.zoomedOut) {
|
||||
_hasZoomedOutManually = true;
|
||||
}
|
||||
|
||||
if (newValue == PhotoViewScaleState.initial) {
|
||||
_hasZoomedOutManually = false;
|
||||
}
|
||||
|
||||
prevScaleState = _scaleStateNotifier.value;
|
||||
_scaleStateNotifier.value = newValue;
|
||||
}
|
||||
|
||||
bool get hasZoomedOutManually => _hasZoomedOutManually;
|
||||
|
||||
/// Checks if its actual value is different than previousValue
|
||||
bool get hasChanged => prevScaleState != scaleState;
|
||||
|
||||
@@ -71,6 +83,15 @@ class PhotoViewScaleStateController {
|
||||
if (_scaleStateNotifier.value == newValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (newValue == PhotoViewScaleState.zoomedOut) {
|
||||
_hasZoomedOutManually = true;
|
||||
}
|
||||
|
||||
if (newValue == PhotoViewScaleState.initial) {
|
||||
_hasZoomedOutManually = false;
|
||||
}
|
||||
|
||||
prevScaleState = _scaleStateNotifier.value;
|
||||
_scaleStateNotifier.updateIgnoring(newValue);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user