Skip to content
103 changes: 65 additions & 38 deletions mobile/lib/features/activity/activity_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ class ActivityPage extends HookConsumerWidget {
final headerTitleStyle = context.textTheme.titleMedium?.copyWith(
fontSize: 22,
fontWeight: FontWeight.w600,
color: navigationPrimaryForeground(context),
);
final topSectionHeight = frostedAppBarHeight(
context,
titleStyle: headerTitleStyle,
bottomHeight: Grid.xxs,
);

final readState = ref.watch(readStateProvider);
Expand Down Expand Up @@ -244,7 +250,8 @@ class ActivityPage extends HookConsumerWidget {
]);
}

final Widget body;
late final Widget body;
var bodyRidesOverTopSection = false;
if (filter.value == InboxFilter.reminders) {
body = _RemindersList(onOpen: openReminder, onRefresh: refresh);
} else if (filter.value == InboxFilter.drafts) {
Expand Down Expand Up @@ -274,54 +281,72 @@ class ActivityPage extends HookConsumerWidget {
? firstReadIndex
: -1;

bodyRidesOverTopSection = true;
body = RefreshIndicator(
edgeOffset: topSectionHeight,
onRefresh: refresh,
child: ListView.builder(
padding: _activityScrollPadding(context),
itemCount: visibleItems.length,
itemBuilder: (context, index) {
final item = visibleItems[index];
final channel = item.item.channelId != null
? channelById[item.item.channelId]
: null;
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
if (index == newBoundaryIndex) const _NewBoundaryDivider(),
_InboxRow(
key: ValueKey(item.id),
item: item,
channel: channel,
currentPubkey: myPk,
isDone: isDone(item),
onTap: () => openItem(item),
onMarkRead: () => markItemRead(item),
onMarkUnread: () => markItemUnread(item),
child: CustomScrollView(
slivers: [
SliverToBoxAdapter(child: SizedBox(height: topSectionHeight)),
DecoratedSliver(
decoration: BoxDecoration(
color: context.colors.surface,
borderRadius: const BorderRadius.vertical(
top: Radius.circular(Radii.dialog),
),
),
sliver: SliverPadding(
padding: _activityScrollPadding(context),
sliver: SliverList.builder(
itemCount: visibleItems.length,
itemBuilder: (context, index) {
final item = visibleItems[index];
final channel = item.item.channelId != null
? channelById[item.item.channelId]
: null;
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
if (index == newBoundaryIndex)
const _NewBoundaryDivider(),
_InboxRow(
key: ValueKey(item.id),
item: item,
channel: channel,
currentPubkey: myPk,
isDone: isDone(item),
onTap: () => openItem(item),
onMarkRead: () => markItemRead(item),
onMarkUnread: () => markItemUnread(item),
),
],
);
},
),
],
);
},
),
),
],
),
);
}

return FrostedScaffold(
backgroundColor: Colors.transparent,
backgroundColor: context.colors.surface,
appBar: FrostedAppBar(
gradient: context.appColors.topSectionGradient,
automaticallyImplyLeading: false,
title: const Text('Activity'),
horizontalInset: Grid.gutter,
showBottomDivider: true,
bottomDividerOpacity: 0.06,
title: Text('Activity', style: headerTitleStyle),
Comment thread
klopez4212 marked this conversation as resolved.
titleStyle: headerTitleStyle,
actions: [
_FilterMenuButton(
_ActivityActionsPill(
filter: filter.value,
dueReminderCount: dueReminderCount,
draftCount: drafts.length,
onChanged: (f) => filter.value = f,
),
_InboxOptionsButton(
unreadOnly: unreadOnly.value,
unreadCount: unreadVisibleCount,
onFilterChanged: (f) => filter.value = f,
onUnreadOnlyChanged: (v) => unreadOnly.value = v,
onMarkAllRead: () {
for (final item in visibleItems) {
Expand All @@ -330,17 +355,19 @@ class ActivityPage extends HookConsumerWidget {
},
),
],
bottomHeight: Grid.xxs,
bottom: const SizedBox.expand(),
),
body: SafeArea(
key: const ValueKey('activity-content-safe-area'),
top: false,
bottom: false,
child: Padding(
padding: EdgeInsets.only(
top: frostedAppBarHeight(context, titleStyle: headerTitleStyle),
),
child: body,
),
child: bodyRidesOverTopSection
? body
: Padding(
padding: EdgeInsets.only(top: topSectionHeight),
child: body,
),
),
);
}
Expand Down
64 changes: 62 additions & 2 deletions mobile/lib/features/activity/activity_page/header_actions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,59 @@ const _filterLabels = <InboxFilter, String>{
InboxFilter.drafts: 'Drafts',
};

class _ActivityActionsPill extends StatelessWidget {
final InboxFilter filter;
final int dueReminderCount;
final int draftCount;
final bool unreadOnly;
final int unreadCount;
final ValueChanged<InboxFilter> onFilterChanged;
final ValueChanged<bool> onUnreadOnlyChanged;
final VoidCallback onMarkAllRead;

const _ActivityActionsPill({
required this.filter,
required this.dueReminderCount,
required this.draftCount,
required this.unreadOnly,
required this.unreadCount,
required this.onFilterChanged,
required this.onUnreadOnlyChanged,
required this.onMarkAllRead,
});

@override
Widget build(BuildContext context) => ClipRRect(
borderRadius: BorderRadius.circular(Radii.full),
child: DecoratedBox(
decoration: BoxDecoration(
color: context.colors.primaryContainer,
borderRadius: BorderRadius.circular(Radii.full),
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: Grid.quarter),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
_FilterMenuButton(
filter: filter,
dueReminderCount: dueReminderCount,
draftCount: draftCount,
onChanged: onFilterChanged,
),
_InboxOptionsButton(
unreadOnly: unreadOnly,
unreadCount: unreadCount,
onUnreadOnlyChanged: onUnreadOnlyChanged,
onMarkAllRead: onMarkAllRead,
),
],
),
),
),
);
}

/// Compact filter dropdown replacing the old chip rail — mirrors desktop's
/// inbox filter menu (`FILTER_OPTIONS`).
class _FilterMenuButton extends StatelessWidget {
Expand Down Expand Up @@ -91,14 +144,15 @@ class _FilterMenuButton extends StatelessWidget {
Text(
_filterLabels[filter]!,
style: context.textTheme.labelLarge?.copyWith(
color: navigationPrimaryForeground(context),
fontWeight: FontWeight.w600,
),
),
const SizedBox(width: Grid.quarter),
Icon(
LucideIcons.chevronDown,
size: 16,
color: context.colors.onSurfaceVariant,
color: navigationPrimaryForeground(context),
),
if (dueReminderCount > 0 || draftCount > 0) ...[
const SizedBox(width: Grid.quarter),
Expand Down Expand Up @@ -133,7 +187,7 @@ class _CountBadge extends StatelessWidget {
vertical: Grid.quarter,
),
decoration: BoxDecoration(
color: context.colors.primary,
color: navigationPrimaryForeground(context),
borderRadius: BorderRadius.circular(Grid.xxs),
),
child: Text(
Expand Down Expand Up @@ -168,6 +222,12 @@ class _InboxOptionsButton extends StatelessWidget {
builder: (buttonContext) => IconButton(
key: const ValueKey('activity-options-menu'),
tooltip: 'Activity options',
color: navigationPrimaryForeground(context),
padding: const EdgeInsets.symmetric(horizontal: Grid.xxs),
constraints: const BoxConstraints.tightFor(
width: Grid.xl,
height: Grid.xl,
),
icon: const Icon(LucideIcons.ellipsis, size: 20),
onPressed: () async {
final selected = await showAnchoredPopover<String>(
Expand Down
Loading
Loading