@magmamath/students-features 0.9.106 → 0.9.107-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commonjs/features/voiceRecord/components/VoiceRecord.js +82 -0
- package/dist/commonjs/features/voiceRecord/components/VoiceRecord.js.map +1 -0
- package/dist/commonjs/features/voiceRecord/components/VoiceRecordButton.js +45 -0
- package/dist/commonjs/features/voiceRecord/components/VoiceRecordButton.js.map +1 -0
- package/dist/commonjs/features/voiceRecord/components/VoiceRecordDelete.js +32 -0
- package/dist/commonjs/features/voiceRecord/components/VoiceRecordDelete.js.map +1 -0
- package/dist/commonjs/features/voiceRecord/components/VoiceRecordDevider.js +27 -0
- package/dist/commonjs/features/voiceRecord/components/VoiceRecordDevider.js.map +1 -0
- package/dist/commonjs/features/voiceRecord/components/VoiceRecordTimer.js +44 -0
- package/dist/commonjs/features/voiceRecord/components/VoiceRecordTimer.js.map +1 -0
- package/dist/commonjs/features/voiceRecord/helpers.js +34 -0
- package/dist/commonjs/features/voiceRecord/helpers.js.map +1 -0
- package/dist/commonjs/features/voiceRecord/hooks/useVoiceRecorder.hook.js +36 -0
- package/dist/commonjs/features/voiceRecord/hooks/useVoiceRecorder.hook.js.map +1 -0
- package/dist/commonjs/features/voiceRecord/index.js +28 -0
- package/dist/commonjs/features/voiceRecord/index.js.map +1 -0
- package/dist/commonjs/features/voiceRecord/model/VoiceRecord.model.js +37 -0
- package/dist/commonjs/features/voiceRecord/model/VoiceRecord.model.js.map +1 -0
- package/dist/commonjs/features/voiceRecord/model/VoiceRecordApi.js +9 -0
- package/dist/commonjs/features/voiceRecord/model/VoiceRecordApi.js.map +1 -0
- package/dist/commonjs/index.js +12 -0
- package/dist/commonjs/index.js.map +1 -1
- package/dist/module/features/voiceRecord/components/VoiceRecord.js +74 -0
- package/dist/module/features/voiceRecord/components/VoiceRecord.js.map +1 -0
- package/dist/module/features/voiceRecord/components/VoiceRecordButton.js +39 -0
- package/dist/module/features/voiceRecord/components/VoiceRecordButton.js.map +1 -0
- package/dist/module/features/voiceRecord/components/VoiceRecordDelete.js +26 -0
- package/dist/module/features/voiceRecord/components/VoiceRecordDelete.js.map +1 -0
- package/dist/module/features/voiceRecord/components/VoiceRecordDevider.js +21 -0
- package/dist/module/features/voiceRecord/components/VoiceRecordDevider.js.map +1 -0
- package/dist/module/features/voiceRecord/components/VoiceRecordTimer.js +38 -0
- package/dist/module/features/voiceRecord/components/VoiceRecordTimer.js.map +1 -0
- package/dist/module/features/voiceRecord/helpers.js +28 -0
- package/dist/module/features/voiceRecord/helpers.js.map +1 -0
- package/dist/module/features/voiceRecord/hooks/useVoiceRecorder.hook.js +31 -0
- package/dist/module/features/voiceRecord/hooks/useVoiceRecorder.hook.js.map +1 -0
- package/dist/module/features/voiceRecord/index.js +5 -0
- package/dist/module/features/voiceRecord/index.js.map +1 -0
- package/dist/module/features/voiceRecord/model/VoiceRecord.model.js +32 -0
- package/dist/module/features/voiceRecord/model/VoiceRecord.model.js.map +1 -0
- package/dist/module/features/voiceRecord/model/VoiceRecordApi.js +4 -0
- package/dist/module/features/voiceRecord/model/VoiceRecordApi.js.map +1 -0
- package/dist/module/index.js +1 -0
- package/dist/module/index.js.map +1 -1
- package/dist/typescript/commonjs/features/voiceRecord/components/VoiceRecord.d.ts +10 -0
- package/dist/typescript/commonjs/features/voiceRecord/components/VoiceRecord.d.ts.map +1 -0
- package/dist/typescript/commonjs/features/voiceRecord/components/VoiceRecordButton.d.ts +10 -0
- package/dist/typescript/commonjs/features/voiceRecord/components/VoiceRecordButton.d.ts.map +1 -0
- package/dist/typescript/commonjs/features/voiceRecord/components/VoiceRecordDelete.d.ts +7 -0
- package/dist/typescript/commonjs/features/voiceRecord/components/VoiceRecordDelete.d.ts.map +1 -0
- package/dist/typescript/commonjs/features/voiceRecord/components/VoiceRecordDevider.d.ts +3 -0
- package/dist/typescript/commonjs/features/voiceRecord/components/VoiceRecordDevider.d.ts.map +1 -0
- package/dist/typescript/commonjs/features/voiceRecord/components/VoiceRecordTimer.d.ts +9 -0
- package/dist/typescript/commonjs/features/voiceRecord/components/VoiceRecordTimer.d.ts.map +1 -0
- package/dist/typescript/commonjs/features/voiceRecord/helpers.d.ts +4 -0
- package/dist/typescript/commonjs/features/voiceRecord/helpers.d.ts.map +1 -0
- package/dist/typescript/commonjs/features/voiceRecord/hooks/useVoiceRecorder.hook.d.ts +9 -0
- package/dist/typescript/commonjs/features/voiceRecord/hooks/useVoiceRecorder.hook.d.ts.map +1 -0
- package/dist/typescript/commonjs/features/voiceRecord/index.d.ts +3 -0
- package/dist/typescript/commonjs/features/voiceRecord/index.d.ts.map +1 -0
- package/dist/typescript/commonjs/features/voiceRecord/model/VoiceRecord.model.d.ts +17 -0
- package/dist/typescript/commonjs/features/voiceRecord/model/VoiceRecord.model.d.ts.map +1 -0
- package/dist/typescript/commonjs/features/voiceRecord/model/VoiceRecordApi.d.ts +3 -0
- package/dist/typescript/commonjs/features/voiceRecord/model/VoiceRecordApi.d.ts.map +1 -0
- package/dist/typescript/commonjs/index.d.ts +1 -0
- package/dist/typescript/commonjs/index.d.ts.map +1 -1
- package/dist/typescript/module/features/voiceRecord/components/VoiceRecord.d.ts +10 -0
- package/dist/typescript/module/features/voiceRecord/components/VoiceRecord.d.ts.map +1 -0
- package/dist/typescript/module/features/voiceRecord/components/VoiceRecordButton.d.ts +10 -0
- package/dist/typescript/module/features/voiceRecord/components/VoiceRecordButton.d.ts.map +1 -0
- package/dist/typescript/module/features/voiceRecord/components/VoiceRecordDelete.d.ts +7 -0
- package/dist/typescript/module/features/voiceRecord/components/VoiceRecordDelete.d.ts.map +1 -0
- package/dist/typescript/module/features/voiceRecord/components/VoiceRecordDevider.d.ts +3 -0
- package/dist/typescript/module/features/voiceRecord/components/VoiceRecordDevider.d.ts.map +1 -0
- package/dist/typescript/module/features/voiceRecord/components/VoiceRecordTimer.d.ts +9 -0
- package/dist/typescript/module/features/voiceRecord/components/VoiceRecordTimer.d.ts.map +1 -0
- package/dist/typescript/module/features/voiceRecord/helpers.d.ts +4 -0
- package/dist/typescript/module/features/voiceRecord/helpers.d.ts.map +1 -0
- package/dist/typescript/module/features/voiceRecord/hooks/useVoiceRecorder.hook.d.ts +9 -0
- package/dist/typescript/module/features/voiceRecord/hooks/useVoiceRecorder.hook.d.ts.map +1 -0
- package/dist/typescript/module/features/voiceRecord/index.d.ts +3 -0
- package/dist/typescript/module/features/voiceRecord/index.d.ts.map +1 -0
- package/dist/typescript/module/features/voiceRecord/model/VoiceRecord.model.d.ts +17 -0
- package/dist/typescript/module/features/voiceRecord/model/VoiceRecord.model.d.ts.map +1 -0
- package/dist/typescript/module/features/voiceRecord/model/VoiceRecordApi.d.ts +3 -0
- package/dist/typescript/module/features/voiceRecord/model/VoiceRecordApi.d.ts.map +1 -0
- package/dist/typescript/module/index.d.ts +1 -0
- package/dist/typescript/module/index.d.ts.map +1 -1
- package/package.json +7 -3
- package/src/features/voiceRecord/components/VoiceRecord.tsx +78 -0
- package/src/features/voiceRecord/components/VoiceRecordButton.tsx +44 -0
- package/src/features/voiceRecord/components/VoiceRecordDelete.tsx +24 -0
- package/src/features/voiceRecord/components/VoiceRecordDevider.tsx +17 -0
- package/src/features/voiceRecord/components/VoiceRecordTimer.tsx +37 -0
- package/src/features/voiceRecord/helpers.ts +30 -0
- package/src/features/voiceRecord/hooks/useVoiceRecorder.hook.ts +39 -0
- package/src/features/voiceRecord/index.ts +2 -0
- package/src/features/voiceRecord/model/VoiceRecord.model.ts +41 -0
- package/src/features/voiceRecord/model/VoiceRecordApi.ts +1 -0
- package/src/index.ts +1 -0
- package/.editorconfig +0 -15
- package/.eslintignore +0 -2
- package/.eslintrc +0 -22
- package/.gitattributes +0 -3
- package/.github/actions/setup/action.yml +0 -37
- package/.github/workflows/ci.yml +0 -73
- package/.gitignore +0 -84
- package/.idea/.gitignore +0 -8
- package/.idea/codeStyles/Project.xml +0 -62
- package/.idea/codeStyles/codeStyleConfig.xml +0 -5
- package/.idea/copilot.data.migration.agent.xml +0 -6
- package/.idea/copilot.data.migration.ask.xml +0 -6
- package/.idea/copilot.data.migration.ask2agent.xml +0 -6
- package/.idea/copilot.data.migration.edit.xml +0 -6
- package/.idea/inspectionProfiles/Project_Default.xml +0 -8
- package/.idea/jsLinters/eslint.xml +0 -6
- package/.idea/modules.xml +0 -8
- package/.idea/prettier.xml +0 -7
- package/.idea/shelf/Uncommitted_changes_before_Checkout_at_30_12_2025,_11_06_[Changes]/shelved.patch +0 -18
- package/.idea/shelf/Uncommitted_changes_before_Checkout_at_30_12_2025,_11_07_[Changes]/shelved.patch +0 -18
- package/.idea/shelf/Uncommitted_changes_before_Checkout_at_30_12_2025__11_06__Changes_.xml +0 -4
- package/.idea/shelf/Uncommitted_changes_before_Checkout_at_30_12_2025__11_07__Changes_.xml +0 -4
- package/.idea/students-features.iml +0 -12
- package/.idea/vcs.xml +0 -6
- package/.idea/workspace.xml +0 -646
- package/.nvmrc +0 -1
- package/.prettierrc +0 -11
- package/.release-it.json +0 -17
- package/.watchmanconfig +0 -1
- package/.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs +0 -541
- package/.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs +0 -28
- package/.yarn/releases/yarn-3.6.1.cjs +0 -874
- package/babel.config.js +0 -5
- package/bob.config.js +0 -25
- package/example/.expo/README.md +0 -8
- package/example/.expo/devices.json +0 -3
- package/example/.expo/web/cache/production/images/favicon/favicon-24272cdaeff82cc5facdaccd982a6f05b60c4504704bbf94c19a6388659880bb-contain-transparent/favicon-48.png +0 -0
- package/example/app.json +0 -30
- package/example/assets/adaptive-icon.png +0 -0
- package/example/assets/favicon.png +0 -0
- package/example/assets/icon.png +0 -0
- package/example/assets/splash-icon.png +0 -0
- package/example/babel.config.js +0 -28
- package/example/index.js +0 -8
- package/example/metro.config.js +0 -18
- package/example/package.json +0 -25
- package/example/src/App.tsx +0 -8
- package/example/tsconfig.json +0 -6
- package/example/yarn.lock +0 -6552
- package/tsconfig.build.json +0 -4
- package/tsconfig.json +0 -34
- package/yarn.lock +0 -8623
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { StyleProp, ViewStyle, StyleSheet } from 'react-native'
|
|
2
|
+
import { VoiceRecordButton } from './VoiceRecordButton'
|
|
3
|
+
import React from 'react'
|
|
4
|
+
import { COLORS, SPACING } from '@magmamath/react-native-ui'
|
|
5
|
+
import { VoiceRecordDelete } from './VoiceRecordDelete'
|
|
6
|
+
import { VoiceRecordDevider } from './VoiceRecordDevider'
|
|
7
|
+
import VoiceRecordTimer from './VoiceRecordTimer'
|
|
8
|
+
import Animated, { FadeIn, FadeOut, useAnimatedStyle, withTiming } from 'react-native-reanimated'
|
|
9
|
+
import { VoiceRecordModel } from '../model/VoiceRecord.model'
|
|
10
|
+
import { useVoiceRecorder } from '../hooks/useVoiceRecorder.hook'
|
|
11
|
+
|
|
12
|
+
type VoiceRecordProps = {
|
|
13
|
+
style?: StyleProp<ViewStyle>
|
|
14
|
+
model: VoiceRecordModel
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const CONTAINER_SIZES = {
|
|
18
|
+
COLLAPSED: 61,
|
|
19
|
+
EXPANDED: 152,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const VoiceRecord = ({ style, model }: VoiceRecordProps) => {
|
|
23
|
+
const { recorder, recorderState, player, startRecording, stopRecording } = useVoiceRecorder(model)
|
|
24
|
+
|
|
25
|
+
const aniamtedStyle = useAnimatedStyle(() => {
|
|
26
|
+
return {
|
|
27
|
+
height: withTiming(
|
|
28
|
+
recorderState.isRecording ? CONTAINER_SIZES.EXPANDED : CONTAINER_SIZES.COLLAPSED,
|
|
29
|
+
{
|
|
30
|
+
duration: 280,
|
|
31
|
+
},
|
|
32
|
+
),
|
|
33
|
+
}
|
|
34
|
+
}, [recorderState])
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<Animated.View style={[styles.container, style, aniamtedStyle]}>
|
|
38
|
+
<VoiceRecordButton
|
|
39
|
+
// onPress={() => setIsRecording((prev) => !prev)}
|
|
40
|
+
onPress={recorderState.isRecording ? stopRecording : startRecording}
|
|
41
|
+
isRecording={recorderState.isRecording}
|
|
42
|
+
/>
|
|
43
|
+
{recorderState.isRecording && (
|
|
44
|
+
<Animated.View entering={FadeIn} exiting={FadeOut} style={styles.expendedContainer}>
|
|
45
|
+
<VoiceRecordTimer
|
|
46
|
+
style={styles.timer}
|
|
47
|
+
//0:00 as default value and format mm:ss
|
|
48
|
+
time={
|
|
49
|
+
recorderState.durationMillis
|
|
50
|
+
? new Date(recorderState.durationMillis).toISOString().substr(14, 5)
|
|
51
|
+
: '0:00'
|
|
52
|
+
}
|
|
53
|
+
/>
|
|
54
|
+
<VoiceRecordDevider />
|
|
55
|
+
<VoiceRecordDelete onPress={model.deleteFile} />
|
|
56
|
+
</Animated.View>
|
|
57
|
+
)}
|
|
58
|
+
</Animated.View>
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const styles = StyleSheet.create({
|
|
63
|
+
container: {
|
|
64
|
+
alignItems: 'center',
|
|
65
|
+
padding: 3,
|
|
66
|
+
paddingBottom: 6,
|
|
67
|
+
backgroundColor: COLORS.NEUTRAL_3,
|
|
68
|
+
borderRadius: 32,
|
|
69
|
+
boxShadow: '0 1px 3px 0 rgba(51, 51, 51, 0.10), 0 0 1px 0 rgba(51, 51, 51, 0.40)',
|
|
70
|
+
overflow: 'hidden',
|
|
71
|
+
},
|
|
72
|
+
timer: {
|
|
73
|
+
marginTop: SPACING[400],
|
|
74
|
+
},
|
|
75
|
+
expendedContainer: {
|
|
76
|
+
alignItems: 'center',
|
|
77
|
+
},
|
|
78
|
+
})
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React, { useMemo } from 'react'
|
|
2
|
+
import {
|
|
3
|
+
Button,
|
|
4
|
+
ButtonColor,
|
|
5
|
+
ButtonSize,
|
|
6
|
+
ButtonStyle,
|
|
7
|
+
ButtonVariant,
|
|
8
|
+
} from '@magmamath/react-native-ui'
|
|
9
|
+
import { ViewStyle } from 'react-native'
|
|
10
|
+
import { MicrophoneIcon, CheckIcon } from '@magmamath/react-native-ui'
|
|
11
|
+
|
|
12
|
+
type VoiceRecordButtonProps = {
|
|
13
|
+
style?: ButtonStyle
|
|
14
|
+
onPress?: () => void
|
|
15
|
+
isRecording: boolean
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const VoiceRecordButton = ({ style, onPress, isRecording }: VoiceRecordButtonProps) => {
|
|
19
|
+
const combinedStyles = useMemo((): ButtonStyle => {
|
|
20
|
+
return {
|
|
21
|
+
button: {
|
|
22
|
+
width: 50,
|
|
23
|
+
...(style?.button as ViewStyle),
|
|
24
|
+
},
|
|
25
|
+
container: {
|
|
26
|
+
...(style?.container as ViewStyle),
|
|
27
|
+
},
|
|
28
|
+
text: {
|
|
29
|
+
...(style?.text as ViewStyle),
|
|
30
|
+
},
|
|
31
|
+
}
|
|
32
|
+
}, [style])
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<Button
|
|
36
|
+
onPress={onPress}
|
|
37
|
+
style={combinedStyles}
|
|
38
|
+
size={ButtonSize.LARGE}
|
|
39
|
+
variant={ButtonVariant.PRIMARY}
|
|
40
|
+
colorScheme={ButtonColor.WHITE}
|
|
41
|
+
icon={isRecording ? <CheckIcon size={25} /> : <MicrophoneIcon size={19} />}
|
|
42
|
+
/>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { StyleSheet, TouchableOpacity } from 'react-native'
|
|
2
|
+
import { TrashcanIcon } from '@magmamath/react-native-ui'
|
|
3
|
+
import React from 'react'
|
|
4
|
+
|
|
5
|
+
type VoiceRecordDeleteProps = {
|
|
6
|
+
onPress?: () => void
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const VoiceRecordDelete = ({ onPress }: VoiceRecordDeleteProps) => {
|
|
10
|
+
return (
|
|
11
|
+
<TouchableOpacity style={styles.container} onPress={onPress}>
|
|
12
|
+
<TrashcanIcon size={20} />
|
|
13
|
+
</TouchableOpacity>
|
|
14
|
+
)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const styles = StyleSheet.create({
|
|
18
|
+
container: {
|
|
19
|
+
width: 36,
|
|
20
|
+
height: 36,
|
|
21
|
+
alignItems: 'center',
|
|
22
|
+
justifyContent: 'center',
|
|
23
|
+
},
|
|
24
|
+
})
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { StyleSheet, View } from 'react-native'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { COLORS } from '@magmamath/react-native-ui'
|
|
4
|
+
|
|
5
|
+
export const VoiceRecordDevider = () => {
|
|
6
|
+
return <View style={styles.container} />
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const styles = StyleSheet.create({
|
|
10
|
+
container: {
|
|
11
|
+
height: 1,
|
|
12
|
+
borderRadius: 1,
|
|
13
|
+
width: 28,
|
|
14
|
+
margin: 8,
|
|
15
|
+
backgroundColor: COLORS.NEUTRAL_6,
|
|
16
|
+
},
|
|
17
|
+
})
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { StyleProp, StyleSheet, Text, View, ViewStyle } from 'react-native'
|
|
2
|
+
import { COLORS, Typography } from '@magmamath/react-native-ui'
|
|
3
|
+
import React from 'react'
|
|
4
|
+
|
|
5
|
+
type VoiceRecordTimerProps = {
|
|
6
|
+
style?: StyleProp<ViewStyle>
|
|
7
|
+
time: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const VoiceRecordTimer = ({ style, time }: VoiceRecordTimerProps) => {
|
|
11
|
+
return (
|
|
12
|
+
<View style={[styles.container, style]}>
|
|
13
|
+
<Typography style={styles.text}>{time}</Typography>
|
|
14
|
+
</View>
|
|
15
|
+
)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default VoiceRecordTimer
|
|
19
|
+
|
|
20
|
+
const styles = StyleSheet.create({
|
|
21
|
+
container: {
|
|
22
|
+
backgroundColor: COLORS.NEUTRAL_1,
|
|
23
|
+
paddingHorizontal: 8,
|
|
24
|
+
paddingVertical: 2,
|
|
25
|
+
alignItems: 'center',
|
|
26
|
+
borderWidth: 0.5,
|
|
27
|
+
borderColor: COLORS.NEUTRAL_4,
|
|
28
|
+
borderRadius: 18,
|
|
29
|
+
},
|
|
30
|
+
text: {
|
|
31
|
+
color: COLORS.NEUTRAL_10,
|
|
32
|
+
fontSize: 13,
|
|
33
|
+
fontWeight: '600',
|
|
34
|
+
lineHeight: 18,
|
|
35
|
+
textTransform: 'uppercase',
|
|
36
|
+
},
|
|
37
|
+
})
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { IS_MOBILE, IS_WEB } from '@magmamath/react-native-ui'
|
|
2
|
+
import {
|
|
3
|
+
AudioRecorder,
|
|
4
|
+
getRecordingPermissionsAsync,
|
|
5
|
+
requestRecordingPermissionsAsync,
|
|
6
|
+
} from 'expo-audio'
|
|
7
|
+
|
|
8
|
+
export const ensureRecordingPermissions = async () => {
|
|
9
|
+
const { status } = await getRecordingPermissionsAsync()
|
|
10
|
+
|
|
11
|
+
if (status !== 'granted') {
|
|
12
|
+
const { granted } = await requestRecordingPermissionsAsync()
|
|
13
|
+
return granted
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return true
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const getAvailableInputs = async (recorder: AudioRecorder) => {
|
|
20
|
+
if (IS_WEB) {
|
|
21
|
+
if (!navigator.mediaDevices?.enumerateDevices) return []
|
|
22
|
+
|
|
23
|
+
const devices = await navigator.mediaDevices.enumerateDevices()
|
|
24
|
+
return devices.filter((d) => d.kind === 'audioinput')
|
|
25
|
+
}
|
|
26
|
+
if (IS_MOBILE) {
|
|
27
|
+
return await recorder.getAvailableInputs()
|
|
28
|
+
}
|
|
29
|
+
return []
|
|
30
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import {
|
|
2
|
+
RecordingPresets,
|
|
3
|
+
useAudioPlayer,
|
|
4
|
+
useAudioRecorder,
|
|
5
|
+
useAudioRecorderState,
|
|
6
|
+
} from 'expo-audio'
|
|
7
|
+
import { ensureRecordingPermissions, getAvailableInputs } from '../helpers'
|
|
8
|
+
import { VoiceRecordModel } from '../model/VoiceRecord.model'
|
|
9
|
+
|
|
10
|
+
export const useVoiceRecorder = (model: VoiceRecordModel) => {
|
|
11
|
+
const recorder = useAudioRecorder(RecordingPresets.LOW_QUALITY, (status) =>
|
|
12
|
+
console.log('Recording status:', status),
|
|
13
|
+
)
|
|
14
|
+
const recorderState = useAudioRecorderState(recorder)
|
|
15
|
+
|
|
16
|
+
const player = useAudioPlayer()
|
|
17
|
+
|
|
18
|
+
const startRecording = async () => {
|
|
19
|
+
if (!(await ensureRecordingPermissions())) return model.showError('No microphone access')
|
|
20
|
+
|
|
21
|
+
await recorder.prepareToRecordAsync()
|
|
22
|
+
|
|
23
|
+
if (await getAvailableInputs(recorder).then((inputs) => inputs.length === 0)) {
|
|
24
|
+
return model.showError('No microphone found')
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
recorder.record()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const stopRecording = async () => {
|
|
31
|
+
await recorder.stop()
|
|
32
|
+
recorder.uri && console.log('Recording stopped and stored at', recorder.uri)
|
|
33
|
+
|
|
34
|
+
player.replace(recorder.uri!)
|
|
35
|
+
player.play()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return { recorder, recorderState, player, startRecording, stopRecording }
|
|
39
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { createEffect, createEvent, restore, sample } from 'effector'
|
|
2
|
+
import { AudioRecorder } from 'expo-audio'
|
|
3
|
+
|
|
4
|
+
type VoiceRecordModelParams = {
|
|
5
|
+
showToatInfo: (message: string) => void
|
|
6
|
+
showToastError: (message: string) => void
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class VoiceRecordModel {
|
|
10
|
+
public readonly startRecord = createEvent()
|
|
11
|
+
public readonly stop = createEvent()
|
|
12
|
+
|
|
13
|
+
public readonly deleteFile = createEvent()
|
|
14
|
+
|
|
15
|
+
public readonly setAudioFilePath = createEvent<string>()
|
|
16
|
+
public readonly clearAudioFilePath = createEvent()
|
|
17
|
+
public readonly $audioFilePath = restore(this.setAudioFilePath, '').reset(this.clearAudioFilePath)
|
|
18
|
+
|
|
19
|
+
public readonly showInfo: (message: string) => void
|
|
20
|
+
public readonly showError: (message: string) => void
|
|
21
|
+
|
|
22
|
+
constructor({ showToatInfo, showToastError }: VoiceRecordModelParams) {
|
|
23
|
+
this.showInfo = showToatInfo
|
|
24
|
+
this.showError = showToastError
|
|
25
|
+
|
|
26
|
+
sample({
|
|
27
|
+
clock: this.deleteFile,
|
|
28
|
+
target: createEffect(async () => {
|
|
29
|
+
this.clearAudioFilePath()
|
|
30
|
+
showToatInfo('Recording deleted')
|
|
31
|
+
}),
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
sample({
|
|
35
|
+
clock: this.startRecord,
|
|
36
|
+
target: createEffect(async () => {
|
|
37
|
+
showToatInfo('Recording started')
|
|
38
|
+
}),
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export class VoiceRecordApi {}
|
package/src/index.ts
CHANGED
package/.editorconfig
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
# EditorConfig helps developers define and maintain consistent
|
|
2
|
-
# coding styles between different editors and IDEs
|
|
3
|
-
# editorconfig.org
|
|
4
|
-
|
|
5
|
-
root = true
|
|
6
|
-
|
|
7
|
-
[*]
|
|
8
|
-
|
|
9
|
-
indent_style = space
|
|
10
|
-
indent_size = 2
|
|
11
|
-
|
|
12
|
-
end_of_line = lf
|
|
13
|
-
charset = utf-8
|
|
14
|
-
trim_trailing_whitespace = true
|
|
15
|
-
insert_final_newline = true
|
package/.eslintignore
DELETED
package/.eslintrc
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"env": {
|
|
3
|
-
"browser": true,
|
|
4
|
-
"es2020": true
|
|
5
|
-
},
|
|
6
|
-
"extends": [
|
|
7
|
-
"eslint:recommended",
|
|
8
|
-
"plugin:@typescript-eslint/recommended",
|
|
9
|
-
"plugin:react-hooks/recommended",
|
|
10
|
-
"plugin:storybook/recommended",
|
|
11
|
-
"prettier"
|
|
12
|
-
],
|
|
13
|
-
"parser": "@typescript-eslint/parser",
|
|
14
|
-
"parserOptions": {
|
|
15
|
-
"ecmaVersion": "latest",
|
|
16
|
-
"sourceType": "module"
|
|
17
|
-
},
|
|
18
|
-
"plugins": ["react-refresh"],
|
|
19
|
-
"rules": {
|
|
20
|
-
"react-refresh/only-export-components": "warn"
|
|
21
|
-
}
|
|
22
|
-
}
|
package/.gitattributes
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
name: Setup
|
|
2
|
-
description: Setup Node.js and install dependencies
|
|
3
|
-
|
|
4
|
-
inputs:
|
|
5
|
-
npmrc-auth-token:
|
|
6
|
-
required: true
|
|
7
|
-
|
|
8
|
-
runs:
|
|
9
|
-
using: composite
|
|
10
|
-
steps:
|
|
11
|
-
- name: Setup Node.js
|
|
12
|
-
uses: actions/setup-node@v3
|
|
13
|
-
with:
|
|
14
|
-
node-version-file: .nvmrc
|
|
15
|
-
|
|
16
|
-
- name: Create .npmrc
|
|
17
|
-
shell: bash
|
|
18
|
-
run: |
|
|
19
|
-
echo "registry=https://registry.npmjs.org" > .npmrc
|
|
20
|
-
echo "//registry.npmjs.org/:_authToken=${{ inputs.npmrc-auth-token }}" >> .npmrc
|
|
21
|
-
|
|
22
|
-
- name: Cache dependencies
|
|
23
|
-
id: yarn-cache
|
|
24
|
-
uses: actions/cache@v3
|
|
25
|
-
with:
|
|
26
|
-
path: |
|
|
27
|
-
**/node_modules
|
|
28
|
-
.yarn/install-state.gz
|
|
29
|
-
key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }}-${{ hashFiles('**/package.json', '!node_modules/**') }}
|
|
30
|
-
restore-keys: |
|
|
31
|
-
${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }}
|
|
32
|
-
${{ runner.os }}-yarn-
|
|
33
|
-
|
|
34
|
-
- name: Install dependencies
|
|
35
|
-
if: steps.yarn-cache.outputs.cache-hit != 'true'
|
|
36
|
-
run: yarn install --immutable
|
|
37
|
-
shell: bash
|
package/.github/workflows/ci.yml
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
name: CI
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches:
|
|
6
|
-
- main
|
|
7
|
-
pull_request:
|
|
8
|
-
branches:
|
|
9
|
-
- main
|
|
10
|
-
merge_group:
|
|
11
|
-
types:
|
|
12
|
-
- checks_requested
|
|
13
|
-
|
|
14
|
-
jobs:
|
|
15
|
-
lint:
|
|
16
|
-
runs-on: ubuntu-latest
|
|
17
|
-
steps:
|
|
18
|
-
- name: Checkout
|
|
19
|
-
uses: actions/checkout@v3
|
|
20
|
-
|
|
21
|
-
- name: Setup
|
|
22
|
-
uses: ./.github/actions/setup
|
|
23
|
-
with:
|
|
24
|
-
npmrc-auth-token: ${{ secrets.MAGMA_NPMRC_TOKEN }}
|
|
25
|
-
|
|
26
|
-
- name: Lint files
|
|
27
|
-
run: yarn lint
|
|
28
|
-
|
|
29
|
-
- name: Typecheck files
|
|
30
|
-
run: yarn typecheck
|
|
31
|
-
|
|
32
|
-
test:
|
|
33
|
-
runs-on: ubuntu-latest
|
|
34
|
-
steps:
|
|
35
|
-
- name: Checkout
|
|
36
|
-
uses: actions/checkout@v3
|
|
37
|
-
|
|
38
|
-
- name: Setup
|
|
39
|
-
uses: ./.github/actions/setup
|
|
40
|
-
with:
|
|
41
|
-
npmrc-auth-token: ${{ secrets.MAGMA_NPMRC_TOKEN }}
|
|
42
|
-
|
|
43
|
-
- name: Run unit tests
|
|
44
|
-
run: yarn test --maxWorkers=2 --coverage
|
|
45
|
-
|
|
46
|
-
build-library:
|
|
47
|
-
runs-on: ubuntu-latest
|
|
48
|
-
steps:
|
|
49
|
-
- name: Checkout
|
|
50
|
-
uses: actions/checkout@v3
|
|
51
|
-
|
|
52
|
-
- name: Setup
|
|
53
|
-
uses: ./.github/actions/setup
|
|
54
|
-
with:
|
|
55
|
-
npmrc-auth-token: ${{ secrets.MAGMA_NPMRC_TOKEN }}
|
|
56
|
-
|
|
57
|
-
- name: Build package
|
|
58
|
-
run: yarn prepare
|
|
59
|
-
|
|
60
|
-
build-web:
|
|
61
|
-
runs-on: ubuntu-latest
|
|
62
|
-
steps:
|
|
63
|
-
- name: Checkout
|
|
64
|
-
uses: actions/checkout@v3
|
|
65
|
-
|
|
66
|
-
- name: Setup
|
|
67
|
-
uses: ./.github/actions/setup
|
|
68
|
-
with:
|
|
69
|
-
npmrc-auth-token: ${{ secrets.MAGMA_NPMRC_TOKEN }}
|
|
70
|
-
|
|
71
|
-
- name: Build example for Web
|
|
72
|
-
run: |
|
|
73
|
-
yarn example expo export --platform web
|
package/.gitignore
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
# OSX
|
|
2
|
-
#
|
|
3
|
-
.DS_Store
|
|
4
|
-
|
|
5
|
-
# XDE
|
|
6
|
-
.expo/
|
|
7
|
-
|
|
8
|
-
# VSCode
|
|
9
|
-
.vscode/
|
|
10
|
-
jsconfig.json
|
|
11
|
-
|
|
12
|
-
# Xcode
|
|
13
|
-
#
|
|
14
|
-
build/
|
|
15
|
-
*.pbxuser
|
|
16
|
-
!default.pbxuser
|
|
17
|
-
*.mode1v3
|
|
18
|
-
!default.mode1v3
|
|
19
|
-
*.mode2v3
|
|
20
|
-
!default.mode2v3
|
|
21
|
-
*.perspectivev3
|
|
22
|
-
!default.perspectivev3
|
|
23
|
-
xcuserdata
|
|
24
|
-
*.xccheckout
|
|
25
|
-
*.moved-aside
|
|
26
|
-
DerivedData
|
|
27
|
-
*.hmap
|
|
28
|
-
*.ipa
|
|
29
|
-
*.xcuserstate
|
|
30
|
-
project.xcworkspace
|
|
31
|
-
|
|
32
|
-
# Android/IJ
|
|
33
|
-
#
|
|
34
|
-
.classpath
|
|
35
|
-
.cxx
|
|
36
|
-
.gradle
|
|
37
|
-
.idea
|
|
38
|
-
.project
|
|
39
|
-
.settings
|
|
40
|
-
local.properties
|
|
41
|
-
android.iml
|
|
42
|
-
|
|
43
|
-
# Cocoapods
|
|
44
|
-
#
|
|
45
|
-
example/ios/Pods
|
|
46
|
-
|
|
47
|
-
# Ruby
|
|
48
|
-
example/vendor/
|
|
49
|
-
|
|
50
|
-
# node.js
|
|
51
|
-
#
|
|
52
|
-
node_modules/
|
|
53
|
-
npm-debug.log
|
|
54
|
-
yarn-debug.log
|
|
55
|
-
yarn-error.log
|
|
56
|
-
|
|
57
|
-
# BUCK
|
|
58
|
-
buck-out/
|
|
59
|
-
\.buckd/
|
|
60
|
-
android/app/libs
|
|
61
|
-
android/keystores/debug.keystore
|
|
62
|
-
|
|
63
|
-
# Yarn
|
|
64
|
-
.yarn/*
|
|
65
|
-
!.yarn/patches
|
|
66
|
-
!.yarn/plugins
|
|
67
|
-
!.yarn/releases
|
|
68
|
-
!.yarn/sdks
|
|
69
|
-
!.yarn/versions
|
|
70
|
-
|
|
71
|
-
# Expo
|
|
72
|
-
.expo/
|
|
73
|
-
|
|
74
|
-
# Turborepo
|
|
75
|
-
.turbo/
|
|
76
|
-
|
|
77
|
-
# generated by bob
|
|
78
|
-
dist/
|
|
79
|
-
!src/lib/
|
|
80
|
-
|
|
81
|
-
# React Native Codegen
|
|
82
|
-
ios/generated
|
|
83
|
-
android/generated
|
|
84
|
-
.npmrc
|
package/.idea/.gitignore
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
<component name="ProjectCodeStyleConfiguration">
|
|
2
|
-
<code_scheme name="Project" version="173">
|
|
3
|
-
<option name="LINE_SEPARATOR" value=" " />
|
|
4
|
-
<HTMLCodeStyleSettings>
|
|
5
|
-
<option name="HTML_SPACE_INSIDE_EMPTY_TAG" value="true" />
|
|
6
|
-
</HTMLCodeStyleSettings>
|
|
7
|
-
<JSCodeStyleSettings version="0">
|
|
8
|
-
<option name="USE_SEMICOLON_AFTER_STATEMENT" value="false" />
|
|
9
|
-
<option name="FORCE_SEMICOLON_STYLE" value="true" />
|
|
10
|
-
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
|
|
11
|
-
<option name="USE_DOUBLE_QUOTES" value="false" />
|
|
12
|
-
<option name="FORCE_QUOTE_STYlE" value="true" />
|
|
13
|
-
<option name="ENFORCE_TRAILING_COMMA" value="WhenMultiline" />
|
|
14
|
-
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
|
|
15
|
-
<option name="SPACES_WITHIN_IMPORTS" value="true" />
|
|
16
|
-
</JSCodeStyleSettings>
|
|
17
|
-
<TypeScriptCodeStyleSettings version="0">
|
|
18
|
-
<option name="USE_SEMICOLON_AFTER_STATEMENT" value="false" />
|
|
19
|
-
<option name="FORCE_SEMICOLON_STYLE" value="true" />
|
|
20
|
-
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
|
|
21
|
-
<option name="USE_DOUBLE_QUOTES" value="false" />
|
|
22
|
-
<option name="FORCE_QUOTE_STYlE" value="true" />
|
|
23
|
-
<option name="ENFORCE_TRAILING_COMMA" value="WhenMultiline" />
|
|
24
|
-
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
|
|
25
|
-
<option name="SPACES_WITHIN_IMPORTS" value="true" />
|
|
26
|
-
</TypeScriptCodeStyleSettings>
|
|
27
|
-
<VueCodeStyleSettings>
|
|
28
|
-
<option name="INTERPOLATION_NEW_LINE_AFTER_START_DELIMITER" value="false" />
|
|
29
|
-
<option name="INTERPOLATION_NEW_LINE_BEFORE_END_DELIMITER" value="false" />
|
|
30
|
-
</VueCodeStyleSettings>
|
|
31
|
-
<codeStyleSettings language="HTML">
|
|
32
|
-
<option name="SOFT_MARGINS" value="100" />
|
|
33
|
-
<indentOptions>
|
|
34
|
-
<option name="INDENT_SIZE" value="2" />
|
|
35
|
-
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
|
36
|
-
<option name="TAB_SIZE" value="2" />
|
|
37
|
-
</indentOptions>
|
|
38
|
-
</codeStyleSettings>
|
|
39
|
-
<codeStyleSettings language="JavaScript">
|
|
40
|
-
<option name="SOFT_MARGINS" value="100" />
|
|
41
|
-
<indentOptions>
|
|
42
|
-
<option name="INDENT_SIZE" value="2" />
|
|
43
|
-
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
|
44
|
-
<option name="TAB_SIZE" value="2" />
|
|
45
|
-
</indentOptions>
|
|
46
|
-
</codeStyleSettings>
|
|
47
|
-
<codeStyleSettings language="TypeScript">
|
|
48
|
-
<option name="SOFT_MARGINS" value="100" />
|
|
49
|
-
<indentOptions>
|
|
50
|
-
<option name="INDENT_SIZE" value="2" />
|
|
51
|
-
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
|
52
|
-
<option name="TAB_SIZE" value="2" />
|
|
53
|
-
</indentOptions>
|
|
54
|
-
</codeStyleSettings>
|
|
55
|
-
<codeStyleSettings language="Vue">
|
|
56
|
-
<option name="SOFT_MARGINS" value="100" />
|
|
57
|
-
<indentOptions>
|
|
58
|
-
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
|
59
|
-
</indentOptions>
|
|
60
|
-
</codeStyleSettings>
|
|
61
|
-
</code_scheme>
|
|
62
|
-
</component>
|