Skip to content

Commit

Permalink
feat: add maxDuration prop
Browse files Browse the repository at this point in the history
  • Loading branch information
lodev09 committed May 14, 2024
1 parent 936a099 commit 259d0d7
Show file tree
Hide file tree
Showing 8 changed files with 38 additions and 35 deletions.
14 changes: 8 additions & 6 deletions src/Recorder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ import {
import type { Metering, PlaybackStatus, RecorderProps, RecorderRef } from './Recorder.types'
import { Waveform } from './components'
import {
MAX_RECORDING_TIME,
METERING_MIN_POWER,
SPRING_CONFIG,
TIMELINE_MS_PER_LINE,
WAVEFORM_LINE_WIDTH,
spacing,
Spacing,
} from './helpers'

const DEFAULT_TIMELINE_GAP_PER_250_MS = spacing.lg
const DEFAULT_MAX_DURATION = 120000 // 2m
const DEFAULT_TIMELINE_GAP_PER_250_MS = Spacing.lg
const DEFAULT_TIMELINE_UPDATE_INTERVAL = 50 // ms

export const Recorder = forwardRef((props: RecorderProps, ref: Ref<RecorderRef>) => {
Expand All @@ -39,6 +39,7 @@ export const Recorder = forwardRef((props: RecorderProps, ref: Ref<RecorderRef>)
onPlaybackStart,
onPlaybackStop,
timelineGap = DEFAULT_TIMELINE_GAP_PER_250_MS,
maxDuration = DEFAULT_MAX_DURATION,
...rest
} = props

Expand Down Expand Up @@ -104,7 +105,7 @@ export const Recorder = forwardRef((props: RecorderProps, ref: Ref<RecorderRef>)
if (status.isRecording && status.durationMillis > 0) {
setDuration(status.durationMillis)

if (status.durationMillis > MAX_RECORDING_TIME) {
if (status.durationMillis > maxDuration) {
return
}

Expand Down Expand Up @@ -246,10 +247,10 @@ export const Recorder = forwardRef((props: RecorderProps, ref: Ref<RecorderRef>)
}, [isPreviewPlaying, position])

useEffect(() => {
if (isRecording && duration >= MAX_RECORDING_TIME) {
if (isRecording && duration >= maxDuration) {
stopRecording()
}
}, [duration, isRecording])
}, [duration, isRecording, maxDuration])

useEffect(() => {
if (isRecording) {
Expand Down Expand Up @@ -305,6 +306,7 @@ export const Recorder = forwardRef((props: RecorderProps, ref: Ref<RecorderRef>)
return (
<Waveform
timelineGap={timelineGap}
maxDuration={maxDuration}
meterings={isRecording ? meterings.slice(-60) : meterings}
waveformMaxWidth={waveformMaxWidth}
recording={isRecording}
Expand Down
7 changes: 7 additions & 0 deletions src/Recorder.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ export interface RecorderProps extends Omit<ViewProps, 'children'> {
*/
progressInterval?: number

/**
* The maximum recording duration in milliseconds.
*
* @default 120000
*/
maxDuration?: number

/**
* Height of the wave form
* @default 160
Expand Down
8 changes: 4 additions & 4 deletions src/components/TimeIndicator.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { memo } from 'react'
import { View, type ColorValue, type ViewStyle } from 'react-native'

import { spacing } from '../helpers'
import { Spacing } from '../helpers'

interface TimeIndicatorProps {
color?: ColorValue
Expand Down Expand Up @@ -29,9 +29,9 @@ const $lineIndicator: ViewStyle = {
const $dot: ViewStyle = {
position: 'absolute',
alignSelf: 'center',
height: spacing.xs,
width: spacing.xs,
borderRadius: spacing.xs / 2,
height: Spacing.xs,
width: Spacing.xs,
borderRadius: Spacing.xs / 2,
}

const $top: ViewStyle = { top: 0 }
Expand Down
21 changes: 12 additions & 9 deletions src/components/Timeline.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,33 @@
import React, { memo } from 'react'
import { View, type TextStyle, type ViewStyle, Text, type ColorValue } from 'react-native'

import { TIMELINES, WAVEFORM_LINE_WIDTH, formatSeconds, spacing } from '../helpers'
import { WAVEFORM_LINE_WIDTH, formatSeconds, Spacing, TIMELINE_MS_PER_LINE } from '../helpers'

const TIMELINE_HEIGHT = spacing.xl
const TIMELINE_HEIGHT = Spacing.xl
const DEFAULT_COLOR = 'rgba(0, 0, 0, 0.5)'

interface TimelineProps {
color?: ColorValue
gap: number
duration: number
}

export const Timeline = memo(({ color, gap }: TimelineProps) => {
export const Timeline = memo(({ color, gap, duration }: TimelineProps) => {
const timelineColor = color ?? DEFAULT_COLOR

const timeline = Array.from({ length: duration / TIMELINE_MS_PER_LINE + 1 })

return (
<View style={[$container, { gap }]}>
{TIMELINES.map((lineMs) => {
const isSeconds = lineMs % 4 === 0
const height = isSeconds ? spacing.sm : spacing.xs
{timeline.map((_, index) => {
const isSeconds = index % 4 === 0
const height = isSeconds ? Spacing.sm : Spacing.xs
return (
<View key={String(lineMs)}>
<View key={String(index)}>
<View style={{ height, width: WAVEFORM_LINE_WIDTH, backgroundColor: timelineColor }} />
{isSeconds && (
<Text style={[$timelineSeconds, { color: timelineColor }]}>
{formatSeconds(lineMs / 4)}
{formatSeconds(index / 4)}
</Text>
)}
</View>
Expand All @@ -36,7 +39,7 @@ export const Timeline = memo(({ color, gap }: TimelineProps) => {

const $timelineSeconds: TextStyle = {
position: 'absolute',
width: spacing.xxl,
width: Spacing.xxl,
fontSize: 12,
bottom: 0,
}
Expand Down
8 changes: 5 additions & 3 deletions src/components/Waveform.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
METERING_MIN_POWER,
TIMELINE_MS_PER_LINE,
WAVEFORM_LINE_WIDTH,
spacing,
Spacing,
} from '../helpers'
import { TimeIndicator } from './TimeIndicator'
import { Timeline } from './Timeline'
Expand All @@ -38,6 +38,7 @@ const DEFAULT_PROGRESS_BACKGROUND_COLOR = '#bbbbbb'

interface WaveformProps extends ViewProps {
meterings: Metering[]
maxDuration: number
recording: boolean
playing: boolean
waveformMaxWidth: number
Expand Down Expand Up @@ -68,6 +69,7 @@ export const Waveform = (props: WaveformProps) => {
playing,
backgroundColor = DEFAULT_BACKGROUND_COLOR,
progressBackgroundColor = DEFAULT_PROGRESS_BACKGROUND_COLOR,
maxDuration,
tintColor,
timelineColor,
timelineGap,
Expand All @@ -79,7 +81,7 @@ export const Waveform = (props: WaveformProps) => {
} = props

const dimensions = useWindowDimensions()
const waveformContainerHeight = waveformHeight + spacing.md * 2
const waveformContainerHeight = waveformHeight + Spacing.md * 2

const prevScrollX = useSharedValue(0)

Expand Down Expand Up @@ -147,7 +149,7 @@ export const Waveform = (props: WaveformProps) => {
/>
))}
</View>
<Timeline gap={timelineGap} color={timelineColor} />
<Timeline duration={maxDuration} gap={timelineGap} color={timelineColor} />
</Animated.View>
{recording && (
<View
Expand Down
4 changes: 1 addition & 3 deletions src/helpers/spacing.ts → src/helpers/Spacing.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const spacing = {
export const Spacing = {
xxxs: 2,
xxs: 4,
xs: 8,
Expand All @@ -8,5 +8,3 @@ export const spacing = {
xl: 32,
xxl: 48,
} as const

export type Spacing = keyof typeof spacing
9 changes: 0 additions & 9 deletions src/helpers/constants.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,11 @@
import { Platform } from 'react-native'
import type { WithSpringConfig } from 'react-native-reanimated'

export const MAX_RECORDING_TIME = 120000 // 2m

export const METERING_MIN_POWER = Platform.select({ default: -50, android: -100 })
export const METERING_MAX_POWER = 0

export const WAVEFORM_LINE_WIDTH = 1

export const TIMELINE_MS_PER_LINE = 250 // ms
export const TIMELINES = Array.from(
{
length: MAX_RECORDING_TIME / TIMELINE_MS_PER_LINE + 1,
},
(_, k) => k
).map((i) => i)

export const SPRING_SHORT_CONFIG: WithSpringConfig = {
stiffness: 120,
Expand Down
2 changes: 1 addition & 1 deletion src/helpers/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export * from './spacing'
export * from './Spacing'
export * from './constants'
export * from './formatSeconds'

0 comments on commit 259d0d7

Please sign in to comment.