From b3381da1c11301163600a931ee6c481dea3de6f4 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Fri, 13 Sep 2024 12:02:58 -0500 Subject: Image/video border + tweaks (#5324) * Image/video border (#5253) * Update AutoSizedImage.tsx * Update AutoSizedImage.tsx * Update Gallery.tsx * Update ExternalLinkEmbed.tsx * Update MediaPreview.tsx * Update UserAvatar.tsx * Update ExternalLinkEmbed.tsx * Update ExternalPlayerEmbed.tsx * Update ExternalGifEmbed.tsx * Update GifEmbed.tsx * Update ExternalGifEmbed.tsx * Update GifEmbed.tsx * Update UserAvatar.tsx * Update ExternalPlayerEmbed.tsx * Update ExternalPlayerEmbed.tsx * video * Update QuoteEmbed.tsx * Tweaks, abstract components --------- Co-authored-by: Minseo Lee --- src/components/Fill.tsx | 11 ++++ src/components/MediaInsetBorder.tsx | 42 +++++++++++++++ src/components/MediaPreview.tsx | 2 + src/view/com/util/UserAvatar.tsx | 4 +- src/view/com/util/images/AutoSizedImage.tsx | 2 + src/view/com/util/images/Gallery.tsx | 4 +- src/view/com/util/post-embeds/ExternalGifEmbed.tsx | 56 ++++++++++++++------ .../com/util/post-embeds/ExternalLinkEmbed.tsx | 57 ++++++++++++--------- .../com/util/post-embeds/ExternalPlayerEmbed.tsx | 59 ++++++++++++++++++---- src/view/com/util/post-embeds/GifEmbed.tsx | 16 +++++- src/view/com/util/post-embeds/QuoteEmbed.tsx | 15 ++++-- .../VideoEmbedInner/VideoEmbedInnerNative.tsx | 2 + .../VideoEmbedInner/VideoEmbedInnerWeb.tsx | 2 + 13 files changed, 214 insertions(+), 58 deletions(-) create mode 100644 src/components/Fill.tsx create mode 100644 src/components/MediaInsetBorder.tsx (limited to 'src') diff --git a/src/components/Fill.tsx b/src/components/Fill.tsx new file mode 100644 index 000000000..ac74f1660 --- /dev/null +++ b/src/components/Fill.tsx @@ -0,0 +1,11 @@ +import React from 'react' +import {View} from 'react-native' + +import {atoms as a, ViewStyleProp} from '#/alf' + +export function Fill({ + children, + style, +}: {children?: React.ReactNode} & ViewStyleProp) { + return {children} +} diff --git a/src/components/MediaInsetBorder.tsx b/src/components/MediaInsetBorder.tsx new file mode 100644 index 000000000..839d79cae --- /dev/null +++ b/src/components/MediaInsetBorder.tsx @@ -0,0 +1,42 @@ +import React from 'react' + +import {atoms as a, useTheme, ViewStyleProp} from '#/alf' +import {Fill} from '#/components/Fill' + +/** + * Applies and thin border within a bounding box. Used to contrast media from + * bg of the container. + */ +export function MediaInsetBorder({ + children, + style, + opaque, +}: { + children?: React.ReactNode + /** + * Used where this border needs to match adjacent borders, such as in + * external link previews + */ + opaque?: boolean +} & ViewStyleProp) { + const t = useTheme() + const isLight = t.name === 'light' + return ( + + {children} + + ) +} diff --git a/src/components/MediaPreview.tsx b/src/components/MediaPreview.tsx index f2ebb4584..28609c6f4 100644 --- a/src/components/MediaPreview.tsx +++ b/src/components/MediaPreview.tsx @@ -11,6 +11,7 @@ import {Trans} from '@lingui/macro' import {parseTenorGif} from '#/lib/strings/embed-player' import {atoms as a, useTheme} from '#/alf' +import {MediaInsetBorder} from '#/components/MediaInsetBorder' import {Text} from '#/components/Typography' import {PlayButtonIcon} from '#/components/video/PlayButtonIcon' @@ -104,6 +105,7 @@ export function ImageItem({ accessibilityHint={alt} accessibilityLabel="" /> + {children} ) diff --git a/src/view/com/util/UserAvatar.tsx b/src/view/com/util/UserAvatar.tsx index eb46a8bdb..4ad37ebd7 100644 --- a/src/view/com/util/UserAvatar.tsx +++ b/src/view/com/util/UserAvatar.tsx @@ -19,7 +19,7 @@ import {colors} from 'lib/styles' import {isAndroid, isNative, isWeb} from 'platform/detection' import {precacheProfile} from 'state/queries/profile' import {HighPriorityImage} from 'view/com/util/images/Image' -import {tokens, useTheme} from '#/alf' +import {atoms as a, tokens, useTheme} from '#/alf' import { Camera_Filled_Stroke2_Corner0_Rounded as CameraFilled, Camera_Stroke2_Corner0_Rounded as Camera, @@ -27,6 +27,7 @@ import { import {StreamingLive_Stroke2_Corner0_Rounded as Library} from '#/components/icons/StreamingLive' import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash' import {Link} from '#/components/Link' +import {MediaInsetBorder} from '#/components/MediaInsetBorder' import * as Menu from '#/components/Menu' import {ProfileHoverCard} from '#/components/ProfileHoverCard' import {openCamera, openCropper, openPicker} from '../../../lib/media/picker' @@ -240,6 +241,7 @@ let UserAvatar = ({ onLoad={onLoad} /> )} + {alert} ) : ( diff --git a/src/view/com/util/images/AutoSizedImage.tsx b/src/view/com/util/images/AutoSizedImage.tsx index 932a18280..9abbe2875 100644 --- a/src/view/com/util/images/AutoSizedImage.tsx +++ b/src/view/com/util/images/AutoSizedImage.tsx @@ -11,6 +11,7 @@ import {isNative} from '#/platform/detection' import {useLargeAltBadgeEnabled} from '#/state/preferences/large-alt-badge' import {atoms as a, useBreakpoints, useTheme} from '#/alf' import {ArrowsDiagonalOut_Stroke2_Corner0_Rounded as Fullscreen} from '#/components/icons/ArrowsDiagonal' +import {MediaInsetBorder} from '#/components/MediaInsetBorder' import {Text} from '#/components/Typography' export function useImageAspectRatio({ @@ -140,6 +141,7 @@ export function AutoSizedImage({ accessibilityLabel={image.alt} accessibilityHint="" /> + {(hasAlt || isCropped) && !hideBadge ? ( void @@ -46,7 +47,7 @@ export const GalleryItem: FC = ({ onLongPress={onLongPress ? () => onLongPress(index) : undefined} style={[ a.flex_1, - a.rounded_xs, + a.rounded_sm, a.overflow_hidden, t.atoms.bg_contrast_25, imageStyle, @@ -62,6 +63,7 @@ export const GalleryItem: FC = ({ accessibilityHint="" accessibilityIgnoresInvertColors /> + {hasAlt && !hideBadges ? ( - {(!isPrefetched || !isAnimating) && ( // If we have not loaded or are not animating, show the overlay - - - {!isAnimating || !isPlayerActive ? ( // Play button when not animating or not active - - ) : ( - // Activity indicator while gif loads - - )} - - - )} + + {(!isPrefetched || !isAnimating) && ( + + + + {!isAnimating || !isPlayerActive ? ( // Play button when not animating or not active + + ) : ( + // Activity indicator while gif loads + + )} + + )} + ) @@ -171,7 +196,6 @@ const styles = StyleSheet.create({ flex: 1, justifyContent: 'center', alignItems: 'center', - backgroundColor: 'rgba(0,0,0,0.5)', }, overlayLayer: { zIndex: 2, diff --git a/src/view/com/util/post-embeds/ExternalLinkEmbed.tsx b/src/view/com/util/post-embeds/ExternalLinkEmbed.tsx index cc742c8c0..0bd65de8b 100644 --- a/src/view/com/util/post-embeds/ExternalLinkEmbed.tsx +++ b/src/view/com/util/post-embeds/ExternalLinkEmbed.tsx @@ -21,6 +21,7 @@ import {ExternalGifEmbed} from 'view/com/util/post-embeds/ExternalGifEmbed' import {ExternalPlayer} from 'view/com/util/post-embeds/ExternalPlayerEmbed' import {GifEmbed} from 'view/com/util/post-embeds/GifEmbed' import {atoms as a, useTheme} from '#/alf' +import {MediaInsetBorder} from '#/components/MediaInsetBorder' import {Text} from '../text/Text' export const ExternalLinkEmbed = ({ @@ -36,6 +37,7 @@ export const ExternalLinkEmbed = ({ }) => { const {_} = useLingui() const pal = usePalette('default') + const t = useTheme() const {isMobile} = useWebMediaQueries() const externalEmbedPrefs = useExternalEmbedsPrefs() @@ -60,19 +62,30 @@ export const ExternalLinkEmbed = ({ {imageUri && !embedPlayerParams ? ( - + + + + ) : undefined} {embedPlayerParams?.isGif ? ( @@ -81,11 +94,18 @@ export const ExternalLinkEmbed = ({ ) : undefined} children: React.ReactNode }) { - const t = useTheme() - const onShareExternal = useCallback(() => { if (link.uri && isNative) { shareUrl(link.uri) @@ -137,14 +155,7 @@ function LinkWrapper({ asAnchor anchorNoUnderline href={link.uri} - style={[ - a.flex_1, - a.border, - a.rounded_sm, - t.atoms.border_contrast_medium, - style, - ]} - hoverStyle={t.atoms.border_contrast_high} + style={[a.flex_1, a.rounded_sm, style]} onBeforePress={onOpen} onLongPress={onShareExternal}> {children} diff --git a/src/view/com/util/post-embeds/ExternalPlayerEmbed.tsx b/src/view/com/util/post-embeds/ExternalPlayerEmbed.tsx index 111867fc6..a1e509ef4 100644 --- a/src/view/com/util/post-embeds/ExternalPlayerEmbed.tsx +++ b/src/view/com/util/post-embeds/ExternalPlayerEmbed.tsx @@ -25,9 +25,11 @@ import {NavigationProp} from '#/lib/routes/types' import {EmbedPlayerParams, getPlayerAspect} from '#/lib/strings/embed-player' import {isNative} from '#/platform/detection' import {useExternalEmbedsPrefs} from '#/state/preferences' -import {atoms as a} from '#/alf' +import {atoms as a, useTheme} from '#/alf' import {useDialogControl} from '#/components/Dialog' import {EmbedConsentDialog} from '#/components/dialogs/EmbedConsent' +import {Fill} from '#/components/Fill' +import {MediaInsetBorder} from '#/components/MediaInsetBorder' import {PlayButtonIcon} from '#/components/video/PlayButtonIcon' import {EventStopper} from '../EventStopper' @@ -106,6 +108,16 @@ function Player({ style={styles.webview} setSupportMultipleWindows={false} // Prevent any redirects from opening a new window (ads) /> + + ) } @@ -118,6 +130,7 @@ export function ExternalPlayer({ link: AppBskyEmbedExternal.ViewExternal params: EmbedPlayerParams }) { + const t = useTheme() const navigation = useNavigation() const insets = useSafeAreaInsets() const windowDims = useWindowDimensions() @@ -211,13 +224,38 @@ export function ExternalPlayer({ onAccept={onAcceptConsent} /> - + {link.thumb && (!isPlayerActive || isLoading) && ( - + <> + + + + )} }) { + const t = useTheme() const {_} = useLingui() const autoplayDisabled = useAutoplayDisabled() @@ -138,6 +139,17 @@ export function GifEmbed({ accessibilityHint={_(msg`Animated GIF`)} accessibilityLabel={parsedAlt.alt} /> + {!playerState.isPlaying && ( + + )} + {!hideAlt && parsedAlt.isPreferred && } diff --git a/src/view/com/util/post-embeds/QuoteEmbed.tsx b/src/view/com/util/post-embeds/QuoteEmbed.tsx index 87a6edebd..d50119025 100644 --- a/src/view/com/util/post-embeds/QuoteEmbed.tsx +++ b/src/view/com/util/post-embeds/QuoteEmbed.tsx @@ -33,7 +33,7 @@ import {InfoCircleIcon} from 'lib/icons' import {makeProfileLink} from 'lib/routes/links' import {precacheProfile} from 'state/queries/profile' import {ComposerOptsQuote} from 'state/shell/composer' -import {atoms as a} from '#/alf' +import {atoms as a, useTheme} from '#/alf' import {RichText} from '#/components/RichText' import {ContentHider} from '../../../../components/moderation/ContentHider' import {PostAlerts} from '../../../../components/moderation/PostAlerts' @@ -56,6 +56,7 @@ export function MaybeQuoteEmbed({ allowNestedQuotes?: boolean viewContext?: QuoteEmbedViewContext }) { + const t = useTheme() const pal = usePalette('default') const {currentAccount} = useSession() if ( @@ -75,7 +76,8 @@ export function MaybeQuoteEmbed({ ) } else if (AppBskyEmbedRecord.isViewBlocked(embed.record)) { return ( - + Blocked @@ -84,7 +86,8 @@ export function MaybeQuoteEmbed({ ) } else if (AppBskyEmbedRecord.isViewNotFound(embed.record)) { return ( - + Deleted @@ -96,7 +99,8 @@ export function MaybeQuoteEmbed({ ? embed.record.uri.includes(currentAccount.did) : false return ( - + {isViewerOwner ? ( @@ -169,6 +173,7 @@ export function QuoteEmbed({ allowNestedQuotes?: boolean viewContext?: QuoteEmbedViewContext }) { + const t = useTheme() const queryClient = useQueryClient() const pal = usePalette('default') const itemUrip = new AtUri(quote.uri) @@ -214,7 +219,7 @@ export function QuoteEmbed({ return ( + ) } diff --git a/src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerWeb.tsx b/src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerWeb.tsx index 441be7572..5f569a818 100644 --- a/src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerWeb.tsx +++ b/src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerWeb.tsx @@ -4,6 +4,7 @@ import {AppBskyEmbedVideo} from '@atproto/api' import Hls from 'hls.js' import {atoms as a} from '#/alf' +import {MediaInsetBorder} from '#/components/MediaInsetBorder' import {Controls} from './VideoWebControls' export function VideoEmbedInnerWeb({ @@ -119,6 +120,7 @@ export function VideoEmbedInnerWeb({ fullscreenRef={containerRef} hasSubtitleTrack={hasSubtitleTrack} /> + ) -- cgit 1.4.1