From 88eb935d2f0be1e1e2fce0e4209489f5b58deb4d Mon Sep 17 00:00:00 2001 From: ashilkn Date: Sat, 26 Jul 2025 14:21:29 +0530 Subject: [PATCH] UI/UX improvement --- .../component/group/group_header_widget.dart | 99 +++++++++++++++---- .../photos/lib/ui/viewer/gallery/gallery.dart | 28 +++++- 2 files changed, 107 insertions(+), 20 deletions(-) diff --git a/mobile/apps/photos/lib/ui/viewer/gallery/component/group/group_header_widget.dart b/mobile/apps/photos/lib/ui/viewer/gallery/component/group/group_header_widget.dart index 1ca10d2550..59485702fa 100644 --- a/mobile/apps/photos/lib/ui/viewer/gallery/component/group/group_header_widget.dart +++ b/mobile/apps/photos/lib/ui/viewer/gallery/component/group/group_header_widget.dart @@ -1,9 +1,11 @@ import "package:flutter/material.dart"; +import "package:flutter_animate/flutter_animate.dart"; import 'package:photos/core/constants.dart'; import "package:photos/generated/l10n.dart"; import "package:photos/models/file/file.dart"; import "package:photos/models/selected_files.dart"; import "package:photos/theme/ente_theme.dart"; +import "package:photos/ui/viewer/gallery/gallery.dart"; import "package:photos/ui/viewer/gallery/layout_settings.dart"; class GroupHeaderWidget extends StatefulWidget { @@ -15,6 +17,8 @@ class GroupHeaderWidget extends StatefulWidget { final bool showSelectAll; final bool showGallerySettingCTA; final bool showTrailingIcons; + final bool isPinnedHeader; + final bool fadeInTrailingIcons; const GroupHeaderWidget({ super.key, @@ -26,6 +30,8 @@ class GroupHeaderWidget extends StatefulWidget { this.showGallerySettingCTA = false, this.height, this.showTrailingIcons = true, + this.isPinnedHeader = false, + this.fadeInTrailingIcons = false, }); @override @@ -102,20 +108,58 @@ class _GroupHeaderWidgetState extends State { : widget.showTrailingIcons ? GestureDetector( behavior: HitTestBehavior.translucent, - child: ValueListenableBuilder( - valueListenable: _areAllFromGroupSelectedNotifier, - builder: (context, dynamic value, _) { - return value - ? const Icon( - Icons.check_circle, - size: 18, - ) - : Icon( - Icons.check_circle_outlined, - color: colorScheme.strokeMuted, - size: 18, - ); - }, + child: Padding( + padding: const EdgeInsets.all(4), + child: ValueListenableBuilder( + valueListenable: _areAllFromGroupSelectedNotifier, + builder: (context, dynamic value, _) { + return value + ? widget.fadeInTrailingIcons + ? const Icon( + Icons.check_circle, + size: 22, + ).animate().fadeIn( + duration: const Duration( + milliseconds: PinnedGroupHeader + .kTrailingIconsFadeInDurationMs, + ), + delay: const Duration( + milliseconds: PinnedGroupHeader + .kScaleDurationInMilliseconds + + PinnedGroupHeader + .kTrailingIconsFadeInDelayMs, + ), + curve: Curves.easeOut, + ) + : const Icon( + Icons.check_circle, + size: 22, + ) + : widget.fadeInTrailingIcons + ? Icon( + Icons.check_circle_outlined, + color: colorScheme.strokeMuted, + size: 22, + ).animate().fadeIn( + duration: const Duration( + milliseconds: PinnedGroupHeader + .kTrailingIconsFadeInDurationMs, + ), + delay: const Duration( + milliseconds: PinnedGroupHeader + .kScaleDurationInMilliseconds + + PinnedGroupHeader + .kTrailingIconsFadeInDelayMs, + ), + curve: Curves.easeOut, + ) + : Icon( + Icons.check_circle_outlined, + color: colorScheme.strokeMuted, + size: 22, + ); + }, + ), ), onTap: () { widget.selectedFiles?.toggleGroupSelection( @@ -133,15 +177,32 @@ class _GroupHeaderWidgetState extends State { onTap: () => _showLayoutSettingsOverflowMenu(context), child: Padding( padding: const EdgeInsets.all(4), - child: Icon( - Icons.more_vert_outlined, - color: colorScheme.strokeBase, - ), + child: widget.fadeInTrailingIcons + ? Icon( + Icons.more_vert_outlined, + color: colorScheme.blurStrokeBase, + ).animate().fadeIn( + duration: const Duration( + milliseconds: PinnedGroupHeader + .kTrailingIconsFadeInDurationMs, + ), + delay: const Duration( + milliseconds: PinnedGroupHeader + .kScaleDurationInMilliseconds + + PinnedGroupHeader + .kTrailingIconsFadeInDelayMs, + ), + curve: Curves.easeOut, + ) + : Icon( + Icons.more_vert_outlined, + color: colorScheme.strokeBase, + ), ), ) : const SizedBox.shrink() : const SizedBox.shrink(), - const SizedBox(width: 12), + SizedBox(width: horizontalPadding - 4.0), ], ), ); diff --git a/mobile/apps/photos/lib/ui/viewer/gallery/gallery.dart b/mobile/apps/photos/lib/ui/viewer/gallery/gallery.dart index 21b6486975..73f6566535 100644 --- a/mobile/apps/photos/lib/ui/viewer/gallery/gallery.dart +++ b/mobile/apps/photos/lib/ui/viewer/gallery/gallery.dart @@ -667,6 +667,9 @@ class PinnedGroupHeader extends StatefulWidget { final bool showSelectAll; final ValueNotifier scrollbarInUseNotifier; final bool showGallerySettingsCTA; + static const kScaleDurationInMilliseconds = 200; + static const kTrailingIconsFadeInDelayMs = 0; + static const kTrailingIconsFadeInDurationMs = 200; const PinnedGroupHeader({ required this.scrollController, @@ -689,6 +692,8 @@ class _PinnedGroupHeaderState extends State { Timer? _enlargeHeaderTimer; late final ValueNotifier _atZeroScrollNotifier; Timer? _timer; + bool lastInUseState = false; + bool fadeInTrailingIcons = false; @override void initState() { super.initState(); @@ -791,9 +796,26 @@ class _PinnedGroupHeaderState extends State { _enlargeHeaderTimer?.cancel(); if (widget.scrollbarInUseNotifier.value) { _enlargeHeader.value = true; + lastInUseState = true; + fadeInTrailingIcons = false; } else { _enlargeHeaderTimer = Timer(const Duration(milliseconds: 250), () { _enlargeHeader.value = false; + if (lastInUseState) { + fadeInTrailingIcons = true; + Future.delayed( + const Duration( + milliseconds: PinnedGroupHeader.kTrailingIconsFadeInDelayMs + + PinnedGroupHeader.kTrailingIconsFadeInDurationMs + + 100, + ), () { + setState(() { + if (!mounted) return; + fadeInTrailingIcons = false; + }); + }); + } + lastInUseState = false; }); } } @@ -814,7 +836,9 @@ class _PinnedGroupHeaderState extends State { return AnimatedScale( scale: inUse ? 1.2 : 1.0, alignment: Alignment.topLeft, - duration: const Duration(milliseconds: 200), + duration: const Duration( + milliseconds: PinnedGroupHeader.kScaleDurationInMilliseconds, + ), curve: Curves.easeInOutSine, child: ValueListenableBuilder( valueListenable: _atZeroScrollNotifier, @@ -854,6 +878,8 @@ class _PinnedGroupHeaderState extends State { showSelectAll: widget.showSelectAll, showGallerySettingCTA: widget.showGallerySettingsCTA, showTrailingIcons: !inUse, + isPinnedHeader: true, + fadeInTrailingIcons: fadeInTrailingIcons, ), ), ),