From 84738af622749eced4dab36c4bc952447a585063 Mon Sep 17 00:00:00 2001 From: Mike Maxim Date: Thu, 15 Aug 2024 10:31:33 -0400 Subject: [PATCH 1/5] Revert "hacky workaround for zoom not rendering (#27573)" This reverts commit acf699079b1fa5275ac8ddb9c0253a1bfa807803. --- shared/common-adapters/zoomable-box.ios.tsx | 12 +++------- .../common-adapters/zoomable-image.native.tsx | 23 ++++++++----------- 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/shared/common-adapters/zoomable-box.ios.tsx b/shared/common-adapters/zoomable-box.ios.tsx index ea77e0bd8992..7d1d7b39b482 100644 --- a/shared/common-adapters/zoomable-box.ios.tsx +++ b/shared/common-adapters/zoomable-box.ios.tsx @@ -127,11 +127,6 @@ export const ZoomableBox = (props: Props) => { }) const taps = Gesture.Exclusive(doubleTap, singleTap) - // this is nasty but i need a way to force this component to render correctly. Passing new zoomScale - // won't necessarily cause it to adopt it - const old = zoomScale ?? 1 - const fixedZoomScale = old === 1 ? old : old + Math.random() * 0.0001 - return ( { onTouchEnd={onSwipe ? onTouchEnd : undefined} onScroll={e => { curScaleRef.current = e.nativeEvent?.zoomScale ?? 0 - const val = { + props.onZoom?.({ height: e.nativeEvent?.contentSize.height ?? 0, scale: e.nativeEvent?.zoomScale ?? 0, width: e.nativeEvent?.contentSize.width ?? 0, x: e.nativeEvent?.contentOffset.x ?? 0, y: e.nativeEvent?.contentOffset.y ?? 0, - } - props.onZoom?.(val) + }) }} scrollEventThrottle={16} scrollsToTop={false} showsHorizontalScrollIndicator={props.showsHorizontalScrollIndicator} showsVerticalScrollIndicator={props.showsVerticalScrollIndicator} style={props.style} - zoomScale={fixedZoomScale} + zoomScale={zoomScale} /> ) diff --git a/shared/common-adapters/zoomable-image.native.tsx b/shared/common-adapters/zoomable-image.native.tsx index bf559f75df02..043323db6f84 100644 --- a/shared/common-adapters/zoomable-image.native.tsx +++ b/shared/common-adapters/zoomable-image.native.tsx @@ -91,20 +91,17 @@ const ZoomableImage = (p: Props) => { [size, loading] ) const measuredStyle = size ? imageSize : dummySize - const content = ( <> - {src ? ( - - ) : null} + {loading ? ( @@ -115,7 +112,7 @@ const ZoomableImage = (p: Props) => { return ( Date: Thu, 15 Aug 2024 10:31:51 -0400 Subject: [PATCH 2/5] Revert "fix image zoom issues on mobile (#27285)" This reverts commit b25bbdc9d30b58b4495b630745af1acb1fbf0eaf. --- shared/common-adapters/image2.d.ts | 1 - shared/common-adapters/image2.native.tsx | 19 +- .../common-adapters/zoomable-box.android.tsx | 172 +++++++++--------- shared/common-adapters/zoomable-box.d.ts | 6 - shared/common-adapters/zoomable-box.ios.tsx | 59 +++--- .../common-adapters/zoomable-image.native.tsx | 143 ++++++--------- shared/profile/edit-avatar/index.native.tsx | 7 +- 7 files changed, 168 insertions(+), 239 deletions(-) diff --git a/shared/common-adapters/image2.d.ts b/shared/common-adapters/image2.d.ts index 1c74414e1dd4..4226fcc4d059 100644 --- a/shared/common-adapters/image2.d.ts +++ b/shared/common-adapters/image2.d.ts @@ -8,7 +8,6 @@ export type Props = { showLoadingStateUntilLoaded?: boolean onLoad?: (e: {target?: unknown; source?: {width: number; height: number}}) => void onError?: () => void - allowDownscaling?: boolean } declare const Image2: (p: Props) => React.ReactNode diff --git a/shared/common-adapters/image2.native.tsx b/shared/common-adapters/image2.native.tsx index 32e3a76c6c73..698cac9eaa2c 100644 --- a/shared/common-adapters/image2.native.tsx +++ b/shared/common-adapters/image2.native.tsx @@ -4,15 +4,7 @@ import type {Props} from './image2' import {Image, type ImageLoadEventData} from 'expo-image' const Image2 = (p: Props) => { - const { - showLoadingStateUntilLoaded, - src, - onLoad, - onError, - style, - contentFit = 'contain', - allowDownscaling, - } = p + const {showLoadingStateUntilLoaded, src, onLoad, onError, style, contentFit = 'contain'} = p // if we don't have showLoadingStateUntilLoaded then just mark as loaded and ignore this state const [loading, setLoading] = React.useState(!showLoadingStateUntilLoaded) const [lastSrc, setLastSrc] = React.useState(src) @@ -40,14 +32,7 @@ const Image2 = (p: Props) => { return ( <> - + {showLoadingStateUntilLoaded && loading ? : null} ) diff --git a/shared/common-adapters/zoomable-box.android.tsx b/shared/common-adapters/zoomable-box.android.tsx index 81f3a2fa69b0..20027edad306 100644 --- a/shared/common-adapters/zoomable-box.android.tsx +++ b/shared/common-adapters/zoomable-box.android.tsx @@ -6,9 +6,9 @@ import Animated, { useAnimatedReaction, useDerivedValue, withTiming, + withSpring, cancelAnimation, runOnJS, - withDecay, } from 'react-native-reanimated' import {View, type LayoutChangeEvent} from 'react-native' import {Gesture, GestureDetector} from 'react-native-gesture-handler' @@ -18,7 +18,7 @@ const needDiff = Styles.dimensionWidth / 3 // mostly based on https://github.com/intergalacticspacehighway/react-native-reanimated-zoom export function ZoomableBox(props: Props) { - const {children, minZoom = 1, maxZoom = 10, style, zoomScale} = props + const {children, minZoom = 1, maxZoom = 10, style} = props const {onZoom, contentContainerStyle, onLayout: _onLayout, onSwipe, onTap: _onTap} = props const onTap = React.useCallback(() => { @@ -27,11 +27,9 @@ export function ZoomableBox(props: Props) { const translationX = useSharedValue(0) const translationY = useSharedValue(0) - const velocityX = useSharedValue(0) - const velocityY = useSharedValue(0) const originX = useSharedValue(0) const originY = useSharedValue(0) - const scale = useSharedValue(zoomScale ?? 1) + const scale = useSharedValue(1) const isPinching = useSharedValue(false) const isZoomed = useSharedValue(false) const viewHeight = useSharedValue(0) @@ -45,24 +43,17 @@ export function ZoomableBox(props: Props) { const panTranslateX = useSharedValue(0) const panTranslateY = useSharedValue(0) const panSwipedCounter = useSharedValue(0) - const panFingers = useSharedValue(0) const containerWidth = useSharedValue(0) const containerHeight = useSharedValue(0) - const lastZoomScaleRef = React.useRef() - if (lastZoomScaleRef.current !== zoomScale && zoomScale !== undefined) { - lastZoomScaleRef.current = zoomScale - scale.value = lastZoomScaleRef.current - } - const gesture = React.useMemo(() => { const resetZoomState = () => { 'worklet' // reset all state - translationX.value = 0 - translationY.value = 0 - scale.value = withTiming(zoomScale ?? 1) + translationX.value = withTiming(0) + translationY.value = withTiming(0) + scale.value = withTiming(1) originX.value = 0 originY.value = 0 isPinching.value = false @@ -75,40 +66,53 @@ export function ZoomableBox(props: Props) { // we only activate pan handler when the image is zoomed or user is not pinching const pan = Gesture.Pan() - .averageTouches(true) - .onStart(e => { - if (!isZoomed.value) { - return - } + .onStart(() => { + if (isPinching.value || !isZoomed.value) return + cancelAnimation(translationX) cancelAnimation(translationY) cancelAnimation(scale) prevTranslationX.value = translationX.value prevTranslationY.value = translationY.value - panFingers.value = e.numberOfPointers }) .onUpdate(e => { - // if we're done panning ignore us letting go - if (e.numberOfPointers < panFingers.value) { - return - } - panFingers.value = e.numberOfPointers - if (!isZoomed.value) { + if (isPinching.value || !isZoomed.value) { panTranslateX.value = e.translationX panTranslateY.value = e.translationY } else { - translationX.value = prevTranslationX.value + e.translationX - translationY.value = prevTranslationY.value + e.translationY - velocityX.value = e.velocityX - velocityY.value = e.velocityY + // imagine what happens to pixels when we zoom in. (they get multiplied by x times scale) + const maxTranslateX = (viewWidth.value / 2) * scale.value - viewWidth.value / 2 + const minTranslateX = -maxTranslateX + + const maxTranslateY = (viewHeight.value / 2) * scale.value - viewHeight.value / 2 + const minTranslateY = -maxTranslateY + + const nextTranslateX = prevTranslationX.value + e.translationX - panTranslateX.value + const nextTranslateY = prevTranslationY.value + e.translationY - panTranslateY.value + + if (nextTranslateX > maxTranslateX) { + translationX.value = maxTranslateX + } else if (nextTranslateX < minTranslateX) { + translationX.value = minTranslateX + } else { + translationX.value = nextTranslateX + } + + if (nextTranslateY > maxTranslateY) { + translationY.value = maxTranslateY + } else if (nextTranslateY < minTranslateY) { + translationY.value = minTranslateY + } else { + translationY.value = nextTranslateY + } } }) - .onEnd(e => { + .onEnd(() => { panSwipedCounter.value++ - panFingers.value = 0 - translationX.value = withDecay({deceleration: 0.9, velocity: e.velocityX}) - translationY.value = withDecay({deceleration: 0.9, velocity: e.velocityY}) + if (isPinching.value || !isZoomed.value) return + panTranslateX.value = 0 + panTranslateY.value = 0 }) const pinch = Gesture.Pinch() @@ -120,33 +124,48 @@ export function ZoomableBox(props: Props) { offsetScale.value = scale.value }) .onUpdate(e => { - const newScale = prevScale.value * e.scale - if (newScale < minZoom || newScale > maxZoom) return - - scale.value = prevScale.value * e.scale - - // maybe this is always true... but not changing this now - // eslint-disable-next-line - if (isPinching.value) { - // translate the image to the focal point as we're zooming - translationX.value = - prevTranslationX.value + - -1 * ((scale.value - offsetScale.value) * (originX.value - viewWidth.value / 2)) - translationY.value = - prevTranslationY.value + - -1 * ((scale.value - offsetScale.value) * (originY.value - viewHeight.value / 2)) + // when pointer is 1 we don't want to translate origin + if (e.numberOfPointers === 1 && isPinching.value) { + prevTranslationX.value = translationX.value + prevTranslationY.value = translationY.value + isPinching.value = false + } else if (e.numberOfPointers === 2) { + const newScale = prevScale.value * e.scale + + if (newScale < minZoom || newScale > maxZoom) return + + scale.value = prevScale.value * e.scale + + // reset the origin + if (!isPinching.value) { + isPinching.value = true + originX.value = e.focalX + originY.value = e.focalY + prevTranslationX.value = translationX.value + prevTranslationY.value = translationY.value + offsetScale.value = scale.value + } + + // maybe this is always true... but not changing this now + // eslint-disable-next-line + if (isPinching.value) { + // translate the image to the focal point as we're zooming + translationX.value = + prevTranslationX.value + + -1 * ((scale.value - offsetScale.value) * (originX.value - viewWidth.value / 2)) + translationY.value = + prevTranslationY.value + + -1 * ((scale.value - offsetScale.value) * (originY.value - viewHeight.value / 2)) + } } }) .onEnd(() => { isPinching.value = false prevTranslationX.value = translationX.value prevTranslationY.value = translationY.value - // stop pan - panFingers.value = 3 - if (zoomScale !== undefined) { - if (scale.value < zoomScale) { - resetZoomState() - } + + if (scale.value < 1.1) { + resetZoomState() } }) @@ -161,7 +180,7 @@ export function ZoomableBox(props: Props) { .numberOfTaps(2) .onStart(e => { // if zoomed in or zoomed out, we want to reset - if (isZoomed.value) { + if (scale.value !== 1) { resetZoomState() } else { const zoom = 3 @@ -194,15 +213,15 @@ export function ZoomableBox(props: Props) { translationX, translationY, panSwipedCounter, - panFingers, - zoomScale, - velocityX, - velocityY, ]) useDerivedValue(() => { - isZoomed.value = scale.value !== zoomScale - }, [zoomScale]) + if (scale.value > 1 && !isZoomed.value) { + isZoomed.value = true + } else if (scale.value === 1 && isZoomed.value) { + isZoomed.value = false + } + }, []) const updateOnZoom = React.useCallback( (scale: number, px: number, py: number) => { @@ -210,20 +229,14 @@ export function ZoomableBox(props: Props) { const width = scale * viewWidth.value const x = width / 2 - px - containerWidth.value / 2 const y = height / 2 - py - containerHeight.value / 2 - onZoom?.({ - height, - scale, - width, - x, - y, - }) + onZoom?.({height, scale, width, x, y}) }, [onZoom, viewHeight, viewWidth, containerHeight, containerWidth] ) useDerivedValue(() => { runOnJS(updateOnZoom)(scale.value, translationX.value, translationY.value) - }, [updateOnZoom]) + }, []) const lastPanSwipedCounter = useSharedValue(0) useAnimatedReaction( @@ -246,22 +259,10 @@ export function ZoomableBox(props: Props) { const as = useAnimatedStyle(() => { return { - position: 'absolute', transform: [ - // pan - {translateX: translationX.value}, - {translateY: translationY.value}, - // center again - {translateX: containerWidth.value / 2 - (viewWidth.value * scale.value) / 2}, - {translateY: containerHeight.value / 2 - (viewHeight.value * scale.value) / 2}, - // Move to center - {translateX: -viewWidth.value / 2}, - {translateY: -viewHeight.value / 2}, - // Apply scale + {translateX: withSpring(translationX.value, {damping: 2000, stiffness: 1000})}, + {translateY: withSpring(translationY.value, {damping: 2000, stiffness: 1000})}, {scale: scale.value}, - // Move back to upper left - {translateX: viewWidth.value / 2}, - {translateY: viewHeight.value / 2}, ], } }, []) @@ -283,6 +284,7 @@ export function ZoomableBox(props: Props) { ) const memoizedStyle = React.useMemo(() => [as, contentContainerStyle], [as, contentContainerStyle]) + return ( diff --git a/shared/common-adapters/zoomable-box.d.ts b/shared/common-adapters/zoomable-box.d.ts index ccef9a476c81..b03444dbb669 100644 --- a/shared/common-adapters/zoomable-box.d.ts +++ b/shared/common-adapters/zoomable-box.d.ts @@ -6,12 +6,6 @@ export type Props = { maxZoom?: number minZoom?: number zoomScale?: number - contentSize?: - | { - width: number - height: number - } - | undefined onLayout?: (e: Partial) => void onZoom?: (e: {height: number; width: number; x: number; y: number; scale: number}) => void style?: Styles.StylesCrossPlatform diff --git a/shared/common-adapters/zoomable-box.ios.tsx b/shared/common-adapters/zoomable-box.ios.tsx index 7d1d7b39b482..2c17ebb55de2 100644 --- a/shared/common-adapters/zoomable-box.ios.tsx +++ b/shared/common-adapters/zoomable-box.ios.tsx @@ -8,7 +8,7 @@ import {runOnJS} from 'react-native-reanimated' const Kb = {ScrollView} export const ZoomableBox = (props: Props) => { - const {onSwipe, onLayout, onTap: _onTap, zoomScale, contentSize, children, contentContainerStyle} = props + const {onSwipe, onLayout, onTap: _onTap} = props const {width: windowWidth} = useWindowDimensions() const needDiff = windowWidth / 3 const onTap = React.useCallback(() => { @@ -37,7 +37,7 @@ export const ZoomableBox = (props: Props) => { if (maxTouches !== 1) { return } - const scaleDiff = Math.abs((zoomScale ?? 1) - curScaleRef.current) + const scaleDiff = Math.abs(1 - curScaleRef.current) if (scaleDiff > 0.1) { return } @@ -47,7 +47,7 @@ export const ZoomableBox = (props: Props) => { onSwipe?.(true) } }, - [onSwipe, needDiff, zoomScale] + [onSwipe, needDiff] ) const widthRef = React.useRef(0) @@ -62,8 +62,7 @@ export const ZoomableBox = (props: Props) => { ) const ref = React.useRef(null) - - const getScroll = React.useCallback(() => { + const onDoubleTap = React.useCallback(() => { const scroll = ref.current as unknown as null | { getScrollResponder?: | undefined @@ -79,38 +78,23 @@ export const ZoomableBox = (props: Props) => { }) => void }) } - return scroll + scroll?.getScrollResponder?.()?.scrollResponderZoomTo( + curScaleRef.current > 1.01 + ? { + animated: true, + height: 2000, + width: 2000, + } + : { + animated: true, + height: heightRef.current / 4, + width: widthRef.current / 4, + x: widthRef.current / 4, + y: heightRef.current / 4, + } + ) }, []) - const onResetZoom = React.useCallback(() => { - if (!contentSize) return - const scroll = getScroll() - scroll?.getScrollResponder?.()?.scrollResponderZoomTo({ - animated: true, - height: contentSize.height, - width: contentSize.width, - x: 0, - y: 0, - }) - }, [contentSize, getScroll]) - - const onDoubleTap = React.useCallback(() => { - const zoomOut = curScaleRef.current > (zoomScale ?? 1) - if (zoomOut) { - onResetZoom() - } else { - const scroll = getScroll() - scroll?.getScrollResponder?.()?.scrollResponderZoomTo({ - animated: true, - height: (contentSize?.height ?? 100) / 4, - width: (contentSize?.width ?? 100) / 4, - // not correct - x: ((contentSize?.width ?? 100) - widthRef.current) / 2, - y: ((contentSize?.height ?? 100) - heightRef.current) / 2, - }) - } - }, [contentSize, zoomScale, onResetZoom, getScroll]) - const singleTap = Gesture.Tap() .maxDuration(250) .numberOfTaps(1) @@ -134,8 +118,8 @@ export const ZoomableBox = (props: Props) => { centerContent={true} alwaysBounceVertical={false} bounces={props.bounces} - children={children} - contentContainerStyle={contentContainerStyle} + children={props.children} + contentContainerStyle={props.contentContainerStyle} indicatorStyle="white" maximumZoomScale={props.maxZoom || 10} minimumZoomScale={props.minZoom || 1} @@ -157,7 +141,6 @@ export const ZoomableBox = (props: Props) => { showsHorizontalScrollIndicator={props.showsHorizontalScrollIndicator} showsVerticalScrollIndicator={props.showsVerticalScrollIndicator} style={props.style} - zoomScale={zoomScale} /> ) diff --git a/shared/common-adapters/zoomable-image.native.tsx b/shared/common-adapters/zoomable-image.native.tsx index 043323db6f84..04e86ded1e63 100644 --- a/shared/common-adapters/zoomable-image.native.tsx +++ b/shared/common-adapters/zoomable-image.native.tsx @@ -1,9 +1,9 @@ import * as React from 'react' import * as Styles from '@/styles' -import {type LayoutChangeEvent} from 'react-native' import {ZoomableBox} from './zoomable-box' import Image2 from './image2.native' import type {Props} from './zoomable-image' +import {type LayoutChangeEvent} from 'react-native' import ProgressIndicator from './progress-indicator.native' import {Box2} from './box' @@ -14,117 +14,70 @@ const Kb = { ZoomableBox, } -const dummySize = {height: 1, width: 1} - const ZoomableImage = (p: Props) => { const {src, style, onChanged, onLoaded, onSwipe, onTap, onError} = p + const onZoom = onChanged const [boxW, setBoxW] = React.useState(0) const [boxH, setBoxH] = React.useState(0) const [loading, setLoading] = React.useState(true) const [lastSrc, setLastSrc] = React.useState(src) - const [size, setSize] = React.useState(undefined) - const [scale, setScale] = React.useState(1) - - const onZoom = onChanged - - const onLayout = React.useCallback((e: Partial) => { - if (!e.nativeEvent) return - const {width, height} = e.nativeEvent.layout - setBoxW(width) - setBoxH(height) - }, []) - const onLoad = React.useCallback( (e: {source?: {width: number; height: number}}) => { - if (!e.source) { - return - } - setSize(e.source) + if (!e.source) return + setLoading(false) onLoaded?.() }, [onLoaded] ) - const initialZoomRef = React.useRef(false) - React.useEffect(() => { - if (initialZoomRef.current || !size || !boxW || !boxH) { - return - } - initialZoomRef.current = true - const sizeRatio = size.width / size.height - const boxRatio = boxW / boxH - const zoom = sizeRatio > boxRatio ? boxW / size.width : boxH / size.height - - // if zoom is the same we still calc this - setScale(zoom + 0.1) - setTimeout(() => { - setScale(zoom) - setTimeout(() => { - setLoading(false) - }, 10) - }, 0) - }, [boxW, boxH, size]) - if (lastSrc !== src) { setLastSrc(src) setLoading(true) - initialZoomRef.current = false } - const imageSize = React.useMemo( - () => - size - ? Styles.isAndroid - ? { - backgroundColor: Styles.globalColors.black, - height: size.height, - opacity: loading ? 0 : 1, - position: 'relative', - width: size.width, - } - : { - height: size.height, - opacity: loading ? 0 : 1, - width: size.width, - } - : undefined, - [size, loading] - ) - const measuredStyle = size ? imageSize : dummySize - const content = ( - <> - - {loading ? ( - - - - ) : null} - - ) + const boxOnLayout = React.useCallback((e: Partial) => { + if (!e.nativeEvent) return + const {width, height} = e.nativeEvent.layout + setBoxW(width) + setBoxH(height) + }, []) + + // in order for the images to not get downscaled we have to make it larger and then transform it + const manualScale = 5 return ( - {content} + + + + {loading ? ( + + + + ) : null} ) } @@ -132,11 +85,29 @@ const ZoomableImage = (p: Props) => { const styles = Styles.styleSheetCreate( () => ({ + contentContainerStyle: { + alignContent: 'center', + height: '100%', + justifyContent: 'center', + maxHeight: '100%', + maxWidth: '100%', + width: '100%', + }, + image: { + height: '100%', + width: '100%', + }, + imageAndroid: {flexGrow: 1}, progress: { left: '50%', position: 'absolute', top: '50%', }, + zoomableBoxContainerAndroid: { + flex: 1, + overflow: 'hidden', + position: 'relative', + }, }) as const ) diff --git a/shared/profile/edit-avatar/index.native.tsx b/shared/profile/edit-avatar/index.native.tsx index a2ddc13bcce5..9ad61dcaba71 100644 --- a/shared/profile/edit-avatar/index.native.tsx +++ b/shared/profile/edit-avatar/index.native.tsx @@ -151,8 +151,7 @@ class AvatarUpload extends React.Component { ) : null } @@ -270,10 +269,6 @@ const styles = Kb.Styles.styleSheetCreate( flexReallyGrow: { flexGrow: 1000, }, - image: { - overflow: 'hidden', - position: 'relative', - }, placeholder: { alignItems: 'center', backgroundColor: Kb.Styles.globalColors.black_05, From 6607d627be60ea5037c968be3e00cd5ecf4d7fc0 Mon Sep 17 00:00:00 2001 From: Mike Maxim Date: Thu, 15 Aug 2024 11:00:44 -0400 Subject: [PATCH 3/5] 6.4.0 --- go/libkb/version.go | 2 +- shared/android/app/build.gradle | 2 +- shared/desktop/CHANGELOG.txt | 9 ++------- shared/ios/Keybase/Info.plist | 2 +- shared/ios/KeybaseShare/Info.plist | 2 +- 5 files changed, 6 insertions(+), 11 deletions(-) diff --git a/go/libkb/version.go b/go/libkb/version.go index 9528c9354ba4..cc49f30461c5 100644 --- a/go/libkb/version.go +++ b/go/libkb/version.go @@ -4,4 +4,4 @@ package libkb // Version is the current version (should be MAJOR.MINOR.PATCH) -const Version = "6.3.2" +const Version = "6.4.0" diff --git a/shared/android/app/build.gradle b/shared/android/app/build.gradle index 28570961a1df..5694bda25ae6 100644 --- a/shared/android/app/build.gradle +++ b/shared/android/app/build.gradle @@ -3,7 +3,7 @@ apply plugin: "com.facebook.react" apply plugin: 'com.github.triplet.play' // KB: app version -def VERSION_NAME = "6.3.2" +def VERSION_NAME = "6.4.0" // KB: Number of commits, like ios Integer getVersionCode() { diff --git a/shared/desktop/CHANGELOG.txt b/shared/desktop/CHANGELOG.txt index 295adee204a4..b1ec2d603fc0 100644 --- a/shared/desktop/CHANGELOG.txt +++ b/shared/desktop/CHANGELOG.txt @@ -1,8 +1,3 @@ -All platforms: +• Improvements for chat attachments +• Bug fixes -Desktop: -• Screenshots of the app disabled by default - -iOS: - -Android: diff --git a/shared/ios/Keybase/Info.plist b/shared/ios/Keybase/Info.plist index 6de287fb81e9..2ffe1827b573 100644 --- a/shared/ios/Keybase/Info.plist +++ b/shared/ios/Keybase/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 6.3.2 + 6.4.0 CFBundleSignature ???? CFBundleURLTypes diff --git a/shared/ios/KeybaseShare/Info.plist b/shared/ios/KeybaseShare/Info.plist index 4763d80ca81d..44d5a03568a9 100644 --- a/shared/ios/KeybaseShare/Info.plist +++ b/shared/ios/KeybaseShare/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType XPC! CFBundleShortVersionString - 6.3.2 + 6.4.0 CFBundleVersion 1 NSExtension From d2e862cc852fae1716816a2657ea69d6c419be98 Mon Sep 17 00:00:00 2001 From: Mike Maxim Date: Thu, 15 Aug 2024 11:29:04 -0400 Subject: [PATCH 4/5] fix s3 multi --- go/chat/s3/multi.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/go/chat/s3/multi.go b/go/chat/s3/multi.go index 2fd68efa6730..8d48711006e5 100644 --- a/go/chat/s3/multi.go +++ b/go/chat/s3/multi.go @@ -121,6 +121,7 @@ func (b *Bucket) InitMulti(ctx context.Context, key string, contType string, per "Content-Length": {"0"}, "x-amz-acl": {string(perm)}, } + b.addTokenHeader(headers) params := map[string][]string{ "uploads": {""}, } @@ -164,6 +165,7 @@ func (m *Multi) putPart(ctx context.Context, n int, r io.ReadSeeker, partSize in "Content-Length": {strconv.FormatInt(partSize, 10)}, "Content-MD5": {md5b64}, } + b.addTokenHeader(headers) params := map[string][]string{ "uploadId": {m.UploadID}, "partNumber": {strconv.FormatInt(int64(n), 10)}, From 3212f60cc53861a56a7442cf1f5f3987b7e5bc0b Mon Sep 17 00:00:00 2001 From: Mike Maxim Date: Thu, 15 Aug 2024 11:43:52 -0400 Subject: [PATCH 5/5] fix s3 multi p2 --- go/chat/s3/multi.go | 43 ++++++++++++++++++++++++++++--------------- go/chat/s3/s3.go | 34 ++++++++++++++++++++++++++-------- 2 files changed, 54 insertions(+), 23 deletions(-) diff --git a/go/chat/s3/multi.go b/go/chat/s3/multi.go index 8d48711006e5..5d4f74fd29dd 100644 --- a/go/chat/s3/multi.go +++ b/go/chat/s3/multi.go @@ -57,11 +57,14 @@ func (b *Bucket) ListMulti(ctx context.Context, prefix, delim string) (multis [] "prefix": {prefix}, "delimiter": {delim}, } + headers := map[string][]string{} + b.addTokenHeader(headers) for attempt := b.S3.AttemptStrategy.Start(); attempt.Next(); { req := &request{ - method: "GET", - bucket: b.Name, - params: params, + method: "GET", + bucket: b.Name, + params: params, + headers: headers, } var resp listMultiResp err := b.S3.query(ctx, req, &resp) @@ -165,7 +168,7 @@ func (m *Multi) putPart(ctx context.Context, n int, r io.ReadSeeker, partSize in "Content-Length": {strconv.FormatInt(partSize, 10)}, "Content-MD5": {md5b64}, } - b.addTokenHeader(headers) + m.Bucket.addTokenHeader(headers) params := map[string][]string{ "uploadId": {m.UploadID}, "partNumber": {strconv.FormatInt(int64(n), 10)}, @@ -249,13 +252,17 @@ func (m *Multi) ListParts(ctx context.Context) ([]Part, error) { "uploadId": {m.UploadID}, "max-parts": {strconv.FormatInt(int64(listPartsMax), 10)}, } + headers := map[string][]string{} + m.Bucket.addTokenHeader(headers) + var parts partSlice for attempt := m.Bucket.S3.AttemptStrategy.Start(); attempt.Next(); { req := &request{ - method: "GET", - bucket: m.Bucket.Name, - path: m.Key, - params: params, + method: "GET", + bucket: m.Bucket.Name, + path: m.Key, + params: params, + headers: headers, } var resp listPartsResp err := m.Bucket.S3.query(ctx, req, &resp) @@ -385,15 +392,17 @@ func (m *Multi) Complete(ctx context.Context, parts []Part) error { // Setting Content-Length prevents breakage on DreamObjects for attempt := m.Bucket.S3.AttemptStrategy.Start(); attempt.Next(); { + headers := map[string][]string{ + "Content-Length": {strconv.Itoa(len(data))}, + } + m.Bucket.addTokenHeader(headers) req := &request{ method: "POST", bucket: m.Bucket.Name, path: m.Key, params: params, payload: bytes.NewReader(data), - headers: map[string][]string{ - "Content-Length": {strconv.Itoa(len(data))}, - }, + headers: headers, } resp := &completeResponse{} @@ -434,12 +443,16 @@ func (m *Multi) Abort(ctx context.Context) error { params := map[string][]string{ "uploadId": {m.UploadID}, } + headers := map[string][]string{} + m.Bucket.addTokenHeader(headers) + for attempt := m.Bucket.S3.AttemptStrategy.Start(); attempt.Next(); { req := &request{ - method: "DELETE", - bucket: m.Bucket.Name, - path: m.Key, - params: params, + method: "DELETE", + bucket: m.Bucket.Name, + path: m.Key, + params: params, + headers: headers, } err := m.Bucket.S3.query(ctx, req, nil) if shouldRetry(err) && attempt.HasNext() { diff --git a/go/chat/s3/s3.go b/go/chat/s3/s3.go index ece5cb31486e..032f2e23caa6 100644 --- a/go/chat/s3/s3.go +++ b/go/chat/s3/s3.go @@ -225,10 +225,14 @@ func (b *Bucket) PutBucket(ctx context.Context, perm ACL) error { // // See http://goo.gl/GoBrY for details. func (b *Bucket) DelBucket() (err error) { + headers := map[string][]string{} + b.addTokenHeader(headers) + req := &request{ - method: "DELETE", - bucket: b.Name, - path: "/", + method: "DELETE", + bucket: b.Name, + path: "/", + headers: headers, } for attempt := b.S3.AttemptStrategy.Start(); attempt.Next(); { err = b.S3.query(context.Background(), req, nil) @@ -321,10 +325,14 @@ func (b *Bucket) GetResponseWithHeaders(ctx context.Context, path string, header // Exists checks whether or not an object exists on an S3 bucket using a HEAD request. func (b *Bucket) Exists(path string) (exists bool, err error) { + headers := map[string][]string{} + b.addTokenHeader(headers) + req := &request{ - method: "HEAD", - bucket: b.Name, - path: path, + method: "HEAD", + bucket: b.Name, + path: path, + headers: headers, } err = b.S3.prepare(req) if err != nil { @@ -543,6 +551,7 @@ func (b *Bucket) PutBucketSubresource(subresource string, r io.Reader, length in headers := map[string][]string{ "Content-Length": {strconv.FormatInt(length, 10)}, } + b.addTokenHeader(headers) req := &request{ path: "/", method: "PUT", @@ -559,6 +568,9 @@ func (b *Bucket) PutBucketSubresource(subresource string, r io.Reader, length in // // See http://goo.gl/APeTt for details. func (b *Bucket) Del(ctx context.Context, path string) error { + headers := map[string][]string{} + b.addTokenHeader(headers) + req := &request{ method: "DELETE", bucket: b.Name, @@ -598,6 +610,8 @@ func (b *Bucket) DelMulti(objects Delete) error { "Content-MD5": {base64.StdEncoding.EncodeToString(digest.Sum(nil))}, "Content-Type": {"text/xml"}, } + b.addTokenHeader(headers) + req := &request{ path: "/", method: "POST", @@ -705,9 +719,13 @@ func (b *Bucket) List(prefix, delim, marker string, max int) (result *ListResp, if max != 0 { params["max-keys"] = []string{strconv.FormatInt(int64(max), 10)} } + headers := map[string][]string{} + b.addTokenHeader(headers) + req := &request{ - bucket: b.Name, - params: params, + bucket: b.Name, + params: params, + headers: headers, } result = &ListResp{} for attempt := b.S3.AttemptStrategy.Start(); attempt.Next(); {