@planningcenter/chat-react-native 3.45.0-rc.1 → 3.45.0-rc.2

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.
@@ -1 +1 @@
1
- {"version":3,"file":"video_attachment.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation/attachments/video_attachment.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,qCAAqC,EAAE,MAAM,2DAA2D,CAAA;AAOjH,wBAAgB,eAAe,CAAC,EAC9B,UAAU,EACV,4BAA4B,EAC5B,UAAU,GACX,EAAE;IACD,UAAU,EAAE,qCAAqC,CAAA;IACjD,4BAA4B,EAAE,CAAC,UAAU,EAAE,qCAAqC,KAAK,IAAI,CAAA;IACzF,UAAU,EAAE,OAAO,CAAA;CACpB,2CA4DA"}
1
+ {"version":3,"file":"video_attachment.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation/attachments/video_attachment.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,qCAAqC,EAAE,MAAM,2DAA2D,CAAA;AAOjH,wBAAgB,eAAe,CAAC,EAC9B,UAAU,EACV,4BAA4B,EAC5B,UAAU,GACX,EAAE;IACD,UAAU,EAAE,qCAAqC,CAAA;IACjD,4BAA4B,EAAE,CAAC,UAAU,EAAE,qCAAqC,KAAK,IAAI,CAAA;IACzF,UAAU,EAAE,OAAO,CAAA;CACpB,2CA6DA"}
@@ -23,12 +23,12 @@ export function VideoAttachment({ attachment, onMessageAttachmentLongPress, isDe
23
23
  setIsOpen(true);
24
24
  }
25
25
  }
26
- function onFullscreenPlayerWillDismiss() {
26
+ function closeVideo() {
27
27
  videoRef.current?.pause();
28
28
  setIsOpen(false);
29
29
  }
30
30
  const viewRef = useRef(null);
31
- return (_jsx(View, { style: styles.container, ref: viewRef, children: _jsxs(PlatformPressable, { onPress: openVideo, onLongPress: () => !isDeleting && onMessageAttachmentLongPress(attachment), android_ripple: { color: colors.androidRippleNeutral, foreground: true }, accessibilityLabel: "Play Video", accessibilityHint: "Press to play video. Long press for more options", disabled: isDeleting, children: [_jsx(View, { style: styles.thumbnailOverlay }), _jsx(Video.Player, { ref: videoRef, source: { uri: url }, aspectRatio: width / height, style: styles.video, onFullscreenPlayerWillDismiss: onFullscreenPlayerWillDismiss }), !isOpen && !isDeleting && (_jsx(View, { style: styles.playContainer, children: _jsx(View, { style: styles.playCircle, children: _jsx(Icon, { name: "services.play", style: styles.playIcon, accessibilityElementsHidden: true }) }) })), isDeleting && _jsx(AttachmentDeletingOverlay, {})] }) }));
31
+ return (_jsx(View, { style: styles.container, ref: viewRef, children: _jsxs(PlatformPressable, { onPress: openVideo, onLongPress: () => !isDeleting && onMessageAttachmentLongPress(attachment), android_ripple: { color: colors.androidRippleNeutral, foreground: true }, accessibilityLabel: "Play Video", accessibilityHint: "Press to play video. Long press for more options", disabled: isDeleting, children: [_jsx(View, { style: styles.thumbnailOverlay }), _jsx(Video.Player, { ref: videoRef, source: { uri: url }, aspectRatio: width / height, style: styles.video, onFullscreenPlayerWillDismiss: closeVideo, onFullscreenPlayerDidDismiss: closeVideo }), !isOpen && !isDeleting && (_jsx(View, { style: styles.playContainer, children: _jsx(View, { style: styles.playCircle, children: _jsx(Icon, { name: "services.play", style: styles.playIcon, accessibilityElementsHidden: true }) }) })), isDeleting && _jsx(AttachmentDeletingOverlay, {})] }) }));
32
32
  }
33
33
  const OVERLAY_Z_INDEX = 1;
34
34
  const useStyles = () => {
@@ -1 +1 @@
1
- {"version":3,"file":"video_attachment.js","sourceRoot":"","sources":["../../../../src/components/conversation/attachments/video_attachment.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAC9D,OAAc,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAC/C,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAEzC,OAAO,EAAE,KAAK,EAAqB,MAAM,gCAAgC,CAAA;AACzE,OAAO,EAAE,MAAM,EAAE,MAAM,iCAAiC,CAAA;AACxD,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AACpC,OAAO,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAA;AACzE,OAAO,EAAE,+BAA+B,EAAE,MAAM,aAAa,CAAA;AAE7D,MAAM,UAAU,eAAe,CAAC,EAC9B,UAAU,EACV,4BAA4B,EAC5B,UAAU,GAKX;IACC,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAA;IAC7B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAE1B,MAAM,EAAE,UAAU,EAAE,GAAG,UAAU,CAAA;IACjC,MAAM,EAAE,KAAK,GAAG,+BAA+B,EAAE,MAAM,GAAG,+BAA+B,EAAE,GACzF,UAAU,CAAC,QAAQ,IAAI,EAAE,CAAA;IAC3B,MAAM,EAAE,GAAG,EAAE,GAAG,UAAU,CAAA;IAE1B,MAAM,QAAQ,GAAG,MAAM,CAAoB,IAAI,CAAC,CAAA;IAChD,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAE3C,SAAS,SAAS;QAChB,IAAI,CAAC,MAAM,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;YAChC,QAAQ,CAAC,OAAO,CAAC,uBAAuB,EAAE,CAAA;YAC1C,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,CAAA;YACvB,SAAS,CAAC,IAAI,CAAC,CAAA;QACjB,CAAC;IACH,CAAC;IAED,SAAS,6BAA6B;QACpC,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,CAAA;QACzB,SAAS,CAAC,KAAK,CAAC,CAAA;IAClB,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,CAAO,IAAI,CAAC,CAAA;IAElC,OAAO,CACL,KAAC,IAAI,IAAC,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,GAAG,EAAE,OAAO,YACzC,MAAC,iBAAiB,IAChB,OAAO,EAAE,SAAS,EAClB,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC,UAAU,IAAI,4BAA4B,CAAC,UAAU,CAAC,EAC1E,cAAc,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,oBAAoB,EAAE,UAAU,EAAE,IAAI,EAAE,EACxE,kBAAkB,EAAC,YAAY,EAC/B,iBAAiB,EAAC,kDAAkD,EACpE,QAAQ,EAAE,UAAU,aAEpB,KAAC,IAAI,IAAC,KAAK,EAAE,MAAM,CAAC,gBAAgB,GAAI,EACxC,KAAC,KAAK,CAAC,MAAM,IACX,GAAG,EAAE,QAAQ,EACb,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,EACpB,WAAW,EAAE,KAAK,GAAG,MAAM,EAC3B,KAAK,EAAE,MAAM,CAAC,KAAK,EACnB,6BAA6B,EAAE,6BAA6B,GAC5D,EACD,CAAC,MAAM,IAAI,CAAC,UAAU,IAAI,CACzB,KAAC,IAAI,IAAC,KAAK,EAAE,MAAM,CAAC,aAAa,YAC/B,KAAC,IAAI,IAAC,KAAK,EAAE,MAAM,CAAC,UAAU,YAC5B,KAAC,IAAI,IACH,IAAI,EAAC,eAAe,EACpB,KAAK,EAAE,MAAM,CAAC,QAAQ,EACtB,2BAA2B,EAAE,IAAI,GACjC,GACG,GACF,CACR,EACA,UAAU,IAAI,KAAC,yBAAyB,KAAG,IAC1B,GACf,CACR,CAAA;AACH,CAAC;AACD,MAAM,eAAe,GAAG,CAAC,CAAA;AAEzB,MAAM,SAAS,GAAG,GAAG,EAAE;IACrB,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAA;IAC7B,MAAM,sBAAsB,GAC1B,MAAM,CAAC,IAAI,KAAK,OAAO;QACrB,CAAC,CAAC,MAAM,CAAC,4BAA4B;QACrC,CAAC,CAAC,MAAM,CAAC,4BAA4B,CAAA;IAEzC,OAAO,UAAU,CAAC,MAAM,CAAC;QACvB,SAAS,EAAE;YACT,YAAY,EAAE,CAAC;YACf,QAAQ,EAAE,QAAQ;SACnB;QACD,KAAK,EAAE;YACL,KAAK,EAAE,MAAM;YACb,eAAe,EAAE,MAAM,CAAC,mBAAmB;SAC5C;QACD,gBAAgB,EAAE;YAChB,QAAQ,EAAE,UAAU;YACpB,GAAG,EAAE,CAAC;YACN,IAAI,EAAE,CAAC;YACP,KAAK,EAAE,CAAC;YACR,MAAM,EAAE,CAAC;YACT,eAAe,EAAE,sBAAsB;YACvC,MAAM,EAAE,eAAe;SACxB;QACD,aAAa,EAAE;YACb,QAAQ,EAAE,UAAU;YACpB,GAAG,EAAE,CAAC;YACN,IAAI,EAAE,CAAC;YACP,KAAK,EAAE,CAAC;YACR,MAAM,EAAE,CAAC;YACT,cAAc,EAAE,QAAQ;YACxB,UAAU,EAAE,QAAQ;YACpB,MAAM,EAAE,eAAe,GAAG,CAAC;SAC5B;QACD,UAAU,EAAE;YACV,cAAc,EAAE,QAAQ;YACxB,UAAU,EAAE,QAAQ;YACpB,KAAK,EAAE,EAAE;YACT,MAAM,EAAE,EAAE;YACV,YAAY,EAAE,EAAE;YAChB,eAAe,EAAE,MAAM,CAAC,2BAA2B;YACnD,WAAW,EAAE,MAAM,CAAC,sBAAsB;YAC1C,WAAW,EAAE,CAAC;SACf;QACD,QAAQ,EAAE;YACR,QAAQ,EAAE,EAAE;SACb;KACF,CAAC,CAAA;AACJ,CAAC,CAAA","sourcesContent":["import { PlatformPressable } from '@react-navigation/elements'\nimport React, { useRef, useState } from 'react'\nimport { View, StyleSheet } from 'react-native'\nimport { useTheme } from '../../../hooks'\nimport { DenormalizedMessageAttachmentResource } from '../../../types/resources/denormalized_attachment_resource'\nimport { Video, VideoPlayerHandle } from '../../../utils/native_adapters'\nimport { tokens } from '../../../vendor/tapestry/tokens'\nimport { Icon } from '../../display'\nimport { AttachmentDeletingOverlay } from './attachment_deleting_overlay'\nimport { MESSAGE_ATTACHMENT_WIDTH_SINGLE } from './constants'\n\nexport function VideoAttachment({\n attachment,\n onMessageAttachmentLongPress,\n isDeleting,\n}: {\n attachment: DenormalizedMessageAttachmentResource\n onMessageAttachmentLongPress: (attachment: DenormalizedMessageAttachmentResource) => void\n isDeleting: boolean\n}) {\n const { colors } = useTheme()\n const styles = useStyles()\n\n const { attributes } = attachment\n const { width = MESSAGE_ATTACHMENT_WIDTH_SINGLE, height = MESSAGE_ATTACHMENT_WIDTH_SINGLE } =\n attributes.metadata || {}\n const { url } = attributes\n\n const videoRef = useRef<VideoPlayerHandle>(null)\n const [isOpen, setIsOpen] = useState(false)\n\n function openVideo() {\n if (!isOpen && videoRef.current) {\n videoRef.current.presentFullscreenPlayer()\n videoRef.current.play()\n setIsOpen(true)\n }\n }\n\n function onFullscreenPlayerWillDismiss() {\n videoRef.current?.pause()\n setIsOpen(false)\n }\n\n const viewRef = useRef<View>(null)\n\n return (\n <View style={styles.container} ref={viewRef}>\n <PlatformPressable\n onPress={openVideo}\n onLongPress={() => !isDeleting && onMessageAttachmentLongPress(attachment)}\n android_ripple={{ color: colors.androidRippleNeutral, foreground: true }}\n accessibilityLabel=\"Play Video\"\n accessibilityHint=\"Press to play video. Long press for more options\"\n disabled={isDeleting}\n >\n <View style={styles.thumbnailOverlay} />\n <Video.Player\n ref={videoRef}\n source={{ uri: url }}\n aspectRatio={width / height}\n style={styles.video}\n onFullscreenPlayerWillDismiss={onFullscreenPlayerWillDismiss}\n />\n {!isOpen && !isDeleting && (\n <View style={styles.playContainer}>\n <View style={styles.playCircle}>\n <Icon\n name=\"services.play\"\n style={styles.playIcon}\n accessibilityElementsHidden={true}\n />\n </View>\n </View>\n )}\n {isDeleting && <AttachmentDeletingOverlay />}\n </PlatformPressable>\n </View>\n )\n}\nconst OVERLAY_Z_INDEX = 1\n\nconst useStyles = () => {\n const { colors } = useTheme()\n const overlayBackgroundColor =\n colors.name === 'light'\n ? tokens.fillColorTransparencyDark010\n : tokens.fillColorTransparencyDark030\n\n return StyleSheet.create({\n container: {\n borderRadius: 8,\n overflow: 'hidden',\n },\n video: {\n width: '100%',\n backgroundColor: colors.fillColorNeutral070,\n },\n thumbnailOverlay: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n backgroundColor: overlayBackgroundColor,\n zIndex: OVERLAY_Z_INDEX,\n },\n playContainer: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n justifyContent: 'center',\n alignItems: 'center',\n zIndex: OVERLAY_Z_INDEX + 1,\n },\n playCircle: {\n justifyContent: 'center',\n alignItems: 'center',\n width: 42,\n height: 42,\n borderRadius: 25,\n backgroundColor: colors.fillColorNeutral100Inverted,\n borderColor: colors.borderColorDefaultBase,\n borderWidth: 1,\n },\n playIcon: {\n fontSize: 20,\n },\n })\n}\n"]}
1
+ {"version":3,"file":"video_attachment.js","sourceRoot":"","sources":["../../../../src/components/conversation/attachments/video_attachment.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAC9D,OAAc,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAC/C,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAEzC,OAAO,EAAE,KAAK,EAAqB,MAAM,gCAAgC,CAAA;AACzE,OAAO,EAAE,MAAM,EAAE,MAAM,iCAAiC,CAAA;AACxD,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AACpC,OAAO,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAA;AACzE,OAAO,EAAE,+BAA+B,EAAE,MAAM,aAAa,CAAA;AAE7D,MAAM,UAAU,eAAe,CAAC,EAC9B,UAAU,EACV,4BAA4B,EAC5B,UAAU,GAKX;IACC,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAA;IAC7B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAE1B,MAAM,EAAE,UAAU,EAAE,GAAG,UAAU,CAAA;IACjC,MAAM,EAAE,KAAK,GAAG,+BAA+B,EAAE,MAAM,GAAG,+BAA+B,EAAE,GACzF,UAAU,CAAC,QAAQ,IAAI,EAAE,CAAA;IAC3B,MAAM,EAAE,GAAG,EAAE,GAAG,UAAU,CAAA;IAE1B,MAAM,QAAQ,GAAG,MAAM,CAAoB,IAAI,CAAC,CAAA;IAChD,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAE3C,SAAS,SAAS;QAChB,IAAI,CAAC,MAAM,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;YAChC,QAAQ,CAAC,OAAO,CAAC,uBAAuB,EAAE,CAAA;YAC1C,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,CAAA;YACvB,SAAS,CAAC,IAAI,CAAC,CAAA;QACjB,CAAC;IACH,CAAC;IAED,SAAS,UAAU;QACjB,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,CAAA;QACzB,SAAS,CAAC,KAAK,CAAC,CAAA;IAClB,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,CAAO,IAAI,CAAC,CAAA;IAElC,OAAO,CACL,KAAC,IAAI,IAAC,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,GAAG,EAAE,OAAO,YACzC,MAAC,iBAAiB,IAChB,OAAO,EAAE,SAAS,EAClB,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC,UAAU,IAAI,4BAA4B,CAAC,UAAU,CAAC,EAC1E,cAAc,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,oBAAoB,EAAE,UAAU,EAAE,IAAI,EAAE,EACxE,kBAAkB,EAAC,YAAY,EAC/B,iBAAiB,EAAC,kDAAkD,EACpE,QAAQ,EAAE,UAAU,aAEpB,KAAC,IAAI,IAAC,KAAK,EAAE,MAAM,CAAC,gBAAgB,GAAI,EACxC,KAAC,KAAK,CAAC,MAAM,IACX,GAAG,EAAE,QAAQ,EACb,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,EACpB,WAAW,EAAE,KAAK,GAAG,MAAM,EAC3B,KAAK,EAAE,MAAM,CAAC,KAAK,EACnB,6BAA6B,EAAE,UAAU,EACzC,4BAA4B,EAAE,UAAU,GACxC,EACD,CAAC,MAAM,IAAI,CAAC,UAAU,IAAI,CACzB,KAAC,IAAI,IAAC,KAAK,EAAE,MAAM,CAAC,aAAa,YAC/B,KAAC,IAAI,IAAC,KAAK,EAAE,MAAM,CAAC,UAAU,YAC5B,KAAC,IAAI,IACH,IAAI,EAAC,eAAe,EACpB,KAAK,EAAE,MAAM,CAAC,QAAQ,EACtB,2BAA2B,EAAE,IAAI,GACjC,GACG,GACF,CACR,EACA,UAAU,IAAI,KAAC,yBAAyB,KAAG,IAC1B,GACf,CACR,CAAA;AACH,CAAC;AACD,MAAM,eAAe,GAAG,CAAC,CAAA;AAEzB,MAAM,SAAS,GAAG,GAAG,EAAE;IACrB,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAA;IAC7B,MAAM,sBAAsB,GAC1B,MAAM,CAAC,IAAI,KAAK,OAAO;QACrB,CAAC,CAAC,MAAM,CAAC,4BAA4B;QACrC,CAAC,CAAC,MAAM,CAAC,4BAA4B,CAAA;IAEzC,OAAO,UAAU,CAAC,MAAM,CAAC;QACvB,SAAS,EAAE;YACT,YAAY,EAAE,CAAC;YACf,QAAQ,EAAE,QAAQ;SACnB;QACD,KAAK,EAAE;YACL,KAAK,EAAE,MAAM;YACb,eAAe,EAAE,MAAM,CAAC,mBAAmB;SAC5C;QACD,gBAAgB,EAAE;YAChB,QAAQ,EAAE,UAAU;YACpB,GAAG,EAAE,CAAC;YACN,IAAI,EAAE,CAAC;YACP,KAAK,EAAE,CAAC;YACR,MAAM,EAAE,CAAC;YACT,eAAe,EAAE,sBAAsB;YACvC,MAAM,EAAE,eAAe;SACxB;QACD,aAAa,EAAE;YACb,QAAQ,EAAE,UAAU;YACpB,GAAG,EAAE,CAAC;YACN,IAAI,EAAE,CAAC;YACP,KAAK,EAAE,CAAC;YACR,MAAM,EAAE,CAAC;YACT,cAAc,EAAE,QAAQ;YACxB,UAAU,EAAE,QAAQ;YACpB,MAAM,EAAE,eAAe,GAAG,CAAC;SAC5B;QACD,UAAU,EAAE;YACV,cAAc,EAAE,QAAQ;YACxB,UAAU,EAAE,QAAQ;YACpB,KAAK,EAAE,EAAE;YACT,MAAM,EAAE,EAAE;YACV,YAAY,EAAE,EAAE;YAChB,eAAe,EAAE,MAAM,CAAC,2BAA2B;YACnD,WAAW,EAAE,MAAM,CAAC,sBAAsB;YAC1C,WAAW,EAAE,CAAC;SACf;QACD,QAAQ,EAAE;YACR,QAAQ,EAAE,EAAE;SACb;KACF,CAAC,CAAA;AACJ,CAAC,CAAA","sourcesContent":["import { PlatformPressable } from '@react-navigation/elements'\nimport React, { useRef, useState } from 'react'\nimport { View, StyleSheet } from 'react-native'\nimport { useTheme } from '../../../hooks'\nimport { DenormalizedMessageAttachmentResource } from '../../../types/resources/denormalized_attachment_resource'\nimport { Video, VideoPlayerHandle } from '../../../utils/native_adapters'\nimport { tokens } from '../../../vendor/tapestry/tokens'\nimport { Icon } from '../../display'\nimport { AttachmentDeletingOverlay } from './attachment_deleting_overlay'\nimport { MESSAGE_ATTACHMENT_WIDTH_SINGLE } from './constants'\n\nexport function VideoAttachment({\n attachment,\n onMessageAttachmentLongPress,\n isDeleting,\n}: {\n attachment: DenormalizedMessageAttachmentResource\n onMessageAttachmentLongPress: (attachment: DenormalizedMessageAttachmentResource) => void\n isDeleting: boolean\n}) {\n const { colors } = useTheme()\n const styles = useStyles()\n\n const { attributes } = attachment\n const { width = MESSAGE_ATTACHMENT_WIDTH_SINGLE, height = MESSAGE_ATTACHMENT_WIDTH_SINGLE } =\n attributes.metadata || {}\n const { url } = attributes\n\n const videoRef = useRef<VideoPlayerHandle>(null)\n const [isOpen, setIsOpen] = useState(false)\n\n function openVideo() {\n if (!isOpen && videoRef.current) {\n videoRef.current.presentFullscreenPlayer()\n videoRef.current.play()\n setIsOpen(true)\n }\n }\n\n function closeVideo() {\n videoRef.current?.pause()\n setIsOpen(false)\n }\n\n const viewRef = useRef<View>(null)\n\n return (\n <View style={styles.container} ref={viewRef}>\n <PlatformPressable\n onPress={openVideo}\n onLongPress={() => !isDeleting && onMessageAttachmentLongPress(attachment)}\n android_ripple={{ color: colors.androidRippleNeutral, foreground: true }}\n accessibilityLabel=\"Play Video\"\n accessibilityHint=\"Press to play video. Long press for more options\"\n disabled={isDeleting}\n >\n <View style={styles.thumbnailOverlay} />\n <Video.Player\n ref={videoRef}\n source={{ uri: url }}\n aspectRatio={width / height}\n style={styles.video}\n onFullscreenPlayerWillDismiss={closeVideo}\n onFullscreenPlayerDidDismiss={closeVideo}\n />\n {!isOpen && !isDeleting && (\n <View style={styles.playContainer}>\n <View style={styles.playCircle}>\n <Icon\n name=\"services.play\"\n style={styles.playIcon}\n accessibilityElementsHidden={true}\n />\n </View>\n </View>\n )}\n {isDeleting && <AttachmentDeletingOverlay />}\n </PlatformPressable>\n </View>\n )\n}\nconst OVERLAY_Z_INDEX = 1\n\nconst useStyles = () => {\n const { colors } = useTheme()\n const overlayBackgroundColor =\n colors.name === 'light'\n ? tokens.fillColorTransparencyDark010\n : tokens.fillColorTransparencyDark030\n\n return StyleSheet.create({\n container: {\n borderRadius: 8,\n overflow: 'hidden',\n },\n video: {\n width: '100%',\n backgroundColor: colors.fillColorNeutral070,\n },\n thumbnailOverlay: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n backgroundColor: overlayBackgroundColor,\n zIndex: OVERLAY_Z_INDEX,\n },\n playContainer: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n justifyContent: 'center',\n alignItems: 'center',\n zIndex: OVERLAY_Z_INDEX + 1,\n },\n playCircle: {\n justifyContent: 'center',\n alignItems: 'center',\n width: 42,\n height: 42,\n borderRadius: 25,\n backgroundColor: colors.fillColorNeutral100Inverted,\n borderColor: colors.borderColorDefaultBase,\n borderWidth: 1,\n },\n playIcon: {\n fontSize: 20,\n },\n })\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planningcenter/chat-react-native",
3
- "version": "3.45.0-rc.1",
3
+ "version": "3.45.0-rc.2",
4
4
  "description": "",
5
5
  "repository": {
6
6
  "type": "git",
@@ -78,5 +78,5 @@
78
78
  "sf-symbols-typescript": "^2.2.0",
79
79
  "typescript": "~6.0.3"
80
80
  },
81
- "gitHead": "4fe204061ac6766858c22a744c8dd808f0b808e6"
81
+ "gitHead": "7756c349c065bd97a28a81e6a0396fc3d2eb2580"
82
82
  }
@@ -0,0 +1,114 @@
1
+ import { DefaultTheme, ThemeProvider } from '@react-navigation/native'
2
+ import { act, fireEvent, render } from '@testing-library/react-native'
3
+ import React, { forwardRef, useImperativeHandle } from 'react'
4
+ import { VideoAttachment } from '../../../../components/conversation/attachments/video_attachment'
5
+ import { DenormalizedMessageAttachmentResource } from '../../../../types/resources/denormalized_attachment_resource'
6
+ import {
7
+ AudioAdapter,
8
+ ChatAdapters,
9
+ ClipboardAdapter,
10
+ ImagePickerAdapter,
11
+ VideoAdapter,
12
+ } from '../../../../utils/native_adapters'
13
+ import { VideoPlayerHandle, VideoPlayerProps } from '../../../../utils/native_adapters/video'
14
+
15
+ const handle: VideoPlayerHandle = {
16
+ play: jest.fn(),
17
+ pause: jest.fn(),
18
+ presentFullscreenPlayer: jest.fn(),
19
+ dismissFullscreen: jest.fn(),
20
+ }
21
+
22
+ const playerRender = jest.fn<void, [VideoPlayerProps]>()
23
+
24
+ const Player = forwardRef<VideoPlayerHandle, VideoPlayerProps>((props, ref) => {
25
+ playerRender(props)
26
+ useImperativeHandle(ref, () => handle)
27
+ return null
28
+ })
29
+
30
+ function latestPlayerProps() {
31
+ return playerRender.mock.calls.at(-1)?.[0]
32
+ }
33
+
34
+ const attachment: DenormalizedMessageAttachmentResource = {
35
+ type: 'MessageAttachment',
36
+ id: '1',
37
+ attributes: {
38
+ filename: 'clip.mp4',
39
+ key: 'clip',
40
+ contentType: 'video/mp4',
41
+ byteSize: 1,
42
+ checksum: 'abc',
43
+ metadata: { width: 100, height: 100 },
44
+ url: 'https://example.com/clip.mp4',
45
+ },
46
+ }
47
+
48
+ describe('VideoAttachment', () => {
49
+ beforeAll(() => {
50
+ ChatAdapters.configure({
51
+ clipboard: new ClipboardAdapter({
52
+ getStringAsync: jest.fn(async () => ''),
53
+ setStringAsync: jest.fn(async () => {}),
54
+ }),
55
+ audio: new AudioAdapter({
56
+ useAudio: () => ({
57
+ play: jest.fn(),
58
+ pause: jest.fn(),
59
+ isPlaying: false,
60
+ duration: 0,
61
+ position: 0,
62
+ AudioPlayer: null,
63
+ }),
64
+ }),
65
+ video: new VideoAdapter({ Player }),
66
+ imagePicker: new ImagePickerAdapter({
67
+ openCameraAsync: async () => ({ canceled: true, assets: null }),
68
+ openImageLibraryAsync: async () => ({ canceled: true, assets: null }),
69
+ }),
70
+ })
71
+ })
72
+
73
+ beforeEach(() => {
74
+ jest.clearAllMocks()
75
+ })
76
+
77
+ function renderAttachment() {
78
+ return render(
79
+ <ThemeProvider value={DefaultTheme}>
80
+ <VideoAttachment
81
+ attachment={attachment}
82
+ onMessageAttachmentLongPress={jest.fn()}
83
+ isDeleting={false}
84
+ />
85
+ </ThemeProvider>
86
+ )
87
+ }
88
+
89
+ it('opens fullscreen and plays once per open', () => {
90
+ const { getByLabelText } = renderAttachment()
91
+
92
+ fireEvent.press(getByLabelText('Play Video'))
93
+ fireEvent.press(getByLabelText('Play Video'))
94
+
95
+ expect(handle.presentFullscreenPlayer).toHaveBeenCalledTimes(1)
96
+ expect(handle.play).toHaveBeenCalledTimes(1)
97
+ })
98
+
99
+ it.each(['onFullscreenPlayerWillDismiss', 'onFullscreenPlayerDidDismiss'] as const)(
100
+ 'pauses and can be reopened after %s',
101
+ dismissEvent => {
102
+ const { getByLabelText } = renderAttachment()
103
+ fireEvent.press(getByLabelText('Play Video'))
104
+
105
+ act(() => latestPlayerProps()?.[dismissEvent]?.())
106
+
107
+ expect(handle.pause).toHaveBeenCalledTimes(1)
108
+
109
+ fireEvent.press(getByLabelText('Play Video'))
110
+
111
+ expect(handle.presentFullscreenPlayer).toHaveBeenCalledTimes(2)
112
+ }
113
+ )
114
+ })
@@ -37,7 +37,7 @@ export function VideoAttachment({
37
37
  }
38
38
  }
39
39
 
40
- function onFullscreenPlayerWillDismiss() {
40
+ function closeVideo() {
41
41
  videoRef.current?.pause()
42
42
  setIsOpen(false)
43
43
  }
@@ -60,7 +60,8 @@ export function VideoAttachment({
60
60
  source={{ uri: url }}
61
61
  aspectRatio={width / height}
62
62
  style={styles.video}
63
- onFullscreenPlayerWillDismiss={onFullscreenPlayerWillDismiss}
63
+ onFullscreenPlayerWillDismiss={closeVideo}
64
+ onFullscreenPlayerDidDismiss={closeVideo}
64
65
  />
65
66
  {!isOpen && !isDeleting && (
66
67
  <View style={styles.playContainer}>