Compare commits

...

1 Commits

Author SHA1 Message Date
Eric Bailey 70a430ceb6 Increase image upload resolution 2026-03-18 18:01:53 -05:00
6 changed files with 61 additions and 10 deletions
+1
View File
@@ -9,6 +9,7 @@ export enum Features {
ImportContactsOnboardingDisable = 'import_contacts:onboarding:disable',
ImportContactsSettingsDisable = 'import_contacts:settings:disable',
LiveNowBetaDisable = 'live_now_beta:disable',
ImageUploadsHighResolution = 'image_uploads:high_resolution',
AATest = 'aa-test',
}
+3
View File
@@ -230,6 +230,9 @@ export type Events = {
'composer:gif:open': {}
'composer:gif:select': {}
'composer:image:edit': {
platform: Platform['OS']
}
'composerPrompt:press': {}
'composerPrompt:camera:press': {}
'composerPrompt:gallery:press': {}
+19 -2
View File
@@ -51,10 +51,15 @@ interface PostOpts {
langs?: string[]
}
type FeatureFlags = {
highResolutionImages?: boolean
}
export async function post(
agent: BskyAgent,
queryClient: QueryClient,
opts: PostOpts,
featureFlags?: FeatureFlags,
) {
const thread = opts.thread
opts.onStateChange?.(t`Processing...`)
@@ -91,6 +96,7 @@ export async function post(
queryClient,
draft,
opts.onStateChange,
featureFlags,
)
let labels: $Typed<ComAtprotoLabelDefs.SelfLabels> | undefined
if (draft.labels.length) {
@@ -230,6 +236,7 @@ async function resolveEmbed(
queryClient: QueryClient,
draft: PostDraft,
onStateChange: ((state: string) => void) | undefined,
featureFlags?: FeatureFlags,
): Promise<
| $Typed<AppBskyEmbedImages.Main>
| $Typed<AppBskyEmbedVideo.Main>
@@ -240,7 +247,13 @@ async function resolveEmbed(
> {
if (draft.embed.quote) {
const [resolvedMedia, resolvedQuote] = await Promise.all([
resolveMedia(agent, queryClient, draft.embed, onStateChange),
resolveMedia(
agent,
queryClient,
draft.embed,
onStateChange,
featureFlags,
),
resolveRecord(agent, queryClient, draft.embed.quote.uri),
])
if (resolvedMedia) {
@@ -263,6 +276,7 @@ async function resolveEmbed(
queryClient,
draft.embed,
onStateChange,
featureFlags,
)
if (resolvedMedia) {
return resolvedMedia
@@ -288,6 +302,7 @@ async function resolveMedia(
queryClient: QueryClient,
embedDraft: EmbedDraft,
onStateChange: ((state: string) => void) | undefined,
featureFlags?: FeatureFlags,
): Promise<
| $Typed<AppBskyEmbedExternal.Main>
| $Typed<AppBskyEmbedImages.Main>
@@ -303,7 +318,9 @@ async function resolveMedia(
const images: AppBskyEmbedImages.Image[] = await Promise.all(
imagesDraft.map(async (image, i) => {
logger.debug(`Compressing image #${i}`)
const {path, width, height, mime} = await compressImage(image)
const {path, width, height, mime} = await compressImage(image, {
highResolution: featureFlags?.highResolutionImages,
})
logger.debug(`Uploading image #${i}`)
const res = await uploadBlob(agent, path, mime)
return {
+16 -2
View File
@@ -200,10 +200,24 @@ export function resetImageManipulation(
return img
}
export async function compressImage(img: ComposerImage): Promise<PickerImage> {
export async function compressImage(
img: ComposerImage,
options?: {
highResolution?: boolean
},
): Promise<PickerImage> {
const source = img.transformed || img.source
const [w, h] = containImageRes(source.width, source.height, POST_IMG_MAX)
const [w, h] = containImageRes(
source.width,
source.height,
options?.highResolution
? {
width: 4000,
height: 4000,
}
: POST_IMG_MAX,
)
let minQualityPercentage = 0
let maxQualityPercentage = 101 // exclusive
+15 -6
View File
@@ -825,12 +825,21 @@ export const ComposePost = ({
try {
logger.info(`composer: posting...`)
postUri = (
await apilib.post(agent, queryClient, {
thread,
replyTo: replyTo?.uri,
onStateChange: setPublishingStage,
langs: currentLanguages,
})
await apilib.post(
agent,
queryClient,
{
thread,
replyTo: replyTo?.uri,
onStateChange: setPublishingStage,
langs: currentLanguages,
},
{
highResolutionImages: ax.features.enabled(
ax.features.ImageUploadsHighResolution,
),
},
)
).uris[0]
/*
+7
View File
@@ -4,6 +4,7 @@ import {
type ImageStyle,
Keyboard,
type LayoutChangeEvent,
Platform,
StyleSheet,
TouchableOpacity,
View,
@@ -24,6 +25,7 @@ import {Admonition} from '#/components/Admonition'
import * as Dialog from '#/components/Dialog'
import {MediaInsetBorder} from '#/components/MediaInsetBorder'
import {Text} from '#/components/Typography'
import {useAnalytics} from '#/analytics'
import {IS_IOS, IS_NATIVE} from '#/env'
import {type PostAction} from '../state/composer'
import {EditImageDialog} from './EditImageDialog'
@@ -147,6 +149,7 @@ const GalleryItem = ({
}: GalleryItemProps): React.ReactNode => {
const {_} = useLingui()
const t = useTheme()
const ax = useAnalytics()
const altTextControl = Dialog.useDialogControl()
const editControl = Dialog.useDialogControl()
@@ -161,6 +164,10 @@ const GalleryItem = ({
}
const onImageEdit = () => {
ax.metric('composer:image:edit', {
platform: Platform.OS,
})
if (IS_NATIVE) {
cropImage(image).then(next => {
onChange(next)