remove unused animations and start pre-caching later

This commit is contained in:
otsmr 2026-06-20 00:01:14 +02:00
parent 19ffed3386
commit c4fc14a909
3 changed files with 101 additions and 141 deletions

View file

@ -662,6 +662,25 @@ class _MediaViewerViewState extends State<MediaViewerView> {
);
}
void _sendTextMessage() {
if (textMessageController.text.isNotEmpty) {
unawaited(
insertAndSendTextMessage(
widget.group.groupId,
textMessageController.text,
currentMessage!.messageId,
),
);
textMessageController.clear();
}
FocusManager.instance.primaryFocus?.unfocus();
setState(() {
showSendTextMessageInput = false;
showShortReactions = false;
_lastTimeInputClosed = clock.now();
});
}
void onScreenTapped() {
if (_lastTimeInputClosed != null &&
clock.now().difference(_lastTimeInputClosed!) <
@ -774,30 +793,8 @@ class _MediaViewerViewState extends State<MediaViewerView> {
if (showSendTextMessageInput)
MediaViewerMessageInput(
controller: textMessageController,
onSubmitted: (value) {
setState(() {
showSendTextMessageInput = false;
showShortReactions = false;
_lastTimeInputClosed = clock.now();
});
},
onSendPressed: () {
if (textMessageController.text.isNotEmpty) {
unawaited(
insertAndSendTextMessage(
widget.group.groupId,
textMessageController.text,
currentMessage!.messageId,
),
);
textMessageController.clear();
}
setState(() {
showSendTextMessageInput = false;
showShortReactions = false;
_lastTimeInputClosed = clock.now();
});
},
onSubmitted: (value) => _sendTextMessage(),
onSendPressed: _sendTextMessage,
),
if (currentMessage != null)
AdditionalMessageContent(currentMessage!),

View file

@ -39,6 +39,7 @@ class HomeViewState extends State<HomeView> with WidgetsBindingObserver {
double _offsetFromOne = 0;
bool _isBottomNavVisible = true;
Timer? _disableCameraTimer;
bool _startPreloading = false;
final MainCameraController _mainCameraController = MainCameraController();
late final PageController _homeViewPageController;
@ -138,6 +139,13 @@ class HomeViewState extends State<HomeView> with WidgetsBindingObserver {
widget.initialPage == 0) {
streamHomeViewPageIndex.add(0);
}
Future.delayed(const Duration(seconds: 1), () {
if (mounted) {
setState(() {
_startPreloading = true;
});
}
});
});
}
@ -319,7 +327,9 @@ class HomeViewState extends State<HomeView> with WidgetsBindingObserver {
scrollDirection: Axis.horizontal,
physics: const PageScrollPhysics(),
controller: _homeViewPageController,
scrollCacheExtent: const ScrollCacheExtent.viewport(1),
scrollCacheExtent: _startPreloading
? const ScrollCacheExtent.viewport(1)
: null,
slivers: [
SliverFillViewport(
delegate: SliverChildListDelegate([

View file

@ -4,6 +4,7 @@ import 'package:twonly/src/database/tables/mediafiles.table.dart';
import 'package:twonly/src/model/memory_item.model.dart';
import 'package:twonly/src/visual/components/selectable_thumbnail.comp.dart';
import 'package:twonly/src/visual/views/memories/components/memory_transition_painter.dart';
class MemoriesThumbnailComp extends StatefulWidget {
const MemoriesThumbnailComp({
required this.galleryItem,
@ -28,14 +29,7 @@ class MemoriesThumbnailComp extends StatefulWidget {
State<MemoriesThumbnailComp> createState() => _MemoriesThumbnailCompState();
}
final Set<String> _alreadyAnimatedIds = {};
class _MemoriesThumbnailCompState extends State<MemoriesThumbnailComp>
with SingleTickerProviderStateMixin {
late final AnimationController _scaleController;
late final Animation<double> _scaleAnimation;
late final Animation<Offset> _slideAnimation;
class _MemoriesThumbnailCompState extends State<MemoriesThumbnailComp> {
ImageProvider? _imageProvider;
ImageStream? _imageStream;
ImageInfo? _imageInfo;
@ -44,40 +38,6 @@ class _MemoriesThumbnailCompState extends State<MemoriesThumbnailComp>
@override
void initState() {
super.initState();
_scaleController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 350),
);
_scaleAnimation = Tween<double>(begin: 0.94, end: 1).animate(
CurvedAnimation(parent: _scaleController, curve: Curves.easeOutCubic),
);
_slideAnimation =
Tween<Offset>(
begin: const Offset(0, 0.125),
end: Offset.zero,
).animate(
CurvedAnimation(parent: _scaleController, curve: Curves.easeOutCubic),
);
final mediaId = widget.galleryItem.mediaService.mediaFile.mediaId;
final shouldAnimate =
widget.index < 20 && !_alreadyAnimatedIds.contains(mediaId);
if (shouldAnimate) {
_alreadyAnimatedIds.add(mediaId);
final delayMs = widget.index * 10;
if (delayMs > 0) {
Future.delayed(Duration(milliseconds: delayMs), () {
if (mounted) {
_scaleController.forward();
}
});
} else {
_scaleController.forward();
}
} else {
_scaleController.value = 1.0;
}
_listener = ImageStreamListener(
(info, _) {
@ -101,8 +61,11 @@ class _MemoriesThumbnailCompState extends State<MemoriesThumbnailComp>
void _resolveImage() {
final media = widget.galleryItem.mediaService;
final hasThumbnail = media.thumbnailPath.existsSync() && media.thumbnailPath.lengthSync() > 0;
final hasStored = media.storedPath.existsSync() && media.storedPath.lengthSync() > 0;
final hasThumbnail =
media.thumbnailPath.existsSync() &&
media.thumbnailPath.lengthSync() > 0;
final hasStored =
media.storedPath.existsSync() && media.storedPath.lengthSync() > 0;
final isImageOrGif =
media.mediaFile.type == MediaType.image ||
media.mediaFile.type == MediaType.gif;
@ -136,7 +99,6 @@ class _MemoriesThumbnailCompState extends State<MemoriesThumbnailComp>
@override
void dispose() {
_scaleController.dispose();
_imageStream?.removeListener(_listener);
super.dispose();
}
@ -169,80 +131,71 @@ class _MemoriesThumbnailCompState extends State<MemoriesThumbnailComp>
);
}
: null,
child: SlideTransition(
position: _slideAnimation,
child: ScaleTransition(
scale: _scaleAnimation,
child: FadeTransition(
opacity: _scaleController,
child: SelectableThumbnailComp(
isSelected: widget.isSelected,
selectionMode: widget.selectionMode,
child: Stack(
fit: StackFit.expand,
children: [
if (cachedInfo != null)
RawImage(
image: cachedInfo.image,
fit: BoxFit.cover,
)
else if (_imageProvider != null)
Image(
image: _imageProvider!,
fit: BoxFit.cover,
gaplessPlayback: true,
errorBuilder: (context, error, stackTrace) {
return ColoredBox(
color: Colors.grey.shade200,
child: const Center(
child: FaIcon(
FontAwesomeIcons.image,
color: Colors.black26,
),
),
);
},
)
else
ColoredBox(
color: Colors.grey.shade200,
child: const Center(
child: FaIcon(
FontAwesomeIcons.image,
color: Colors.black26,
),
child: SelectableThumbnailComp(
isSelected: widget.isSelected,
selectionMode: widget.selectionMode,
child: Stack(
fit: StackFit.expand,
children: [
if (cachedInfo != null)
RawImage(
image: cachedInfo.image,
fit: BoxFit.cover,
)
else if (_imageProvider != null)
Image(
image: _imageProvider!,
fit: BoxFit.cover,
gaplessPlayback: true,
errorBuilder: (context, error, stackTrace) {
return ColoredBox(
color: Colors.grey.shade200,
child: const Center(
child: FaIcon(
FontAwesomeIcons.image,
color: Colors.black26,
),
),
if (isVideo)
const Positioned.fill(
child: Center(
child: FaIcon(
FontAwesomeIcons.circlePlay,
color: Colors.white,
size: 32,
shadows: [
Shadow(color: Colors.black54, blurRadius: 6),
],
),
),
),
if (media.mediaFile.isFavorite)
const Positioned(
bottom: 6,
left: 6,
child: Icon(
Icons.favorite,
color: Colors.redAccent,
size: 16,
shadows: [
Shadow(color: Colors.black54, blurRadius: 4),
],
),
),
],
);
},
)
else
ColoredBox(
color: Colors.grey.shade200,
child: const Center(
child: FaIcon(
FontAwesomeIcons.image,
color: Colors.black26,
),
),
),
),
),
if (isVideo)
const Positioned.fill(
child: Center(
child: FaIcon(
FontAwesomeIcons.circlePlay,
color: Colors.white,
size: 32,
shadows: [
Shadow(color: Colors.black54, blurRadius: 6),
],
),
),
),
if (media.mediaFile.isFavorite)
const Positioned(
bottom: 6,
left: 6,
child: Icon(
Icons.favorite,
color: Colors.redAccent,
size: 16,
shadows: [
Shadow(color: Colors.black54, blurRadius: 4),
],
),
),
],
),
),
);