Skip to content

Commit 33661bf

Browse files
committed
Feed view show reply to. Server to return event hint for profile
1 parent dc68539 commit 33661bf

4 files changed

Lines changed: 75 additions & 14 deletions

File tree

apps/polycentric/src/features/post/Post.tsx

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,14 @@ import { useWebHover } from '@/src/common/lib/useWebHover';
1414
import { PostImages } from './PostImages';
1515
import { PostToolbar } from './PostToolbar';
1616
import { Atoms, useTheme, withHexOpacity } from '@/src/common/theme';
17+
import { v2 } from '@polycentric/react-native';
1718
import { router } from 'expo-router';
1819
import { memo, useCallback, useEffect, useMemo, useState } from 'react';
1920
import { Pressable, View } from 'react-native';
20-
import { getKeyFingerprint } from '@/src/common/lib/polycentric-hooks/helpers';
21+
import {
22+
getKeyFingerprint,
23+
hexToBytes,
24+
} from '@/src/common/lib/polycentric-hooks/helpers';
2125

2226
const PREVIEW_LIMIT = 240;
2327
const MAX_DISPLAY_LIMIT = 2000;
@@ -37,7 +41,7 @@ interface PostProps {
3741

3842
export const Post = memo(function Post({
3943
post,
40-
hideReplyingTo: _hideReplyingTo = false,
44+
hideReplyingTo = false,
4145
disablePress = false,
4246
showThreadLineAbove = false,
4347
showThreadLineBelow = false,
@@ -231,6 +235,10 @@ export const Post = memo(function Post({
231235
) : null}
232236
</View>
233237

238+
{!hideReplyingTo && post.reply?.parentId ? (
239+
<ReplyingToSubheader parentId={post.reply.parentId} />
240+
) : null}
241+
234242
{displayContent ? (
235243
<Text variant="secondary" style={[Atoms.mt_xs]}>
236244
{displayContent}
@@ -272,6 +280,40 @@ export const Post = memo(function Post({
272280
);
273281
});
274282

283+
function ReplyingToSubheader({ parentId }: { parentId: string }) {
284+
const parentIdentity = useMemo(() => {
285+
try {
286+
return v2.EventKey.fromBinary(hexToBytes(parentId)).identity;
287+
} catch {
288+
return null;
289+
}
290+
}, [parentId]);
291+
292+
const parentProfile = useProfile(parentIdentity);
293+
const parentName = parentProfile.name ?? '';
294+
295+
const handlePress = useCallback(() => {
296+
if (!parentIdentity) return;
297+
router.push(Routes.tabs.profile(parentIdentity));
298+
}, [parentIdentity]);
299+
300+
if (!parentIdentity) return null;
301+
302+
return (
303+
<Pressable
304+
onPress={handlePress}
305+
style={[Atoms.flex_row, Atoms.mt_xs, { alignItems: 'baseline' }]}
306+
>
307+
<Text variant="small" color="neutral_500" fontWeight="regular">
308+
Reply to{' '}
309+
</Text>
310+
<Text variant="small" color="primary_500">
311+
{truncateName(parentName || '…', 24)}
312+
</Text>
313+
</Pressable>
314+
);
315+
}
316+
275317
function PostAuthorName({
276318
name,
277319
onPress,

packages/react-native/src/NativeReactNative.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ export interface Spec extends TurboModule {
77
cleanupRustCrate(): boolean;
88
}
99

10-
export default TurboModuleRegistry.getEnforcing<Spec>('ReactNative');
10+
export default TurboModuleRegistry.getEnforcing<Spec>('ReactNative');

packages/react-native/src/uniffi-init.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,3 @@ export async function uniffiInitAsync() {
3838
export default {
3939
polycentric_core,
4040
};
41-

services/server/src/service/feeds/feeds_service.rs

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
use super::feeds_repository::{self as FeedsRepository, FeedRow};
2+
use crate::service::proto::content::ContentBody;
23
use crate::service::proto::feeds_service_server::{
34
FeedsService, FeedsServiceServer,
45
};
56
use crate::service::proto::{
6-
EventBundle, EventHint, FeedPageParams, GetExploreFeedRequest,
7+
Content, EventBundle, EventHint, FeedPageParams, GetExploreFeedRequest,
78
GetFeedResponse, GetFollowingFeedRequest, GetIdentityFeedRequest,
89
GetPostThreadRequest, GetPostThreadResponse, SerializedContent,
910
SignedEvent,
1011
};
12+
use prost::Message;
1113
use tonic::{Request, Response, Status};
1214

1315
#[derive(Debug)]
@@ -252,19 +254,25 @@ impl FeedsService for FeedsServiceImpl {
252254
}
253255

254256
/// Build the `event_hints` for a feed/thread response: collect the
255-
/// unique author identities from `rows`, fetch the latest PROFILE
256-
/// event for each, and wrap them in `EventHint`s. Returned as a
257-
/// `Status` error if the DB lookup fails.
257+
/// unique author identities from `rows` — plus the identities of any
258+
/// reply-parent posts decoded from each row's serialized Content —
259+
/// fetch the latest PROFILE event for each, and wrap them in
260+
/// `EventHint`s. Returned as a `Status` error if the DB lookup fails.
258261
async fn build_profile_hints(
259262
db: &sea_orm::DatabaseConnection,
260263
rows: &[FeedRow],
261264
) -> Result<Vec<EventHint>, Status> {
262-
let identities: Vec<String> = rows
263-
.iter()
264-
.map(|(event, _)| event.identity.clone())
265-
.collect::<std::collections::HashSet<_>>()
266-
.into_iter()
267-
.collect();
265+
let mut identity_set: std::collections::HashSet<String> =
266+
std::collections::HashSet::new();
267+
for (event, content) in rows {
268+
identity_set.insert(event.identity.clone());
269+
if let Some(parent_identity) =
270+
content.as_ref().and_then(reply_parent_identity)
271+
{
272+
identity_set.insert(parent_identity);
273+
}
274+
}
275+
let identities: Vec<String> = identity_set.into_iter().collect();
268276

269277
let profile_rows =
270278
FeedsRepository::Query::list_latest_profiles_for_identities(
@@ -281,6 +289,18 @@ async fn build_profile_hints(
281289
.collect())
282290
}
283291

292+
fn reply_parent_identity(
293+
content: &::entity::content_model::Model,
294+
) -> Option<String> {
295+
let decoded = Content::decode(content.serialized_bytes.as_slice()).ok()?;
296+
match decoded.content_body? {
297+
ContentBody::Post(post) => {
298+
Some(post.reply?.parent?.identity).filter(|s| !s.is_empty())
299+
}
300+
_ => None,
301+
}
302+
}
303+
284304
fn rows_to_bundles(rows: Vec<FeedRow>) -> Vec<EventBundle> {
285305
rows.into_iter()
286306
.map(|(event, content)| EventBundle {

0 commit comments

Comments
 (0)