mirror of
https://github.com/immich-app/immich
synced 2025-10-17 18:19:27 +00:00
fix: display thumbnail while scrubbing paused (#22164)
* fix: display thumbnail while scrubbing paused * pr feedback * pr feedback * tune timeout
This commit is contained in:
parent
d36c26bf97
commit
e42886b767
4 changed files with 34 additions and 16 deletions
|
|
@ -3,7 +3,7 @@
|
||||||
archiveVersion = 1;
|
archiveVersion = 1;
|
||||||
classes = {
|
classes = {
|
||||||
};
|
};
|
||||||
objectVersion = 77;
|
objectVersion = 54;
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
|
|
@ -133,6 +133,8 @@
|
||||||
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
||||||
B2CF7F8C2DDE4EBB00744BF6 /* Sync */ = {
|
B2CF7F8C2DDE4EBB00744BF6 /* Sync */ = {
|
||||||
isa = PBXFileSystemSynchronizedRootGroup;
|
isa = PBXFileSystemSynchronizedRootGroup;
|
||||||
|
exceptions = (
|
||||||
|
);
|
||||||
path = Sync;
|
path = Sync;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
|
@ -519,14 +521,10 @@
|
||||||
inputFileListPaths = (
|
inputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
|
||||||
);
|
);
|
||||||
inputPaths = (
|
|
||||||
);
|
|
||||||
name = "[CP] Copy Pods Resources";
|
name = "[CP] Copy Pods Resources";
|
||||||
outputFileListPaths = (
|
outputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
|
||||||
);
|
);
|
||||||
outputPaths = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
||||||
|
|
@ -555,14 +553,10 @@
|
||||||
inputFileListPaths = (
|
inputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||||
);
|
);
|
||||||
inputPaths = (
|
|
||||||
);
|
|
||||||
name = "[CP] Embed Pods Frameworks";
|
name = "[CP] Embed Pods Frameworks";
|
||||||
outputFileListPaths = (
|
outputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||||
);
|
);
|
||||||
outputPaths = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,6 @@ class _FixedSegmentRow extends ConsumerWidget {
|
||||||
if (isScrubbing) {
|
if (isScrubbing) {
|
||||||
return _buildPlaceholder(context);
|
return _buildPlaceholder(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timelineService.hasRange(assetIndex, assetCount)) {
|
if (timelineService.hasRange(assetIndex, assetCount)) {
|
||||||
return _buildAssetRow(context, timelineService.getAssets(assetIndex, assetCount), timelineService);
|
return _buildAssetRow(context, timelineService.getAssets(assetIndex, assetCount), timelineService);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import 'package:immich_mobile/presentation/widgets/timeline/constants.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/timeline/segment.model.dart';
|
import 'package:immich_mobile/presentation/widgets/timeline/segment.model.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/timeline/timeline.state.dart';
|
import 'package:immich_mobile/presentation/widgets/timeline/timeline.state.dart';
|
||||||
import 'package:immich_mobile/providers/haptic_feedback.provider.dart';
|
import 'package:immich_mobile/providers/haptic_feedback.provider.dart';
|
||||||
|
import 'package:immich_mobile/utils/debounce.dart';
|
||||||
import 'package:intl/intl.dart' hide TextDirection;
|
import 'package:intl/intl.dart' hide TextDirection;
|
||||||
|
|
||||||
/// A widget that will display a BoxScrollView with a ScrollThumb that can be dragged
|
/// A widget that will display a BoxScrollView with a ScrollThumb that can be dragged
|
||||||
|
|
@ -81,6 +82,8 @@ class ScrubberState extends ConsumerState<Scrubber> with TickerProviderStateMixi
|
||||||
bool _isDragging = false;
|
bool _isDragging = false;
|
||||||
List<_Segment> _segments = [];
|
List<_Segment> _segments = [];
|
||||||
int _monthCount = 0;
|
int _monthCount = 0;
|
||||||
|
DateTime? _currentScrubberDate;
|
||||||
|
Debouncer? _scrubberDebouncer;
|
||||||
|
|
||||||
late AnimationController _thumbAnimationController;
|
late AnimationController _thumbAnimationController;
|
||||||
Timer? _fadeOutTimer;
|
Timer? _fadeOutTimer;
|
||||||
|
|
@ -133,6 +136,7 @@ class ScrubberState extends ConsumerState<Scrubber> with TickerProviderStateMixi
|
||||||
_thumbAnimationController.dispose();
|
_thumbAnimationController.dispose();
|
||||||
_labelAnimationController.dispose();
|
_labelAnimationController.dispose();
|
||||||
_fadeOutTimer?.cancel();
|
_fadeOutTimer?.cancel();
|
||||||
|
_scrubberDebouncer?.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -176,11 +180,25 @@ class ScrubberState extends ConsumerState<Scrubber> with TickerProviderStateMixi
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onDragStart(DragStartDetails _) {
|
void _onScrubberDateChanged(DateTime date) {
|
||||||
if (_monthCount >= kMinMonthsToEnableScrubberSnap) {
|
if (_currentScrubberDate != date) {
|
||||||
|
// Date changed, immediately set scrubbing to true
|
||||||
|
_currentScrubberDate = date;
|
||||||
ref.read(timelineStateProvider.notifier).setScrubbing(true);
|
ref.read(timelineStateProvider.notifier).setScrubbing(true);
|
||||||
|
|
||||||
|
// Initialize debouncer if needed
|
||||||
|
_scrubberDebouncer ??= Debouncer(interval: const Duration(milliseconds: 50));
|
||||||
|
|
||||||
|
// Debounce setting scrubbing to false
|
||||||
|
_scrubberDebouncer!.run(() {
|
||||||
|
if (_currentScrubberDate == date) {
|
||||||
|
ref.read(timelineStateProvider.notifier).setScrubbing(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _onDragStart(DragStartDetails _) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_isDragging = true;
|
_isDragging = true;
|
||||||
_labelAnimationController.forward();
|
_labelAnimationController.forward();
|
||||||
|
|
@ -206,6 +224,11 @@ class ScrubberState extends ConsumerState<Scrubber> with TickerProviderStateMixi
|
||||||
if (_lastLabel != label) {
|
if (_lastLabel != label) {
|
||||||
ref.read(hapticFeedbackProvider.notifier).selectionClick();
|
ref.read(hapticFeedbackProvider.notifier).selectionClick();
|
||||||
_lastLabel = label;
|
_lastLabel = label;
|
||||||
|
|
||||||
|
// Notify timeline state of the new scrubber date position
|
||||||
|
if (_monthCount >= kMinMonthsToEnableScrubberSnap) {
|
||||||
|
_onScrubberDateChanged(nearestMonthSegment.date);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -294,12 +317,16 @@ class ScrubberState extends ConsumerState<Scrubber> with TickerProviderStateMixi
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onDragEnd(DragEndDetails _) {
|
void _onDragEnd(DragEndDetails _) {
|
||||||
ref.read(timelineStateProvider.notifier).setScrubbing(false);
|
|
||||||
_labelAnimationController.reverse();
|
_labelAnimationController.reverse();
|
||||||
setState(() {
|
setState(() {
|
||||||
_isDragging = false;
|
_isDragging = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Reset scrubber tracking when drag ends
|
||||||
|
_currentScrubberDate = null;
|
||||||
|
_scrubberDebouncer?.dispose();
|
||||||
|
_scrubberDebouncer = null;
|
||||||
|
|
||||||
_resetThumbTimer();
|
_resetThumbTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,8 +72,6 @@ class TimelineState {
|
||||||
}
|
}
|
||||||
|
|
||||||
class TimelineStateNotifier extends Notifier<TimelineState> {
|
class TimelineStateNotifier extends Notifier<TimelineState> {
|
||||||
TimelineStateNotifier();
|
|
||||||
|
|
||||||
void setScrubbing(bool isScrubbing) {
|
void setScrubbing(bool isScrubbing) {
|
||||||
state = state.copyWith(isScrubbing: isScrubbing);
|
state = state.copyWith(isScrubbing: isScrubbing);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue