Skip to content
Merged
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
71 changes: 44 additions & 27 deletions src/features/recorder/preview-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@ import { Icon } from '@/components/icon';
import { VideoView, type VideoPlayer } from 'expo-video';
import { Pressable, StyleSheet, Text, View } from 'react-native';

import { GlassPill } from '@/components/glass-pill';
import { Spacing } from '@/constants/theme';
import { formatDurationPadded } from '@/utils/format';

// Action badge diameter. With hitSlop 4 the effective tap target is 48pt (≥ the 44pt HIG
// minimum) while the ✂ and 🗑 hit areas — 8pt apart — still can't overlap.
const BADGE_SIZE = 40;
const BADGE_HIT_SLOP = 4;

type Props = {
player: VideoPlayer;
isPlaying: boolean;
Expand Down Expand Up @@ -45,46 +51,52 @@ export function PreviewModal({
/>
{!isPlaying && (
<View style={styles.playOverlay} pointerEvents="none">
<View style={styles.playBadge}>
<Icon name="play.fill" size={24} tintColor="#fff" />
</View>
<GlassPill style={styles.playBadge}>
<Icon name="play.fill" size={28} tintColor="#fff" />
</GlassPill>
</View>
)}
</Pressable>

<Pressable
onPress={onClose}
hitSlop={8}
hitSlop={BADGE_HIT_SLOP}
accessibilityRole="button"
accessibilityLabel="Close preview"
style={[styles.badge, styles.close]}>
<Icon name="xmark" size={14} weight="semibold" tintColor="#fff" />
style={styles.close}>
<GlassPill style={styles.badge}>
<Icon name="xmark" size={18} weight="semibold" tintColor="#fff" />
</GlassPill>
</Pressable>

<Pressable
onPress={onTrim}
hitSlop={8}
hitSlop={BADGE_HIT_SLOP}
accessibilityRole="button"
accessibilityLabel="Edit clip"
style={[styles.badge, styles.trim]}>
<Icon name="scissors" size={16} weight="semibold" tintColor="#fff" />
style={styles.trim}>
<GlassPill style={styles.badge}>
<Icon name="scissors" size={20} weight="semibold" tintColor="#fff" />
</GlassPill>
</Pressable>

<Pressable
onPress={onDelete}
hitSlop={8}
hitSlop={BADGE_HIT_SLOP}
accessibilityRole="button"
accessibilityLabel="Delete clip"
style={[styles.badge, styles.delete]}>
<Icon name="trash" size={16} weight="semibold" tintColor="#fff" />
style={styles.delete}>
<GlassPill style={styles.badge}>
<Icon name="trash" size={20} weight="semibold" tintColor="#fff" />
</GlassPill>
</Pressable>

<View style={styles.timeRow} pointerEvents="none">
<View style={styles.timePill}>
<GlassPill style={styles.timePill}>
<Text style={styles.timeText}>
{formatDurationPadded(positionMs)} / {formatDurationPadded(totalMs)}
</Text>
</View>
</GlassPill>
</View>
</View>
);
Expand All @@ -109,34 +121,39 @@ const styles = StyleSheet.create({
alignItems: 'center',
justifyContent: 'center',
},
// Shape only — GlassPill owns the surface. paddingLeft optically centers the ▶ glyph.
playBadge: {
width: 56,
height: 56,
borderRadius: 28,
backgroundColor: 'rgba(0,0,0,0.45)',
width: 64,
height: 64,
borderRadius: 32,
alignItems: 'center',
justifyContent: 'center',
paddingLeft: 4,
},
// Badge shape only — GlassPill owns the surface (Liquid Glass on iOS 26+, dark scrim
// fallback), so no backgroundColor here. Position lives on the wrapping Pressable.
badge: {
position: 'absolute',
top: Spacing.two,
width: 28,
height: 28,
borderRadius: 14,
backgroundColor: 'rgba(0,0,0,0.55)',
width: BADGE_SIZE,
height: BADGE_SIZE,
borderRadius: BADGE_SIZE / 2,
alignItems: 'center',
justifyContent: 'center',
},
close: {
position: 'absolute',
top: Spacing.two,
left: Spacing.two,
},
delete: {
position: 'absolute',
top: Spacing.two,
right: Spacing.two,
},
// Left of the delete badge (28 wide + an 8pt gap).
// Left of the delete badge (one badge width + an 8pt gap).
trim: {
right: Spacing.two + 28 + Spacing.two,
position: 'absolute',
top: Spacing.two,
right: Spacing.two + BADGE_SIZE + Spacing.two,
},
timeRow: {
position: 'absolute',
Expand All @@ -145,11 +162,11 @@ const styles = StyleSheet.create({
bottom: Spacing.two,
alignItems: 'center',
},
// Shape only — GlassPill owns the surface, same as the badges above.
timePill: {
paddingHorizontal: Spacing.two,
paddingVertical: 4,
borderRadius: 12,
backgroundColor: 'rgba(0,0,0,0.55)',
},
timeText: {
color: '#fff',
Expand Down