stream-chat-react-native-core 10.0.0-rc.2 → 10.0.0-rc.3
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/lib/commonjs/ai-components/README.md +50 -2
- package/lib/commonjs/ai-components/index.js +24 -0
- package/lib/commonjs/ai-components/index.js.map +1 -1
- package/lib/commonjs/ai-components/message-composer/ComposerView.js +4 -2
- package/lib/commonjs/ai-components/message-composer/ComposerView.js.map +1 -1
- package/lib/commonjs/ai-components/message-composer/SpeechToTextButton.js +4 -1
- package/lib/commonjs/ai-components/message-composer/SpeechToTextButton.js.map +1 -1
- package/lib/commonjs/ai-components/native/AIDictation.js +6 -0
- package/lib/commonjs/ai-components/native/AIDictation.js.map +1 -1
- package/lib/commonjs/ai-components/store/dictation/store.js +4 -2
- package/lib/commonjs/ai-components/store/dictation/store.js.map +1 -1
- package/lib/commonjs/ai-components/store/dictation/useDictationState.js +4 -2
- package/lib/commonjs/ai-components/store/dictation/useDictationState.js.map +1 -1
- package/lib/commonjs/ai-components/store/index.js +22 -0
- package/lib/commonjs/ai-components/store/index.js.map +1 -1
- package/lib/commonjs/ai-components/theme.js +3 -0
- package/lib/commonjs/ai-components/theme.js.map +1 -1
- package/lib/commonjs/ai-components/transcription/useDictation.js +7 -3
- package/lib/commonjs/ai-components/transcription/useDictation.js.map +1 -1
- package/lib/commonjs/ai-components/transcription/useDictationAudioLevel.js +32 -0
- package/lib/commonjs/ai-components/transcription/useDictationAudioLevel.js.map +1 -0
- package/lib/commonjs/ai-components/voice-visualization/VoiceGlow.js +79 -0
- package/lib/commonjs/ai-components/voice-visualization/VoiceGlow.js.map +1 -0
- package/lib/commonjs/ai-components/voice-visualization/VoiceVisualizationView.js +147 -0
- package/lib/commonjs/ai-components/voice-visualization/VoiceVisualizationView.js.map +1 -0
- package/lib/commonjs/ai-components/voice-visualization/VoiceWave.js +58 -0
- package/lib/commonjs/ai-components/voice-visualization/VoiceWave.js.map +1 -0
- package/lib/commonjs/ai-components/voice-visualization/bounce.js +60 -0
- package/lib/commonjs/ai-components/voice-visualization/bounce.js.map +1 -0
- package/lib/commonjs/ai-components/voice-visualization/driver.js +208 -0
- package/lib/commonjs/ai-components/voice-visualization/driver.js.map +1 -0
- package/lib/commonjs/ai-components/voice-visualization/glowShader.js +218 -0
- package/lib/commonjs/ai-components/voice-visualization/glowShader.js.map +1 -0
- package/lib/commonjs/ai-components/voice-visualization/index.js +18 -0
- package/lib/commonjs/ai-components/voice-visualization/index.js.map +1 -0
- package/lib/commonjs/ai-components/voice-visualization/math.js +70 -0
- package/lib/commonjs/ai-components/voice-visualization/math.js.map +1 -0
- package/lib/commonjs/ai-components/voice-visualization/palette.js +47 -0
- package/lib/commonjs/ai-components/voice-visualization/palette.js.map +1 -0
- package/lib/commonjs/ai-components/voice-visualization/simplex.js +77 -0
- package/lib/commonjs/ai-components/voice-visualization/simplex.js.map +1 -0
- package/lib/commonjs/ai-components/voice-visualization/styles.js +33 -0
- package/lib/commonjs/ai-components/voice-visualization/styles.js.map +1 -0
- package/lib/commonjs/ai-components/voice-visualization/types.js +4 -0
- package/lib/commonjs/ai-components/voice-visualization/types.js.map +1 -0
- package/lib/commonjs/ai-components/voice-visualization/useReduceMotion.js +28 -0
- package/lib/commonjs/ai-components/voice-visualization/useReduceMotion.js.map +1 -0
- package/lib/commonjs/ai-components/voice-visualization/useVoiceVisualization.js +129 -0
- package/lib/commonjs/ai-components/voice-visualization/useVoiceVisualization.js.map +1 -0
- package/lib/commonjs/ai-components/voice-visualization/waveGeometry.js +124 -0
- package/lib/commonjs/ai-components/voice-visualization/waveGeometry.js.map +1 -0
- package/lib/commonjs/components/Channel/hooks/useChannelLifecycle.js +2 -1
- package/lib/commonjs/components/Channel/hooks/useChannelLifecycle.js.map +1 -1
- package/lib/commonjs/components/ChannelDetails/components/members/ChannelMemberItem.js +1 -1
- package/lib/commonjs/components/ChannelDetails/components/members/ChannelMemberItem.js.map +1 -1
- package/lib/commonjs/components/ChannelDetails/hooks/useChannelDetailsMemberStatusText.js +1 -1
- package/lib/commonjs/components/ChannelDetails/hooks/useChannelDetailsMemberStatusText.js.map +1 -1
- package/lib/commonjs/components/ChannelList/ChannelListView.js +0 -2
- package/lib/commonjs/components/ChannelList/ChannelListView.js.map +1 -1
- package/lib/commonjs/components/ChannelList/hooks/usePaginatedChannels.js +1 -1
- package/lib/commonjs/components/ChannelList/hooks/usePaginatedChannels.js.map +1 -1
- package/lib/commonjs/components/ChannelPreview/ChannelDetailsBottomSheet.js +1 -1
- package/lib/commonjs/components/ChannelPreview/ChannelDetailsBottomSheet.js.map +1 -1
- package/lib/commonjs/components/ChannelPreview/ChannelLastMessagePreview.js +1 -0
- package/lib/commonjs/components/ChannelPreview/ChannelLastMessagePreview.js.map +1 -1
- package/lib/commonjs/components/ChannelPreview/ChannelMessagePreviewDeliveryStatus.js +2 -0
- package/lib/commonjs/components/ChannelPreview/ChannelMessagePreviewDeliveryStatus.js.map +1 -1
- package/lib/commonjs/components/ChannelPreview/ChannelPreviewTitle.js +1 -0
- package/lib/commonjs/components/ChannelPreview/ChannelPreviewTitle.js.map +1 -1
- package/lib/commonjs/components/ChannelPreview/ChannelPreviewView.js +1 -1
- package/lib/commonjs/components/ChannelPreview/ChannelPreviewView.js.map +1 -1
- package/lib/commonjs/components/ChannelPreview/hooks/useChannelPreviewData.js +5 -5
- package/lib/commonjs/components/ChannelPreview/hooks/useChannelPreviewData.js.map +1 -1
- package/lib/commonjs/components/ChannelPreview/hooks/useChannelPreviewDisplayName.js +1 -1
- package/lib/commonjs/components/ChannelPreview/hooks/useChannelPreviewDisplayName.js.map +1 -1
- package/lib/commonjs/components/ChannelPreview/hooks/useChannelPreviewDisplayPresence.js +1 -1
- package/lib/commonjs/components/ChannelPreview/hooks/useChannelPreviewDisplayPresence.js.map +1 -1
- package/lib/commonjs/components/ChannelPreview/hooks/useChannelPreviewPollLabel.js +4 -1
- package/lib/commonjs/components/ChannelPreview/hooks/useChannelPreviewPollLabel.js.map +1 -1
- package/lib/commonjs/components/Chat/hooks/useConnectionLifecycle.js +6 -2
- package/lib/commonjs/components/Chat/hooks/useConnectionLifecycle.js.map +1 -1
- package/lib/commonjs/components/Indicators/LoadingErrorIndicator.js +5 -0
- package/lib/commonjs/components/Indicators/LoadingErrorIndicator.js.map +1 -1
- package/lib/commonjs/components/Message/Message.js +1 -1
- package/lib/commonjs/components/Message/Message.js.map +1 -1
- package/lib/commonjs/components/Message/MessageItemView/MessageStatus.js +4 -0
- package/lib/commonjs/components/Message/MessageItemView/MessageStatus.js.map +1 -1
- package/lib/commonjs/components/Message/MessageItemView/MessageWrapper.js +7 -4
- package/lib/commonjs/components/Message/MessageItemView/MessageWrapper.js.map +1 -1
- package/lib/commonjs/components/Message/hooks/useCreateMessageActionHandlers.js +3 -3
- package/lib/commonjs/components/Message/hooks/useCreateMessageActionHandlers.js.map +1 -1
- package/lib/commonjs/components/Message/hooks/useProcessReactions.js +2 -2
- package/lib/commonjs/components/Message/hooks/useProcessReactions.js.map +1 -1
- package/lib/commonjs/components/Message/hooks/useUserMuteActive.js +1 -1
- package/lib/commonjs/components/Message/hooks/useUserMuteActive.js.map +1 -1
- package/lib/commonjs/components/MessageInput/MessageComposer.js +2 -1
- package/lib/commonjs/components/MessageInput/MessageComposer.js.map +1 -1
- package/lib/commonjs/components/MessageList/MessageFlashList.js +2 -2
- package/lib/commonjs/components/MessageList/MessageFlashList.js.map +1 -1
- package/lib/commonjs/components/MessageList/MessageList.js +2 -2
- package/lib/commonjs/components/MessageList/MessageList.js.map +1 -1
- package/lib/commonjs/components/MessageList/hooks/useOwnUnreadCount.js +1 -1
- package/lib/commonjs/components/MessageList/hooks/useOwnUnreadCount.js.map +1 -1
- package/lib/commonjs/components/MessageMenu/MessageUserReactionsItem.js +1 -1
- package/lib/commonjs/components/MessageMenu/MessageUserReactionsItem.js.map +1 -1
- package/lib/commonjs/components/MessageMenu/hooks/useMessageOwnReactions.js +2 -2
- package/lib/commonjs/components/MessageMenu/hooks/useMessageOwnReactions.js.map +1 -1
- package/lib/commonjs/components/Poll/components/PollAnswersList.js +1 -1
- package/lib/commonjs/components/Poll/components/PollAnswersList.js.map +1 -1
- package/lib/commonjs/components/Poll/components/PollButtons.js +1 -1
- package/lib/commonjs/components/Poll/components/PollButtons.js.map +1 -1
- package/lib/commonjs/components/Poll/hook/useIsPollCreatedByCurrentUser.js +1 -1
- package/lib/commonjs/components/Poll/hook/useIsPollCreatedByCurrentUser.js.map +1 -1
- package/lib/commonjs/components/Thread/Thread.js +1 -1
- package/lib/commonjs/components/Thread/Thread.js.map +1 -1
- package/lib/commonjs/components/ThreadList/ThreadListItem.js +1 -1
- package/lib/commonjs/components/ThreadList/ThreadListItem.js.map +1 -1
- package/lib/commonjs/components/ThreadList/ThreadListUnreadBanner.js +9 -2
- package/lib/commonjs/components/ThreadList/ThreadListUnreadBanner.js.map +1 -1
- package/lib/commonjs/components/index.js +24 -0
- package/lib/commonjs/components/index.js.map +1 -1
- package/lib/commonjs/contexts/componentsContext/defaultComponents.js +0 -2
- package/lib/commonjs/contexts/componentsContext/defaultComponents.js.map +1 -1
- package/lib/commonjs/contexts/liveLocationManagerContext/LiveLocationManagerContext.js +1 -1
- package/lib/commonjs/contexts/liveLocationManagerContext/LiveLocationManagerContext.js.map +1 -1
- package/lib/commonjs/hooks/actions/useChannelActionItems.js +1 -1
- package/lib/commonjs/hooks/actions/useChannelActionItems.js.map +1 -1
- package/lib/commonjs/hooks/actions/useChannelActions.js +2 -2
- package/lib/commonjs/hooks/actions/useChannelActions.js.map +1 -1
- package/lib/commonjs/hooks/actions/useChannelMemberActionItems.js +1 -1
- package/lib/commonjs/hooks/actions/useChannelMemberActionItems.js.map +1 -1
- package/lib/commonjs/hooks/index.js +11 -0
- package/lib/commonjs/hooks/index.js.map +1 -1
- package/lib/commonjs/hooks/messagePreview/useMessageDeliveryStatus.js +6 -6
- package/lib/commonjs/hooks/messagePreview/useMessageDeliveryStatus.js.map +1 -1
- package/lib/commonjs/hooks/useIsDirectChat.js +1 -1
- package/lib/commonjs/hooks/useIsDirectChat.js.map +1 -1
- package/lib/commonjs/i18n/runtimeDefaults.js +1 -0
- package/lib/commonjs/i18n/runtimeDefaults.js.map +1 -1
- package/lib/commonjs/store/apis/getChannelMessages.js +5 -3
- package/lib/commonjs/store/apis/getChannelMessages.js.map +1 -1
- package/lib/commonjs/store/apis/getChannels.js +6 -3
- package/lib/commonjs/store/apis/getChannels.js.map +1 -1
- package/lib/commonjs/store/apis/getChannelsForFilterSort.js +2 -1
- package/lib/commonjs/store/apis/getChannelsForFilterSort.js.map +1 -1
- package/lib/commonjs/store/apis/queries/selectMessagesForChannels.js +7 -5
- package/lib/commonjs/store/apis/queries/selectMessagesForChannels.js.map +1 -1
- package/lib/commonjs/utils/installNativeMultipartAdapter.js.map +1 -1
- package/lib/commonjs/version.json +1 -1
- package/lib/module/ai-components/README.md +50 -2
- package/lib/module/ai-components/index.js +24 -0
- package/lib/module/ai-components/index.js.map +1 -1
- package/lib/module/ai-components/message-composer/ComposerView.js +4 -2
- package/lib/module/ai-components/message-composer/ComposerView.js.map +1 -1
- package/lib/module/ai-components/message-composer/SpeechToTextButton.js +4 -1
- package/lib/module/ai-components/message-composer/SpeechToTextButton.js.map +1 -1
- package/lib/module/ai-components/native/AIDictation.js +6 -0
- package/lib/module/ai-components/native/AIDictation.js.map +1 -1
- package/lib/module/ai-components/store/dictation/store.js +4 -2
- package/lib/module/ai-components/store/dictation/store.js.map +1 -1
- package/lib/module/ai-components/store/dictation/useDictationState.js +4 -2
- package/lib/module/ai-components/store/dictation/useDictationState.js.map +1 -1
- package/lib/module/ai-components/store/index.js +22 -0
- package/lib/module/ai-components/store/index.js.map +1 -1
- package/lib/module/ai-components/theme.js +3 -0
- package/lib/module/ai-components/theme.js.map +1 -1
- package/lib/module/ai-components/transcription/useDictation.js +7 -3
- package/lib/module/ai-components/transcription/useDictation.js.map +1 -1
- package/lib/module/ai-components/transcription/useDictationAudioLevel.js +32 -0
- package/lib/module/ai-components/transcription/useDictationAudioLevel.js.map +1 -0
- package/lib/module/ai-components/voice-visualization/VoiceGlow.js +79 -0
- package/lib/module/ai-components/voice-visualization/VoiceGlow.js.map +1 -0
- package/lib/module/ai-components/voice-visualization/VoiceVisualizationView.js +147 -0
- package/lib/module/ai-components/voice-visualization/VoiceVisualizationView.js.map +1 -0
- package/lib/module/ai-components/voice-visualization/VoiceWave.js +58 -0
- package/lib/module/ai-components/voice-visualization/VoiceWave.js.map +1 -0
- package/lib/module/ai-components/voice-visualization/bounce.js +60 -0
- package/lib/module/ai-components/voice-visualization/bounce.js.map +1 -0
- package/lib/module/ai-components/voice-visualization/driver.js +208 -0
- package/lib/module/ai-components/voice-visualization/driver.js.map +1 -0
- package/lib/module/ai-components/voice-visualization/glowShader.js +218 -0
- package/lib/module/ai-components/voice-visualization/glowShader.js.map +1 -0
- package/lib/module/ai-components/voice-visualization/index.js +18 -0
- package/lib/module/ai-components/voice-visualization/index.js.map +1 -0
- package/lib/module/ai-components/voice-visualization/math.js +70 -0
- package/lib/module/ai-components/voice-visualization/math.js.map +1 -0
- package/lib/module/ai-components/voice-visualization/palette.js +47 -0
- package/lib/module/ai-components/voice-visualization/palette.js.map +1 -0
- package/lib/module/ai-components/voice-visualization/simplex.js +77 -0
- package/lib/module/ai-components/voice-visualization/simplex.js.map +1 -0
- package/lib/module/ai-components/voice-visualization/styles.js +33 -0
- package/lib/module/ai-components/voice-visualization/styles.js.map +1 -0
- package/lib/module/ai-components/voice-visualization/types.js +4 -0
- package/lib/module/ai-components/voice-visualization/types.js.map +1 -0
- package/lib/module/ai-components/voice-visualization/useReduceMotion.js +28 -0
- package/lib/module/ai-components/voice-visualization/useReduceMotion.js.map +1 -0
- package/lib/module/ai-components/voice-visualization/useVoiceVisualization.js +129 -0
- package/lib/module/ai-components/voice-visualization/useVoiceVisualization.js.map +1 -0
- package/lib/module/ai-components/voice-visualization/waveGeometry.js +124 -0
- package/lib/module/ai-components/voice-visualization/waveGeometry.js.map +1 -0
- package/lib/module/components/Channel/hooks/useChannelLifecycle.js +2 -1
- package/lib/module/components/Channel/hooks/useChannelLifecycle.js.map +1 -1
- package/lib/module/components/ChannelDetails/components/members/ChannelMemberItem.js +1 -1
- package/lib/module/components/ChannelDetails/components/members/ChannelMemberItem.js.map +1 -1
- package/lib/module/components/ChannelDetails/hooks/useChannelDetailsMemberStatusText.js +1 -1
- package/lib/module/components/ChannelDetails/hooks/useChannelDetailsMemberStatusText.js.map +1 -1
- package/lib/module/components/ChannelList/ChannelListView.js +0 -2
- package/lib/module/components/ChannelList/ChannelListView.js.map +1 -1
- package/lib/module/components/ChannelList/hooks/usePaginatedChannels.js +1 -1
- package/lib/module/components/ChannelList/hooks/usePaginatedChannels.js.map +1 -1
- package/lib/module/components/ChannelPreview/ChannelDetailsBottomSheet.js +1 -1
- package/lib/module/components/ChannelPreview/ChannelDetailsBottomSheet.js.map +1 -1
- package/lib/module/components/ChannelPreview/ChannelLastMessagePreview.js +1 -0
- package/lib/module/components/ChannelPreview/ChannelLastMessagePreview.js.map +1 -1
- package/lib/module/components/ChannelPreview/ChannelMessagePreviewDeliveryStatus.js +2 -0
- package/lib/module/components/ChannelPreview/ChannelMessagePreviewDeliveryStatus.js.map +1 -1
- package/lib/module/components/ChannelPreview/ChannelPreviewTitle.js +1 -0
- package/lib/module/components/ChannelPreview/ChannelPreviewTitle.js.map +1 -1
- package/lib/module/components/ChannelPreview/ChannelPreviewView.js +1 -1
- package/lib/module/components/ChannelPreview/ChannelPreviewView.js.map +1 -1
- package/lib/module/components/ChannelPreview/hooks/useChannelPreviewData.js +5 -5
- package/lib/module/components/ChannelPreview/hooks/useChannelPreviewData.js.map +1 -1
- package/lib/module/components/ChannelPreview/hooks/useChannelPreviewDisplayName.js +1 -1
- package/lib/module/components/ChannelPreview/hooks/useChannelPreviewDisplayName.js.map +1 -1
- package/lib/module/components/ChannelPreview/hooks/useChannelPreviewDisplayPresence.js +1 -1
- package/lib/module/components/ChannelPreview/hooks/useChannelPreviewDisplayPresence.js.map +1 -1
- package/lib/module/components/ChannelPreview/hooks/useChannelPreviewPollLabel.js +4 -1
- package/lib/module/components/ChannelPreview/hooks/useChannelPreviewPollLabel.js.map +1 -1
- package/lib/module/components/Chat/hooks/useConnectionLifecycle.js +6 -2
- package/lib/module/components/Chat/hooks/useConnectionLifecycle.js.map +1 -1
- package/lib/module/components/Indicators/LoadingErrorIndicator.js +5 -0
- package/lib/module/components/Indicators/LoadingErrorIndicator.js.map +1 -1
- package/lib/module/components/Message/Message.js +1 -1
- package/lib/module/components/Message/Message.js.map +1 -1
- package/lib/module/components/Message/MessageItemView/MessageStatus.js +4 -0
- package/lib/module/components/Message/MessageItemView/MessageStatus.js.map +1 -1
- package/lib/module/components/Message/MessageItemView/MessageWrapper.js +7 -4
- package/lib/module/components/Message/MessageItemView/MessageWrapper.js.map +1 -1
- package/lib/module/components/Message/hooks/useCreateMessageActionHandlers.js +3 -3
- package/lib/module/components/Message/hooks/useCreateMessageActionHandlers.js.map +1 -1
- package/lib/module/components/Message/hooks/useProcessReactions.js +2 -2
- package/lib/module/components/Message/hooks/useProcessReactions.js.map +1 -1
- package/lib/module/components/Message/hooks/useUserMuteActive.js +1 -1
- package/lib/module/components/Message/hooks/useUserMuteActive.js.map +1 -1
- package/lib/module/components/MessageInput/MessageComposer.js +2 -1
- package/lib/module/components/MessageInput/MessageComposer.js.map +1 -1
- package/lib/module/components/MessageList/MessageFlashList.js +2 -2
- package/lib/module/components/MessageList/MessageFlashList.js.map +1 -1
- package/lib/module/components/MessageList/MessageList.js +2 -2
- package/lib/module/components/MessageList/MessageList.js.map +1 -1
- package/lib/module/components/MessageList/hooks/useOwnUnreadCount.js +1 -1
- package/lib/module/components/MessageList/hooks/useOwnUnreadCount.js.map +1 -1
- package/lib/module/components/MessageMenu/MessageUserReactionsItem.js +1 -1
- package/lib/module/components/MessageMenu/MessageUserReactionsItem.js.map +1 -1
- package/lib/module/components/MessageMenu/hooks/useMessageOwnReactions.js +2 -2
- package/lib/module/components/MessageMenu/hooks/useMessageOwnReactions.js.map +1 -1
- package/lib/module/components/Poll/components/PollAnswersList.js +1 -1
- package/lib/module/components/Poll/components/PollAnswersList.js.map +1 -1
- package/lib/module/components/Poll/components/PollButtons.js +1 -1
- package/lib/module/components/Poll/components/PollButtons.js.map +1 -1
- package/lib/module/components/Poll/hook/useIsPollCreatedByCurrentUser.js +1 -1
- package/lib/module/components/Poll/hook/useIsPollCreatedByCurrentUser.js.map +1 -1
- package/lib/module/components/Thread/Thread.js +1 -1
- package/lib/module/components/Thread/Thread.js.map +1 -1
- package/lib/module/components/ThreadList/ThreadListItem.js +1 -1
- package/lib/module/components/ThreadList/ThreadListItem.js.map +1 -1
- package/lib/module/components/ThreadList/ThreadListUnreadBanner.js +9 -2
- package/lib/module/components/ThreadList/ThreadListUnreadBanner.js.map +1 -1
- package/lib/module/components/index.js +24 -0
- package/lib/module/components/index.js.map +1 -1
- package/lib/module/contexts/componentsContext/defaultComponents.js +0 -2
- package/lib/module/contexts/componentsContext/defaultComponents.js.map +1 -1
- package/lib/module/contexts/liveLocationManagerContext/LiveLocationManagerContext.js +1 -1
- package/lib/module/contexts/liveLocationManagerContext/LiveLocationManagerContext.js.map +1 -1
- package/lib/module/hooks/actions/useChannelActionItems.js +1 -1
- package/lib/module/hooks/actions/useChannelActionItems.js.map +1 -1
- package/lib/module/hooks/actions/useChannelActions.js +2 -2
- package/lib/module/hooks/actions/useChannelActions.js.map +1 -1
- package/lib/module/hooks/actions/useChannelMemberActionItems.js +1 -1
- package/lib/module/hooks/actions/useChannelMemberActionItems.js.map +1 -1
- package/lib/module/hooks/index.js +11 -0
- package/lib/module/hooks/index.js.map +1 -1
- package/lib/module/hooks/messagePreview/useMessageDeliveryStatus.js +6 -6
- package/lib/module/hooks/messagePreview/useMessageDeliveryStatus.js.map +1 -1
- package/lib/module/hooks/useIsDirectChat.js +1 -1
- package/lib/module/hooks/useIsDirectChat.js.map +1 -1
- package/lib/module/i18n/runtimeDefaults.js +1 -0
- package/lib/module/i18n/runtimeDefaults.js.map +1 -1
- package/lib/module/store/apis/getChannelMessages.js +5 -3
- package/lib/module/store/apis/getChannelMessages.js.map +1 -1
- package/lib/module/store/apis/getChannels.js +6 -3
- package/lib/module/store/apis/getChannels.js.map +1 -1
- package/lib/module/store/apis/getChannelsForFilterSort.js +2 -1
- package/lib/module/store/apis/getChannelsForFilterSort.js.map +1 -1
- package/lib/module/store/apis/queries/selectMessagesForChannels.js +7 -5
- package/lib/module/store/apis/queries/selectMessagesForChannels.js.map +1 -1
- package/lib/module/utils/installNativeMultipartAdapter.js.map +1 -1
- package/lib/module/version.json +1 -1
- package/lib/typescript/ai-components/index.d.ts +3 -1
- package/lib/typescript/ai-components/index.d.ts.map +1 -1
- package/lib/typescript/ai-components/message-composer/ComposerView.d.ts.map +1 -1
- package/lib/typescript/ai-components/native/AIDictation.d.ts +6 -0
- package/lib/typescript/ai-components/native/AIDictation.d.ts.map +1 -1
- package/lib/typescript/ai-components/store/dictation/store.d.ts +7 -0
- package/lib/typescript/ai-components/store/dictation/store.d.ts.map +1 -1
- package/lib/typescript/ai-components/store/dictation/useDictationState.d.ts +1 -0
- package/lib/typescript/ai-components/store/dictation/useDictationState.d.ts.map +1 -1
- package/lib/typescript/ai-components/store/index.d.ts +2 -0
- package/lib/typescript/ai-components/store/index.d.ts.map +1 -1
- package/lib/typescript/ai-components/theme.d.ts +13 -0
- package/lib/typescript/ai-components/theme.d.ts.map +1 -1
- package/lib/typescript/ai-components/transcription/useDictation.d.ts +9 -1
- package/lib/typescript/ai-components/transcription/useDictation.d.ts.map +1 -1
- package/lib/typescript/ai-components/transcription/useDictationAudioLevel.d.ts +11 -0
- package/lib/typescript/ai-components/transcription/useDictationAudioLevel.d.ts.map +1 -0
- package/lib/typescript/ai-components/voice-visualization/VoiceGlow.d.ts +13 -0
- package/lib/typescript/ai-components/voice-visualization/VoiceGlow.d.ts.map +1 -0
- package/lib/typescript/ai-components/voice-visualization/VoiceVisualizationView.d.ts +26 -0
- package/lib/typescript/ai-components/voice-visualization/VoiceVisualizationView.d.ts.map +1 -0
- package/lib/typescript/ai-components/voice-visualization/VoiceWave.d.ts +13 -0
- package/lib/typescript/ai-components/voice-visualization/VoiceWave.d.ts.map +1 -0
- package/lib/typescript/ai-components/voice-visualization/bounce.d.ts +20 -0
- package/lib/typescript/ai-components/voice-visualization/bounce.d.ts.map +1 -0
- package/lib/typescript/ai-components/voice-visualization/driver.d.ts +96 -0
- package/lib/typescript/ai-components/voice-visualization/driver.d.ts.map +1 -0
- package/lib/typescript/ai-components/voice-visualization/glowShader.d.ts +7 -0
- package/lib/typescript/ai-components/voice-visualization/glowShader.d.ts.map +1 -0
- package/lib/typescript/ai-components/voice-visualization/index.d.ts +4 -0
- package/lib/typescript/ai-components/voice-visualization/index.d.ts.map +1 -0
- package/lib/typescript/ai-components/voice-visualization/math.d.ts +26 -0
- package/lib/typescript/ai-components/voice-visualization/math.d.ts.map +1 -0
- package/lib/typescript/ai-components/voice-visualization/palette.d.ts +18 -0
- package/lib/typescript/ai-components/voice-visualization/palette.d.ts.map +1 -0
- package/lib/typescript/ai-components/voice-visualization/simplex.d.ts +11 -0
- package/lib/typescript/ai-components/voice-visualization/simplex.d.ts.map +1 -0
- package/lib/typescript/ai-components/voice-visualization/styles.d.ts +24 -0
- package/lib/typescript/ai-components/voice-visualization/styles.d.ts.map +1 -0
- package/lib/typescript/ai-components/voice-visualization/types.d.ts +45 -0
- package/lib/typescript/ai-components/voice-visualization/types.d.ts.map +1 -0
- package/lib/typescript/ai-components/voice-visualization/useReduceMotion.d.ts +10 -0
- package/lib/typescript/ai-components/voice-visualization/useReduceMotion.d.ts.map +1 -0
- package/lib/typescript/ai-components/voice-visualization/useVoiceVisualization.d.ts +18 -0
- package/lib/typescript/ai-components/voice-visualization/useVoiceVisualization.d.ts.map +1 -0
- package/lib/typescript/ai-components/voice-visualization/waveGeometry.d.ts +25 -0
- package/lib/typescript/ai-components/voice-visualization/waveGeometry.d.ts.map +1 -0
- package/lib/typescript/components/Channel/hooks/useChannelLifecycle.d.ts.map +1 -1
- package/lib/typescript/components/ChannelList/ChannelListView.d.ts +1 -1
- package/lib/typescript/components/ChannelList/ChannelListView.d.ts.map +1 -1
- package/lib/typescript/components/ChannelPreview/ChannelMessagePreviewDeliveryStatus.d.ts.map +1 -1
- package/lib/typescript/components/ChannelPreview/hooks/useChannelPreviewData.d.ts.map +1 -1
- package/lib/typescript/components/Chat/hooks/useConnectionLifecycle.d.ts +5 -4
- package/lib/typescript/components/Chat/hooks/useConnectionLifecycle.d.ts.map +1 -1
- package/lib/typescript/components/Indicators/LoadingErrorIndicator.d.ts +1 -1
- package/lib/typescript/components/Indicators/LoadingErrorIndicator.d.ts.map +1 -1
- package/lib/typescript/components/Message/MessageItemView/MessageStatus.d.ts.map +1 -1
- package/lib/typescript/components/Message/MessageItemView/MessageWrapper.d.ts.map +1 -1
- package/lib/typescript/components/MessageInput/MessageComposer.d.ts.map +1 -1
- package/lib/typescript/components/ThreadList/ThreadListUnreadBanner.d.ts.map +1 -1
- package/lib/typescript/components/index.d.ts +2 -0
- package/lib/typescript/components/index.d.ts.map +1 -1
- package/lib/typescript/contexts/componentsContext/defaultComponents.d.ts +0 -1
- package/lib/typescript/contexts/componentsContext/defaultComponents.d.ts.map +1 -1
- package/lib/typescript/hooks/index.d.ts +1 -0
- package/lib/typescript/hooks/index.d.ts.map +1 -1
- package/lib/typescript/hooks/messagePreview/useMessageDeliveryStatus.d.ts +3 -0
- package/lib/typescript/hooks/messagePreview/useMessageDeliveryStatus.d.ts.map +1 -1
- package/lib/typescript/i18n/keys.d.ts +3 -1
- package/lib/typescript/i18n/keys.d.ts.map +1 -1
- package/lib/typescript/i18n/runtimeDefaults.d.ts +1 -0
- package/lib/typescript/i18n/runtimeDefaults.d.ts.map +1 -1
- package/lib/typescript/store/apis/getChannelMessages.d.ts +2 -1
- package/lib/typescript/store/apis/getChannelMessages.d.ts.map +1 -1
- package/lib/typescript/store/apis/getChannels.d.ts +3 -1
- package/lib/typescript/store/apis/getChannels.d.ts.map +1 -1
- package/lib/typescript/store/apis/getChannelsForFilterSort.d.ts.map +1 -1
- package/lib/typescript/store/apis/queries/selectMessagesForChannels.d.ts +3 -1
- package/lib/typescript/store/apis/queries/selectMessagesForChannels.d.ts.map +1 -1
- package/lib/typescript/utils/installNativeMultipartAdapter.d.ts +5 -3
- package/lib/typescript/utils/installNativeMultipartAdapter.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/__tests__/offline-support/offline-feature.tsx +7 -7
- package/src/__tests__/offline-support/optimistic-update.tsx +5 -5
- package/src/ai-components/README.md +50 -2
- package/src/ai-components/__tests__/VoiceVisualization.test.tsx +208 -0
- package/src/ai-components/__tests__/dictation.test.tsx +58 -1
- package/src/ai-components/__tests__/voiceDriver.test.ts +317 -0
- package/src/ai-components/__tests__/voicePalette.test.ts +124 -0
- package/src/ai-components/index.ts +3 -1
- package/src/ai-components/message-composer/ComposerView.tsx +6 -3
- package/src/ai-components/message-composer/SpeechToTextButton.tsx +5 -2
- package/src/ai-components/native/AIDictation.ts +11 -0
- package/src/ai-components/store/dictation/store.ts +9 -0
- package/src/ai-components/store/dictation/useDictationState.ts +2 -1
- package/src/ai-components/store/index.ts +2 -0
- package/src/ai-components/theme.ts +16 -0
- package/src/ai-components/transcription/useDictation.ts +16 -3
- package/src/ai-components/transcription/useDictationAudioLevel.ts +38 -0
- package/src/ai-components/voice-visualization/VoiceGlow.tsx +79 -0
- package/src/ai-components/voice-visualization/VoiceVisualizationView.tsx +179 -0
- package/src/ai-components/voice-visualization/VoiceWave.tsx +67 -0
- package/src/ai-components/voice-visualization/bounce.ts +61 -0
- package/src/ai-components/voice-visualization/driver.ts +240 -0
- package/src/ai-components/voice-visualization/glowShader.ts +227 -0
- package/src/ai-components/voice-visualization/index.ts +3 -0
- package/src/ai-components/voice-visualization/math.ts +73 -0
- package/src/ai-components/voice-visualization/palette.ts +59 -0
- package/src/ai-components/voice-visualization/simplex.ts +92 -0
- package/src/ai-components/voice-visualization/styles.ts +42 -0
- package/src/ai-components/voice-visualization/types.ts +44 -0
- package/src/ai-components/voice-visualization/useReduceMotion.ts +34 -0
- package/src/ai-components/voice-visualization/useVoiceVisualization.ts +153 -0
- package/src/ai-components/voice-visualization/waveGeometry.ts +137 -0
- package/src/components/Channel/__tests__/Channel.test.tsx +44 -5
- package/src/components/Channel/hooks/useChannelLifecycle.ts +4 -1
- package/src/components/ChannelDetails/__tests__/ChannelDetails.test.tsx +1 -1
- package/src/components/ChannelDetails/__tests__/ChannelDetailsActionsSection.test.tsx +1 -1
- package/src/components/ChannelDetails/__tests__/ChannelDetailsEditButton.test.tsx +1 -1
- package/src/components/ChannelDetails/__tests__/ChannelDetailsMemberSection.test.tsx +1 -1
- package/src/components/ChannelDetails/__tests__/ChannelDetailsNavHeader.test.tsx +1 -1
- package/src/components/ChannelDetails/__tests__/ChannelDetailsProfile.test.tsx +2 -2
- package/src/components/ChannelDetails/__tests__/ChannelEditDetailsForm.test.tsx +1 -1
- package/src/components/ChannelDetails/__tests__/ChannelEditDetailsFormContent.test.tsx +2 -2
- package/src/components/ChannelDetails/__tests__/ChannelEditName.test.tsx +1 -1
- package/src/components/ChannelDetails/__tests__/members/ChannelAddMembersForm.test.tsx +1 -1
- package/src/components/ChannelDetails/__tests__/members/ChannelMemberActionsSheet.test.tsx +2 -2
- package/src/components/ChannelDetails/__tests__/members/ChannelMemberItem.test.tsx +1 -1
- package/src/components/ChannelDetails/__tests__/useChannelDetailsMemberStatusText.test.tsx +1 -1
- package/src/components/ChannelDetails/components/members/ChannelMemberItem.tsx +1 -1
- package/src/components/ChannelDetails/hooks/useChannelDetailsMemberStatusText.ts +1 -1
- package/src/components/ChannelList/ChannelListView.tsx +1 -3
- package/src/components/ChannelList/__tests__/ChannelList.test.tsx +44 -0
- package/src/components/ChannelList/hooks/usePaginatedChannels.ts +1 -1
- package/src/components/ChannelPreview/ChannelDetailsBottomSheet.tsx +1 -1
- package/src/components/ChannelPreview/ChannelLastMessagePreview.tsx +1 -1
- package/src/components/ChannelPreview/ChannelMessagePreviewDeliveryStatus.tsx +8 -2
- package/src/components/ChannelPreview/ChannelPreviewTitle.tsx +1 -1
- package/src/components/ChannelPreview/ChannelPreviewView.tsx +1 -1
- package/src/components/ChannelPreview/__tests__/ChannelPreview.test.tsx +4 -4
- package/src/components/ChannelPreview/__tests__/ChannelPreviewView.test.tsx +40 -0
- package/src/components/ChannelPreview/hooks/__tests__/useChannelPreviewData.test.tsx +51 -0
- package/src/components/ChannelPreview/hooks/__tests__/useChannelPreviewDisplayName.test.tsx +1 -1
- package/src/components/ChannelPreview/hooks/__tests__/useChannelPreviewDisplayPresence.test.tsx +1 -1
- package/src/components/ChannelPreview/hooks/__tests__/useChannelPreviewPollLabel.test.tsx +87 -0
- package/src/components/ChannelPreview/hooks/useChannelPreviewData.ts +3 -4
- package/src/components/ChannelPreview/hooks/useChannelPreviewDisplayName.ts +1 -1
- package/src/components/ChannelPreview/hooks/useChannelPreviewDisplayPresence.ts +1 -1
- package/src/components/ChannelPreview/hooks/useChannelPreviewPollLabel.ts +1 -1
- package/src/components/Chat/__tests__/Chat.test.tsx +31 -1
- package/src/components/Chat/hooks/useConnectionLifecycle.ts +12 -6
- package/src/components/Indicators/LoadingErrorIndicator.tsx +8 -1
- package/src/components/Message/Message.tsx +1 -1
- package/src/components/Message/MessageItemView/MessageStatus.tsx +16 -2
- package/src/components/Message/MessageItemView/MessageWrapper.tsx +14 -4
- package/src/components/Message/MessageItemView/__tests__/MessageStatus.test.tsx +21 -0
- package/src/components/Message/hooks/__tests__/useCreateMessageActionHandlers.test.tsx +1 -1
- package/src/components/Message/hooks/__tests__/useUserMuteActive.test.tsx +1 -1
- package/src/components/Message/hooks/useCreateMessageActionHandlers.ts +3 -3
- package/src/components/Message/hooks/useProcessReactions.ts +2 -2
- package/src/components/Message/hooks/useUserMuteActive.ts +1 -1
- package/src/components/MessageInput/MessageComposer.tsx +4 -2
- package/src/components/MessageList/MessageFlashList.tsx +2 -2
- package/src/components/MessageList/MessageList.tsx +2 -2
- package/src/components/MessageList/__tests__/MessageList.test.tsx +26 -8
- package/src/components/MessageList/__tests__/ScrollToBottomButton.test.tsx +3 -3
- package/src/components/MessageList/hooks/useOwnUnreadCount.ts +1 -1
- package/src/components/MessageMenu/MessageUserReactionsItem.tsx +1 -1
- package/src/components/MessageMenu/hooks/useMessageOwnReactions.ts +2 -2
- package/src/components/Poll/components/PollAnswersList.tsx +1 -1
- package/src/components/Poll/components/PollButtons.tsx +1 -1
- package/src/components/Poll/hook/useIsPollCreatedByCurrentUser.ts +1 -1
- package/src/components/Thread/Thread.tsx +1 -1
- package/src/components/Thread/__tests__/Thread.test.tsx +4 -2
- package/src/components/ThreadList/ThreadListItem.tsx +1 -1
- package/src/components/ThreadList/ThreadListUnreadBanner.tsx +6 -2
- package/src/components/ThreadList/__tests__/ThreadList.test.tsx +21 -0
- package/src/components/index.ts +2 -0
- package/src/contexts/componentsContext/defaultComponents.ts +0 -2
- package/src/contexts/liveLocationManagerContext/LiveLocationManagerContext.tsx +1 -1
- package/src/hooks/__tests__/useChannelMuteActive.test.tsx +1 -1
- package/src/hooks/__tests__/useIsDirectChat.test.tsx +1 -1
- package/src/hooks/actions/__tests__/useChannelActionItems.test.tsx +1 -1
- package/src/hooks/actions/__tests__/useChannelActions.test.tsx +1 -1
- package/src/hooks/actions/__tests__/useChannelMemberActionItems.test.tsx +6 -6
- package/src/hooks/actions/useChannelActionItems.tsx +1 -1
- package/src/hooks/actions/useChannelActions.ts +2 -2
- package/src/hooks/actions/useChannelMemberActionItems.tsx +1 -1
- package/src/hooks/index.ts +1 -0
- package/src/hooks/messagePreview/__tests__/useMessageDeliveryStatus.test.tsx +57 -32
- package/src/hooks/messagePreview/useMessageDeliveryStatus.ts +13 -7
- package/src/hooks/useIsDirectChat.ts +1 -1
- package/src/i18n/__tests__/catalog.fixture.json +2 -0
- package/src/i18n/keys.ts +3 -0
- package/src/i18n/runtimeDefaults.ts +1 -0
- package/src/store/__tests__/selectMessagesForChannels.test.ts +34 -12
- package/src/store/apis/getChannelMessages.ts +4 -1
- package/src/store/apis/getChannels.ts +5 -1
- package/src/store/apis/getChannelsForFilterSort.ts +1 -0
- package/src/store/apis/queries/selectMessagesForChannels.ts +7 -2
- package/src/utils/installNativeMultipartAdapter.ts +5 -3
- package/src/version.json +1 -1
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
import { type SharedValue, useSharedValue } from 'react-native-reanimated';
|
|
4
|
+
|
|
5
|
+
import { AIDictation } from '../native/AIDictation';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The microphone's live level while dictation listens, from 0 to 1, for the `audioLevel` of
|
|
9
|
+
* `VoiceWave` and `VoiceGlow`. It is `null` while dictation is not listening, which lets a
|
|
10
|
+
* visualization animate speech on its own.
|
|
11
|
+
*
|
|
12
|
+
* The level is a shared value rather than state, so a level changing many times a second
|
|
13
|
+
* re-renders nothing: the visualizations read it once a frame on the UI thread.
|
|
14
|
+
*/
|
|
15
|
+
export const useDictationAudioLevel = (): SharedValue<number | null> => {
|
|
16
|
+
const level = useSharedValue<number | null>(null);
|
|
17
|
+
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
const unsubscribeLevel = AIDictation.addLevelListener((payload) => {
|
|
20
|
+
level.value = typeof payload?.level === 'number' ? payload.level : null;
|
|
21
|
+
});
|
|
22
|
+
const unsubscribeState = AIDictation.addStateListener(({ state }) => {
|
|
23
|
+
if (state !== 'listening' && state !== 'starting') level.value = null;
|
|
24
|
+
});
|
|
25
|
+
const unsubscribeError = AIDictation.addErrorListener(() => {
|
|
26
|
+
level.value = null;
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
return () => {
|
|
30
|
+
unsubscribeLevel();
|
|
31
|
+
unsubscribeState();
|
|
32
|
+
unsubscribeError();
|
|
33
|
+
level.value = null;
|
|
34
|
+
};
|
|
35
|
+
}, [level]);
|
|
36
|
+
|
|
37
|
+
return level;
|
|
38
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { useDerivedValue } from 'react-native-reanimated';
|
|
4
|
+
|
|
5
|
+
import { Canvas, Fill, Shader } from '@shopify/react-native-skia';
|
|
6
|
+
|
|
7
|
+
import { driverReact, driverScale } from './driver';
|
|
8
|
+
import { getGlowEffect } from './glowShader';
|
|
9
|
+
import { GLOW_STYLE } from './styles';
|
|
10
|
+
import type { VoiceVisualizationProps } from './types';
|
|
11
|
+
import type { VoiceVisualization } from './useVoiceVisualization';
|
|
12
|
+
import { type VoiceCanvasSize, VoiceVisualizationView } from './VoiceVisualizationView';
|
|
13
|
+
|
|
14
|
+
export type VoiceGlowProps = VoiceVisualizationProps;
|
|
15
|
+
|
|
16
|
+
const GlowCanvas = ({
|
|
17
|
+
size: { height, width },
|
|
18
|
+
visualization: { dark, driver },
|
|
19
|
+
}: {
|
|
20
|
+
size: VoiceCanvasSize;
|
|
21
|
+
visualization: VoiceVisualization;
|
|
22
|
+
}) => {
|
|
23
|
+
const effect = getGlowEffect();
|
|
24
|
+
const uniforms = useDerivedValue(() => {
|
|
25
|
+
const d = driver.value;
|
|
26
|
+
const color = (i: number) => [d.colors[i].hue, d.colors[i].saturation, d.colors[i].value, 0];
|
|
27
|
+
return {
|
|
28
|
+
bright: d.bright,
|
|
29
|
+
col0: color(0),
|
|
30
|
+
col1: color(1),
|
|
31
|
+
col2: color(2),
|
|
32
|
+
col3: color(3),
|
|
33
|
+
col4: color(4),
|
|
34
|
+
count: d.count,
|
|
35
|
+
dark: dark.value,
|
|
36
|
+
flow: d.flow,
|
|
37
|
+
flowSpin: d.flowSpin,
|
|
38
|
+
hover: [d.hoverX, d.hoverY],
|
|
39
|
+
hoverAmt: d.hoverAmount,
|
|
40
|
+
load: d.load,
|
|
41
|
+
mic: d.mic,
|
|
42
|
+
orbSpin: d.orbSpin,
|
|
43
|
+
react: driverReact(d),
|
|
44
|
+
resolution: [width, height],
|
|
45
|
+
sat: d.sat,
|
|
46
|
+
scale: driverScale(d),
|
|
47
|
+
tap: [d.tapX, d.tapY],
|
|
48
|
+
tapTime: d.tapAge,
|
|
49
|
+
time: d.time,
|
|
50
|
+
voice: d.voice,
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
if (!effect) return null;
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<Canvas style={{ height, width }}>
|
|
58
|
+
<Fill>
|
|
59
|
+
<Shader source={effect} uniforms={uniforms} />
|
|
60
|
+
</Fill>
|
|
61
|
+
</Canvas>
|
|
62
|
+
);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const renderGlow = (visualization: VoiceVisualization, size: VoiceCanvasSize) => (
|
|
66
|
+
<GlowCanvas size={size} visualization={visualization} />
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* A voice agent as a soft, airy globe: color masses orbit inside it and swell with speech, and the
|
|
71
|
+
* gaps between them let the background show through. Tapping the globe bounces it and ripples it
|
|
72
|
+
* from the touch, and so does a hovering mouse or pen.
|
|
73
|
+
*
|
|
74
|
+
* It has no size of its own and draws in the middle of the view it is given, about half as wide
|
|
75
|
+
* as its shorter side, so give it a square.
|
|
76
|
+
*/
|
|
77
|
+
export const VoiceGlow = (props: VoiceGlowProps) => (
|
|
78
|
+
<VoiceVisualizationView {...props} renderCanvas={renderGlow} visualStyle={GLOW_STYLE} />
|
|
79
|
+
);
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import React, { type ReactNode, useCallback, useMemo, useState } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
type GestureResponderEvent,
|
|
4
|
+
type LayoutChangeEvent,
|
|
5
|
+
PixelRatio,
|
|
6
|
+
type PointerEvent,
|
|
7
|
+
StyleSheet,
|
|
8
|
+
View,
|
|
9
|
+
} from 'react-native';
|
|
10
|
+
|
|
11
|
+
import Animated from 'react-native-reanimated';
|
|
12
|
+
|
|
13
|
+
import type { VoiceVisualizationStyle } from './styles';
|
|
14
|
+
import type { VoiceAgentState, VoiceVisualizationProps } from './types';
|
|
15
|
+
import { useVoiceVisualization, type VoiceVisualization } from './useVoiceVisualization';
|
|
16
|
+
|
|
17
|
+
/** What the renderer draws in: the canvas size, in its own units, and the screen's pixels per unit. */
|
|
18
|
+
export type VoiceCanvasSize = { height: number; pixelRatio: number; width: number };
|
|
19
|
+
|
|
20
|
+
type ViewProps = VoiceVisualizationProps & {
|
|
21
|
+
/** Draws the visualization into a canvas of the given size. */
|
|
22
|
+
renderCanvas: (visualization: VoiceVisualization, size: VoiceCanvasSize) => ReactNode;
|
|
23
|
+
visualStyle: VoiceVisualizationStyle;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const DEFAULT_STATE_LABELS: Record<VoiceAgentState, string> = {
|
|
27
|
+
connecting: 'Connecting',
|
|
28
|
+
idle: 'Ready',
|
|
29
|
+
listening: 'Listening',
|
|
30
|
+
speaking: 'Speaking',
|
|
31
|
+
thinking: 'Thinking',
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* What VoiceWave and VoiceGlow share: the motion, the canvas kept at the view's size and at most
|
|
36
|
+
* the style's density, reduced motion, taps and hover, and accessibility.
|
|
37
|
+
*
|
|
38
|
+
* It names itself "Voice agent" with its state as the value, as on iOS and Android. Touches are
|
|
39
|
+
* only watched, never claimed, so a press handler on the view or a parent still gets them, and
|
|
40
|
+
* only the shape takes them: around it they reach whatever is behind.
|
|
41
|
+
*/
|
|
42
|
+
export const VoiceVisualizationView = ({
|
|
43
|
+
accessibilityLabel = 'Voice agent',
|
|
44
|
+
accessibilityValue,
|
|
45
|
+
audioLevel,
|
|
46
|
+
colors,
|
|
47
|
+
expressivity,
|
|
48
|
+
onLayout,
|
|
49
|
+
pointerEvents = 'box-none',
|
|
50
|
+
renderCanvas,
|
|
51
|
+
state,
|
|
52
|
+
stateLabels,
|
|
53
|
+
style,
|
|
54
|
+
visualStyle,
|
|
55
|
+
...restProps
|
|
56
|
+
}: ViewProps) => {
|
|
57
|
+
const visualization = useVoiceVisualization(
|
|
58
|
+
{ audioLevel, colors, expressivity, state },
|
|
59
|
+
visualStyle,
|
|
60
|
+
);
|
|
61
|
+
const { hover, opacity, tap } = visualization;
|
|
62
|
+
const [layout, setLayout] = useState({ height: 0, width: 0 });
|
|
63
|
+
|
|
64
|
+
const handleLayout = useCallback(
|
|
65
|
+
(event: LayoutChangeEvent) => {
|
|
66
|
+
onLayout?.(event);
|
|
67
|
+
const { height, width } = event.nativeEvent.layout;
|
|
68
|
+
setLayout((current) =>
|
|
69
|
+
current.width === width && current.height === height ? current : { height, width },
|
|
70
|
+
);
|
|
71
|
+
},
|
|
72
|
+
[onLayout],
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
const side = Math.min(layout.width, layout.height);
|
|
76
|
+
const pixelRatio = PixelRatio.get();
|
|
77
|
+
// Drawn at no more than the style's density, then scaled up to the view: the glow's soft
|
|
78
|
+
// gradients look the same at 2x with fewer pixels to fill, while the wave's line needs 3x.
|
|
79
|
+
const density = Math.min(1, visualStyle.maxScale / pixelRatio);
|
|
80
|
+
const canvasSize = useMemo<VoiceCanvasSize>(
|
|
81
|
+
() => ({
|
|
82
|
+
height: layout.height * density,
|
|
83
|
+
pixelRatio: pixelRatio * density,
|
|
84
|
+
width: layout.width * density,
|
|
85
|
+
}),
|
|
86
|
+
[density, layout.height, layout.width, pixelRatio],
|
|
87
|
+
);
|
|
88
|
+
const hitWidth = visualStyle.hitArea.width * side;
|
|
89
|
+
const hitHeight = visualStyle.hitArea.height * side;
|
|
90
|
+
|
|
91
|
+
/** A touch on the hit area, centred on the view and normalized to its shorter side, y up. */
|
|
92
|
+
const toLocalPoint = useCallback(
|
|
93
|
+
(locationX: number, locationY: number) => ({
|
|
94
|
+
x: (locationX - hitWidth / 2) / (side || 1),
|
|
95
|
+
y: (hitHeight / 2 - locationY) / (side || 1),
|
|
96
|
+
}),
|
|
97
|
+
[hitHeight, hitWidth, side],
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
const handleTouchEnd = useCallback(
|
|
101
|
+
(event: GestureResponderEvent) => {
|
|
102
|
+
const { x, y } = toLocalPoint(event.nativeEvent.locationX, event.nativeEvent.locationY);
|
|
103
|
+
if (visualStyle.contains(x, y)) tap(x, y);
|
|
104
|
+
},
|
|
105
|
+
[tap, toLocalPoint, visualStyle],
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
const handlePointerMove = useCallback(
|
|
109
|
+
(event: PointerEvent) => {
|
|
110
|
+
// Only a hovering mouse or pen ripples it; a finger has no hover.
|
|
111
|
+
const { buttons, offsetX, offsetY, pointerType } = event.nativeEvent;
|
|
112
|
+
if (pointerType === 'touch') return;
|
|
113
|
+
const { x, y } = toLocalPoint(offsetX, offsetY);
|
|
114
|
+
const hovering = buttons === 0 && visualStyle.contains(x, y);
|
|
115
|
+
hover(hovering ? x : null, hovering ? y : null);
|
|
116
|
+
},
|
|
117
|
+
[hover, toLocalPoint, visualStyle],
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
const handlePointerLeave = useCallback(() => hover(null, null), [hover]);
|
|
121
|
+
|
|
122
|
+
return (
|
|
123
|
+
<View
|
|
124
|
+
accessibilityLabel={accessibilityLabel}
|
|
125
|
+
accessibilityRole='image'
|
|
126
|
+
accessibilityValue={
|
|
127
|
+
accessibilityValue ?? { text: stateLabels?.[state] ?? DEFAULT_STATE_LABELS[state] }
|
|
128
|
+
}
|
|
129
|
+
accessible
|
|
130
|
+
onLayout={handleLayout}
|
|
131
|
+
pointerEvents={pointerEvents}
|
|
132
|
+
style={style}
|
|
133
|
+
{...restProps}
|
|
134
|
+
>
|
|
135
|
+
{side > 0 ? (
|
|
136
|
+
<>
|
|
137
|
+
<Animated.View
|
|
138
|
+
pointerEvents='none'
|
|
139
|
+
style={[
|
|
140
|
+
styles.canvas,
|
|
141
|
+
{
|
|
142
|
+
height: canvasSize.height,
|
|
143
|
+
left: (layout.width - canvasSize.width) / 2,
|
|
144
|
+
opacity,
|
|
145
|
+
top: (layout.height - canvasSize.height) / 2,
|
|
146
|
+
transform: [{ scale: 1 / density }],
|
|
147
|
+
width: canvasSize.width,
|
|
148
|
+
},
|
|
149
|
+
]}
|
|
150
|
+
>
|
|
151
|
+
{renderCanvas(visualization, canvasSize)}
|
|
152
|
+
</Animated.View>
|
|
153
|
+
<View
|
|
154
|
+
// A transparent view with only handlers could be flattened away, leaving no target.
|
|
155
|
+
collapsable={false}
|
|
156
|
+
onPointerLeave={handlePointerLeave}
|
|
157
|
+
onPointerMove={handlePointerMove}
|
|
158
|
+
onTouchEnd={handleTouchEnd}
|
|
159
|
+
style={[
|
|
160
|
+
styles.hitArea,
|
|
161
|
+
{
|
|
162
|
+
height: hitHeight,
|
|
163
|
+
left: (layout.width - hitWidth) / 2,
|
|
164
|
+
top: (layout.height - hitHeight) / 2,
|
|
165
|
+
width: hitWidth,
|
|
166
|
+
},
|
|
167
|
+
]}
|
|
168
|
+
testID='voice-visualization-hit-area'
|
|
169
|
+
/>
|
|
170
|
+
</>
|
|
171
|
+
) : null}
|
|
172
|
+
</View>
|
|
173
|
+
);
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const styles = StyleSheet.create({
|
|
177
|
+
canvas: { position: 'absolute' },
|
|
178
|
+
hitArea: { position: 'absolute' },
|
|
179
|
+
});
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { useDerivedValue } from 'react-native-reanimated';
|
|
4
|
+
|
|
5
|
+
import { Canvas, LinearGradient, Path, vec } from '@shopify/react-native-skia';
|
|
6
|
+
|
|
7
|
+
import { WAVE_STYLE } from './styles';
|
|
8
|
+
import type { VoiceVisualizationProps } from './types';
|
|
9
|
+
import type { VoiceVisualization } from './useVoiceVisualization';
|
|
10
|
+
import { type VoiceCanvasSize, VoiceVisualizationView } from './VoiceVisualizationView';
|
|
11
|
+
import {
|
|
12
|
+
WAVE_END,
|
|
13
|
+
WAVE_POSITIONS,
|
|
14
|
+
WAVE_START,
|
|
15
|
+
waveColors,
|
|
16
|
+
wavePath,
|
|
17
|
+
waveStrokeWidth,
|
|
18
|
+
} from './waveGeometry';
|
|
19
|
+
|
|
20
|
+
export type VoiceWaveProps = VoiceVisualizationProps;
|
|
21
|
+
|
|
22
|
+
const WaveCanvas = ({
|
|
23
|
+
size: { height, pixelRatio, width },
|
|
24
|
+
visualization: { dark, driver },
|
|
25
|
+
}: {
|
|
26
|
+
size: VoiceCanvasSize;
|
|
27
|
+
visualization: VoiceVisualization;
|
|
28
|
+
}) => {
|
|
29
|
+
const path = useDerivedValue(() => wavePath(driver.value, width, height));
|
|
30
|
+
const colors = useDerivedValue(() => waveColors(driver.value, dark.value));
|
|
31
|
+
const m = Math.min(width, height);
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<Canvas style={{ height, width }}>
|
|
35
|
+
<Path
|
|
36
|
+
path={path}
|
|
37
|
+
strokeCap='round'
|
|
38
|
+
strokeJoin='round'
|
|
39
|
+
strokeWidth={waveStrokeWidth(width, height, pixelRatio)}
|
|
40
|
+
style='stroke'
|
|
41
|
+
>
|
|
42
|
+
<LinearGradient
|
|
43
|
+
colors={colors}
|
|
44
|
+
end={vec(width / 2 + WAVE_END * m, 0)}
|
|
45
|
+
positions={WAVE_POSITIONS}
|
|
46
|
+
start={vec(width / 2 + WAVE_START * m, 0)}
|
|
47
|
+
/>
|
|
48
|
+
</Path>
|
|
49
|
+
</Canvas>
|
|
50
|
+
);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const renderWave = (visualization: VoiceVisualization, size: VoiceCanvasSize) => (
|
|
54
|
+
<WaveCanvas size={size} visualization={visualization} />
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* A voice agent as a single string, flat at its ends, carrying a wave packet that erupts with
|
|
59
|
+
* speech while its colors flow along it. Tapping the string ripples it from the touch, and so does
|
|
60
|
+
* a hovering mouse or pen.
|
|
61
|
+
*
|
|
62
|
+
* It has no size of its own and draws in the middle of the view it is given, about 80% as wide as
|
|
63
|
+
* its shorter side, so give it a square or a wide box.
|
|
64
|
+
*/
|
|
65
|
+
export const VoiceWave = (props: VoiceWaveProps) => (
|
|
66
|
+
<VoiceVisualizationView {...props} renderCanvas={renderWave} visualStyle={WAVE_STYLE} />
|
|
67
|
+
);
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The bounce of a tap: a dip to 93% and an overshoot to 103% before settling, over 340 ms.
|
|
3
|
+
*
|
|
4
|
+
* These are authored keyframes rather than a spring: the ease-out curve times the whole run and
|
|
5
|
+
* the keyframes are linear between their stops.
|
|
6
|
+
*/
|
|
7
|
+
export const BOUNCE_DURATION = 0.34;
|
|
8
|
+
|
|
9
|
+
const OFFSETS = [0, 0.3, 0.62, 1];
|
|
10
|
+
const SCALES = [1, 0.93, 1.03, 1];
|
|
11
|
+
|
|
12
|
+
/** How long ago the last bounce started, in seconds; infinite before the first. */
|
|
13
|
+
export type BounceState = { age: number };
|
|
14
|
+
|
|
15
|
+
export const createBounce = (): BounceState => ({ age: Number.POSITIVE_INFINITY });
|
|
16
|
+
|
|
17
|
+
export const startBounce = (bounce: BounceState) => {
|
|
18
|
+
'worklet';
|
|
19
|
+
bounce.age = 0;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const advanceBounce = (bounce: BounceState, seconds: number) => {
|
|
23
|
+
'worklet';
|
|
24
|
+
bounce.age += seconds;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/** CSS `ease-out`, `cubic-bezier(0, 0, 0.58, 1)`. */
|
|
28
|
+
export const easeOut = (x: number) => {
|
|
29
|
+
'worklet';
|
|
30
|
+
const bx = 3 * 0.58;
|
|
31
|
+
const ax = 1 - bx;
|
|
32
|
+
const by = 3;
|
|
33
|
+
const ay = 1 - by;
|
|
34
|
+
let low = 0;
|
|
35
|
+
let high = 1;
|
|
36
|
+
for (let i = 0; i < 24; i++) {
|
|
37
|
+
const middle = (low + high) / 2;
|
|
38
|
+
if ((ax * middle + bx) * middle * middle < x) low = middle;
|
|
39
|
+
else high = middle;
|
|
40
|
+
}
|
|
41
|
+
const t = (low + high) / 2;
|
|
42
|
+
return (ay * t + by) * t * t;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/** The keyframed scale at `progress`, from 0 to 1. */
|
|
46
|
+
export const scaleAt = (progress: number) => {
|
|
47
|
+
'worklet';
|
|
48
|
+
for (let i = 1; i < OFFSETS.length; i++) {
|
|
49
|
+
if (progress <= OFFSETS[i]) {
|
|
50
|
+
const fraction = (progress - OFFSETS[i - 1]) / (OFFSETS[i] - OFFSETS[i - 1]);
|
|
51
|
+
return SCALES[i - 1] + (SCALES[i] - SCALES[i - 1]) * fraction;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return 1;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const bounceScale = (bounce: BounceState) => {
|
|
58
|
+
'worklet';
|
|
59
|
+
if (bounce.age >= BOUNCE_DURATION) return 1;
|
|
60
|
+
return scaleAt(easeOut(Math.max(bounce.age, 0) / BOUNCE_DURATION));
|
|
61
|
+
};
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { advanceBounce, type BounceState, bounceScale, createBounce, startBounce } from './bounce';
|
|
2
|
+
import { MAXIMUM_COLORS } from './palette';
|
|
3
|
+
import type { Hsv, VoiceAgentState } from './types';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The share of the way the live level moves each frame at 60 Hz, toward a louder or a quieter
|
|
7
|
+
* level.
|
|
8
|
+
*/
|
|
9
|
+
export type LevelResponse = { rise: number; fall: number };
|
|
10
|
+
|
|
11
|
+
export const LEVEL_RESPONSE = {
|
|
12
|
+
/** Follows the level closely, both ways. The glow's. */
|
|
13
|
+
steady: { fall: 0.35, rise: 0.35 },
|
|
14
|
+
/**
|
|
15
|
+
* Follows the level like a VU meter: about 0.1 s up to a louder reading, about 0.3 s down from
|
|
16
|
+
* it, so a meter's per-syllable jumps swell with the phrase instead. The wave's.
|
|
17
|
+
*/
|
|
18
|
+
smooth: { fall: 0.05, rise: 0.16 },
|
|
19
|
+
} satisfies Record<string, LevelResponse>;
|
|
20
|
+
|
|
21
|
+
export type VoiceDriverInput = {
|
|
22
|
+
state: VoiceAgentState;
|
|
23
|
+
/** One to five colors. */
|
|
24
|
+
colors: Hsv[];
|
|
25
|
+
/** From 0 to 2. */
|
|
26
|
+
expressivity: number;
|
|
27
|
+
/** From 0 to 1, or null when no live audio drives the motion. */
|
|
28
|
+
audioLevel: number | null;
|
|
29
|
+
reduceMotion: boolean;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The motion of a voice visualization: where it is in time, how it moves, and its colors. A plain
|
|
34
|
+
* object rather than a class, so it can live in a shared value and be advanced on the UI thread.
|
|
35
|
+
*/
|
|
36
|
+
export type VoiceDriverState = {
|
|
37
|
+
speed: number;
|
|
38
|
+
bright: number;
|
|
39
|
+
sat: number;
|
|
40
|
+
load: number;
|
|
41
|
+
flow: number;
|
|
42
|
+
baseReact: number;
|
|
43
|
+
expressivity: number;
|
|
44
|
+
time: number;
|
|
45
|
+
flowSpin: number;
|
|
46
|
+
orbSpin: number;
|
|
47
|
+
count: number;
|
|
48
|
+
tapX: number;
|
|
49
|
+
tapY: number;
|
|
50
|
+
tapAge: number;
|
|
51
|
+
hoverX: number;
|
|
52
|
+
hoverY: number;
|
|
53
|
+
hoverAmount: number;
|
|
54
|
+
isHovering: boolean;
|
|
55
|
+
mic: number;
|
|
56
|
+
voice: number;
|
|
57
|
+
/** The colors drawn, eased in place toward the input's color slots. */
|
|
58
|
+
colors: Hsv[];
|
|
59
|
+
bounce: BounceState;
|
|
60
|
+
levelResponse: LevelResponse;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* How a state moves. `load`, `flow` and `react` each select a motion pattern, one per state, so
|
|
65
|
+
* easing between states crossfades the patterns.
|
|
66
|
+
*/
|
|
67
|
+
type VoiceMotion = {
|
|
68
|
+
bright: number;
|
|
69
|
+
flow: number;
|
|
70
|
+
load: number;
|
|
71
|
+
react: number;
|
|
72
|
+
sat: number;
|
|
73
|
+
speed: number;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const MOTIONS: Record<VoiceAgentState, VoiceMotion> = {
|
|
77
|
+
connecting: { bright: 1, flow: 0, load: 1, react: 0, sat: 1, speed: 1 },
|
|
78
|
+
idle: { bright: 1, flow: 0, load: 0, react: 0.12, sat: 1, speed: 0.4 },
|
|
79
|
+
listening: { bright: 1, flow: 0, load: 0, react: 0.45, sat: 1, speed: 0.9 },
|
|
80
|
+
speaking: { bright: 1, flow: 0, load: 0, react: 1, sat: 1, speed: 1.25 },
|
|
81
|
+
thinking: { bright: 1, flow: 1, load: 0, react: 0, sat: 1, speed: 1.25 },
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const NO_TAP = 100;
|
|
85
|
+
const MAX_FRAME = 0.05;
|
|
86
|
+
/** How fast time runs under reduced motion. */
|
|
87
|
+
export const REDUCED = 0.07;
|
|
88
|
+
const DRIVERS = 0.08;
|
|
89
|
+
const GENTLE = 0.12;
|
|
90
|
+
const VOICE = 0.1;
|
|
91
|
+
|
|
92
|
+
/** Expressivity scales amplitude and speed, each with a floor so the motion breathes at 0. */
|
|
93
|
+
export const scales = (expressivity: number) => {
|
|
94
|
+
'worklet';
|
|
95
|
+
return { amplitude: 0.15 + 0.85 * expressivity, speed: 0.6 + 0.4 * expressivity };
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* The share of the way a value moves in `dt` seconds when it moves `perFrame` of the way each
|
|
100
|
+
* frame at 60 Hz.
|
|
101
|
+
*/
|
|
102
|
+
export const ease = (perFrame: number, dt: number) => {
|
|
103
|
+
'worklet';
|
|
104
|
+
return 1 - Math.pow(1 - perFrame, dt * 60);
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const rem = (x: number, m: number) => {
|
|
108
|
+
'worklet';
|
|
109
|
+
return ((x % m) + m) % m;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
/** Eases an HSV color in place, its hue taking the shorter way round the wheel. */
|
|
113
|
+
const easeHsv = (color: Hsv, target: Hsv, fraction: number) => {
|
|
114
|
+
'worklet';
|
|
115
|
+
const hueStep = (rem(target.hue - color.hue + 1.5, 1) - 0.5) * fraction;
|
|
116
|
+
color.hue = rem(color.hue + hueStep + 1, 1);
|
|
117
|
+
color.saturation += (target.saturation - color.saturation) * fraction;
|
|
118
|
+
color.value += (target.value - color.value) * fraction;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
/** The five color slots the renderers read; past the palette they repeat its first color. */
|
|
122
|
+
export const slots = (colors: Hsv[]): Hsv[] => {
|
|
123
|
+
'worklet';
|
|
124
|
+
const first = colors[0] ?? { hue: 0, saturation: 0, value: 0 };
|
|
125
|
+
const result: Hsv[] = [];
|
|
126
|
+
for (let i = 0; i < MAXIMUM_COLORS; i++) result.push(colors[i] ?? first);
|
|
127
|
+
return result;
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
/** A driver settled on `input`, so the first frame shows it rather than easing into it. */
|
|
131
|
+
export const createDriverState = (
|
|
132
|
+
input: VoiceDriverInput,
|
|
133
|
+
levelResponse: LevelResponse = LEVEL_RESPONSE.steady,
|
|
134
|
+
): VoiceDriverState => {
|
|
135
|
+
const m = MOTIONS[input.state];
|
|
136
|
+
const s = scales(input.expressivity);
|
|
137
|
+
return {
|
|
138
|
+
baseReact: m.react * s.amplitude,
|
|
139
|
+
bounce: createBounce(),
|
|
140
|
+
bright: m.bright,
|
|
141
|
+
// Copies, as they are eased in place and the palette belongs to the caller.
|
|
142
|
+
colors: slots(input.colors).map((color) => ({ ...color })),
|
|
143
|
+
count: input.colors.length,
|
|
144
|
+
expressivity: input.expressivity,
|
|
145
|
+
flow: m.flow * s.amplitude,
|
|
146
|
+
flowSpin: 0,
|
|
147
|
+
hoverAmount: 0,
|
|
148
|
+
hoverX: 0,
|
|
149
|
+
hoverY: 0,
|
|
150
|
+
isHovering: false,
|
|
151
|
+
levelResponse,
|
|
152
|
+
load: m.load * s.amplitude,
|
|
153
|
+
mic: 0,
|
|
154
|
+
orbSpin: 0,
|
|
155
|
+
sat: m.sat,
|
|
156
|
+
speed: m.speed * s.speed,
|
|
157
|
+
tapAge: NO_TAP,
|
|
158
|
+
tapX: 0,
|
|
159
|
+
tapY: 0,
|
|
160
|
+
time: 0,
|
|
161
|
+
voice: 0,
|
|
162
|
+
};
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
/** Live audio lifts the motion to its level, whatever the state. */
|
|
166
|
+
export const driverReact = (d: VoiceDriverState) => {
|
|
167
|
+
'worklet';
|
|
168
|
+
return d.baseReact + (Math.max(d.baseReact, d.mic) - d.baseReact) * d.voice;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
/** The scale of a tap's bounce. */
|
|
172
|
+
export const driverScale = (d: VoiceDriverState) => {
|
|
173
|
+
'worklet';
|
|
174
|
+
return bounceScale(d.bounce);
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
/** A tap at (x, y), centred and normalized to the shorter side with y up. */
|
|
178
|
+
export const tapDriver = (d: VoiceDriverState, input: VoiceDriverInput, x: number, y: number) => {
|
|
179
|
+
'worklet';
|
|
180
|
+
if (input.reduceMotion) return;
|
|
181
|
+
d.tapX = x;
|
|
182
|
+
d.tapY = y;
|
|
183
|
+
d.tapAge = 0;
|
|
184
|
+
startBounce(d.bounce);
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
/** Where a pointer hovers, or null once it has left. */
|
|
188
|
+
export const hoverDriver = (
|
|
189
|
+
d: VoiceDriverState,
|
|
190
|
+
input: VoiceDriverInput,
|
|
191
|
+
x: number | null,
|
|
192
|
+
y: number | null,
|
|
193
|
+
) => {
|
|
194
|
+
'worklet';
|
|
195
|
+
if (x === null || y === null || input.reduceMotion) {
|
|
196
|
+
d.isHovering = false;
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
d.hoverX = x;
|
|
200
|
+
d.hoverY = y;
|
|
201
|
+
d.isHovering = true;
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Advances the motion by `seconds`, easing each value toward the input's motion by a fixed share
|
|
206
|
+
* per frame at 60 Hz, converted to time, so it moves the same at any refresh rate.
|
|
207
|
+
*/
|
|
208
|
+
export const advanceDriver = (d: VoiceDriverState, input: VoiceDriverInput, seconds: number) => {
|
|
209
|
+
'worklet';
|
|
210
|
+
// Clamped so a frame after a stall cannot leap the motion.
|
|
211
|
+
const dt = Math.min(Math.max(seconds, 0), MAX_FRAME);
|
|
212
|
+
if (input.reduceMotion) d.isHovering = false;
|
|
213
|
+
const m = MOTIONS[input.state];
|
|
214
|
+
const s = scales(input.expressivity);
|
|
215
|
+
const drivers = ease(DRIVERS, dt);
|
|
216
|
+
d.speed += (m.speed * s.speed - d.speed) * drivers;
|
|
217
|
+
d.bright += (m.bright - d.bright) * drivers;
|
|
218
|
+
d.sat += (m.sat - d.sat) * drivers;
|
|
219
|
+
d.load += (m.load * s.amplitude - d.load) * drivers;
|
|
220
|
+
d.flow += (m.flow * s.amplitude - d.flow) * drivers;
|
|
221
|
+
d.baseReact += (m.react * s.amplitude - d.baseReact) * drivers;
|
|
222
|
+
d.expressivity += (input.expressivity - d.expressivity) * drivers;
|
|
223
|
+
// Integrated rather than computed as time times a weight, so a change of state eases the turns
|
|
224
|
+
// instead of jumping their angles.
|
|
225
|
+
const step = dt * (input.reduceMotion ? REDUCED : 1) * d.speed;
|
|
226
|
+
d.time += step;
|
|
227
|
+
d.flowSpin += step * d.flow;
|
|
228
|
+
d.orbSpin += step * (1 + 0.5 * d.flow + 0.1 * d.baseReact);
|
|
229
|
+
d.tapAge += dt;
|
|
230
|
+
advanceBounce(d.bounce, dt);
|
|
231
|
+
const gentle = ease(GENTLE, dt);
|
|
232
|
+
d.hoverAmount += ((d.isHovering ? 1 : 0) - d.hoverAmount) * gentle;
|
|
233
|
+
d.voice += ((input.audioLevel === null ? 0 : 1) - d.voice) * ease(VOICE, dt);
|
|
234
|
+
const level = input.audioLevel ?? 0;
|
|
235
|
+
const response = level > d.mic ? d.levelResponse.rise : d.levelResponse.fall;
|
|
236
|
+
d.mic += (level - d.mic) * ease(response, dt);
|
|
237
|
+
const targets = slots(input.colors);
|
|
238
|
+
for (let i = 0; i < d.colors.length; i++) easeHsv(d.colors[i], targets[i], gentle);
|
|
239
|
+
d.count += (input.colors.length - d.count) * gentle;
|
|
240
|
+
};
|