Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions mobile/lib/features/activity/activity_page.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import 'dart:async';
import 'dart:math' as math;
import 'dart:ui' show SemanticsRole;

import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
Expand All @@ -11,6 +9,7 @@ import '../../shared/relay/relay.dart';
import '../../shared/theme/theme.dart';
import '../../shared/utils/string_utils.dart';
import '../../shared/widgets/avatar_image.dart';
import '../../shared/widgets/anchored_popover_menu.dart';
import '../../shared/widgets/buzz_loading_indicator.dart';
import '../../shared/widgets/frosted_app_bar.dart';
import '../../shared/widgets/frosted_scaffold.dart';
Expand All @@ -34,7 +33,6 @@ import 'reminders_provider.dart';
part 'activity_page/header_actions.dart';
part 'activity_page/inbox_row.dart';
part 'activity_page/lists.dart';
part 'activity_page/popover_menu.dart';
part 'activity_page/status_views.dart';

/// Conversation-oriented Activity inbox.
Expand Down Expand Up @@ -284,6 +282,7 @@ class ActivityPage extends HookConsumerWidget {
}

return FrostedScaffold(
backgroundColor: Colors.transparent,
appBar: FrostedAppBar(
gradient: context.appColors.topSectionGradient,
automaticallyImplyLeading: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ class _FilterMenuButton extends StatelessWidget {
key: const ValueKey('activity-filter-menu'),
borderRadius: BorderRadius.circular(Radii.md),
onTap: () async {
final selected = await _showActivityPopover<InboxFilter>(
final selected = await showAnchoredPopover<InboxFilter>(
context: buttonContext,
width: 240,
alignment: _ActivityPopoverAlignment.start,
alignment: AnchoredPopoverAlignment.start,
offset: const Offset(0, Grid.half),
menuPadding: const EdgeInsets.symmetric(vertical: Grid.half),
color: context.colors.surface.withValues(alpha: 0.98),
Expand Down Expand Up @@ -179,10 +179,10 @@ class _InboxOptionsButton extends StatelessWidget {
tooltip: 'Activity options',
icon: const Icon(LucideIcons.ellipsis, size: 20),
onPressed: () async {
final selected = await _showActivityPopover<String>(
final selected = await showAnchoredPopover<String>(
context: buttonContext,
width: 216,
alignment: _ActivityPopoverAlignment.end,
alignment: AnchoredPopoverAlignment.end,
color: context.colors.surface,
elevation: 4,
shadowColor: context.colors.shadow.withValues(alpha: 0.18),
Expand Down
286 changes: 148 additions & 138 deletions mobile/lib/features/channels/channel_detail_page/message_bubble.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,156 +52,166 @@ class _MessageBubble extends ConsumerWidget {
}
}

return Material(
color: Colors.transparent,
borderRadius: BorderRadius.circular(Radii.md),
// The media carousel intentionally continues through the list's trailing
// gutter. InkWell still clips its ink to [borderRadius], while leaving
// overflowing message content visible.
clipBehavior: Clip.none,
child: InkWell(
key: ValueKey('message-row-${message.id}'),
return Padding(
padding: EdgeInsets.only(top: showAuthor ? Grid.xs : 0),
child: Material(
color: Colors.transparent,
borderRadius: BorderRadius.circular(Radii.md),
highlightColor: context.colors.primary.withValues(alpha: 0.1),
onLongPress: () => showMessageActions(
context: context,
ref: ref,
message: message,
channelId: currentChannelId,
canManageMessage: canManageMessage,
allMessages: allMessages,
currentPubkey: currentPubkey,
isMember: isMember,
isArchived: isArchived,
),
child: Padding(
padding: EdgeInsets.only(
top: showAuthor ? Grid.xs : Grid.xxs,
bottom: showAuthor ? 0 : Grid.xxs,
// The media carousel intentionally continues through the list's trailing
// gutter. InkWell still clips its ink to [borderRadius], while leaving
// overflowing message content visible.
clipBehavior: Clip.none,
child: InkWell(
key: ValueKey('message-row-${message.id}'),
borderRadius: BorderRadius.circular(Radii.md),
highlightColor: context.colors.primary.withValues(alpha: 0.1),
onLongPress: () => showMessageActions(
context: context,
ref: ref,
message: message,
channelId: currentChannelId,
canManageMessage: canManageMessage,
allMessages: allMessages,
currentPubkey: currentPubkey,
isMember: isMember,
isArchived: isArchived,
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (showAuthor)
GestureDetector(
onTap: () => showUserProfileSheet(context, message.pubkey),
child: _UserAvatar(profile: profile, pubkey: message.pubkey),
)
else
const SizedBox(width: messageAvatarSize),
const SizedBox(width: messageAvatarContentGap),
Expanded(
child: Transform.translate(
offset: Offset(0, showAuthor ? -Grid.quarter : 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (showAuthor)
Padding(
padding: const EdgeInsets.only(bottom: Grid.quarter),
child: Row(
children: [
Expanded(
child: MessageAuthorMeta(
displayName: displayName,
username: messageUsernameLabel(profile),
timestamp: formatMessageTime(
message.createdAt,
),
nameColor: context.colors.onSurface,
metadataColor:
context.colors.onSurfaceVariant,
onAuthorTap: () => showUserProfileSheet(
context,
message.pubkey,
),
displayNameKey: ValueKey(
'message-author-${message.id}',
),
usernameKey: ValueKey(
'message-username-${message.id}',
),
timestampKey: ValueKey(
'message-timestamp-${message.id}',
child: Padding(
padding: EdgeInsets.only(
top: showAuthor ? 0 : Grid.xxs,
bottom: showAuthor ? 0 : Grid.xxs,
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (showAuthor)
GestureDetector(
onTap: () => showUserProfileSheet(context, message.pubkey),
child: _UserAvatar(
profile: profile,
pubkey: message.pubkey,
),
)
else
const SizedBox(width: messageAvatarSize),
const SizedBox(width: messageAvatarContentGap),
Expanded(
child: Padding(
padding: EdgeInsets.only(top: showAuthor ? Grid.half : 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (showAuthor)
Padding(
padding: const EdgeInsets.only(
bottom: Grid.quarter,
),
child: Row(
children: [
Expanded(
child: MessageAuthorMeta(
displayName: displayName,
username: messageUsernameLabel(profile),
timestamp: formatMessageTime(
message.createdAt,
),
nameColor: context.colors.onSurface,
metadataColor:
context.colors.onSurfaceVariant,
onAuthorTap: () => showUserProfileSheet(
context,
message.pubkey,
),
displayNameKey: ValueKey(
'message-author-${message.id}',
),
usernameKey: ValueKey(
'message-username-${message.id}',
),
timestampKey: ValueKey(
'message-timestamp-${message.id}',
),
),
),
),
if (message.edited) ...[
const SizedBox(width: Grid.half),
Text(
'(edited)',
style: context.textTheme.labelSmall?.copyWith(
color: context.colors.onSurfaceVariant,
fontStyle: FontStyle.italic,
if (message.edited) ...[
const SizedBox(width: Grid.half),
Text(
'(edited)',
style: context.textTheme.labelSmall
?.copyWith(
color:
context.colors.onSurfaceVariant,
fontStyle: FontStyle.italic,
),
),
),
],
],
],
),
),
),
MessageContent(
content: message.content,
mentionNames: mentionNames,
agentMentionPubkeys: agentMentionPubkeys,
channelNames: channelNames,
tags: message.tags,
baseStyle: messageBodyTextStyle.copyWith(
color: context.colors.onSurface,
),
mediaCarouselTrailingOverflow: Grid.gutter,
onMediaReply: allMessages == null
? null
: () {
if (!context.mounted) return;
Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (_) => ThreadDetailPage(
threadHead: message,
allMessages: allMessages!,
channelId: currentChannelId,
currentPubkey: currentPubkey,
isMember: isMember,
isArchived: isArchived,
MessageContent(
content: message.content,
mentionNames: mentionNames,
agentMentionPubkeys: agentMentionPubkeys,
channelNames: channelNames,
tags: message.tags,
baseStyle: messageBodyTextStyle.copyWith(
color: context.colors.onSurface,
),
mediaCarouselTrailingOverflow: Grid.gutter,
onMediaReply: allMessages == null
? null
: () {
if (!context.mounted) return;
Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (_) => ThreadDetailPage(
threadHead: message,
allMessages: allMessages!,
channelId: currentChannelId,
currentPubkey: currentPubkey,
isMember: isMember,
isArchived: isArchived,
),
),
),
);
},
onMediaMore: (viewerContext, imageUrl) =>
showImageActions(
context: viewerContext,
);
},
onMediaMore: (viewerContext, imageUrl) =>
showImageActions(
context: viewerContext,
ref: ref,
message: message,
channelId: currentChannelId,
imageUrl: imageUrl,
canManageMessage: canManageMessage,
onDeleted: () {
if (viewerContext.mounted) {
Navigator.of(viewerContext).maybePop();
}
},
),
onChannelTap: (channelId) {
openChannelLink(
context: context,
ref: ref,
message: message,
channelId: currentChannelId,
imageUrl: imageUrl,
canManageMessage: canManageMessage,
onDeleted: () {
if (viewerContext.mounted) {
Navigator.of(viewerContext).maybePop();
}
},
),
onChannelTap: (channelId) {
openChannelLink(
context: context,
ref: ref,
channelId: channelId,
currentChannelId: currentChannelId,
);
},
onMentionTap: (pubkey) =>
showUserProfileSheet(context, pubkey),
),
if (message.reactions.isNotEmpty)
ReactionRow(
reactions: message.reactions,
onToggle: (emoji) =>
toggleReaction(ref, message, emoji),
channelId: channelId,
currentChannelId: currentChannelId,
);
},
onMentionTap: (pubkey) =>
showUserProfileSheet(context, pubkey),
),
],
if (message.reactions.isNotEmpty)
ReactionRow(
reactions: message.reactions,
onToggle: (emoji) =>
toggleReaction(ref, message, emoji),
),
],
),
),
),
),
],
],
),
),
),
),
Expand Down
2 changes: 2 additions & 0 deletions mobile/lib/features/channels/channels_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import '../../shared/community/community_icon_provider.dart';
import '../../shared/relay/relay.dart';
import '../../shared/theme/theme.dart';
import '../../shared/widgets/avatar_image.dart';
import '../../shared/widgets/anchored_popover_menu.dart';
import '../../shared/widgets/buzz_loading_indicator.dart';
import '../../shared/widgets/frosted_app_bar.dart';
import '../../shared/widgets/frosted_scaffold.dart';
Expand Down Expand Up @@ -226,6 +227,7 @@ class ChannelsPage extends HookConsumerWidget {
}, [isReconnectingWithContent]);

return FrostedScaffold(
backgroundColor: Colors.transparent,
appBar: FrostedAppBar(
horizontalInset: _kTopSectionInset,
// Under a Buzz theme the community + account avatar strip carries the
Expand Down
5 changes: 4 additions & 1 deletion mobile/lib/features/channels/channels_page/body.dart
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,10 @@ class _SliverChannelsList extends HookConsumerWidget {
}

return SliverPadding(
padding: const EdgeInsets.only(top: Grid.xxs, bottom: 80),
padding: EdgeInsets.only(
top: Grid.xxs,
bottom: MediaQuery.paddingOf(context).bottom,
),
sliver: SliverList.list(
children: [
if (visibleChannels.isEmpty)
Expand Down
Loading
Loading