fix: chat list filter pills spacing issue (#632)
* refactor: expose method in wn search field to get height * fix: chat list filter pills spacing issue * docs: update changelog
This commit is contained in:
@@ -21,15 +21,14 @@ import 'package:whitenoise/widgets/offline_system_notice.dart';
|
||||
import 'package:whitenoise/widgets/wn_button.dart';
|
||||
import 'package:whitenoise/widgets/wn_chat_list.dart';
|
||||
import 'package:whitenoise/widgets/wn_icon.dart';
|
||||
import 'package:whitenoise/widgets/wn_search_field.dart';
|
||||
import 'package:whitenoise/widgets/wn_slate.dart';
|
||||
import 'package:whitenoise/widgets/wn_system_notice.dart';
|
||||
|
||||
const _zapstoreUrl = 'https://zapstore.dev/apps/org.parres.whitenoise';
|
||||
|
||||
const _slateHeight = 80;
|
||||
const _searchAndFiltersHeight = 68;
|
||||
const _searchAndFiltersWithChipsHeight = 108;
|
||||
const _filterChipsHeight = 48;
|
||||
const _filterChipsHeight = 40;
|
||||
|
||||
enum ChatListFilter { chats, archive }
|
||||
|
||||
@@ -202,6 +201,9 @@ class ChatListScreen extends HookConsumerWidget {
|
||||
}, [pubkey]);
|
||||
|
||||
final isArchiveView = selectedFilter.value == ChatListFilter.archive;
|
||||
final searchFieldH = WnSearchField.heightOf(context);
|
||||
final archiveHeaderH = 16.h + searchFieldH;
|
||||
final chatsHeaderH = archiveHeaderH + 8.h + 32.h;
|
||||
final activeChatList = isArchiveView ? archivedChatListResult.chats : chatListResult.chats;
|
||||
final filteredChats = filterChatsBySearchWithMessageMatches(
|
||||
activeChatList,
|
||||
@@ -232,9 +234,7 @@ class ChatListScreen extends HookConsumerWidget {
|
||||
onChatsSelected: (_) => selectedFilter.value = ChatListFilter.chats,
|
||||
onArchiveSelected: (_) => selectedFilter.value = ChatListFilter.archive,
|
||||
),
|
||||
headerHeight: isArchiveView
|
||||
? _searchAndFiltersHeight.h
|
||||
: _searchAndFiltersWithChipsHeight.h,
|
||||
headerHeight: isArchiveView ? archiveHeaderH : chatsHeaderH,
|
||||
pinnedHeader: isArchiveView
|
||||
? Padding(
|
||||
padding: EdgeInsets.only(top: 8.h),
|
||||
@@ -247,6 +247,7 @@ class ChatListScreen extends HookConsumerWidget {
|
||||
)
|
||||
: null,
|
||||
pinnedHeaderHeight: isArchiveView ? _filterChipsHeight.h : 0,
|
||||
pinnedHeaderMinOffset: isArchiveView ? 8.h : 0,
|
||||
emptyStateContent: isEmpty
|
||||
? isArchiveView
|
||||
? Center(
|
||||
|
||||
@@ -25,6 +25,7 @@ class WnChatList extends HookWidget {
|
||||
this.headerHeight = 0,
|
||||
this.pinnedHeader,
|
||||
this.pinnedHeaderHeight = 0,
|
||||
this.pinnedHeaderMinOffset = 0,
|
||||
this.emptyStateContent,
|
||||
});
|
||||
|
||||
@@ -39,6 +40,7 @@ class WnChatList extends HookWidget {
|
||||
|
||||
final Widget? pinnedHeader;
|
||||
final double pinnedHeaderHeight;
|
||||
final double pinnedHeaderMinOffset;
|
||||
|
||||
final Widget? emptyStateContent;
|
||||
|
||||
@@ -171,10 +173,12 @@ class WnChatList extends HookWidget {
|
||||
}
|
||||
|
||||
final effectiveHeaderHeight = headerHeight * headerRevealAnimation;
|
||||
final emptyStateTopInset = topPadding + effectiveHeaderHeight + pinnedHeaderHeight;
|
||||
final effectivePinnedOffset = effectiveHeaderHeight > pinnedHeaderMinOffset
|
||||
? effectiveHeaderHeight
|
||||
: pinnedHeaderMinOffset;
|
||||
final emptyStateTopInset = topPadding + effectivePinnedOffset + pinnedHeaderHeight;
|
||||
final listPadding = EdgeInsets.only(
|
||||
top:
|
||||
topPadding + effectiveHeaderHeight + pinnedHeaderHeight + (hasPinnedHeader ? 24.h : 16.h),
|
||||
top: topPadding + effectivePinnedOffset + pinnedHeaderHeight + 16.h,
|
||||
left: horizontalPadding,
|
||||
right: horizontalPadding,
|
||||
);
|
||||
@@ -239,7 +243,7 @@ class WnChatList extends HookWidget {
|
||||
if (hasPinnedHeader)
|
||||
Positioned(
|
||||
key: const Key('chat_list_pinned_header'),
|
||||
top: topPadding + effectiveHeaderHeight,
|
||||
top: topPadding + effectivePinnedOffset,
|
||||
left: horizontalPadding,
|
||||
right: horizontalPadding,
|
||||
height: pinnedHeaderHeight,
|
||||
|
||||
@@ -4,6 +4,10 @@ import 'package:whitenoise/theme.dart';
|
||||
import 'package:whitenoise/widgets/wn_icon.dart';
|
||||
import 'package:whitenoise/widgets/wn_input_field_button.dart';
|
||||
|
||||
const double _verticalPadding = 12;
|
||||
const double _horizontalPadding = 14;
|
||||
const double _borderWidth = 1;
|
||||
|
||||
class WnSearchField extends StatelessWidget {
|
||||
const WnSearchField({
|
||||
super.key,
|
||||
@@ -22,6 +26,15 @@ class WnSearchField extends StatelessWidget {
|
||||
final VoidCallback? onScan;
|
||||
final bool isLoading;
|
||||
|
||||
static double heightOf(BuildContext context) {
|
||||
final style = context.typographyScaled.medium14;
|
||||
final fontSize = style.fontSize ?? 14.sp;
|
||||
final lineHeightFactor = style.height ?? 1.0;
|
||||
final textLineHeight = fontSize * lineHeightFactor;
|
||||
final raw = (_verticalPadding * 2).h + textLineHeight + (_borderWidth * 2);
|
||||
return raw < kMinInteractiveDimension ? kMinInteractiveDimension : raw;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colors = context.colors;
|
||||
@@ -80,8 +93,8 @@ class WnSearchField extends StatelessWidget {
|
||||
filled: true,
|
||||
fillColor: colors.backgroundPrimary,
|
||||
contentPadding: EdgeInsets.symmetric(
|
||||
vertical: 12.h,
|
||||
horizontal: 14.w,
|
||||
vertical: _verticalPadding.h,
|
||||
horizontal: _horizontalPadding.w,
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8.r),
|
||||
|
||||
Reference in New Issue
Block a user