diff --git a/src/components/dialogs/nuxs/TenMillion/index.tsx b/src/components/dialogs/nuxs/TenMillion/index.tsx
index 4e7a171aad..8960824094 100644
--- a/src/components/dialogs/nuxs/TenMillion/index.tsx
+++ b/src/components/dialogs/nuxs/TenMillion/index.tsx
@@ -197,6 +197,27 @@ export function TenMillionInner({
const isLoadingData = isProfileLoading || !moderation || !profile
const isLoadingImage = !uri
+ const displayName = React.useMemo(() => {
+ if (!profile || !moderation) return ''
+ return sanitizeDisplayName(
+ profile.displayName || sanitizeHandle(profile.handle),
+ moderation.ui('displayName'),
+ )
+ }, [profile, moderation])
+ const handle = React.useMemo(() => {
+ if (!profile) return ''
+ return sanitizeHandle(profile.handle, '@')
+ }, [profile])
+ const joinedDate = React.useMemo(() => {
+ if (!profile || !profile.createdAt) return ''
+ const date = i18n.date(profile.createdAt, {
+ month: 'short',
+ day: 'numeric',
+ year: 'numeric',
+ })
+ return date
+ }, [i18n, profile])
+
const error: string = React.useMemo(() => {
if (profileError) {
return _(
@@ -235,19 +256,34 @@ export function TenMillionInner({
msg`Bluesky now has over 10 million users, and I was #${i18n.number(
userNumber,
)}!`,
- ), // TODO
+ ),
imageUris: [
{
uri,
width: WIDTH,
height: HEIGHT,
+ altText: _(
+ msg`A virtual certificate with text "Celebrating 10M users on Bluesky, #${i18n.number(
+ userNumber,
+ )}, ${displayName} ${handle}, joined on ${joinedDate}"`,
+ ),
},
],
})
}, 1e3)
})
}
- }, [_, i18n, control, openComposer, uri, userNumber])
+ }, [
+ _,
+ i18n,
+ control,
+ openComposer,
+ uri,
+ userNumber,
+ displayName,
+ handle,
+ joinedDate,
+ ])
const onNativeShare = React.useCallback(() => {
if (uri) {
control.close(() => {
@@ -490,11 +526,7 @@ export function TenMillionInner({
a.leading_tight,
{maxWidth: '60%'},
]}>
- {sanitizeDisplayName(
- profile.displayName ||
- sanitizeHandle(profile.handle),
- moderation.ui('displayName'),
- )}
+ {displayName}
@@ -508,7 +540,7 @@ export function TenMillionInner({
a.leading_snug,
lightTheme.atoms.text_contrast_medium,
]}>
- {sanitizeHandle(profile.handle, '@')}
+ {handle}
{profile.createdAt && (
@@ -524,14 +556,7 @@ export function TenMillionInner({
a.text_right,
lightTheme.atoms.text_contrast_low,
]}>
-
- Joined{' '}
- {i18n.date(profile.createdAt, {
- month: 'short',
- day: 'numeric',
- year: 'numeric',
- })}
-
+ Joined on {joinedDate}
)}
diff --git a/src/locale/locales/ca/messages.po b/src/locale/locales/ca/messages.po
index 180089fd1d..bb09cd6cf9 100644
--- a/src/locale/locales/ca/messages.po
+++ b/src/locale/locales/ca/messages.po
@@ -75,7 +75,7 @@ msgstr "{0, plural, one {# segon} other {# segons}}"
#: src/components/KnownFollowers.tsx:179
#~ msgid "{0, plural, one {and # other} other {and # others}}"
-#~ msgstr "{0, plural, one {i # altre} other {i # altres}"
+#~ msgstr "{0, plural, one {i # altre} other {i # altres}}"
#: src/components/ProfileHoverCard/index.web.tsx:398
#: src/screens/Profile/Header/Metrics.tsx:23
diff --git a/src/state/models/media/gallery.ts b/src/state/models/media/gallery.ts
index 9c8c13010d..828905002e 100644
--- a/src/state/models/media/gallery.ts
+++ b/src/state/models/media/gallery.ts
@@ -1,19 +1,20 @@
import {makeAutoObservable, runInAction} from 'mobx'
-import {ImageModel} from './image'
-import {Image as RNImage} from 'react-native-image-crop-picker'
-import {openPicker} from 'lib/media/picker'
+
import {getImageDim} from 'lib/media/manip'
+import {openPicker} from 'lib/media/picker'
+import {ImageInitOptions, ImageModel} from './image'
interface InitialImageUri {
uri: string
width: number
height: number
+ altText?: string
}
export class GalleryModel {
images: ImageModel[] = []
- constructor(uris?: {uri: string; width: number; height: number}[]) {
+ constructor(uris?: InitialImageUri[]) {
makeAutoObservable(this)
if (uris) {
@@ -33,7 +34,7 @@ export class GalleryModel {
return this.images.some(image => image.altText.trim() === '')
}
- *add(image_: Omit) {
+ *add(image_: ImageInitOptions) {
if (this.size >= 4) {
return
}
@@ -59,7 +60,6 @@ export class GalleryModel {
path: uri,
height,
width,
- mime: 'image/jpeg',
}
runInAction(() => {
@@ -100,10 +100,10 @@ export class GalleryModel {
async addFromUris(uris: InitialImageUri[]) {
for (const uriObj of uris) {
this.add({
- mime: 'image/jpeg',
height: uriObj.height,
width: uriObj.width,
path: uriObj.uri,
+ altText: uriObj.altText,
})
}
}
diff --git a/src/state/models/media/image.ts b/src/state/models/media/image.ts
index 5c547c148f..55f6364911 100644
--- a/src/state/models/media/image.ts
+++ b/src/state/models/media/image.ts
@@ -1,14 +1,15 @@
import {Image as RNImage} from 'react-native-image-crop-picker'
-import {makeAutoObservable, runInAction} from 'mobx'
-import {POST_IMG_MAX} from 'lib/constants'
import * as ImageManipulator from 'expo-image-manipulator'
-import {getDataUriSize} from 'lib/media/util'
-import {openCropper} from 'lib/media/picker'
import {ActionCrop, FlipType, SaveFormat} from 'expo-image-manipulator'
+import {makeAutoObservable, runInAction} from 'mobx'
import {Position} from 'react-avatar-editor'
-import {Dimensions} from 'lib/media/types'
-import {isIOS} from 'platform/detection'
+
import {logger} from '#/logger'
+import {POST_IMG_MAX} from 'lib/constants'
+import {openCropper} from 'lib/media/picker'
+import {Dimensions} from 'lib/media/types'
+import {getDataUriSize} from 'lib/media/util'
+import {isIOS} from 'platform/detection'
export interface ImageManipulationAttributes {
aspectRatio?: '4:3' | '1:1' | '3:4' | 'None'
@@ -19,6 +20,13 @@ export interface ImageManipulationAttributes {
flipVertical?: boolean
}
+export interface ImageInitOptions {
+ path: string
+ width: number
+ height: number
+ altText?: string
+}
+
const MAX_IMAGE_SIZE_IN_BYTES = 976560
export class ImageModel implements Omit {
@@ -41,12 +49,15 @@ export class ImageModel implements Omit {
}
prevAttributes: ImageManipulationAttributes = {}
- constructor(image: Omit) {
+ constructor(image: ImageInitOptions) {
makeAutoObservable(this)
this.path = image.path
this.width = image.width
this.height = image.height
+ if (image.altText !== undefined) {
+ this.setAltText(image.altText)
+ }
}
setRatio(aspectRatio: ImageManipulationAttributes['aspectRatio']) {
diff --git a/src/state/shell/composer/index.tsx b/src/state/shell/composer/index.tsx
index 612388ff86..6755ec9a66 100644
--- a/src/state/shell/composer/index.tsx
+++ b/src/state/shell/composer/index.tsx
@@ -36,7 +36,7 @@ export interface ComposerOpts {
mention?: string // handle of user to mention
openEmojiPicker?: (pos: DOMRect | undefined) => void
text?: string
- imageUris?: {uri: string; width: number; height: number}[]
+ imageUris?: {uri: string; width: number; height: number; altText?: string}[]
}
type StateContext = ComposerOpts | undefined