mirror of
https://github.com/immich-app/immich.git
synced 2026-05-18 03:10:24 +03:00
fix: selection outline changing to transparent before animation finish
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -11,6 +11,7 @@ import 'package:immich_mobile/presentation/widgets/timeline/constants.dart';
|
|||||||
import 'package:immich_mobile/providers/infrastructure/setting.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/setting.provider.dart';
|
||||||
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/asset_viewer/current_asset.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/asset_viewer/current_asset.provider.dart';
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
class _DelayedAnimation extends StatefulWidget {
|
class _DelayedAnimation extends StatefulWidget {
|
||||||
final Widget child;
|
final Widget child;
|
||||||
@@ -23,10 +24,10 @@ class _DelayedAnimation extends StatefulWidget {
|
|||||||
const _DelayedAnimation({
|
const _DelayedAnimation({
|
||||||
required this.child,
|
required this.child,
|
||||||
required this.show,
|
required this.show,
|
||||||
this.showDelay = const Duration(milliseconds: 300),
|
this.showDelay = const Duration(milliseconds: 0),
|
||||||
this.hideDelay = const Duration(milliseconds: 0),
|
this.hideDelay = const Duration(milliseconds: 0),
|
||||||
this.showDuration = const Duration(milliseconds: 200),
|
this.showDuration = const Duration(milliseconds: 0),
|
||||||
this.hideDuration = const Duration(milliseconds: 150),
|
this.hideDuration = const Duration(milliseconds: 0),
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -36,6 +37,7 @@ class _DelayedAnimation extends StatefulWidget {
|
|||||||
class _DelayedAnimationState extends State<_DelayedAnimation> {
|
class _DelayedAnimationState extends State<_DelayedAnimation> {
|
||||||
bool _show = false;
|
bool _show = false;
|
||||||
Duration _currentDuration = const Duration(milliseconds: 200);
|
Duration _currentDuration = const Duration(milliseconds: 200);
|
||||||
|
Timer? _delayTimer;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@@ -43,7 +45,7 @@ class _DelayedAnimationState extends State<_DelayedAnimation> {
|
|||||||
// If starting with show=true, show immediately (no delay on initial render)
|
// If starting with show=true, show immediately (no delay on initial render)
|
||||||
if (widget.show) {
|
if (widget.show) {
|
||||||
_show = true;
|
_show = true;
|
||||||
_currentDuration = const Duration(milliseconds: 200);
|
_currentDuration = widget.showDuration;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,30 +53,50 @@ class _DelayedAnimationState extends State<_DelayedAnimation> {
|
|||||||
void didUpdateWidget(_DelayedAnimation oldWidget) {
|
void didUpdateWidget(_DelayedAnimation oldWidget) {
|
||||||
super.didUpdateWidget(oldWidget);
|
super.didUpdateWidget(oldWidget);
|
||||||
|
|
||||||
|
// Cancel any pending timer
|
||||||
|
_delayTimer?.cancel();
|
||||||
|
|
||||||
if (widget.show && !oldWidget.show) {
|
if (widget.show && !oldWidget.show) {
|
||||||
// Showing: use show duration and delay
|
// Showing: set duration, then delay, then show
|
||||||
setState(() => _currentDuration = widget.showDuration);
|
_currentDuration = widget.showDuration;
|
||||||
Future.delayed(widget.showDelay, () {
|
if (widget.showDelay == Duration.zero) {
|
||||||
if (mounted) {
|
setState(() => _show = true);
|
||||||
setState(() => _show = true);
|
} else {
|
||||||
}
|
_delayTimer = Timer(widget.showDelay, () {
|
||||||
});
|
|
||||||
} else if (!widget.show && oldWidget.show) {
|
|
||||||
// Hiding: use hide duration and no delay
|
|
||||||
setState(() {
|
|
||||||
_currentDuration = widget.hideDuration;
|
|
||||||
Future.delayed(widget.hideDelay, () {
|
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
setState(() => _show = false);
|
setState(() => _show = true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
} else if (!widget.show && oldWidget.show) {
|
||||||
|
// Hiding: delay, then set duration and hide
|
||||||
|
if (widget.hideDelay == Duration.zero) {
|
||||||
|
setState(() {
|
||||||
|
_currentDuration = widget.hideDuration;
|
||||||
|
_show = false;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
_delayTimer = Timer(widget.hideDelay, () {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_currentDuration = widget.hideDuration;
|
||||||
|
_show = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_delayTimer?.cancel();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AnimatedOpacity(duration: _currentDuration, opacity: widget.show && _show ? 1.0 : 0.0, child: widget.child);
|
return AnimatedOpacity(duration: _currentDuration, opacity: _show ? 1.0 : 0.0, child: widget.child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,10 +140,7 @@ class ThumbnailTile extends ConsumerWidget {
|
|||||||
children: [
|
children: [
|
||||||
_DelayedAnimation(
|
_DelayedAnimation(
|
||||||
show: isSelected || lockSelection,
|
show: isSelected || lockSelection,
|
||||||
showDelay: Duration.zero,
|
hideDelay: Durations.short4,
|
||||||
hideDelay: Durations.short4, // Wait for indicators to finish
|
|
||||||
showDuration: Duration.zero,
|
|
||||||
hideDuration: Duration.zero,
|
|
||||||
child: Container(color: lockSelection ? context.colorScheme.surfaceContainerHighest : assetContainerColor),
|
child: Container(color: lockSelection ? context.colorScheme.surfaceContainerHighest : assetContainerColor),
|
||||||
),
|
),
|
||||||
AnimatedContainer(
|
AnimatedContainer(
|
||||||
@@ -146,6 +165,9 @@ class ThumbnailTile extends ConsumerWidget {
|
|||||||
if (asset != null)
|
if (asset != null)
|
||||||
_DelayedAnimation(
|
_DelayedAnimation(
|
||||||
show: showIndicators,
|
show: showIndicators,
|
||||||
|
showDelay: const Duration(milliseconds: 300),
|
||||||
|
showDuration: const Duration(milliseconds: 200),
|
||||||
|
hideDuration: const Duration(milliseconds: 150),
|
||||||
child: Align(
|
child: Align(
|
||||||
alignment: Alignment.topRight,
|
alignment: Alignment.topRight,
|
||||||
child: _AssetTypeIcons(asset: asset),
|
child: _AssetTypeIcons(asset: asset),
|
||||||
@@ -155,6 +177,9 @@ class ThumbnailTile extends ConsumerWidget {
|
|||||||
if (storageIndicator && asset != null)
|
if (storageIndicator && asset != null)
|
||||||
_DelayedAnimation(
|
_DelayedAnimation(
|
||||||
show: showIndicators,
|
show: showIndicators,
|
||||||
|
showDelay: const Duration(milliseconds: 300),
|
||||||
|
showDuration: const Duration(milliseconds: 200),
|
||||||
|
hideDuration: const Duration(milliseconds: 150),
|
||||||
child: switch (asset.storage) {
|
child: switch (asset.storage) {
|
||||||
AssetState.local => const Align(
|
AssetState.local => const Align(
|
||||||
alignment: Alignment.bottomRight,
|
alignment: Alignment.bottomRight,
|
||||||
@@ -183,6 +208,9 @@ class ThumbnailTile extends ConsumerWidget {
|
|||||||
if (asset != null && asset.isFavorite)
|
if (asset != null && asset.isFavorite)
|
||||||
_DelayedAnimation(
|
_DelayedAnimation(
|
||||||
show: showIndicators,
|
show: showIndicators,
|
||||||
|
showDelay: const Duration(milliseconds: 300),
|
||||||
|
showDuration: const Duration(milliseconds: 200),
|
||||||
|
hideDuration: const Duration(milliseconds: 150),
|
||||||
child: const Align(
|
child: const Align(
|
||||||
alignment: Alignment.bottomLeft,
|
alignment: Alignment.bottomLeft,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
|
|||||||
Reference in New Issue
Block a user