Skip to content

Commit 8d56be0

Browse files
committed
feat: add more config props
1 parent 6d02fa7 commit 8d56be0

File tree

8 files changed

+145
-89
lines changed

8 files changed

+145
-89
lines changed

example/components/ThemedRecorderSheet.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,14 @@ export const ThemedRecorderSheet = forwardRef(
5858
const recorderRef = useRef<RecorderRef>(null)
5959

6060
const backgroundColor = useThemeColor({ light: lightColor, dark: darkColor }, 'recorderSheet')
61+
const progressBackgroundColor = useThemeColor({}, 'recorderProgress')
6162
const iconColor = useThemeColor({}, 'recorderIcon')
6263
const tintColor = useThemeColor({}, 'recorderTint')
6364
const timelineColor = useThemeColor({}, 'recorderTimeline')
6465
const positionColor = useThemeColor({}, 'text')
6566
const recordBorderColor = useThemeColor({ light: 'rgba(0,0,0,0.3)' }, 'text')
6667
const recorderBackgroundColor = useThemeColor({}, 'recorderBackground')
68+
const waveformInactiveColor = useThemeColor({}, 'recorderWaveformInactive')
6769

6870
const scale = useSharedValue(1)
6971

@@ -121,8 +123,11 @@ export const ThemedRecorderSheet = forwardRef(
121123
<Recorder
122124
ref={recorderRef}
123125
tintColor={tintColor}
126+
waveformInactiveColor={waveformInactiveColor}
127+
progressInterval={50}
124128
timelineColor={timelineColor}
125129
backgroundColor={recorderBackgroundColor}
130+
progressBackgroundColor={progressBackgroundColor}
126131
onRecordReset={() => {
127132
scale.value = 1
128133
setIsRecording(false)
@@ -141,7 +146,7 @@ export const ThemedRecorderSheet = forwardRef(
141146
}}
142147
onPlaybackStart={() => setIsPlaying(true)}
143148
onPlaybackStop={() => setIsPlaying(false)}
144-
onPositionChange={(position: number) => setPosition(position)}
149+
onPositionChange={(pos: number) => setPosition(pos)}
145150
/>
146151
<View style={{ padding: Spacing.md, marginTop: Spacing.xxl }}>
147152
<Text style={[$positionText, { color: positionColor ?? '#333333' }]}>

example/constants/Colors.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@ export const Colors = {
1515
icon: '#687076',
1616
tabIconDefault: '#687076',
1717
tabIconSelected: tintColorLight,
18-
recorderBackground: 'rgba(121, 135, 160, 0.2)',
18+
recorderBackground: '#cfd4dd',
19+
recorderProgress: 'rgba(121, 135, 160, 0.2)',
1920
recorderTimeline: 'rgba(0, 0, 0, 0.5)',
2021
recorderTint: tintColorLight,
22+
recorderWaveformInactive: '#687076',
2123
recorderSheet: '#f9f9f9',
2224
recorderIcon: tintColorLight,
2325
},
@@ -29,9 +31,11 @@ export const Colors = {
2931
icon: '#9BA1A6',
3032
tabIconDefault: '#9BA1A6',
3133
tabIconSelected: tintColorDark,
32-
recorderBackground: 'rgba(13, 14, 17, 0.5)',
34+
recorderBackground: '#20242c',
35+
recorderProgress: 'rgba(13, 14, 17, 0.5)',
3336
recorderTimeline: 'rgba(255, 255, 255, 0.5)',
3437
recorderTint: tintColorLight,
38+
recorderWaveformInactive: '#7987a0',
3539
recorderSheet: '#282e37',
3640
recorderIcon: tintColorDark,
3741
},

src/Recorder.tsx

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,24 @@ import { Waveform } from './components'
2020
import {
2121
MAX_RECORDING_TIME,
2222
METERING_MIN_POWER,
23-
RECORDING_INDICATOR_SCALE,
2423
SPRING_CONFIG,
25-
SPRING_SHORT_CONFIG,
2624
TIMELINE_MS_PER_LINE,
27-
TIMELINE_TOTAL_WIDTH_PER_250_MS,
28-
TIMELINE_UPDATE_INTERVAL,
25+
spacing,
2926
} from './helpers'
3027

28+
const DEFAULT_TIMELINE_GAP_PER_250_MS = spacing.lg
29+
const DEFAULT_TIMELINE_UPDATE_INTERVAL = 50 // ms
30+
3131
export const Recorder = forwardRef((props: RecorderProps, ref: Ref<RecorderRef>) => {
3232
const {
33+
progressInterval = DEFAULT_TIMELINE_UPDATE_INTERVAL,
3334
onPositionChange,
3435
onRecordStart,
3536
onRecordStop,
3637
onRecordReset,
3738
onPlaybackStart,
3839
onPlaybackStop,
40+
timelineGap = DEFAULT_TIMELINE_GAP_PER_250_MS,
3941
...rest
4042
} = props
4143

@@ -50,11 +52,10 @@ export const Recorder = forwardRef((props: RecorderProps, ref: Ref<RecorderRef>)
5052
const [position, setPosition] = useState(0)
5153
const [duration, setDuration] = useState(0)
5254

53-
const waveformMaxWidth = (duration / TIMELINE_MS_PER_LINE) * TIMELINE_TOTAL_WIDTH_PER_250_MS
55+
const waveformMaxWidth = (duration / TIMELINE_MS_PER_LINE) * timelineGap
5456

5557
const isScrollAnimating = useSharedValue(false)
5658
const scrollX = useSharedValue(0)
57-
const scale = useSharedValue(1)
5859
const currentMs = useSharedValue(0)
5960

6061
const updatePosition = (positionMs: number) => {
@@ -69,9 +70,7 @@ export const Recorder = forwardRef((props: RecorderProps, ref: Ref<RecorderRef>)
6970

7071
if (scrollX.value <= 0) {
7172
const ms =
72-
Math.floor(
73-
((Math.abs(scrollX.value) / TIMELINE_TOTAL_WIDTH_PER_250_MS) * TIMELINE_MS_PER_LINE) / 100
74-
) * 100
73+
Math.floor(((Math.abs(scrollX.value) / timelineGap) * TIMELINE_MS_PER_LINE) / 100) * 100
7574

7675
if (ms <= duration && ms !== currentMs.value) {
7776
runOnJS(updatePosition)(ms)
@@ -135,7 +134,7 @@ export const Recorder = forwardRef((props: RecorderProps, ref: Ref<RecorderRef>)
135134
playsInSilentModeIOS: true,
136135
})
137136

138-
newRecording.setProgressUpdateInterval(TIMELINE_UPDATE_INTERVAL)
137+
newRecording.setProgressUpdateInterval(progressInterval)
139138
newRecording.setOnRecordingStatusUpdate(handleRecordingStatus)
140139

141140
await newRecording.prepareToRecordAsync(Audio.RecordingOptionsPresets.HIGH_QUALITY)
@@ -202,7 +201,7 @@ export const Recorder = forwardRef((props: RecorderProps, ref: Ref<RecorderRef>)
202201
newSound.setOnPlaybackStatusUpdate(handlePlaybackStatus)
203202

204203
await newSound.loadAsync({ uri })
205-
await newSound.setProgressUpdateIntervalAsync(TIMELINE_UPDATE_INTERVAL)
204+
await newSound.setProgressUpdateIntervalAsync(progressInterval)
206205

207206
// Sync position and duration ms
208207
const currentStatus = await newSound.getStatusAsync()
@@ -229,15 +228,15 @@ export const Recorder = forwardRef((props: RecorderProps, ref: Ref<RecorderRef>)
229228

230229
useEffect(() => {
231230
if (isRecording) {
232-
scrollX.value = withTiming(-waveformMaxWidth, { duration: TIMELINE_UPDATE_INTERVAL })
231+
scrollX.value = withTiming(-waveformMaxWidth, { duration: progressInterval })
233232
}
234233
}, [isRecording, waveformMaxWidth])
235234

236235
useEffect(() => {
237236
if (isPreviewPlaying) {
238-
const x = (position / TIMELINE_MS_PER_LINE) * TIMELINE_TOTAL_WIDTH_PER_250_MS
237+
const x = (position / TIMELINE_MS_PER_LINE) * timelineGap
239238
scrollX.value = withTiming(-Math.min(x, waveformMaxWidth), {
240-
duration: TIMELINE_UPDATE_INTERVAL,
239+
duration: progressInterval,
241240
})
242241
}
243242
}, [isPreviewPlaying, position])
@@ -250,10 +249,7 @@ export const Recorder = forwardRef((props: RecorderProps, ref: Ref<RecorderRef>)
250249

251250
useEffect(() => {
252251
if (isRecording) {
253-
scale.value = withSpring(RECORDING_INDICATOR_SCALE, SPRING_SHORT_CONFIG)
254252
scrollX.value = withSpring(0, SPRING_CONFIG)
255-
} else {
256-
scale.value = withSpring(1, SPRING_SHORT_CONFIG)
257253
}
258254
}, [isRecording])
259255

@@ -304,6 +300,7 @@ export const Recorder = forwardRef((props: RecorderProps, ref: Ref<RecorderRef>)
304300

305301
return (
306302
<Waveform
303+
timelineGap={timelineGap}
307304
meterings={isRecording ? meterings.slice(-60) : meterings}
308305
waveformMaxWidth={waveformMaxWidth}
309306
recording={isRecording}

src/Recorder.types.ts

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,55 @@ export interface PlaybackStatus {
88
export interface RecorderProps extends Omit<ViewProps, 'children'> {
99
/**
1010
* The main background color of the waveform container.
11-
* Tip: pass in an RGBA color.
1211
*/
1312
backgroundColor?: ColorValue
1413

14+
/**
15+
* The background color of the recording progress.
16+
*/
17+
progressBackgroundColor?: ColorValue
18+
19+
/**
20+
* The progress update interval while recording.
21+
* In milliseconds
22+
*
23+
* @default 50
24+
*/
25+
progressInterval?: number
26+
27+
/**
28+
* Height of the wave form
29+
* @default 160
30+
*/
31+
waveformHeight?: number
32+
33+
/**
34+
* The waveform active tint color
35+
*
36+
* @default #d72d66
37+
*/
38+
waveformActiveColor?: ColorValue
39+
40+
/**
41+
* Inactive waveform color
42+
*
43+
* @default #7987a0
44+
*/
45+
waveformInactiveColor?: ColorValue
46+
1547
/**
1648
* Tint color used on the time indicator.
1749
* @type {[type]}
1850
*/
1951
tintColor?: ColorValue
2052

53+
/**
54+
* The gap between timelines per 250ms.
55+
*
56+
* @default 24
57+
*/
58+
timelineGap?: number
59+
2160
/**
2261
* The color of the timeline.
2362
*/

src/components/TimeIndicator.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
import React, { memo } from 'react'
22
import { View, type ColorValue, type ViewStyle } from 'react-native'
33

4-
import { TIMELINE_POSITION_INDICATOR_WIDTH, WAVEFORM_CONTAINER_HEIGHT, spacing } from '../helpers'
4+
import { spacing } from '../helpers'
55

66
interface TimeIndicatorProps {
77
color?: ColorValue
8+
height: number
89
}
910

10-
export const TimeIndicator = memo(({ color }: TimeIndicatorProps) => {
11+
export const TimeIndicator = memo(({ color, height }: TimeIndicatorProps) => {
1112
const backgroundColor = color ?? 'white'
1213
return (
13-
<View style={[$lineIndicator, { backgroundColor }]}>
14+
<View style={[$lineIndicator, { backgroundColor, height }]}>
1415
<View style={[$dot, { backgroundColor }, $top]} />
1516
<View style={[$dot, { backgroundColor }, $bottom]} />
1617
</View>
@@ -19,8 +20,7 @@ export const TimeIndicator = memo(({ color }: TimeIndicatorProps) => {
1920

2021
const $lineIndicator: ViewStyle = {
2122
position: 'absolute',
22-
height: WAVEFORM_CONTAINER_HEIGHT,
23-
width: TIMELINE_POSITION_INDICATOR_WIDTH,
23+
width: 2,
2424
alignSelf: 'center',
2525
alignItems: 'center',
2626
justifyContent: 'center',

src/components/Timeline.tsx

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,21 @@
11
import React, { memo } from 'react'
22
import { View, type TextStyle, type ViewStyle, Text, type ColorValue } from 'react-native'
33

4-
import {
5-
TIMELINES,
6-
TIMELINE_GAP_PER_250_MS,
7-
TIMELINE_HEIGHT,
8-
WAVEFORM_LINE_WIDTH,
9-
formatSeconds,
10-
spacing,
11-
} from '../helpers'
4+
import { TIMELINES, WAVEFORM_LINE_WIDTH, formatSeconds, spacing } from '../helpers'
125

6+
const TIMELINE_HEIGHT = spacing.xl
137
const DEFAULT_COLOR = 'rgba(0, 0, 0, 0.5)'
148

159
interface TimelineProps {
1610
color?: ColorValue
11+
gap: number
1712
}
1813

19-
export const Timeline = memo(({ color }: TimelineProps) => {
14+
export const Timeline = memo(({ color, gap }: TimelineProps) => {
2015
const timelineColor = color ?? DEFAULT_COLOR
2116

2217
return (
23-
<View style={$container}>
18+
<View style={[$container, { gap }]}>
2419
{TIMELINES.map((lineMs) => {
2520
const isSeconds = lineMs % 4 === 0
2621
const height = isSeconds ? spacing.sm : spacing.xs
@@ -48,8 +43,7 @@ const $timelineSeconds: TextStyle = {
4843

4944
const $container: ViewStyle = {
5045
position: 'absolute',
51-
bottom: -TIMELINE_HEIGHT,
5246
flexDirection: 'row',
5347
height: TIMELINE_HEIGHT,
54-
gap: TIMELINE_GAP_PER_250_MS,
48+
bottom: -TIMELINE_HEIGHT,
5549
}

0 commit comments

Comments
 (0)