@multiplayer-app/session-recorder-react-native 1.0.1-beta.3 → 1.0.1-beta.4
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/LICENSE +1 -2
- package/README.md +216 -155
- package/SessionRecorderNative.podspec +9 -14
- package/android/build.gradle +21 -44
- package/android/gradle.properties +4 -4
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/com/multiplayer/sessionrecordernative/SessionRecorderNativeConfig.kt +52 -0
- package/android/src/main/java/com/multiplayer/sessionrecordernative/SessionRecorderNativeModule.kt +860 -0
- package/android/src/main/java/com/multiplayer/sessionrecordernative/SessionRecorderNativeModuleSpec.kt +51 -0
- package/android/src/main/java/com/multiplayer/sessionrecordernative/SessionRecorderNativePackage.kt +33 -0
- package/android/src/main/java/com/multiplayer/sessionrecordernative/model/TargetInfo.kt +9 -0
- package/android/src/main/java/com/multiplayer/sessionrecordernative/util/ViewUtils.kt +72 -0
- package/android/src/main/java/com/xxx/XxxModule.kt +23 -0
- package/ios/SessionRecorderNative.podspec +4 -2
- package/ios/SessionRecorderNative.swift +1 -1
- package/ios/SessionRecorderNativeSpec.swift +3 -3
- package/ios/Xxx.h +5 -0
- package/ios/Xxx.mm +21 -0
- package/lib/module/components/ScreenRecorderView/ScreenRecorderView.js +23 -0
- package/lib/module/components/ScreenRecorderView/ScreenRecorderView.js.map +1 -0
- package/lib/module/components/ScreenRecorderView/index.js +4 -0
- package/lib/module/components/ScreenRecorderView/index.js.map +1 -0
- package/lib/module/components/SessionRecorderWidget/ErrorBanner.js +64 -0
- package/lib/module/components/SessionRecorderWidget/ErrorBanner.js.map +1 -0
- package/lib/module/components/SessionRecorderWidget/FinalPopover.js +74 -0
- package/lib/module/components/SessionRecorderWidget/FinalPopover.js.map +1 -0
- package/lib/module/components/SessionRecorderWidget/FloatingButton.js +191 -0
- package/lib/module/components/SessionRecorderWidget/FloatingButton.js.map +1 -0
- package/lib/module/components/SessionRecorderWidget/InitialPopover.js +138 -0
- package/lib/module/components/SessionRecorderWidget/InitialPopover.js.map +1 -0
- package/lib/module/components/SessionRecorderWidget/ModalContainer.js +177 -0
- package/lib/module/components/SessionRecorderWidget/ModalContainer.js.map +1 -0
- package/lib/module/components/SessionRecorderWidget/ModalHeader.js +27 -0
- package/lib/module/components/SessionRecorderWidget/ModalHeader.js.map +1 -0
- package/lib/module/components/SessionRecorderWidget/SessionRecorderWidget.js +133 -0
- package/lib/module/components/SessionRecorderWidget/SessionRecorderWidget.js.map +1 -0
- package/lib/module/components/SessionRecorderWidget/icons.js +93 -0
- package/lib/module/components/SessionRecorderWidget/icons.js.map +1 -0
- package/lib/module/components/SessionRecorderWidget/index.js +5 -0
- package/lib/module/components/SessionRecorderWidget/index.js.map +1 -0
- package/lib/module/components/SessionRecorderWidget/styles.js +173 -0
- package/lib/module/components/SessionRecorderWidget/styles.js.map +1 -0
- package/lib/module/components/index.js +5 -0
- package/lib/module/components/index.js.map +1 -0
- package/lib/module/config/constants.js +42 -0
- package/lib/module/config/constants.js.map +1 -0
- package/lib/module/config/defaults.js +81 -0
- package/lib/module/config/defaults.js.map +1 -0
- package/lib/module/config/index.js +9 -0
- package/lib/module/config/index.js.map +1 -0
- package/lib/module/config/masking.js +35 -0
- package/lib/module/config/masking.js.map +1 -0
- package/lib/module/config/session-recorder.js +44 -0
- package/lib/module/config/session-recorder.js.map +1 -0
- package/lib/module/config/validators.js +28 -0
- package/lib/module/config/validators.js.map +1 -0
- package/lib/module/config/widget.js +35 -0
- package/lib/module/config/widget.js.map +1 -0
- package/lib/module/context/SessionRecorderContext.js +93 -0
- package/lib/module/context/SessionRecorderContext.js.map +1 -0
- package/lib/module/context/SessionRecorderStore.js +12 -0
- package/lib/module/context/SessionRecorderStore.js.map +1 -0
- package/lib/module/context/useSessionRecorderStore.js +20 -0
- package/lib/module/context/useSessionRecorderStore.js.map +1 -0
- package/lib/module/context/useStoreSelector.js +27 -0
- package/lib/module/context/useStoreSelector.js.map +1 -0
- package/lib/module/index.js +13 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/native/SessionRecorderNative.js +74 -0
- package/lib/module/native/SessionRecorderNative.js.map +1 -0
- package/lib/module/native/index.js +4 -0
- package/lib/module/native/index.js.map +1 -0
- package/lib/module/otel/helpers.js +218 -0
- package/lib/module/otel/helpers.js.map +1 -0
- package/lib/module/otel/index.js +95 -0
- package/lib/module/otel/index.js.map +1 -0
- package/lib/module/otel/instrumentations/index.js +102 -0
- package/lib/module/otel/instrumentations/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/patch/index.js +4 -0
- package/lib/module/patch/index.js.map +1 -0
- package/lib/module/patch/xhr.js +116 -0
- package/lib/module/patch/xhr.js.map +1 -0
- package/lib/module/recorder/eventExporter.js +130 -0
- package/lib/module/recorder/eventExporter.js.map +1 -0
- package/lib/module/recorder/gestureRecorder.js +641 -0
- package/lib/module/recorder/gestureRecorder.js.map +1 -0
- package/lib/module/recorder/index.js +168 -0
- package/lib/module/recorder/index.js.map +1 -0
- package/lib/module/recorder/navigationTracker.js +228 -0
- package/lib/module/recorder/navigationTracker.js.map +1 -0
- package/lib/module/recorder/screenRecorder.js +495 -0
- package/lib/module/recorder/screenRecorder.js.map +1 -0
- package/lib/module/services/api.service.js +149 -0
- package/lib/module/services/api.service.js.map +1 -0
- package/lib/module/services/network.service.js +178 -0
- package/lib/module/services/network.service.js.map +1 -0
- package/lib/module/services/screenMaskingService.js +107 -0
- package/lib/module/services/screenMaskingService.js.map +1 -0
- package/lib/module/services/storage.service.js +179 -0
- package/lib/module/services/storage.service.js.map +1 -0
- package/lib/module/session-recorder.js +541 -0
- package/lib/module/session-recorder.js.map +1 -0
- package/lib/module/types/configs.js +4 -0
- package/lib/module/types/configs.js.map +1 -0
- package/lib/module/types/expo-constants.d.js +2 -0
- package/lib/module/types/expo-constants.d.js.map +1 -0
- package/lib/module/types/index.js +11 -0
- package/lib/module/types/index.js.map +1 -0
- package/lib/module/types/session-recorder.js +68 -0
- package/lib/module/types/session-recorder.js.map +1 -0
- package/lib/module/types/session.js +9 -0
- package/lib/module/types/session.js.map +1 -0
- package/lib/module/utils/app-metadata.js +28 -0
- package/lib/module/utils/app-metadata.js.map +1 -0
- package/lib/module/utils/constants.optional.expo.js +6 -0
- package/lib/module/utils/constants.optional.expo.js.map +1 -0
- package/lib/module/utils/constants.optional.js +8 -0
- package/lib/module/utils/constants.optional.js.map +1 -0
- package/lib/module/utils/createStore.js +27 -0
- package/lib/module/utils/createStore.js.map +1 -0
- package/lib/module/utils/index.js +11 -0
- package/lib/module/utils/index.js.map +1 -0
- package/lib/module/utils/logger.js +193 -0
- package/lib/module/utils/logger.js.map +1 -0
- package/lib/module/utils/platform.js +340 -0
- package/lib/module/utils/platform.js.map +1 -0
- package/lib/module/utils/request-utils.js +58 -0
- package/lib/module/utils/request-utils.js.map +1 -0
- package/lib/module/utils/rrweb-events.js +276 -0
- package/lib/module/utils/rrweb-events.js.map +1 -0
- package/lib/module/utils/session.js +21 -0
- package/lib/module/utils/session.js.map +1 -0
- package/lib/module/utils/shallowEqual.js +17 -0
- package/lib/module/utils/shallowEqual.js.map +1 -0
- package/lib/module/utils/time.js +17 -0
- package/lib/module/utils/time.js.map +1 -0
- package/lib/module/utils/type-utils.js +69 -0
- package/lib/module/utils/type-utils.js.map +1 -0
- package/lib/module/version.js +4 -0
- package/lib/module/version.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/components/ScreenRecorderView/ScreenRecorderView.d.ts +6 -0
- package/lib/typescript/src/components/ScreenRecorderView/ScreenRecorderView.d.ts.map +1 -0
- package/lib/typescript/src/components/ScreenRecorderView/index.d.ts +2 -0
- package/lib/typescript/src/components/ScreenRecorderView/index.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/components/SessionRecorderWidget/ErrorBanner.d.ts +1 -0
- package/lib/typescript/src/components/SessionRecorderWidget/ErrorBanner.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/components/SessionRecorderWidget/FinalPopover.d.ts +2 -1
- package/lib/typescript/src/components/SessionRecorderWidget/FinalPopover.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/components/SessionRecorderWidget/FloatingButton.d.ts +1 -0
- package/lib/typescript/src/components/SessionRecorderWidget/FloatingButton.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/components/SessionRecorderWidget/InitialPopover.d.ts +2 -1
- package/lib/typescript/src/components/SessionRecorderWidget/InitialPopover.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/components/SessionRecorderWidget/ModalContainer.d.ts +1 -0
- package/lib/typescript/src/components/SessionRecorderWidget/ModalContainer.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/components/SessionRecorderWidget/ModalHeader.d.ts +1 -0
- package/lib/typescript/src/components/SessionRecorderWidget/ModalHeader.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/components/SessionRecorderWidget/SessionRecorderWidget.d.ts +1 -0
- package/lib/typescript/src/components/SessionRecorderWidget/SessionRecorderWidget.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/components/SessionRecorderWidget/icons.d.ts +1 -0
- package/lib/typescript/src/components/SessionRecorderWidget/icons.d.ts.map +1 -0
- package/lib/typescript/src/components/SessionRecorderWidget/index.d.ts +3 -0
- package/lib/typescript/src/components/SessionRecorderWidget/index.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/components/SessionRecorderWidget/styles.d.ts +4 -3
- package/lib/typescript/src/components/SessionRecorderWidget/styles.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/components/index.d.ts +1 -0
- package/lib/typescript/src/components/index.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/config/constants.d.ts +1 -0
- package/lib/typescript/src/config/constants.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/config/defaults.d.ts +2 -1
- package/lib/typescript/src/config/defaults.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/config/index.d.ts +1 -0
- package/lib/typescript/src/config/index.d.ts.map +1 -0
- package/lib/typescript/src/config/masking.d.ts +3 -0
- package/lib/typescript/src/config/masking.d.ts.map +1 -0
- package/lib/typescript/src/config/session-recorder.d.ts +3 -0
- package/lib/typescript/src/config/session-recorder.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/config/validators.d.ts +1 -0
- package/lib/typescript/src/config/validators.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/config/widget.d.ts +2 -1
- package/lib/typescript/src/config/widget.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/context/SessionRecorderContext.d.ts +3 -2
- package/lib/typescript/src/context/SessionRecorderContext.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/context/SessionRecorderStore.d.ts +2 -1
- package/lib/typescript/src/context/SessionRecorderStore.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/context/useSessionRecorderStore.d.ts +2 -1
- package/lib/typescript/src/context/useSessionRecorderStore.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/context/useStoreSelector.d.ts +2 -1
- package/lib/typescript/src/context/useStoreSelector.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/index.d.ts +1 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/native/SessionRecorderNative.d.ts +21 -3
- package/lib/typescript/src/native/SessionRecorderNative.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/native/index.d.ts +1 -0
- package/lib/typescript/src/native/index.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/otel/helpers.d.ts +3 -2
- package/lib/typescript/src/otel/helpers.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/otel/index.d.ts +2 -2
- package/lib/typescript/src/otel/index.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/otel/instrumentations/index.d.ts +2 -1
- package/lib/typescript/src/otel/instrumentations/index.d.ts.map +1 -0
- package/lib/typescript/src/patch/index.d.ts +2 -0
- package/lib/typescript/src/patch/index.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/patch/xhr.d.ts +1 -0
- package/lib/typescript/src/patch/xhr.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/recorder/eventExporter.d.ts +2 -1
- package/lib/typescript/src/recorder/eventExporter.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/recorder/gestureRecorder.d.ts +3 -2
- package/lib/typescript/src/recorder/gestureRecorder.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/recorder/index.d.ts +3 -2
- package/lib/typescript/src/recorder/index.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/recorder/navigationTracker.d.ts +2 -1
- package/lib/typescript/src/recorder/navigationTracker.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/recorder/screenRecorder.d.ts +4 -4
- package/lib/typescript/src/recorder/screenRecorder.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/services/api.service.d.ts +2 -1
- package/lib/typescript/src/services/api.service.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/services/network.service.d.ts +1 -0
- package/lib/typescript/src/services/network.service.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/services/screenMaskingService.d.ts +2 -1
- package/lib/typescript/src/services/screenMaskingService.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/services/storage.service.d.ts +2 -1
- package/lib/typescript/src/services/storage.service.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/session-recorder.d.ts +3 -2
- package/lib/typescript/src/session-recorder.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/types/configs.d.ts +3 -2
- package/lib/typescript/src/types/configs.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/types/index.d.ts +1 -0
- package/lib/typescript/src/types/index.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/types/session-recorder.d.ts +3 -2
- package/lib/typescript/src/types/session-recorder.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/types/session.d.ts +1 -0
- package/lib/typescript/src/types/session.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/utils/app-metadata.d.ts +1 -0
- package/lib/typescript/src/utils/app-metadata.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/utils/constants.optional.d.ts +1 -0
- package/lib/typescript/src/utils/constants.optional.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/utils/constants.optional.expo.d.ts +1 -0
- package/lib/typescript/src/utils/constants.optional.expo.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/utils/createStore.d.ts +1 -0
- package/lib/typescript/src/utils/createStore.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/utils/index.d.ts +1 -0
- package/lib/typescript/src/utils/index.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/utils/logger.d.ts +1 -0
- package/lib/typescript/src/utils/logger.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/utils/platform.d.ts +2 -1
- package/lib/typescript/src/utils/platform.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/utils/request-utils.d.ts +1 -0
- package/lib/typescript/src/utils/request-utils.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/utils/rrweb-events.d.ts +2 -1
- package/lib/typescript/src/utils/rrweb-events.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/utils/session.d.ts +1 -0
- package/lib/typescript/src/utils/session.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/utils/shallowEqual.d.ts +1 -0
- package/lib/typescript/src/utils/shallowEqual.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/utils/time.d.ts +1 -0
- package/lib/typescript/src/utils/time.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/utils/type-utils.d.ts +1 -0
- package/lib/typescript/src/utils/type-utils.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/version.d.ts +1 -0
- package/lib/typescript/src/version.d.ts.map +1 -0
- package/package.json +133 -44
- package/src/components/ScreenRecorderView/ScreenRecorderView.tsx +20 -0
- package/src/components/SessionRecorderWidget/ErrorBanner.tsx +58 -0
- package/src/components/SessionRecorderWidget/FinalPopover.tsx +96 -0
- package/src/components/SessionRecorderWidget/FloatingButton.tsx +176 -0
- package/src/components/SessionRecorderWidget/InitialPopover.tsx +167 -0
- package/src/components/SessionRecorderWidget/ModalContainer.tsx +189 -0
- package/src/components/SessionRecorderWidget/ModalHeader.tsx +24 -0
- package/src/components/SessionRecorderWidget/SessionRecorderWidget.tsx +136 -0
- package/src/components/SessionRecorderWidget/icons.tsx +52 -0
- package/{dist/components/SessionRecorderWidget/index.d.ts → src/components/SessionRecorderWidget/index.ts} +1 -0
- package/src/components/SessionRecorderWidget/styles.ts +169 -0
- package/src/components/index.ts +2 -0
- package/src/config/constants.ts +68 -0
- package/src/config/defaults.ts +101 -0
- package/src/config/index.ts +6 -0
- package/src/config/masking.ts +34 -0
- package/src/config/session-recorder.ts +59 -0
- package/src/config/validators.ts +31 -0
- package/src/config/widget.ts +38 -0
- package/src/context/SessionRecorderContext.tsx +138 -0
- package/src/context/SessionRecorderStore.ts +21 -0
- package/src/context/useSessionRecorderStore.ts +27 -0
- package/src/context/useStoreSelector.ts +34 -0
- package/src/index.ts +10 -0
- package/src/native/SessionRecorderNative.ts +164 -0
- package/src/native/index.ts +1 -0
- package/src/otel/helpers.ts +274 -0
- package/src/otel/index.ts +135 -0
- package/src/otel/instrumentations/index.ts +115 -0
- package/src/patch/index.ts +1 -0
- package/src/patch/xhr.ts +149 -0
- package/src/recorder/eventExporter.ts +155 -0
- package/src/recorder/gestureRecorder.ts +681 -0
- package/src/recorder/index.ts +190 -0
- package/src/recorder/navigationTracker.ts +245 -0
- package/src/recorder/screenRecorder.ts +549 -0
- package/src/services/api.service.ts +215 -0
- package/src/services/network.service.ts +182 -0
- package/src/services/screenMaskingService.ts +122 -0
- package/src/services/storage.service.ts +219 -0
- package/src/session-recorder.ts +591 -0
- package/src/types/configs.ts +96 -0
- package/src/types/expo-constants.d.ts +7 -0
- package/src/types/index.ts +29 -0
- package/src/types/session-recorder.ts +386 -0
- package/src/types/session.ts +65 -0
- package/src/utils/app-metadata.ts +31 -0
- package/src/utils/constants.optional.expo.ts +5 -0
- package/src/utils/constants.optional.ts +16 -0
- package/src/utils/createStore.ts +29 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/logger.ts +216 -0
- package/src/utils/platform.ts +370 -0
- package/src/utils/request-utils.ts +61 -0
- package/src/utils/rrweb-events.ts +316 -0
- package/src/utils/session.ts +19 -0
- package/src/utils/shallowEqual.ts +14 -0
- package/src/utils/time.ts +17 -0
- package/src/utils/type-utils.ts +75 -0
- package/src/version.ts +1 -0
- package/REACT_NATIVE_SETUP.md +0 -91
- package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/android/gradle/wrapper/gradle-wrapper.properties +0 -7
- package/android/gradlew +0 -249
- package/android/gradlew.bat +0 -92
- package/copy-react-native-dist.sh +0 -56
- package/dist/components/ScreenRecorderView/ScreenRecorderView.d.ts +0 -5
- package/dist/components/ScreenRecorderView/ScreenRecorderView.js +0 -1
- package/dist/components/ScreenRecorderView/ScreenRecorderView.js.map +0 -1
- package/dist/components/ScreenRecorderView/index.js +0 -1
- package/dist/components/ScreenRecorderView/index.js.map +0 -1
- package/dist/components/SessionRecorderWidget/ErrorBanner.js +0 -1
- package/dist/components/SessionRecorderWidget/ErrorBanner.js.map +0 -1
- package/dist/components/SessionRecorderWidget/FinalPopover.js +0 -1
- package/dist/components/SessionRecorderWidget/FinalPopover.js.map +0 -1
- package/dist/components/SessionRecorderWidget/FloatingButton.js +0 -1
- package/dist/components/SessionRecorderWidget/FloatingButton.js.map +0 -1
- package/dist/components/SessionRecorderWidget/InitialPopover.js +0 -1
- package/dist/components/SessionRecorderWidget/InitialPopover.js.map +0 -1
- package/dist/components/SessionRecorderWidget/ModalContainer.js +0 -1
- package/dist/components/SessionRecorderWidget/ModalContainer.js.map +0 -1
- package/dist/components/SessionRecorderWidget/ModalHeader.js +0 -1
- package/dist/components/SessionRecorderWidget/ModalHeader.js.map +0 -1
- package/dist/components/SessionRecorderWidget/SessionRecorderWidget.js +0 -1
- package/dist/components/SessionRecorderWidget/SessionRecorderWidget.js.map +0 -1
- package/dist/components/SessionRecorderWidget/icons.js +0 -1
- package/dist/components/SessionRecorderWidget/icons.js.map +0 -1
- package/dist/components/SessionRecorderWidget/index.js +0 -1
- package/dist/components/SessionRecorderWidget/index.js.map +0 -1
- package/dist/components/SessionRecorderWidget/styles.js +0 -1
- package/dist/components/SessionRecorderWidget/styles.js.map +0 -1
- package/dist/components/index.js +0 -1
- package/dist/components/index.js.map +0 -1
- package/dist/config/constants.js +0 -1
- package/dist/config/constants.js.map +0 -1
- package/dist/config/defaults.js +0 -1
- package/dist/config/defaults.js.map +0 -1
- package/dist/config/index.js +0 -1
- package/dist/config/index.js.map +0 -1
- package/dist/config/masking.d.ts +0 -2
- package/dist/config/masking.js +0 -1
- package/dist/config/masking.js.map +0 -1
- package/dist/config/session-recorder.d.ts +0 -2
- package/dist/config/session-recorder.js +0 -1
- package/dist/config/session-recorder.js.map +0 -1
- package/dist/config/validators.js +0 -1
- package/dist/config/validators.js.map +0 -1
- package/dist/config/widget.js +0 -1
- package/dist/config/widget.js.map +0 -1
- package/dist/context/SessionRecorderContext.js +0 -1
- package/dist/context/SessionRecorderContext.js.map +0 -1
- package/dist/context/SessionRecorderStore.js +0 -1
- package/dist/context/SessionRecorderStore.js.map +0 -1
- package/dist/context/useSessionRecorderStore.js +0 -1
- package/dist/context/useSessionRecorderStore.js.map +0 -1
- package/dist/context/useStoreSelector.js +0 -1
- package/dist/context/useStoreSelector.js.map +0 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +0 -1
- package/dist/native/GestureRecorderNative.d.ts +0 -57
- package/dist/native/GestureRecorderNative.js +0 -1
- package/dist/native/GestureRecorderNative.js.map +0 -1
- package/dist/native/GestureRecorderNativeTurboSpec.d.ts +0 -31
- package/dist/native/GestureRecorderNativeTurboSpec.js +0 -1
- package/dist/native/GestureRecorderNativeTurboSpec.js.map +0 -1
- package/dist/native/SessionRecorderNative.js +0 -1
- package/dist/native/SessionRecorderNative.js.map +0 -1
- package/dist/native/SessionRecorderNativeTurboSpec.d.ts +0 -17
- package/dist/native/SessionRecorderNativeTurboSpec.js +0 -1
- package/dist/native/SessionRecorderNativeTurboSpec.js.map +0 -1
- package/dist/native/index.js +0 -1
- package/dist/native/index.js.map +0 -1
- package/dist/otel/helpers.js +0 -1
- package/dist/otel/helpers.js.map +0 -1
- package/dist/otel/index.js +0 -1
- package/dist/otel/index.js.map +0 -1
- package/dist/otel/instrumentations/index.js +0 -1
- package/dist/otel/instrumentations/index.js.map +0 -1
- package/dist/patch/index.d.ts +0 -1
- package/dist/patch/index.js +0 -1
- package/dist/patch/index.js.map +0 -1
- package/dist/patch/xhr.js +0 -1
- package/dist/patch/xhr.js.map +0 -1
- package/dist/recorder/eventExporter.js +0 -1
- package/dist/recorder/eventExporter.js.map +0 -1
- package/dist/recorder/gestureRecorder.js +0 -1
- package/dist/recorder/gestureRecorder.js.map +0 -1
- package/dist/recorder/index.js +0 -1
- package/dist/recorder/index.js.map +0 -1
- package/dist/recorder/navigationTracker.js +0 -1
- package/dist/recorder/navigationTracker.js.map +0 -1
- package/dist/recorder/screenRecorder.js +0 -1
- package/dist/recorder/screenRecorder.js.map +0 -1
- package/dist/services/api.service.js +0 -1
- package/dist/services/api.service.js.map +0 -1
- package/dist/services/network.service.js +0 -1
- package/dist/services/network.service.js.map +0 -1
- package/dist/services/screenMaskingService.js +0 -1
- package/dist/services/screenMaskingService.js.map +0 -1
- package/dist/services/storage.service.js +0 -1
- package/dist/services/storage.service.js.map +0 -1
- package/dist/session-recorder.js +0 -1
- package/dist/session-recorder.js.map +0 -1
- package/dist/types/configs.js +0 -1
- package/dist/types/configs.js.map +0 -1
- package/dist/types/index.js +0 -1
- package/dist/types/index.js.map +0 -1
- package/dist/types/session-recorder.js +0 -1
- package/dist/types/session-recorder.js.map +0 -1
- package/dist/types/session.js +0 -1
- package/dist/types/session.js.map +0 -1
- package/dist/utils/app-metadata.js +0 -1
- package/dist/utils/app-metadata.js.map +0 -1
- package/dist/utils/constants.optional.expo.js +0 -1
- package/dist/utils/constants.optional.expo.js.map +0 -1
- package/dist/utils/constants.optional.js +0 -1
- package/dist/utils/constants.optional.js.map +0 -1
- package/dist/utils/createStore.js +0 -1
- package/dist/utils/createStore.js.map +0 -1
- package/dist/utils/index.js +0 -1
- package/dist/utils/index.js.map +0 -1
- package/dist/utils/logger.js +0 -1
- package/dist/utils/logger.js.map +0 -1
- package/dist/utils/platform.js +0 -1
- package/dist/utils/platform.js.map +0 -1
- package/dist/utils/request-utils.js +0 -1
- package/dist/utils/request-utils.js.map +0 -1
- package/dist/utils/rrweb-events.js +0 -1
- package/dist/utils/rrweb-events.js.map +0 -1
- package/dist/utils/session.js +0 -1
- package/dist/utils/session.js.map +0 -1
- package/dist/utils/shallowEqual.js +0 -1
- package/dist/utils/shallowEqual.js.map +0 -1
- package/dist/utils/time.js +0 -1
- package/dist/utils/time.js.map +0 -1
- package/dist/utils/type-utils.js +0 -1
- package/dist/utils/type-utils.js.map +0 -1
- package/dist/version.js +0 -1
- package/dist/version.js.map +0 -1
- package/docs/AUTO_METADATA_DETECTION.md +0 -108
- package/react-native.config.js +0 -13
- /package/{dist/components/ScreenRecorderView/index.d.ts → src/components/ScreenRecorderView/index.ts} +0 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import React, { useRef, useEffect, useMemo } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
StyleSheet,
|
|
4
|
+
Platform,
|
|
5
|
+
Animated,
|
|
6
|
+
PanResponder,
|
|
7
|
+
View,
|
|
8
|
+
Dimensions,
|
|
9
|
+
} from 'react-native';
|
|
10
|
+
import { SessionState } from '../../types';
|
|
11
|
+
import { StorageService } from '../../services/storage.service';
|
|
12
|
+
import { RecordIcon, CapturingIcon, PausedIcon } from './icons';
|
|
13
|
+
|
|
14
|
+
interface FloatingButtonProps {
|
|
15
|
+
sessionState: SessionState | null;
|
|
16
|
+
onPress: () => void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const buttonSize = 52;
|
|
20
|
+
const rightOffset = 20;
|
|
21
|
+
const topOffset = Platform.OS === 'ios' ? 60 : 40;
|
|
22
|
+
|
|
23
|
+
const FloatingButton: React.FC<FloatingButtonProps> = ({
|
|
24
|
+
sessionState,
|
|
25
|
+
onPress,
|
|
26
|
+
}) => {
|
|
27
|
+
const position = useRef(new Animated.ValueXY({ x: 0, y: 0 })).current;
|
|
28
|
+
const lastPosition = useRef({ top: topOffset, right: rightOffset });
|
|
29
|
+
const storageService = useRef(StorageService.getInstance()).current;
|
|
30
|
+
|
|
31
|
+
const screenBounds = useMemo(() => {
|
|
32
|
+
const { width, height } = Dimensions.get('window');
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
minTop: topOffset,
|
|
36
|
+
maxTop: height - buttonSize,
|
|
37
|
+
minRight: 0,
|
|
38
|
+
maxRight: width - buttonSize,
|
|
39
|
+
};
|
|
40
|
+
}, []);
|
|
41
|
+
|
|
42
|
+
// Load saved position on component mount
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
const savedPosition = storageService.getFloatingButtonPosition();
|
|
45
|
+
if (savedPosition) {
|
|
46
|
+
const { width } = Dimensions.get('window');
|
|
47
|
+
const top = savedPosition.y;
|
|
48
|
+
const right = width - savedPosition.x - buttonSize;
|
|
49
|
+
lastPosition.current = { top, right };
|
|
50
|
+
position.setValue({ x: right, y: top });
|
|
51
|
+
} else {
|
|
52
|
+
position.setValue({
|
|
53
|
+
x: lastPosition.current.right,
|
|
54
|
+
y: lastPosition.current.top,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}, []);
|
|
58
|
+
|
|
59
|
+
const panResponder = useRef(
|
|
60
|
+
PanResponder.create({
|
|
61
|
+
onStartShouldSetPanResponder: () => true,
|
|
62
|
+
onMoveShouldSetPanResponder: (_, gestureState) => {
|
|
63
|
+
const distance = Math.sqrt(
|
|
64
|
+
gestureState.dx * gestureState.dx + gestureState.dy * gestureState.dy
|
|
65
|
+
);
|
|
66
|
+
return distance > 5;
|
|
67
|
+
},
|
|
68
|
+
onPanResponderGrant: () => {
|
|
69
|
+
// Set the initial position for this gesture
|
|
70
|
+
position.setValue({
|
|
71
|
+
x: lastPosition.current.right,
|
|
72
|
+
y: lastPosition.current.top,
|
|
73
|
+
});
|
|
74
|
+
},
|
|
75
|
+
onPanResponderMove: (_, gestureState) => {
|
|
76
|
+
// Calculate new position based on gesture movement
|
|
77
|
+
const newTop = lastPosition.current.top + gestureState.dy;
|
|
78
|
+
const newRight = lastPosition.current.right - gestureState.dx;
|
|
79
|
+
|
|
80
|
+
// Update position during drag
|
|
81
|
+
position.setValue({ x: newRight, y: newTop });
|
|
82
|
+
},
|
|
83
|
+
onPanResponderRelease: (_, gestureState) => {
|
|
84
|
+
// Check if this was actually a drag (significant movement)
|
|
85
|
+
const distance = Math.sqrt(
|
|
86
|
+
gestureState.dx * gestureState.dx + gestureState.dy * gestureState.dy
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
// If it was a tap (no significant movement), trigger onPress
|
|
90
|
+
if (distance <= 5) {
|
|
91
|
+
onPress();
|
|
92
|
+
} else {
|
|
93
|
+
// Calculate new position after dragging
|
|
94
|
+
const newTop = lastPosition.current.top + gestureState.dy;
|
|
95
|
+
const newRight = lastPosition.current.right - gestureState.dx;
|
|
96
|
+
|
|
97
|
+
// Clamp to screen bounds
|
|
98
|
+
const clampedTop = Math.max(
|
|
99
|
+
screenBounds.minTop,
|
|
100
|
+
Math.min(screenBounds.maxTop, newTop)
|
|
101
|
+
);
|
|
102
|
+
const clampedRight = Math.max(
|
|
103
|
+
screenBounds.minRight,
|
|
104
|
+
Math.min(screenBounds.maxRight, newRight)
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
// Update position
|
|
108
|
+
lastPosition.current = { top: clampedTop, right: clampedRight };
|
|
109
|
+
position.setValue({ x: clampedRight, y: clampedTop });
|
|
110
|
+
|
|
111
|
+
// Convert back to x,y coordinates for storage
|
|
112
|
+
const { width } = Dimensions.get('window');
|
|
113
|
+
const storagePosition = {
|
|
114
|
+
x: width - clampedRight - buttonSize,
|
|
115
|
+
y: clampedTop,
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// Persist position to AsyncStorage (debounced)
|
|
119
|
+
storageService.saveFloatingButtonPosition(storagePosition);
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
})
|
|
123
|
+
).current;
|
|
124
|
+
|
|
125
|
+
// Memoized button icon and color for performance
|
|
126
|
+
const content = useMemo(() => {
|
|
127
|
+
switch (sessionState) {
|
|
128
|
+
case SessionState.started:
|
|
129
|
+
return {
|
|
130
|
+
icon: <CapturingIcon size={28} color="white" />,
|
|
131
|
+
color: '#FF4444',
|
|
132
|
+
};
|
|
133
|
+
case SessionState.paused:
|
|
134
|
+
return {
|
|
135
|
+
icon: <PausedIcon size={28} color="white" />,
|
|
136
|
+
color: '#FFA500',
|
|
137
|
+
};
|
|
138
|
+
default:
|
|
139
|
+
return {
|
|
140
|
+
icon: <RecordIcon size={28} color="#718096" />,
|
|
141
|
+
color: '#ffffff',
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
}, [sessionState]);
|
|
145
|
+
|
|
146
|
+
return (
|
|
147
|
+
<Animated.View
|
|
148
|
+
style={[styles.draggableButton, { top: position.y, right: position.x }]}
|
|
149
|
+
{...panResponder.panHandlers}
|
|
150
|
+
>
|
|
151
|
+
<View style={[styles.floatingButton, { backgroundColor: content.color }]}>
|
|
152
|
+
{content.icon}
|
|
153
|
+
</View>
|
|
154
|
+
</Animated.View>
|
|
155
|
+
);
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const styles = StyleSheet.create({
|
|
159
|
+
draggableButton: {
|
|
160
|
+
position: 'absolute',
|
|
161
|
+
},
|
|
162
|
+
floatingButton: {
|
|
163
|
+
elevation: 8,
|
|
164
|
+
shadowRadius: 4,
|
|
165
|
+
width: buttonSize,
|
|
166
|
+
shadowColor: '#000',
|
|
167
|
+
height: buttonSize,
|
|
168
|
+
shadowOpacity: 0.25,
|
|
169
|
+
alignItems: 'center',
|
|
170
|
+
justifyContent: 'center',
|
|
171
|
+
borderRadius: buttonSize / 2,
|
|
172
|
+
shadowOffset: { width: 0, height: 2 },
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
export default FloatingButton;
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import React, { useMemo, useState } from 'react';
|
|
2
|
+
import { View, Text, Pressable, Switch } from 'react-native';
|
|
3
|
+
import { SessionType } from '@multiplayer-app/session-recorder-common';
|
|
4
|
+
import { type TextOverridesOptions } from '../../types';
|
|
5
|
+
import { sharedStyles } from './styles';
|
|
6
|
+
import ModalHeader from './ModalHeader';
|
|
7
|
+
import { CapturingIcon } from './icons';
|
|
8
|
+
import { logger } from '../../utils';
|
|
9
|
+
|
|
10
|
+
interface InitialPopoverProps extends React.PropsWithChildren {
|
|
11
|
+
isContinuous: boolean;
|
|
12
|
+
showContinuousRecording: boolean;
|
|
13
|
+
textOverrides: TextOverridesOptions;
|
|
14
|
+
onStartRecording: (sessionType: SessionType) => void;
|
|
15
|
+
onStopRecording: (comment?: string) => void;
|
|
16
|
+
onSaveContinuousSession: () => void;
|
|
17
|
+
onClose: () => void;
|
|
18
|
+
isSubmitting: boolean;
|
|
19
|
+
isOnline: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const InitialPopover: React.FC<InitialPopoverProps> = ({
|
|
23
|
+
isContinuous,
|
|
24
|
+
textOverrides,
|
|
25
|
+
showContinuousRecording,
|
|
26
|
+
onStartRecording,
|
|
27
|
+
onStopRecording,
|
|
28
|
+
onSaveContinuousSession,
|
|
29
|
+
isOnline,
|
|
30
|
+
children,
|
|
31
|
+
}) => {
|
|
32
|
+
const [saving, setSaving] = useState(false);
|
|
33
|
+
const [loading, setLoading] = useState(false);
|
|
34
|
+
const [continuousRecording, setContinuousRecording] = useState(isContinuous);
|
|
35
|
+
|
|
36
|
+
const handleStartRecording = async () => {
|
|
37
|
+
try {
|
|
38
|
+
setLoading(true);
|
|
39
|
+
await onStartRecording(SessionType.PLAIN);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
logger.error('InitialPopover', 'Failed to start recording', error);
|
|
42
|
+
} finally {
|
|
43
|
+
setLoading(false);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const handleToggleContinuousRecording = async (value: boolean) => {
|
|
48
|
+
try {
|
|
49
|
+
setLoading(true);
|
|
50
|
+
setContinuousRecording(value);
|
|
51
|
+
if (value) {
|
|
52
|
+
await onStartRecording(SessionType.CONTINUOUS);
|
|
53
|
+
} else {
|
|
54
|
+
await onStopRecording();
|
|
55
|
+
}
|
|
56
|
+
} catch (error) {
|
|
57
|
+
logger.error(
|
|
58
|
+
'InitialPopover',
|
|
59
|
+
'Failed to toggle continuous recording',
|
|
60
|
+
error
|
|
61
|
+
);
|
|
62
|
+
} finally {
|
|
63
|
+
setLoading(false);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const handleSaveContinuousSession = async () => {
|
|
68
|
+
try {
|
|
69
|
+
setSaving(true);
|
|
70
|
+
await onSaveContinuousSession();
|
|
71
|
+
} catch (error) {
|
|
72
|
+
logger.error(
|
|
73
|
+
'InitialPopover',
|
|
74
|
+
'Failed to save continuous session',
|
|
75
|
+
error
|
|
76
|
+
);
|
|
77
|
+
} finally {
|
|
78
|
+
setSaving(false);
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const textContent = useMemo(() => {
|
|
83
|
+
return {
|
|
84
|
+
label: textOverrides.continuousRecordingLabel,
|
|
85
|
+
title: showContinuousRecording
|
|
86
|
+
? textOverrides.initialTitleWithContinuous
|
|
87
|
+
: textOverrides.initialTitleWithoutContinuous,
|
|
88
|
+
description: showContinuousRecording
|
|
89
|
+
? textOverrides.initialDescriptionWithContinuous
|
|
90
|
+
: textOverrides.initialDescriptionWithoutContinuous,
|
|
91
|
+
};
|
|
92
|
+
}, [showContinuousRecording, textOverrides]);
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<View style={sharedStyles.popoverContent}>
|
|
96
|
+
<ModalHeader />
|
|
97
|
+
<View style={sharedStyles.popoverBody}>
|
|
98
|
+
{children}
|
|
99
|
+
{showContinuousRecording && (
|
|
100
|
+
<View style={sharedStyles.continuousRecordingSection}>
|
|
101
|
+
<Text style={sharedStyles.continuousRecordingLabel}>
|
|
102
|
+
{textContent.label}
|
|
103
|
+
</Text>
|
|
104
|
+
<Switch
|
|
105
|
+
disabled={loading || !isOnline}
|
|
106
|
+
value={continuousRecording}
|
|
107
|
+
ios_backgroundColor="#e2e8f0"
|
|
108
|
+
onValueChange={handleToggleContinuousRecording}
|
|
109
|
+
trackColor={{ false: '#e2e8f0', true: '#493bff' }}
|
|
110
|
+
thumbColor={'#ffffff'}
|
|
111
|
+
/>
|
|
112
|
+
</View>
|
|
113
|
+
)}
|
|
114
|
+
{!continuousRecording ? (
|
|
115
|
+
<>
|
|
116
|
+
<Text style={sharedStyles.title}>{textContent.title}</Text>
|
|
117
|
+
<Text style={sharedStyles.description}>
|
|
118
|
+
{textContent.description}
|
|
119
|
+
</Text>
|
|
120
|
+
<View style={sharedStyles.popoverFooter}>
|
|
121
|
+
<Pressable
|
|
122
|
+
disabled={loading || !isOnline}
|
|
123
|
+
onPress={handleStartRecording}
|
|
124
|
+
style={[sharedStyles.actionButton, sharedStyles.startButton]}
|
|
125
|
+
>
|
|
126
|
+
<Text style={sharedStyles.actionButtonText}>
|
|
127
|
+
{loading
|
|
128
|
+
? 'Starting to record...'
|
|
129
|
+
: textOverrides.startRecordingButtonText}
|
|
130
|
+
</Text>
|
|
131
|
+
</Pressable>
|
|
132
|
+
</View>
|
|
133
|
+
</>
|
|
134
|
+
) : (
|
|
135
|
+
<>
|
|
136
|
+
<View style={sharedStyles.continuousOverlay}>
|
|
137
|
+
<View style={sharedStyles.continuousOverlayHeader}>
|
|
138
|
+
<CapturingIcon size={20} color="red" />
|
|
139
|
+
<Text style={sharedStyles.continuousOverlayTitle}>
|
|
140
|
+
{textOverrides.continuousOverlayTitle}
|
|
141
|
+
</Text>
|
|
142
|
+
</View>
|
|
143
|
+
<Text style={sharedStyles.continuousOverlayDescription}>
|
|
144
|
+
{textOverrides.continuousOverlayDescription}
|
|
145
|
+
</Text>
|
|
146
|
+
</View>
|
|
147
|
+
<View style={sharedStyles.popoverFooter}>
|
|
148
|
+
<Pressable
|
|
149
|
+
disabled={saving || !isOnline}
|
|
150
|
+
onPress={handleSaveContinuousSession}
|
|
151
|
+
style={[sharedStyles.actionButton, sharedStyles.saveButton]}
|
|
152
|
+
>
|
|
153
|
+
<Text style={sharedStyles.actionButtonText}>
|
|
154
|
+
{saving
|
|
155
|
+
? 'Saving...'
|
|
156
|
+
: textOverrides.saveLastSnapshotButtonText}
|
|
157
|
+
</Text>
|
|
158
|
+
</Pressable>
|
|
159
|
+
</View>
|
|
160
|
+
</>
|
|
161
|
+
)}
|
|
162
|
+
</View>
|
|
163
|
+
</View>
|
|
164
|
+
);
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
export default InitialPopover;
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
Animated,
|
|
4
|
+
Pressable,
|
|
5
|
+
StyleSheet,
|
|
6
|
+
Dimensions,
|
|
7
|
+
Modal,
|
|
8
|
+
PanResponder,
|
|
9
|
+
Platform,
|
|
10
|
+
} from 'react-native';
|
|
11
|
+
import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';
|
|
12
|
+
|
|
13
|
+
const { height: SCREEN_HEIGHT } = Dimensions.get('window');
|
|
14
|
+
const MODAL_HEIGHT = SCREEN_HEIGHT * 0.7;
|
|
15
|
+
|
|
16
|
+
interface ModalContainerProps {
|
|
17
|
+
isVisible: boolean;
|
|
18
|
+
onClose: () => void;
|
|
19
|
+
children: React.ReactNode;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const ModalContainer: React.FC<ModalContainerProps> = ({
|
|
23
|
+
isVisible,
|
|
24
|
+
onClose,
|
|
25
|
+
children,
|
|
26
|
+
}) => {
|
|
27
|
+
const fadeAnim = useRef(new Animated.Value(0)).current;
|
|
28
|
+
const translateY = useRef(new Animated.Value(0)).current;
|
|
29
|
+
const [visible, setVisible] = useState<boolean>(isVisible);
|
|
30
|
+
|
|
31
|
+
const SWIPE_THRESHOLD = 100; // Distance to trigger close
|
|
32
|
+
|
|
33
|
+
const animateClose = () => {
|
|
34
|
+
Animated.parallel([
|
|
35
|
+
Animated.timing(fadeAnim, {
|
|
36
|
+
toValue: 0,
|
|
37
|
+
duration: 250,
|
|
38
|
+
useNativeDriver: true,
|
|
39
|
+
}),
|
|
40
|
+
Animated.timing(translateY, {
|
|
41
|
+
toValue: MODAL_HEIGHT,
|
|
42
|
+
duration: 250,
|
|
43
|
+
useNativeDriver: true,
|
|
44
|
+
}),
|
|
45
|
+
]).start(() => {
|
|
46
|
+
setVisible(false);
|
|
47
|
+
onClose();
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
if (isVisible) {
|
|
53
|
+
setVisible(true);
|
|
54
|
+
// Start from bottom and animate to position
|
|
55
|
+
translateY.setValue(MODAL_HEIGHT);
|
|
56
|
+
Animated.parallel([
|
|
57
|
+
Animated.timing(fadeAnim, {
|
|
58
|
+
toValue: 1,
|
|
59
|
+
duration: 300,
|
|
60
|
+
useNativeDriver: true,
|
|
61
|
+
}),
|
|
62
|
+
Animated.timing(translateY, {
|
|
63
|
+
toValue: 0,
|
|
64
|
+
duration: 300,
|
|
65
|
+
useNativeDriver: true,
|
|
66
|
+
}),
|
|
67
|
+
]).start();
|
|
68
|
+
} else if (visible) {
|
|
69
|
+
// If external isVisible turned false, animate close then hide
|
|
70
|
+
Animated.parallel([
|
|
71
|
+
Animated.timing(fadeAnim, {
|
|
72
|
+
toValue: 0,
|
|
73
|
+
duration: 250,
|
|
74
|
+
useNativeDriver: true,
|
|
75
|
+
}),
|
|
76
|
+
Animated.timing(translateY, {
|
|
77
|
+
toValue: MODAL_HEIGHT,
|
|
78
|
+
duration: 250,
|
|
79
|
+
useNativeDriver: true,
|
|
80
|
+
}),
|
|
81
|
+
]).start(() => {
|
|
82
|
+
setVisible(false);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}, [isVisible, fadeAnim, translateY, visible]);
|
|
86
|
+
|
|
87
|
+
// PanResponder for swipe-to-dismiss functionality
|
|
88
|
+
const panResponder = useRef(
|
|
89
|
+
PanResponder.create({
|
|
90
|
+
onStartShouldSetPanResponder: () => true,
|
|
91
|
+
onMoveShouldSetPanResponder: (_, gestureState) => {
|
|
92
|
+
// Only respond to downward swipes
|
|
93
|
+
return gestureState.dy > 10;
|
|
94
|
+
},
|
|
95
|
+
onPanResponderGrant: () => {
|
|
96
|
+
// Reset any ongoing animations
|
|
97
|
+
translateY.stopAnimation();
|
|
98
|
+
},
|
|
99
|
+
onPanResponderMove: (_, gestureState) => {
|
|
100
|
+
// Only allow downward movement
|
|
101
|
+
if (gestureState.dy > 0) {
|
|
102
|
+
translateY.setValue(gestureState.dy);
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
onPanResponderRelease: (_, gestureState) => {
|
|
106
|
+
const { dy, vy } = gestureState;
|
|
107
|
+
|
|
108
|
+
// If swiped down with sufficient distance or velocity, close modal
|
|
109
|
+
if (dy > SWIPE_THRESHOLD || vy > 500) {
|
|
110
|
+
animateClose();
|
|
111
|
+
} else {
|
|
112
|
+
// Snap back to original position
|
|
113
|
+
Animated.spring(translateY, {
|
|
114
|
+
toValue: 0,
|
|
115
|
+
useNativeDriver: true,
|
|
116
|
+
tension: 100,
|
|
117
|
+
friction: 8,
|
|
118
|
+
}).start();
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
})
|
|
122
|
+
).current;
|
|
123
|
+
|
|
124
|
+
return (
|
|
125
|
+
<Modal
|
|
126
|
+
visible={visible}
|
|
127
|
+
transparent
|
|
128
|
+
animationType="none"
|
|
129
|
+
onRequestClose={onClose}
|
|
130
|
+
>
|
|
131
|
+
<SafeAreaProvider>
|
|
132
|
+
<Animated.View style={{ ...styles.backdrop, opacity: fadeAnim }}>
|
|
133
|
+
<Pressable style={styles.backdropPressable} onPress={animateClose} />
|
|
134
|
+
<Animated.View
|
|
135
|
+
style={[styles.modal, { transform: [{ translateY }] }]}
|
|
136
|
+
{...panResponder.panHandlers}
|
|
137
|
+
>
|
|
138
|
+
<SafeAreaView style={styles.safeArea} edges={['bottom']}>
|
|
139
|
+
{children}
|
|
140
|
+
</SafeAreaView>
|
|
141
|
+
</Animated.View>
|
|
142
|
+
</Animated.View>
|
|
143
|
+
</SafeAreaProvider>
|
|
144
|
+
</Modal>
|
|
145
|
+
);
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const styles = StyleSheet.create({
|
|
149
|
+
backdrop: {
|
|
150
|
+
position: 'absolute',
|
|
151
|
+
top: 0,
|
|
152
|
+
left: 0,
|
|
153
|
+
right: 0,
|
|
154
|
+
bottom: 0,
|
|
155
|
+
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
|
156
|
+
},
|
|
157
|
+
backdropPressable: {
|
|
158
|
+
flex: 1,
|
|
159
|
+
},
|
|
160
|
+
safeArea: {
|
|
161
|
+
flex: 1,
|
|
162
|
+
backgroundColor: 'white',
|
|
163
|
+
borderTopLeftRadius: 20,
|
|
164
|
+
borderTopRightRadius: 20,
|
|
165
|
+
},
|
|
166
|
+
modal: {
|
|
167
|
+
position: 'absolute',
|
|
168
|
+
bottom: 0,
|
|
169
|
+
left: 0,
|
|
170
|
+
right: 0,
|
|
171
|
+
maxHeight: MODAL_HEIGHT,
|
|
172
|
+
backgroundColor: 'white',
|
|
173
|
+
borderTopLeftRadius: 20,
|
|
174
|
+
borderTopRightRadius: 20,
|
|
175
|
+
...Platform.select({
|
|
176
|
+
ios: {
|
|
177
|
+
shadowColor: '#000',
|
|
178
|
+
shadowOffset: { width: 0, height: -2 },
|
|
179
|
+
shadowOpacity: 0.1,
|
|
180
|
+
shadowRadius: 8,
|
|
181
|
+
},
|
|
182
|
+
android: {
|
|
183
|
+
elevation: 8,
|
|
184
|
+
},
|
|
185
|
+
}),
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
export default ModalContainer;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { View, Pressable, Linking } from 'react-native'
|
|
3
|
+
import { sharedStyles } from './styles'
|
|
4
|
+
import { LogoIcon } from './icons'
|
|
5
|
+
|
|
6
|
+
interface ModalHeaderProps {
|
|
7
|
+
children?: React.ReactNode
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const ModalHeader: React.FC<ModalHeaderProps> = ({ children }) => {
|
|
11
|
+
return (
|
|
12
|
+
<View style={sharedStyles.popoverHeader}>
|
|
13
|
+
<View style={sharedStyles.modalHandle} />
|
|
14
|
+
<View style={sharedStyles.popoverHeaderContent}>
|
|
15
|
+
<Pressable onPress={() => Linking.openURL('https://www.multiplayer.app')}>
|
|
16
|
+
<LogoIcon size={42} />
|
|
17
|
+
</Pressable>
|
|
18
|
+
{children}
|
|
19
|
+
</View>
|
|
20
|
+
</View>
|
|
21
|
+
)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default ModalHeader
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import React, { useState, useCallback, memo } from 'react'
|
|
2
|
+
import { View, StyleSheet } from 'react-native'
|
|
3
|
+
import { SessionState } from '../../types'
|
|
4
|
+
import { SessionType } from '@multiplayer-app/session-recorder-common'
|
|
5
|
+
import { useSessionRecorder } from '../../context/SessionRecorderContext'
|
|
6
|
+
|
|
7
|
+
import FinalPopover from './FinalPopover'
|
|
8
|
+
import ModalContainer from './ModalContainer'
|
|
9
|
+
import InitialPopover from './InitialPopover'
|
|
10
|
+
import FloatingButton from './FloatingButton'
|
|
11
|
+
import ErrorBanner from './ErrorBanner'
|
|
12
|
+
import { logger } from '../../utils'
|
|
13
|
+
import { useSessionRecorderStore } from '../../context/useSessionRecorderStore'
|
|
14
|
+
import { sessionRecorderStore } from '../../context/SessionRecorderStore'
|
|
15
|
+
|
|
16
|
+
interface SessionRecorderWidgetProps {}
|
|
17
|
+
|
|
18
|
+
const SessionRecorderWidget: React.FC<SessionRecorderWidgetProps> = memo(() => {
|
|
19
|
+
const { instance, openWidgetModal, closeWidgetModal } = useSessionRecorder()
|
|
20
|
+
const isOnline = useSessionRecorderStore<boolean>((s) => s.isOnline)
|
|
21
|
+
const sessionType = useSessionRecorderStore<SessionType | null>((s) => s.sessionType)
|
|
22
|
+
const isModalVisible = useSessionRecorderStore<boolean>((s) => s.isWidgetModalVisible)
|
|
23
|
+
const sessionState = useSessionRecorderStore<SessionState | null>((s) => s.sessionState)
|
|
24
|
+
const error = useSessionRecorderStore<string | null>((s) => s.error)
|
|
25
|
+
const [isSubmitting, setIsSubmitting] = useState(false)
|
|
26
|
+
|
|
27
|
+
// Get configuration from instance
|
|
28
|
+
const { widget, showContinuousRecording } = instance.config
|
|
29
|
+
|
|
30
|
+
const dismissError = useCallback(() => {
|
|
31
|
+
sessionRecorderStore.setState({ error: null })
|
|
32
|
+
}, [])
|
|
33
|
+
|
|
34
|
+
const handleError = useCallback((error: any, message: string) => {
|
|
35
|
+
const errorMessage = error instanceof Error ? error.message : message
|
|
36
|
+
logger.error('SessionRecorderWidget', message, error)
|
|
37
|
+
sessionRecorderStore.setState({ error: errorMessage })
|
|
38
|
+
}, [])
|
|
39
|
+
|
|
40
|
+
const onStartRecording = useCallback(
|
|
41
|
+
async (sessionType: SessionType) => {
|
|
42
|
+
if (!isOnline) {
|
|
43
|
+
handleError(new Error('Cannot start recording while offline'), 'Cannot start recording while offline')
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
await instance.start(sessionType)
|
|
48
|
+
closeWidgetModal()
|
|
49
|
+
} catch (error) {
|
|
50
|
+
handleError(error, 'Failed to start recording')
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
[isOnline, handleError]
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
const onStopRecording = useCallback(
|
|
57
|
+
async (comment?: string) => {
|
|
58
|
+
try {
|
|
59
|
+
setIsSubmitting(true)
|
|
60
|
+
await instance.stop(comment)
|
|
61
|
+
closeWidgetModal()
|
|
62
|
+
} catch (error) {
|
|
63
|
+
handleError(error, 'Failed to stop recording')
|
|
64
|
+
} finally {
|
|
65
|
+
setIsSubmitting(false)
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
[handleError]
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
const onCancelSession = useCallback(async () => {
|
|
72
|
+
try {
|
|
73
|
+
await instance.cancel()
|
|
74
|
+
closeWidgetModal()
|
|
75
|
+
} catch (error) {
|
|
76
|
+
handleError(error, 'Failed to cancel session')
|
|
77
|
+
}
|
|
78
|
+
}, [handleError])
|
|
79
|
+
|
|
80
|
+
const onSaveContinuousSession = useCallback(async () => {
|
|
81
|
+
try {
|
|
82
|
+
await instance.save()
|
|
83
|
+
} catch (error) {
|
|
84
|
+
handleError(error, 'Failed to save continuous session')
|
|
85
|
+
}
|
|
86
|
+
}, [handleError])
|
|
87
|
+
|
|
88
|
+
const isStarted = sessionState === SessionState.started || sessionState === SessionState.paused
|
|
89
|
+
const isContinuous = sessionType === SessionType.CONTINUOUS
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<>
|
|
93
|
+
{widget.button?.visible && (
|
|
94
|
+
<View pointerEvents='box-none' style={styles.overlayContainer}>
|
|
95
|
+
<FloatingButton sessionState={sessionState} onPress={openWidgetModal} />
|
|
96
|
+
</View>
|
|
97
|
+
)}
|
|
98
|
+
<ModalContainer isVisible={isModalVisible} onClose={closeWidgetModal}>
|
|
99
|
+
{isStarted && !isContinuous ? (
|
|
100
|
+
<FinalPopover
|
|
101
|
+
isOnline={isOnline}
|
|
102
|
+
isSubmitting={isSubmitting}
|
|
103
|
+
textOverrides={widget.textOverrides}
|
|
104
|
+
onClose={closeWidgetModal}
|
|
105
|
+
onStopRecording={onStopRecording}
|
|
106
|
+
onCancelSession={onCancelSession}
|
|
107
|
+
>
|
|
108
|
+
{error && <ErrorBanner error={error} onDismiss={dismissError} />}
|
|
109
|
+
</FinalPopover>
|
|
110
|
+
) : (
|
|
111
|
+
<InitialPopover
|
|
112
|
+
isOnline={isOnline}
|
|
113
|
+
isSubmitting={isSubmitting}
|
|
114
|
+
textOverrides={widget.textOverrides}
|
|
115
|
+
isContinuous={isStarted && isContinuous}
|
|
116
|
+
showContinuousRecording={showContinuousRecording}
|
|
117
|
+
onClose={closeWidgetModal}
|
|
118
|
+
onStopRecording={onStopRecording}
|
|
119
|
+
onStartRecording={onStartRecording}
|
|
120
|
+
onSaveContinuousSession={onSaveContinuousSession}
|
|
121
|
+
>
|
|
122
|
+
{error && <ErrorBanner error={error} onDismiss={dismissError} />}
|
|
123
|
+
</InitialPopover>
|
|
124
|
+
)}
|
|
125
|
+
</ModalContainer>
|
|
126
|
+
</>
|
|
127
|
+
)
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
export default SessionRecorderWidget
|
|
131
|
+
|
|
132
|
+
const styles = StyleSheet.create({
|
|
133
|
+
overlayContainer: {
|
|
134
|
+
...StyleSheet.absoluteFillObject
|
|
135
|
+
}
|
|
136
|
+
})
|