@sendbird/uikit-react-native 3.1.1 → 3.2.0
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/README.md +67 -42
- package/lib/commonjs/components/ChannelInput/MessageToReplyPreview.js +145 -0
- package/lib/commonjs/components/ChannelInput/MessageToReplyPreview.js.map +1 -0
- package/lib/commonjs/components/ChannelInput/SendInput.js +147 -312
- package/lib/commonjs/components/ChannelInput/SendInput.js.map +1 -1
- package/lib/commonjs/components/ChannelInput/VoiceMessageInput.js +238 -0
- package/lib/commonjs/components/ChannelInput/VoiceMessageInput.js.map +1 -0
- package/lib/commonjs/components/ChannelInput/index.js +5 -1
- package/lib/commonjs/components/ChannelInput/index.js.map +1 -1
- package/lib/commonjs/components/ChannelMessageList/index.js +1 -1
- package/lib/commonjs/components/ChannelMessageList/index.js.map +1 -1
- package/lib/commonjs/components/ChatFlatList/index.js +15 -3
- package/lib/commonjs/components/ChatFlatList/index.js.map +1 -1
- package/lib/commonjs/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.js +24 -13
- package/lib/commonjs/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.js.map +1 -1
- package/lib/commonjs/components/GroupChannelMessageRenderer/index.js +100 -5
- package/lib/commonjs/components/GroupChannelMessageRenderer/index.js.map +1 -1
- package/lib/commonjs/components/MessageSearchResultItem.js +1 -0
- package/lib/commonjs/components/MessageSearchResultItem.js.map +1 -1
- package/lib/commonjs/components/OpenChannelMessageRenderer/index.js +1 -0
- package/lib/commonjs/components/OpenChannelMessageRenderer/index.js.map +1 -1
- package/lib/commonjs/components/ReactionBottomSheets/ReactionUserListBottomSheet.js +2 -2
- package/lib/commonjs/components/ReactionBottomSheets/ReactionUserListBottomSheet.js.map +1 -1
- package/lib/commonjs/components/ReactionBottomSheets/index.js.map +1 -1
- package/lib/commonjs/components/StatusComposition.js.map +1 -1
- package/lib/commonjs/constants.js +5 -1
- package/lib/commonjs/constants.js.map +1 -1
- package/lib/commonjs/containers/GroupChannelPreviewContainer.js +1 -0
- package/lib/commonjs/containers/GroupChannelPreviewContainer.js.map +1 -1
- package/lib/commonjs/containers/InternalErrorBoundaryContainer.js.map +1 -1
- package/lib/commonjs/containers/SendbirdUIKitContainer.js +84 -34
- package/lib/commonjs/containers/SendbirdUIKitContainer.js.map +1 -1
- package/lib/commonjs/contexts/PlatformServiceCtx.js +16 -12
- package/lib/commonjs/contexts/PlatformServiceCtx.js.map +1 -1
- package/lib/commonjs/contexts/ReactionCtx.js +3 -2
- package/lib/commonjs/contexts/ReactionCtx.js.map +1 -1
- package/lib/commonjs/contexts/SendbirdChatCtx.js +2 -0
- package/lib/commonjs/contexts/SendbirdChatCtx.js.map +1 -1
- package/lib/commonjs/domain/groupChannel/component/GroupChannelMessageList.js +27 -42
- package/lib/commonjs/domain/groupChannel/component/GroupChannelMessageList.js.map +1 -1
- package/lib/commonjs/domain/groupChannel/module/moduleContext.js +109 -5
- package/lib/commonjs/domain/groupChannel/module/moduleContext.js.map +1 -1
- package/lib/commonjs/domain/groupChannel/types.js.map +1 -1
- package/lib/commonjs/domain/userList/types.js.map +1 -1
- package/lib/commonjs/fragments/createGroupChannelFragment.js +30 -4
- package/lib/commonjs/fragments/createGroupChannelFragment.js.map +1 -1
- package/lib/commonjs/fragments/createMessageSearchFragment.js +1 -1
- package/lib/commonjs/fragments/createMessageSearchFragment.js.map +1 -1
- package/lib/commonjs/hooks/useChannelInputItems.js +211 -0
- package/lib/commonjs/hooks/useChannelInputItems.js.map +1 -0
- package/lib/commonjs/hooks/useConnection.js +1 -1
- package/lib/commonjs/hooks/useConnection.js.map +1 -1
- package/lib/commonjs/hooks/useMentionSuggestion.js +1 -1
- package/lib/commonjs/hooks/useMentionSuggestion.js.map +1 -1
- package/lib/commonjs/hooks/useVoiceMessageInput.js +207 -0
- package/lib/commonjs/hooks/useVoiceMessageInput.js.map +1 -0
- package/lib/commonjs/index.js +32 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/libs/MentionManager.js.map +1 -1
- package/lib/commonjs/libs/SBUUtils.js +4 -0
- package/lib/commonjs/libs/SBUUtils.js.map +1 -1
- package/lib/commonjs/libs/VoiceMessageConfig.js +30 -0
- package/lib/commonjs/libs/VoiceMessageConfig.js.map +1 -0
- package/lib/commonjs/localization/StringSet.type.js.map +1 -1
- package/lib/commonjs/localization/createBaseStringSet.js +24 -9
- package/lib/commonjs/localization/createBaseStringSet.js.map +1 -1
- package/lib/commonjs/platform/createFileService.expo.js +10 -0
- package/lib/commonjs/platform/createFileService.expo.js.map +1 -1
- package/lib/commonjs/platform/createFileService.native.js +19 -0
- package/lib/commonjs/platform/createFileService.native.js.map +1 -1
- package/lib/commonjs/platform/createPlayerService.expo.js +137 -0
- package/lib/commonjs/platform/createPlayerService.expo.js.map +1 -0
- package/lib/commonjs/platform/createPlayerService.native.js +139 -0
- package/lib/commonjs/platform/createPlayerService.native.js.map +1 -0
- package/lib/commonjs/platform/createRecorderService.expo.js +158 -0
- package/lib/commonjs/platform/createRecorderService.expo.js.map +1 -0
- package/lib/commonjs/platform/createRecorderService.native.js +157 -0
- package/lib/commonjs/platform/createRecorderService.native.js.map +1 -0
- package/lib/commonjs/platform/types.js.map +1 -1
- package/lib/commonjs/types.js.map +1 -1
- package/lib/commonjs/version.js +1 -1
- package/lib/commonjs/version.js.map +1 -1
- package/lib/module/components/ChannelInput/MessageToReplyPreview.js +137 -0
- package/lib/module/components/ChannelInput/MessageToReplyPreview.js.map +1 -0
- package/lib/module/components/ChannelInput/SendInput.js +149 -314
- package/lib/module/components/ChannelInput/SendInput.js.map +1 -1
- package/lib/module/components/ChannelInput/VoiceMessageInput.js +228 -0
- package/lib/module/components/ChannelInput/VoiceMessageInput.js.map +1 -0
- package/lib/module/components/ChannelInput/index.js +5 -1
- package/lib/module/components/ChannelInput/index.js.map +1 -1
- package/lib/module/components/ChannelMessageList/index.js +2 -2
- package/lib/module/components/ChannelMessageList/index.js.map +1 -1
- package/lib/module/components/ChatFlatList/index.js +15 -3
- package/lib/module/components/ChatFlatList/index.js.map +1 -1
- package/lib/module/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.js +24 -13
- package/lib/module/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.js.map +1 -1
- package/lib/module/components/GroupChannelMessageRenderer/index.js +99 -6
- package/lib/module/components/GroupChannelMessageRenderer/index.js.map +1 -1
- package/lib/module/components/MessageSearchResultItem.js +2 -1
- package/lib/module/components/MessageSearchResultItem.js.map +1 -1
- package/lib/module/components/OpenChannelMessageRenderer/index.js +1 -0
- package/lib/module/components/OpenChannelMessageRenderer/index.js.map +1 -1
- package/lib/module/components/ReactionBottomSheets/ReactionUserListBottomSheet.js +2 -2
- package/lib/module/components/ReactionBottomSheets/ReactionUserListBottomSheet.js.map +1 -1
- package/lib/module/components/ReactionBottomSheets/index.js.map +1 -1
- package/lib/module/components/StatusComposition.js.map +1 -1
- package/lib/module/constants.js +2 -0
- package/lib/module/constants.js.map +1 -1
- package/lib/module/containers/GroupChannelPreviewContainer.js +2 -1
- package/lib/module/containers/GroupChannelPreviewContainer.js.map +1 -1
- package/lib/module/containers/InternalErrorBoundaryContainer.js.map +1 -1
- package/lib/module/containers/SendbirdUIKitContainer.js +86 -36
- package/lib/module/containers/SendbirdUIKitContainer.js.map +1 -1
- package/lib/module/contexts/PlatformServiceCtx.js +14 -11
- package/lib/module/contexts/PlatformServiceCtx.js.map +1 -1
- package/lib/module/contexts/ReactionCtx.js +3 -2
- package/lib/module/contexts/ReactionCtx.js.map +1 -1
- package/lib/module/contexts/SendbirdChatCtx.js +2 -0
- package/lib/module/contexts/SendbirdChatCtx.js.map +1 -1
- package/lib/module/domain/groupChannel/component/GroupChannelMessageList.js +28 -43
- package/lib/module/domain/groupChannel/component/GroupChannelMessageList.js.map +1 -1
- package/lib/module/domain/groupChannel/module/moduleContext.js +111 -7
- package/lib/module/domain/groupChannel/module/moduleContext.js.map +1 -1
- package/lib/module/domain/groupChannel/types.js.map +1 -1
- package/lib/module/domain/userList/types.js.map +1 -1
- package/lib/module/fragments/createGroupChannelFragment.js +32 -6
- package/lib/module/fragments/createGroupChannelFragment.js.map +1 -1
- package/lib/module/fragments/createMessageSearchFragment.js +1 -1
- package/lib/module/fragments/createMessageSearchFragment.js.map +1 -1
- package/lib/module/hooks/useChannelInputItems.js +203 -0
- package/lib/module/hooks/useChannelInputItems.js.map +1 -0
- package/lib/module/hooks/useConnection.js +1 -1
- package/lib/module/hooks/useConnection.js.map +1 -1
- package/lib/module/hooks/useMentionSuggestion.js +1 -1
- package/lib/module/hooks/useMentionSuggestion.js.map +1 -1
- package/lib/module/hooks/useVoiceMessageInput.js +199 -0
- package/lib/module/hooks/useVoiceMessageInput.js.map +1 -0
- package/lib/module/index.js +4 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/libs/MentionManager.js.map +1 -1
- package/lib/module/libs/SBUUtils.js +4 -0
- package/lib/module/libs/SBUUtils.js.map +1 -1
- package/lib/module/libs/VoiceMessageConfig.js +23 -0
- package/lib/module/libs/VoiceMessageConfig.js.map +1 -0
- package/lib/module/localization/StringSet.type.js.map +1 -1
- package/lib/module/localization/createBaseStringSet.js +25 -10
- package/lib/module/localization/createBaseStringSet.js.map +1 -1
- package/lib/module/platform/createFileService.expo.js +10 -0
- package/lib/module/platform/createFileService.expo.js.map +1 -1
- package/lib/module/platform/createFileService.native.js +19 -0
- package/lib/module/platform/createFileService.native.js.map +1 -1
- package/lib/module/platform/createPlayerService.expo.js +129 -0
- package/lib/module/platform/createPlayerService.expo.js.map +1 -0
- package/lib/module/platform/createPlayerService.native.js +132 -0
- package/lib/module/platform/createPlayerService.native.js.map +1 -0
- package/lib/module/platform/createRecorderService.expo.js +150 -0
- package/lib/module/platform/createRecorderService.expo.js.map +1 -0
- package/lib/module/platform/createRecorderService.native.js +149 -0
- package/lib/module/platform/createRecorderService.native.js.map +1 -0
- package/lib/module/platform/types.js.map +1 -1
- package/lib/module/types.js.map +1 -1
- package/lib/module/version.js +1 -1
- package/lib/module/version.js.map +1 -1
- package/lib/typescript/src/components/ChannelCover.d.ts +2 -1
- package/lib/typescript/src/components/ChannelInput/AttachmentsButton.d.ts +2 -1
- package/lib/typescript/src/components/ChannelInput/MessageToReplyPreview.d.ts +7 -0
- package/lib/typescript/src/components/ChannelInput/VoiceMessageInput.d.ts +11 -0
- package/lib/typescript/src/components/ChannelInput/index.d.ts +7 -3
- package/lib/typescript/src/components/ChannelMessageList/index.d.ts +1 -1
- package/lib/typescript/src/components/FileViewer.d.ts +2 -1
- package/lib/typescript/src/components/GroupChannelMessageRenderer/GroupChannelMessageDateSeparator.d.ts +2 -1
- package/lib/typescript/src/components/GroupChannelMessageRenderer/GroupChannelMessageFocusAnimation.d.ts +1 -1
- package/lib/typescript/src/components/GroupChannelMessageRenderer/GroupChannelMessageOutgoingStatus.d.ts +1 -1
- package/lib/typescript/src/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.d.ts +4 -2
- package/lib/typescript/src/components/NewMessagesButton.d.ts +1 -1
- package/lib/typescript/src/components/OpenChannelMessageRenderer/OpenChannelMessageDateSeparator.d.ts +2 -1
- package/lib/typescript/src/components/ProviderLayout.d.ts +1 -1
- package/lib/typescript/src/components/ReactionAddons/BottomSheetReactionAddon.d.ts +2 -1
- package/lib/typescript/src/components/ReactionAddons/MessageReactionAddon.d.ts +2 -1
- package/lib/typescript/src/components/ReactionAddons/ReactionRoundedButton.d.ts +3 -2
- package/lib/typescript/src/components/ReactionAddons/index.d.ts +3 -2
- package/lib/typescript/src/components/ReactionBottomSheets/ReactionListBottomSheet.d.ts +2 -1
- package/lib/typescript/src/components/ReactionBottomSheets/ReactionUserListBottomSheet.d.ts +2 -1
- package/lib/typescript/src/components/ReactionBottomSheets/index.d.ts +4 -4
- package/lib/typescript/src/components/ScrollToBottomButton.d.ts +1 -1
- package/lib/typescript/src/components/StatusComposition.d.ts +4 -4
- package/lib/typescript/src/components/TypedPlaceholder.d.ts +2 -1
- package/lib/typescript/src/components/UserActionBar.d.ts +2 -1
- package/lib/typescript/src/components/UserSelectableBar.d.ts +2 -1
- package/lib/typescript/src/constants.d.ts +2 -0
- package/lib/typescript/src/containers/GroupChannelPreviewContainer.d.ts +2 -1
- package/lib/typescript/src/containers/InternalErrorBoundaryContainer.d.ts +3 -3
- package/lib/typescript/src/containers/SendbirdUIKitContainer.d.ts +18 -6
- package/lib/typescript/src/contexts/LocalizationCtx.d.ts +1 -1
- package/lib/typescript/src/contexts/PlatformServiceCtx.d.ts +8 -8
- package/lib/typescript/src/contexts/ReactionCtx.d.ts +5 -2
- package/lib/typescript/src/contexts/SendbirdChatCtx.d.ts +6 -3
- package/lib/typescript/src/contexts/UserProfileCtx.d.ts +1 -1
- package/lib/typescript/src/domain/groupChannel/component/GroupChannelHeader.d.ts +2 -1
- package/lib/typescript/src/domain/groupChannel/component/GroupChannelInput.d.ts +1 -1
- package/lib/typescript/src/domain/groupChannel/component/GroupChannelMessageList.d.ts +1 -1
- package/lib/typescript/src/domain/groupChannel/component/GroupChannelStatusEmpty.d.ts +2 -1
- package/lib/typescript/src/domain/groupChannel/component/GroupChannelStatusLoading.d.ts +2 -1
- package/lib/typescript/src/domain/groupChannel/component/GroupChannelSuggestedMentionList.d.ts +2 -1
- package/lib/typescript/src/domain/groupChannel/types.d.ts +45 -0
- package/lib/typescript/src/domain/groupChannelBannedUsers/component/GroupChannelBannedUsersHeader.d.ts +2 -1
- package/lib/typescript/src/domain/groupChannelBannedUsers/component/GroupChannelBannedUsersList.d.ts +2 -1
- package/lib/typescript/src/domain/groupChannelBannedUsers/component/GroupChannelBannedUsersStatusEmpty.d.ts +2 -1
- package/lib/typescript/src/domain/groupChannelBannedUsers/component/GroupChannelBannedUsersStatusLoading.d.ts +2 -1
- package/lib/typescript/src/domain/groupChannelList/component/GroupChannelListHeader.d.ts +2 -1
- package/lib/typescript/src/domain/groupChannelList/component/GroupChannelListList.d.ts +2 -1
- package/lib/typescript/src/domain/groupChannelList/component/GroupChannelListStatusEmpty.d.ts +2 -1
- package/lib/typescript/src/domain/groupChannelList/component/GroupChannelListStatusLoading.d.ts +2 -1
- package/lib/typescript/src/domain/groupChannelList/component/GroupChannelListTypeSelector.d.ts +2 -1
- package/lib/typescript/src/domain/groupChannelModeration/component/GroupChannelModerationHeader.d.ts +2 -1
- package/lib/typescript/src/domain/groupChannelModeration/component/GroupChannelModerationMenu.d.ts +2 -1
- package/lib/typescript/src/domain/groupChannelMutedMembers/component/GroupChannelMutedMembersHeader.d.ts +2 -1
- package/lib/typescript/src/domain/groupChannelMutedMembers/component/GroupChannelMutedMembersList.d.ts +2 -1
- package/lib/typescript/src/domain/groupChannelMutedMembers/component/GroupChannelMutedMembersStatusEmpty.d.ts +2 -1
- package/lib/typescript/src/domain/groupChannelMutedMembers/component/GroupChannelMutedMembersStatusLoading.d.ts +2 -1
- package/lib/typescript/src/domain/groupChannelNotifications/component/GroupChannelNotificationsHeader.d.ts +2 -1
- package/lib/typescript/src/domain/groupChannelNotifications/component/GroupChannelNotificationsView.d.ts +2 -1
- package/lib/typescript/src/domain/groupChannelOperators/component/GroupChannelOperatorsHeader.d.ts +2 -1
- package/lib/typescript/src/domain/groupChannelOperators/component/GroupChannelOperatorsList.d.ts +2 -1
- package/lib/typescript/src/domain/groupChannelOperators/component/GroupChannelOperatorsStatusEmpty.d.ts +2 -1
- package/lib/typescript/src/domain/groupChannelOperators/component/GroupChannelOperatorsStatusLoading.d.ts +2 -1
- package/lib/typescript/src/domain/groupChannelSettings/component/GroupChannelSettingsHeader.d.ts +2 -1
- package/lib/typescript/src/domain/groupChannelSettings/component/GroupChannelSettingsInfo.d.ts +2 -1
- package/lib/typescript/src/domain/groupChannelSettings/component/GroupChannelSettingsMenu.d.ts +2 -1
- package/lib/typescript/src/domain/messageSearch/component/MessageSearchHeader.d.ts +2 -1
- package/lib/typescript/src/domain/messageSearch/component/MessageSearchList.d.ts +2 -1
- package/lib/typescript/src/domain/messageSearch/component/MessageSearchStatusEmpty.d.ts +2 -1
- package/lib/typescript/src/domain/messageSearch/component/MessageSearchStatusLoading.d.ts +2 -1
- package/lib/typescript/src/domain/openChannel/component/OpenChannelHeader.d.ts +2 -2
- package/lib/typescript/src/domain/openChannel/component/OpenChannelInput.d.ts +1 -1
- package/lib/typescript/src/domain/openChannel/component/OpenChannelMessageList.d.ts +1 -1
- package/lib/typescript/src/domain/openChannel/component/OpenChannelStatusEmpty.d.ts +2 -1
- package/lib/typescript/src/domain/openChannel/component/OpenChannelStatusLoading.d.ts +2 -1
- package/lib/typescript/src/domain/openChannelBannedUsers/component/OpenChannelBannedUsersHeader.d.ts +2 -1
- package/lib/typescript/src/domain/openChannelBannedUsers/component/OpenChannelBannedUsersList.d.ts +2 -1
- package/lib/typescript/src/domain/openChannelBannedUsers/component/OpenChannelBannedUsersStatusEmpty.d.ts +2 -1
- package/lib/typescript/src/domain/openChannelBannedUsers/component/OpenChannelBannedUsersStatusLoading.d.ts +2 -1
- package/lib/typescript/src/domain/openChannelCreate/component/OpenChannelCreateHeader.d.ts +2 -1
- package/lib/typescript/src/domain/openChannelCreate/component/OpenChannelCreateProfileInput.d.ts +2 -1
- package/lib/typescript/src/domain/openChannelCreate/component/OpenChannelCreateStatusLoading.d.ts +2 -1
- package/lib/typescript/src/domain/openChannelList/component/OpenChannelListHeader.d.ts +2 -1
- package/lib/typescript/src/domain/openChannelList/component/OpenChannelListList.d.ts +2 -1
- package/lib/typescript/src/domain/openChannelList/component/OpenChannelListStatusEmpty.d.ts +2 -1
- package/lib/typescript/src/domain/openChannelList/component/OpenChannelListStatusLoading.d.ts +2 -1
- package/lib/typescript/src/domain/openChannelModeration/component/OpenChannelModerationHeader.d.ts +2 -1
- package/lib/typescript/src/domain/openChannelModeration/component/OpenChannelModerationMenu.d.ts +2 -1
- package/lib/typescript/src/domain/openChannelMutedParticipants/component/OpenChannelMutedParticipantsHeader.d.ts +2 -1
- package/lib/typescript/src/domain/openChannelMutedParticipants/component/OpenChannelMutedParticipantsList.d.ts +2 -1
- package/lib/typescript/src/domain/openChannelMutedParticipants/component/OpenChannelMutedParticipantsStatusEmpty.d.ts +2 -1
- package/lib/typescript/src/domain/openChannelMutedParticipants/component/OpenChannelMutedParticipantsStatusLoading.d.ts +2 -1
- package/lib/typescript/src/domain/openChannelOperators/component/OpenChannelOperatorsHeader.d.ts +2 -1
- package/lib/typescript/src/domain/openChannelOperators/component/OpenChannelOperatorsList.d.ts +2 -1
- package/lib/typescript/src/domain/openChannelOperators/component/OpenChannelOperatorsStatusEmpty.d.ts +2 -1
- package/lib/typescript/src/domain/openChannelOperators/component/OpenChannelOperatorsStatusLoading.d.ts +2 -1
- package/lib/typescript/src/domain/openChannelSettings/component/OpenChannelSettingsHeader.d.ts +2 -1
- package/lib/typescript/src/domain/openChannelSettings/component/OpenChannelSettingsInfo.d.ts +2 -1
- package/lib/typescript/src/domain/openChannelSettings/component/OpenChannelSettingsMenu.d.ts +2 -1
- package/lib/typescript/src/domain/userList/component/UserListHeader.d.ts +3 -3
- package/lib/typescript/src/domain/userList/component/UserListList.d.ts +1 -1
- package/lib/typescript/src/domain/userList/component/UserListStatusEmpty.d.ts +2 -1
- package/lib/typescript/src/domain/userList/component/UserListStatusLoading.d.ts +2 -1
- package/lib/typescript/src/domain/userList/types.d.ts +2 -2
- package/lib/typescript/src/hooks/useChannelInputItems.d.ts +10 -0
- package/lib/typescript/src/hooks/useVoiceMessageInput.d.ts +53 -0
- package/lib/typescript/src/index.d.ts +4 -0
- package/lib/typescript/src/libs/MentionManager.d.ts +2 -1
- package/lib/typescript/src/libs/SBUUtils.d.ts +1 -0
- package/lib/typescript/src/libs/VoiceMessageConfig.d.ts +25 -0
- package/lib/typescript/src/localization/StringSet.type.d.ts +7 -0
- package/lib/typescript/src/platform/createPlayerService.expo.d.ts +7 -0
- package/lib/typescript/src/platform/createPlayerService.native.d.ts +9 -0
- package/lib/typescript/src/platform/createRecorderService.expo.d.ts +7 -0
- package/lib/typescript/src/platform/createRecorderService.native.d.ts +9 -0
- package/lib/typescript/src/platform/types.d.ts +100 -1
- package/lib/typescript/src/types.d.ts +1 -1
- package/lib/typescript/src/version.d.ts +1 -1
- package/package.json +9 -11
- package/src/components/ChannelInput/MessageToReplyPreview.tsx +133 -0
- package/src/components/ChannelInput/SendInput.tsx +129 -320
- package/src/components/ChannelInput/VoiceMessageInput.tsx +206 -0
- package/src/components/ChannelInput/index.tsx +12 -4
- package/src/components/ChannelMessageList/index.tsx +3 -1
- package/src/components/ChatFlatList/index.tsx +14 -3
- package/src/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.tsx +24 -11
- package/src/components/GroupChannelMessageRenderer/index.tsx +80 -3
- package/src/components/MessageSearchResultItem.tsx +2 -1
- package/src/components/OpenChannelMessageRenderer/index.tsx +1 -0
- package/src/components/ReactionBottomSheets/ReactionUserListBottomSheet.tsx +2 -2
- package/src/components/ReactionBottomSheets/index.tsx +3 -2
- package/src/components/StatusComposition.tsx +3 -3
- package/src/constants.ts +2 -0
- package/src/containers/GroupChannelPreviewContainer.tsx +2 -0
- package/src/containers/InternalErrorBoundaryContainer.tsx +1 -1
- package/src/containers/SendbirdUIKitContainer.tsx +105 -54
- package/src/contexts/PlatformServiceCtx.tsx +22 -20
- package/src/contexts/ReactionCtx.tsx +7 -5
- package/src/contexts/SendbirdChatCtx.tsx +10 -2
- package/src/domain/groupChannel/component/GroupChannelMessageList.tsx +29 -43
- package/src/domain/groupChannel/module/moduleContext.tsx +119 -7
- package/src/domain/groupChannel/types.ts +41 -0
- package/src/domain/userList/types.ts +2 -2
- package/src/fragments/createGroupChannelFragment.tsx +32 -5
- package/src/fragments/createMessageSearchFragment.tsx +1 -1
- package/src/hooks/useChannelInputItems.ts +215 -0
- package/src/hooks/useConnection.ts +1 -1
- package/src/hooks/useMentionSuggestion.ts +2 -1
- package/src/hooks/useVoiceMessageInput.ts +237 -0
- package/src/index.ts +4 -0
- package/src/libs/MentionManager.tsx +1 -1
- package/src/libs/SBUUtils.ts +5 -0
- package/src/libs/VoiceMessageConfig.ts +28 -0
- package/src/localization/StringSet.type.ts +8 -0
- package/src/localization/createBaseStringSet.ts +27 -11
- package/src/platform/createFileService.expo.ts +10 -0
- package/src/platform/createFileService.native.ts +19 -0
- package/src/platform/createPlayerService.expo.tsx +142 -0
- package/src/platform/createPlayerService.native.tsx +148 -0
- package/src/platform/createRecorderService.expo.tsx +160 -0
- package/src/platform/createRecorderService.native.tsx +170 -0
- package/src/platform/types.ts +114 -1
- package/src/types.ts +1 -1
- package/src/version.ts +1 -1
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { Platform } from 'react-native';
|
|
2
|
+
import type * as RNAudioRecorder from 'react-native-audio-recorder-player';
|
|
3
|
+
import * as Permissions from 'react-native-permissions';
|
|
4
|
+
|
|
5
|
+
import { matchesOneOf, sleep } from '@sendbird/uikit-utils';
|
|
6
|
+
|
|
7
|
+
import type { PlayerServiceInterface, Unsubscribe } from './types';
|
|
8
|
+
|
|
9
|
+
type Modules = {
|
|
10
|
+
audioRecorderModule: typeof RNAudioRecorder;
|
|
11
|
+
permissionModule: typeof Permissions;
|
|
12
|
+
};
|
|
13
|
+
type PlaybackListener = Parameters<PlayerServiceInterface['addPlaybackListener']>[number];
|
|
14
|
+
type StateListener = Parameters<PlayerServiceInterface['addStateListener']>[number];
|
|
15
|
+
const createNativePlayerService = ({ audioRecorderModule, permissionModule }: Modules): PlayerServiceInterface => {
|
|
16
|
+
const module = new audioRecorderModule.default();
|
|
17
|
+
|
|
18
|
+
class VoicePlayer implements PlayerServiceInterface {
|
|
19
|
+
uri?: string;
|
|
20
|
+
state: PlayerServiceInterface['state'] = 'idle';
|
|
21
|
+
|
|
22
|
+
private readonly playbackSubscribers = new Set<PlaybackListener>();
|
|
23
|
+
private readonly stateSubscribers = new Set<StateListener>();
|
|
24
|
+
|
|
25
|
+
constructor() {
|
|
26
|
+
module.setSubscriptionDuration(0.1);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
private setState = (state: PlayerServiceInterface['state']) => {
|
|
30
|
+
this.state = state;
|
|
31
|
+
this.stateSubscribers.forEach((callback) => {
|
|
32
|
+
callback(state);
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
private setListener = () => {
|
|
37
|
+
module.addPlayBackListener((data) => {
|
|
38
|
+
const stopped = data.currentPosition >= data.duration;
|
|
39
|
+
|
|
40
|
+
if (stopped) this.stop();
|
|
41
|
+
if (this.state === 'playing') {
|
|
42
|
+
this.playbackSubscribers.forEach((callback) => {
|
|
43
|
+
callback({ currentTime: data.currentPosition, duration: data.duration, stopped });
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
private removeListener = () => {
|
|
50
|
+
module.removePlayBackListener();
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
public requestPermission = async (): Promise<boolean> => {
|
|
54
|
+
if (Platform.OS === 'android') {
|
|
55
|
+
const { READ_MEDIA_AUDIO, READ_EXTERNAL_STORAGE } = permissionModule.PERMISSIONS.ANDROID;
|
|
56
|
+
const permission = Platform.Version > 32 ? READ_MEDIA_AUDIO : READ_EXTERNAL_STORAGE;
|
|
57
|
+
|
|
58
|
+
const status = await permissionModule.check(permission);
|
|
59
|
+
if (status === 'granted') {
|
|
60
|
+
return true;
|
|
61
|
+
} else {
|
|
62
|
+
const status = await permissionModule.request(permission);
|
|
63
|
+
return status === 'granted';
|
|
64
|
+
}
|
|
65
|
+
} else {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
public addPlaybackListener = (callback: PlaybackListener): Unsubscribe => {
|
|
71
|
+
this.playbackSubscribers.add(callback);
|
|
72
|
+
return () => {
|
|
73
|
+
this.playbackSubscribers.delete(callback);
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
public addStateListener = (callback: (state: PlayerServiceInterface['state']) => void): Unsubscribe => {
|
|
78
|
+
this.stateSubscribers.add(callback);
|
|
79
|
+
return () => {
|
|
80
|
+
this.stateSubscribers.delete(callback);
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
public play = async (uri: string): Promise<void> => {
|
|
85
|
+
if (matchesOneOf(this.state, ['idle', 'stopped'])) {
|
|
86
|
+
try {
|
|
87
|
+
this.setState('preparing');
|
|
88
|
+
this.uri = uri;
|
|
89
|
+
this.setListener();
|
|
90
|
+
|
|
91
|
+
// FIXME: Workaround, `module.startPlayer()` caused a significant frame-drop and prevented the 'preparing' UI transition.
|
|
92
|
+
await sleep(0);
|
|
93
|
+
await module.startPlayer(uri);
|
|
94
|
+
|
|
95
|
+
this.setState('playing');
|
|
96
|
+
} catch (e) {
|
|
97
|
+
this.setState('idle');
|
|
98
|
+
this.uri = undefined;
|
|
99
|
+
this.removeListener();
|
|
100
|
+
throw e;
|
|
101
|
+
}
|
|
102
|
+
} else if (matchesOneOf(this.state, ['paused']) && this.uri === uri) {
|
|
103
|
+
try {
|
|
104
|
+
this.setListener();
|
|
105
|
+
await module.resumePlayer();
|
|
106
|
+
this.setState('playing');
|
|
107
|
+
} catch (e) {
|
|
108
|
+
this.removeListener();
|
|
109
|
+
throw e;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
public pause = async (): Promise<void> => {
|
|
115
|
+
if (matchesOneOf(this.state, ['playing'])) {
|
|
116
|
+
await module.pausePlayer();
|
|
117
|
+
this.removeListener();
|
|
118
|
+
this.setState('paused');
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
public stop = async (): Promise<void> => {
|
|
123
|
+
if (matchesOneOf(this.state, ['preparing', 'playing', 'paused'])) {
|
|
124
|
+
await module.stopPlayer();
|
|
125
|
+
this.removeListener();
|
|
126
|
+
this.setState('stopped');
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
public reset = async (): Promise<void> => {
|
|
131
|
+
await this.stop();
|
|
132
|
+
this.setState('idle');
|
|
133
|
+
this.uri = undefined;
|
|
134
|
+
this.playbackSubscribers.clear();
|
|
135
|
+
this.stateSubscribers.clear();
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
public seek = async (time: number): Promise<void> => {
|
|
139
|
+
if (matchesOneOf(this.state, ['playing', 'paused'])) {
|
|
140
|
+
await module.seekToPlayer(time);
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return new VoicePlayer();
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
export default createNativePlayerService;
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import * as ExpoAV from 'expo-av';
|
|
2
|
+
import type { RecordingOptions } from 'expo-av/build/Audio/Recording.types';
|
|
3
|
+
import { Platform } from 'react-native';
|
|
4
|
+
|
|
5
|
+
import { matchesOneOf, sleep } from '@sendbird/uikit-utils';
|
|
6
|
+
|
|
7
|
+
import VoiceMessageConfig from '../libs/VoiceMessageConfig';
|
|
8
|
+
import expoPermissionGranted from '../utils/expoPermissionGranted';
|
|
9
|
+
import type { RecorderServiceInterface, Unsubscribe } from './types';
|
|
10
|
+
|
|
11
|
+
type RecordingListener = Parameters<RecorderServiceInterface['addRecordingListener']>[number];
|
|
12
|
+
type StateListener = Parameters<RecorderServiceInterface['addStateListener']>[number];
|
|
13
|
+
type Modules = {
|
|
14
|
+
avModule: typeof ExpoAV;
|
|
15
|
+
};
|
|
16
|
+
const createExpoRecorderService = ({ avModule }: Modules): RecorderServiceInterface => {
|
|
17
|
+
class VoiceRecorder implements RecorderServiceInterface {
|
|
18
|
+
public uri: RecorderServiceInterface['uri'] = undefined;
|
|
19
|
+
public state: RecorderServiceInterface['state'] = 'idle';
|
|
20
|
+
public options: RecorderServiceInterface['options'] = {
|
|
21
|
+
minDuration: VoiceMessageConfig.DEFAULT.RECORDER.MIN_DURATION,
|
|
22
|
+
maxDuration: VoiceMessageConfig.DEFAULT.RECORDER.MAX_DURATION,
|
|
23
|
+
extension: VoiceMessageConfig.DEFAULT.RECORDER.EXTENSION,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// NOTE: In Android, even when startRecorder() is awaited, if stop() is executed immediately afterward, an error occurs
|
|
27
|
+
private _recordStartedAt = 0;
|
|
28
|
+
private _getRecorderStopSafeBuffer = () => {
|
|
29
|
+
const minWaitingTime = 500;
|
|
30
|
+
const elapsedTime = Date.now() - this._recordStartedAt;
|
|
31
|
+
if (elapsedTime > minWaitingTime) return 0;
|
|
32
|
+
else return minWaitingTime - elapsedTime;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
private _recorder = new avModule.Audio.Recording();
|
|
36
|
+
private readonly _recordingSubscribers = new Set<RecordingListener>();
|
|
37
|
+
private readonly _stateSubscribers = new Set<StateListener>();
|
|
38
|
+
private readonly _audioSettings = {
|
|
39
|
+
sampleRate: VoiceMessageConfig.DEFAULT.RECORDER.SAMPLE_RATE,
|
|
40
|
+
bitRate: VoiceMessageConfig.DEFAULT.RECORDER.BIT_RATE,
|
|
41
|
+
numberOfChannels: VoiceMessageConfig.DEFAULT.RECORDER.CHANNELS,
|
|
42
|
+
// encoding: mpeg4_aac
|
|
43
|
+
};
|
|
44
|
+
private readonly _audioOptions: RecordingOptions = {
|
|
45
|
+
android: {
|
|
46
|
+
...this._audioSettings,
|
|
47
|
+
extension: `.${this.options.extension}`,
|
|
48
|
+
audioEncoder: avModule.Audio.AndroidAudioEncoder.AAC,
|
|
49
|
+
outputFormat: avModule.Audio.AndroidOutputFormat.MPEG_4,
|
|
50
|
+
},
|
|
51
|
+
ios: {
|
|
52
|
+
...this._audioSettings,
|
|
53
|
+
extension: `.${this.options.extension}`,
|
|
54
|
+
outputFormat: avModule.Audio.IOSOutputFormat.MPEG4AAC,
|
|
55
|
+
audioQuality: avModule.Audio.IOSAudioQuality.HIGH,
|
|
56
|
+
},
|
|
57
|
+
web: {},
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
private prepare = async () => {
|
|
61
|
+
this.setState('preparing');
|
|
62
|
+
if (Platform.OS === 'ios') {
|
|
63
|
+
await avModule.Audio.setAudioModeAsync({ allowsRecordingIOS: true, playsInSilentModeIOS: true });
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (this._recorder._isDoneRecording) {
|
|
67
|
+
this._recorder = new avModule.Audio.Recording();
|
|
68
|
+
}
|
|
69
|
+
this._recorder.setProgressUpdateInterval(100);
|
|
70
|
+
this._recorder.setOnRecordingStatusUpdate((status) => {
|
|
71
|
+
const completed = status.durationMillis >= this.options.maxDuration;
|
|
72
|
+
if (completed) this.stop();
|
|
73
|
+
if (status.isRecording) {
|
|
74
|
+
this._recordingSubscribers.forEach((callback) => {
|
|
75
|
+
callback({ currentTime: status.durationMillis, completed: completed });
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
await this._recorder.prepareToRecordAsync(this._audioOptions);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
private setState = (state: RecorderServiceInterface['state']) => {
|
|
83
|
+
this.state = state;
|
|
84
|
+
this._stateSubscribers.forEach((callback) => {
|
|
85
|
+
callback(state);
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
public requestPermission = async (): Promise<boolean> => {
|
|
90
|
+
const status = await avModule.Audio.getPermissionsAsync();
|
|
91
|
+
if (expoPermissionGranted([status])) {
|
|
92
|
+
return true;
|
|
93
|
+
} else {
|
|
94
|
+
const status = await avModule.Audio.requestPermissionsAsync();
|
|
95
|
+
return expoPermissionGranted([status]);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
public addRecordingListener = (callback: RecordingListener): Unsubscribe => {
|
|
100
|
+
this._recordingSubscribers.add(callback);
|
|
101
|
+
return () => {
|
|
102
|
+
this._recordingSubscribers.delete(callback);
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
public addStateListener = (callback: StateListener): Unsubscribe => {
|
|
107
|
+
this._stateSubscribers.add(callback);
|
|
108
|
+
return () => {
|
|
109
|
+
this._stateSubscribers.delete(callback);
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
public record = async (): Promise<void> => {
|
|
114
|
+
if (matchesOneOf(this.state, ['idle', 'completed'])) {
|
|
115
|
+
try {
|
|
116
|
+
await this.prepare();
|
|
117
|
+
await this._recorder.startAsync();
|
|
118
|
+
|
|
119
|
+
if (Platform.OS === 'android') {
|
|
120
|
+
this._recordStartedAt = Date.now();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const uri = this._recorder.getURI();
|
|
124
|
+
if (uri) this.uri = uri;
|
|
125
|
+
this.setState('recording');
|
|
126
|
+
} catch (e) {
|
|
127
|
+
this.setState('idle');
|
|
128
|
+
throw e;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
public stop = async (): Promise<void> => {
|
|
134
|
+
if (matchesOneOf(this.state, ['recording'])) {
|
|
135
|
+
if (Platform.OS === 'android') {
|
|
136
|
+
const buffer = this._getRecorderStopSafeBuffer();
|
|
137
|
+
if (buffer > 0) await sleep(buffer);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
await this._recorder.stopAndUnloadAsync();
|
|
141
|
+
if (Platform.OS === 'ios') {
|
|
142
|
+
await avModule.Audio.setAudioModeAsync({ allowsRecordingIOS: false, playsInSilentModeIOS: false });
|
|
143
|
+
}
|
|
144
|
+
this.setState('completed');
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
public reset = async (): Promise<void> => {
|
|
149
|
+
await this.stop();
|
|
150
|
+
this.uri = undefined;
|
|
151
|
+
this._recordingSubscribers.clear();
|
|
152
|
+
this._recorder = new avModule.Audio.Recording();
|
|
153
|
+
this.setState('idle');
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return new VoiceRecorder();
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export default createExpoRecorderService;
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { Platform } from 'react-native';
|
|
2
|
+
import * as RNAudioRecorder from 'react-native-audio-recorder-player';
|
|
3
|
+
import * as Permissions from 'react-native-permissions';
|
|
4
|
+
import { Permission } from 'react-native-permissions/src/types';
|
|
5
|
+
|
|
6
|
+
import { matchesOneOf, sleep } from '@sendbird/uikit-utils';
|
|
7
|
+
|
|
8
|
+
import VoiceMessageConfig from '../libs/VoiceMessageConfig';
|
|
9
|
+
import nativePermissionGranted from '../utils/nativePermissionGranted';
|
|
10
|
+
import type { RecorderServiceInterface, Unsubscribe } from './types';
|
|
11
|
+
|
|
12
|
+
type RecordingListener = Parameters<RecorderServiceInterface['addRecordingListener']>[number];
|
|
13
|
+
type StateListener = Parameters<RecorderServiceInterface['addStateListener']>[number];
|
|
14
|
+
type Modules = {
|
|
15
|
+
audioRecorderModule: typeof RNAudioRecorder;
|
|
16
|
+
permissionModule: typeof Permissions;
|
|
17
|
+
};
|
|
18
|
+
const createNativeRecorderService = ({ audioRecorderModule, permissionModule }: Modules): RecorderServiceInterface => {
|
|
19
|
+
const module = new audioRecorderModule.default();
|
|
20
|
+
|
|
21
|
+
class VoiceRecorder implements RecorderServiceInterface {
|
|
22
|
+
public uri: RecorderServiceInterface['uri'] = undefined;
|
|
23
|
+
public state: RecorderServiceInterface['state'] = 'idle';
|
|
24
|
+
public options: RecorderServiceInterface['options'] = {
|
|
25
|
+
minDuration: VoiceMessageConfig.DEFAULT.RECORDER.MIN_DURATION,
|
|
26
|
+
maxDuration: VoiceMessageConfig.DEFAULT.RECORDER.MAX_DURATION,
|
|
27
|
+
extension: VoiceMessageConfig.DEFAULT.RECORDER.EXTENSION,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// NOTE: In Android, even when startRecorder() is awaited, if stop() is executed immediately afterward, an error occurs
|
|
31
|
+
private _recordStartedAt = 0;
|
|
32
|
+
private _getRecorderStopSafeBuffer = () => {
|
|
33
|
+
const minWaitingTime = 500;
|
|
34
|
+
const elapsedTime = Date.now() - this._recordStartedAt;
|
|
35
|
+
if (elapsedTime > minWaitingTime) return 0;
|
|
36
|
+
else return minWaitingTime - elapsedTime;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
private readonly recordingSubscribers = new Set<RecordingListener>();
|
|
40
|
+
private readonly stateSubscribers = new Set<StateListener>();
|
|
41
|
+
private readonly audioSettings = {
|
|
42
|
+
sampleRate: VoiceMessageConfig.DEFAULT.RECORDER.SAMPLE_RATE,
|
|
43
|
+
bitRate: VoiceMessageConfig.DEFAULT.RECORDER.BIT_RATE,
|
|
44
|
+
audioChannels: VoiceMessageConfig.DEFAULT.RECORDER.CHANNELS,
|
|
45
|
+
// encoding: mpeg4_aac
|
|
46
|
+
};
|
|
47
|
+
private readonly audioOptions = Platform.select({
|
|
48
|
+
android: {
|
|
49
|
+
AudioEncodingBitRateAndroid: this.audioSettings.bitRate,
|
|
50
|
+
AudioChannelsAndroid: this.audioSettings.audioChannels,
|
|
51
|
+
AudioSamplingRateAndroid: this.audioSettings.sampleRate,
|
|
52
|
+
AudioEncoderAndroid: audioRecorderModule.AudioEncoderAndroidType.AAC,
|
|
53
|
+
OutputFormatAndroid: audioRecorderModule.OutputFormatAndroidType.MPEG_4,
|
|
54
|
+
AudioSourceAndroid: audioRecorderModule.AudioSourceAndroidType.VOICE_RECOGNITION,
|
|
55
|
+
},
|
|
56
|
+
ios: {
|
|
57
|
+
AVEncoderBitRateKeyIOS: this.audioSettings.bitRate,
|
|
58
|
+
AVNumberOfChannelsKeyIOS: this.audioSettings.audioChannels,
|
|
59
|
+
AVSampleRateKeyIOS: this.audioSettings.sampleRate,
|
|
60
|
+
AVFormatIDKeyIOS: audioRecorderModule.AVEncodingOption.mp4, // same with aac
|
|
61
|
+
AVEncoderAudioQualityKeyIOS: audioRecorderModule.AVEncoderAudioQualityIOSType.high,
|
|
62
|
+
},
|
|
63
|
+
default: {},
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
constructor() {
|
|
67
|
+
module.setSubscriptionDuration(0.1);
|
|
68
|
+
module.addRecordBackListener((data) => {
|
|
69
|
+
const completed = data.currentPosition >= this.options.maxDuration;
|
|
70
|
+
|
|
71
|
+
if (completed) this.stop();
|
|
72
|
+
if (this.state === 'recording') {
|
|
73
|
+
this.recordingSubscribers.forEach((callback) => {
|
|
74
|
+
callback({ currentTime: data.currentPosition, completed });
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private setState = (state: RecorderServiceInterface['state']) => {
|
|
81
|
+
this.state = state;
|
|
82
|
+
this.stateSubscribers.forEach((callback) => {
|
|
83
|
+
callback(state);
|
|
84
|
+
});
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
public requestPermission = async (): Promise<boolean> => {
|
|
88
|
+
const permission: Permission[] | undefined = Platform.select({
|
|
89
|
+
android: [permissionModule.PERMISSIONS.ANDROID.RECORD_AUDIO],
|
|
90
|
+
ios: [permissionModule.PERMISSIONS.IOS.MICROPHONE],
|
|
91
|
+
windows: [permissionModule.PERMISSIONS.WINDOWS.MICROPHONE],
|
|
92
|
+
default: undefined,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
if (Platform.OS === 'android' && Platform.Version <= 28) {
|
|
96
|
+
permission?.push(permissionModule.PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (permission) {
|
|
100
|
+
const status = await permissionModule.checkMultiple(permission);
|
|
101
|
+
if (nativePermissionGranted(status)) {
|
|
102
|
+
return true;
|
|
103
|
+
} else {
|
|
104
|
+
const status = await permissionModule.requestMultiple(permission);
|
|
105
|
+
return nativePermissionGranted(status);
|
|
106
|
+
}
|
|
107
|
+
} else {
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
public addRecordingListener = (callback: RecordingListener): Unsubscribe => {
|
|
113
|
+
this.recordingSubscribers.add(callback);
|
|
114
|
+
return () => {
|
|
115
|
+
this.recordingSubscribers.delete(callback);
|
|
116
|
+
};
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
public addStateListener = (callback: StateListener): Unsubscribe => {
|
|
120
|
+
this.stateSubscribers.add(callback);
|
|
121
|
+
return () => {
|
|
122
|
+
this.stateSubscribers.delete(callback);
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
public record = async (uri: string): Promise<void> => {
|
|
127
|
+
if (matchesOneOf(this.state, ['idle', 'completed'])) {
|
|
128
|
+
try {
|
|
129
|
+
this.setState('preparing');
|
|
130
|
+
await module.startRecorder(uri, {
|
|
131
|
+
...this.audioOptions,
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
if (Platform.OS === 'android') {
|
|
135
|
+
this._recordStartedAt = Date.now();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
this.uri = uri;
|
|
139
|
+
this.setState('recording');
|
|
140
|
+
} catch (e) {
|
|
141
|
+
this.setState('idle');
|
|
142
|
+
throw e;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
public stop = async (): Promise<void> => {
|
|
148
|
+
if (matchesOneOf(this.state, ['recording'])) {
|
|
149
|
+
if (Platform.OS === 'android') {
|
|
150
|
+
const buffer = this._getRecorderStopSafeBuffer();
|
|
151
|
+
if (buffer > 0) await sleep(buffer);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
await module.stopRecorder();
|
|
155
|
+
this.setState('completed');
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
public reset = async (): Promise<void> => {
|
|
160
|
+
await this.stop();
|
|
161
|
+
this.uri = undefined;
|
|
162
|
+
this.recordingSubscribers.clear();
|
|
163
|
+
this.setState('idle');
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return new VoiceRecorder();
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
export default createNativeRecorderService;
|
package/src/platform/types.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
|
|
1
3
|
import type SBUError from '../libs/SBUError';
|
|
2
4
|
|
|
3
5
|
export type Unsubscribe = () => void | undefined;
|
|
@@ -58,6 +60,7 @@ export interface FileSystemServiceInterface {
|
|
|
58
60
|
// - Supports opening documents in place
|
|
59
61
|
// - Application supports iTunes file sharing
|
|
60
62
|
save(options?: SaveOptions): Promise<DownloadedPath | null>;
|
|
63
|
+
createRecordFilePath(customExtension?: string): { recordFilePath: string; uri: string };
|
|
61
64
|
}
|
|
62
65
|
|
|
63
66
|
// ---------- MediaService ---------- //
|
|
@@ -99,7 +102,117 @@ export type CompressImageOptions = {
|
|
|
99
102
|
export type CompressImageResult = Promise<{ uri: string; size: number } | null>;
|
|
100
103
|
|
|
101
104
|
export interface MediaServiceInterface {
|
|
102
|
-
VideoComponent<Props = {}>(props: VideoProps & Props):
|
|
105
|
+
VideoComponent<Props = {}>(props: VideoProps & Props): ReactNode;
|
|
103
106
|
getVideoThumbnail(options: GetVideoThumbnailOptions): GetVideoThumbnailResult;
|
|
104
107
|
compressImage(options: CompressImageOptions): CompressImageResult;
|
|
105
108
|
}
|
|
109
|
+
|
|
110
|
+
// ---------- PlayerService ---------- //
|
|
111
|
+
export interface PlayerServiceInterface {
|
|
112
|
+
uri?: string;
|
|
113
|
+
state: 'idle' | 'preparing' | 'playing' | 'paused' | 'stopped';
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Check and request permission for the player.
|
|
117
|
+
* */
|
|
118
|
+
requestPermission(): Promise<boolean>;
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Add a playback listener.
|
|
122
|
+
* */
|
|
123
|
+
addPlaybackListener(
|
|
124
|
+
callback: (params: { currentTime: number; duration: number; stopped: boolean }) => void,
|
|
125
|
+
): Unsubscribe;
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Add a state listener.
|
|
129
|
+
* */
|
|
130
|
+
addStateListener(callback: (state: PlayerServiceInterface['state']) => void): Unsubscribe;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* State transition:
|
|
134
|
+
* [idle, stopped] to [playing] - start from the beginning
|
|
135
|
+
* [paused] to [playing] - resume
|
|
136
|
+
* */
|
|
137
|
+
play(uri: string): Promise<void>;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* State transition:
|
|
141
|
+
* [playing] to [paused]
|
|
142
|
+
* */
|
|
143
|
+
pause(): Promise<void>;
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* State transition:
|
|
147
|
+
* [preparing, playing, paused] to [stop]
|
|
148
|
+
* */
|
|
149
|
+
stop(): Promise<void>;
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* State transition:
|
|
153
|
+
* [*] to [idle]
|
|
154
|
+
* */
|
|
155
|
+
reset(): Promise<void>;
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Seek time, only available when the state is [playing, paused].
|
|
159
|
+
* */
|
|
160
|
+
seek(time: number): Promise<void>;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// ---------- RecorderService ---------- //
|
|
164
|
+
export interface RecorderOptions {
|
|
165
|
+
/**
|
|
166
|
+
* Minimum recording duration (milliseconds).
|
|
167
|
+
* */
|
|
168
|
+
minDuration: number;
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Maximum recording duration (milliseconds).
|
|
172
|
+
* */
|
|
173
|
+
maxDuration: number;
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* File extension for recorded audio file
|
|
177
|
+
* */
|
|
178
|
+
extension: string;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export interface RecorderServiceInterface {
|
|
182
|
+
uri?: string;
|
|
183
|
+
options: RecorderOptions;
|
|
184
|
+
state: 'idle' | 'preparing' | 'recording' | 'completed';
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Check and request permission for the recorder.
|
|
188
|
+
* */
|
|
189
|
+
requestPermission(): Promise<boolean>;
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Add recording listener.
|
|
193
|
+
* */
|
|
194
|
+
addRecordingListener(callback: (params: { currentTime: number; completed: boolean }) => void): Unsubscribe;
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Add state listener.
|
|
198
|
+
* */
|
|
199
|
+
addStateListener(callback: (state: RecorderServiceInterface['state']) => void): Unsubscribe;
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* State transition:
|
|
203
|
+
* [idle, completed] to [recording]
|
|
204
|
+
* */
|
|
205
|
+
record(uri?: string): Promise<void>;
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* State transition:
|
|
209
|
+
* [recording] to [completed]
|
|
210
|
+
* */
|
|
211
|
+
stop(): Promise<void>;
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* State transition:
|
|
215
|
+
* [*] to [idle]
|
|
216
|
+
* */
|
|
217
|
+
reset(): Promise<void>;
|
|
218
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -17,7 +17,7 @@ export interface LocalCacheStorage {
|
|
|
17
17
|
|
|
18
18
|
export type ErrorBoundaryProps = { error: Error; errorInfo: ErrorInfo; reset: () => void };
|
|
19
19
|
|
|
20
|
-
export type CommonComponent<P = {}> = (props: P & { children?: ReactNode }) => null |
|
|
20
|
+
export type CommonComponent<P = {}> = (props: P & { children?: ReactNode }) => null | ReactNode;
|
|
21
21
|
|
|
22
22
|
export type MentionedUser = {
|
|
23
23
|
range: Range;
|
package/src/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const VERSION = '3.
|
|
1
|
+
const VERSION = '3.2.0';
|
|
2
2
|
export default VERSION;
|