fix(mobile): auto-follow newly sent particles in stream view #226
@@ -56,6 +56,13 @@ interface ComposeDockProps {
|
||||
silentPresence?: boolean;
|
||||
submitMedia?: (params: SubmitMediaParams) => Promise<void>;
|
||||
submitText?: (content: string) => Promise<void>;
|
||||
/**
|
||||
* Called with the new particle's id right after it's created on the default
|
||||
* send path. Not fired when `submitMedia`/`submitText` overrides are supplied,
|
||||
* since those own the created particle themselves. Lets the stream follow a
|
||||
* just-sent particle when the user was at the end.
|
||||
*/
|
||||
onParticleCreated?: (particleId: string) => void;
|
||||
}
|
||||
|
||||
export function ComposeDock({
|
||||
@@ -64,6 +71,7 @@ export function ComposeDock({
|
||||
silentPresence = false,
|
||||
submitMedia,
|
||||
submitText: submitTextOverride,
|
||||
onParticleCreated,
|
||||
}: ComposeDockProps) {
|
||||
const userId = useAuthStore((s) => s.user?.id);
|
||||
|
||||
@@ -147,7 +155,7 @@ export function ComposeDock({
|
||||
source: "camera",
|
||||
});
|
||||
} else {
|
||||
await uploadMediaParticle({
|
||||
const particleId = await uploadMediaParticle({
|
||||
networkId,
|
||||
targetPath,
|
||||
fileUri: captured.uri,
|
||||
@@ -156,6 +164,7 @@ export function ComposeDock({
|
||||
source: "camera",
|
||||
createdByHumanId: userId,
|
||||
});
|
||||
onParticleCreated?.(particleId);
|
||||
}
|
||||
void Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
|
||||
setUi({ kind: "idle" });
|
||||
@@ -174,12 +183,13 @@ export function ComposeDock({
|
||||
if (submitTextOverride) {
|
||||
await submitTextOverride(content);
|
||||
} else {
|
||||
await createTextParticle({
|
||||
const particleId = await createTextParticle({
|
||||
networkId,
|
||||
targetPath,
|
||||
content,
|
||||
createdByHumanId: userId,
|
||||
});
|
||||
onParticleCreated?.(particleId);
|
||||
}
|
||||
void Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
|
||||
});
|
||||
|
||||
@@ -105,8 +105,15 @@ function StreamViewInner({ streamParticle, path, onExit }: StreamViewProps) {
|
||||
const insets = useSafeAreaInsets();
|
||||
const { composingUsers } = useStreamComposing();
|
||||
|
||||
const { children, currentParticle, currentIndex, status, next, prev } =
|
||||
useStreamPlayback(streamParticle, path);
|
||||
const {
|
||||
children,
|
||||
currentParticle,
|
||||
currentIndex,
|
||||
status,
|
||||
next,
|
||||
prev,
|
||||
goToParticle,
|
||||
} = useStreamPlayback(streamParticle, path);
|
||||
|
||||
const paused = usePlaybackPauseStore(selectIsPaused);
|
||||
const composing = usePlaybackPauseStore(selectIsComposing);
|
||||
@@ -257,6 +264,22 @@ function StreamViewInner({ streamParticle, path, onExit }: StreamViewProps) {
|
||||
|
||||
const openReactions = useCallback(() => setReactionsOpen(true), []);
|
||||
|
||||
// When the local user sends a particle while sitting on the last one, follow
|
||||
// it forward so they stay caught up and the stream isn't left unseen. If they
|
||||
// were browsing earlier particles, leave their position untouched. `children`
|
||||
// is still the pre-send snapshot here (the live query hasn't delivered the new
|
||||
// particle yet), so the last slot is children.length - 1; goToParticle resolves
|
||||
// once it arrives. Mirrors desktop's StreamView.handleParticleCreated.
|
||||
const handleParticleCreated = useCallback(
|
||||
(particleId: string) => {
|
||||
if (currentIndex === -1) return;
|
||||
if (currentIndex === children.length - 1) {
|
||||
goToParticle(particleId);
|
||||
}
|
||||
},
|
||||
[children.length, currentIndex, goToParticle],
|
||||
);
|
||||
|
||||
// Reset progress whenever the active particle changes.
|
||||
useEffect(() => {
|
||||
setProgress(0);
|
||||
@@ -642,7 +665,11 @@ function StreamViewInner({ streamParticle, path, onExit }: StreamViewProps) {
|
||||
{/* Compose dock + recording overlays. Sits above the GestureDetector
|
||||
so its hold-FAB pan gesture isn't competed-with by the StreamView
|
||||
tap zones. */}
|
||||
<ComposeDock networkId={networkId} targetPath={path} />
|
||||
<ComposeDock
|
||||
networkId={networkId}
|
||||
targetPath={path}
|
||||
onParticleCreated={handleParticleCreated}
|
||||
/>
|
||||
|
||||
{/* Reaction sheet — slides up over everything, suspends playback
|
||||
internally while open. */}
|
||||
|
||||
Reference in New Issue
Block a user