=> {
const _maximum =
maximum ||
getInstanceConfigurationStatusMaxAttachments(store.getState()) ||
@@ -105,79 +62,30 @@ const mediaSelector = async ({
return new Promise((resolve, reject) => {
const selectImage = async () => {
- const images = await ImagePicker.openPicker({
+ const images = await launchImageLibrary({
mediaType: 'photo',
- includeExif: false,
- multiple: true,
- minFiles: 1,
- maxFiles: _maximum,
- smartAlbums: ['UserLibrary'],
- writeTempFile: false,
- loadingLabelText: ''
- }).catch(() => {})
+ ...(resize && { maxWidth: resize.width, maxHeight: resize.height }),
+ includeBase64: false,
+ includeExtra: false,
+ selectionLimit: _maximum
+ })
- if (!images) {
+ if (!images.assets) {
return reject()
}
- // react-native-image-crop-picker may return HEIC as JPG that causes upload failure
- if (Platform.OS === 'ios') {
- for (const [index, image] of images.entries()) {
- if (image.mime === 'image/heic') {
- const converted = await manipulateAsync(image.sourceURL!, [], {
- base64: false,
- compress: 0.8,
- format: SaveFormat.JPEG
- })
- images[index] = {
- ...images[index],
- sourceURL: converted.uri,
- mime: 'image/jpeg'
- }
- }
- }
- }
-
- if (!resize) {
- return resolve(
- images.map(image => ({
- ...image,
- uri: image.sourceURL || `file://${image.path}`
- }))
- )
- } else {
- const croppedImages: Image[] = []
- for (const image of images) {
- const croppedImage = await ImagePicker.openCropper({
- mediaType: 'photo',
- path: image.sourceURL || image.path,
- width: resize.width,
- height: resize.height,
- cropperChooseText: i18next.t('common:buttons.apply'),
- cropperCancelText: i18next.t('common:buttons.cancel'),
- hideBottomControls: true
- }).catch(() => {})
- croppedImage && croppedImages.push(croppedImage)
- }
- return resolve(
- croppedImages.map(image => ({
- ...image,
- uri: `file://${image.path}`
- }))
- )
- }
+ return resolve(images.assets)
}
const selectVideo = async () => {
- const video = await ImagePicker.openPicker({
+ const video = await launchImageLibrary({
mediaType: 'video',
- includeExif: false,
- loadingLabelText: ''
- }).catch(() => {})
+ includeBase64: false,
+ includeExtra: false,
+ selectionLimit: 1
+ })
- if (video) {
- return resolve([
- { ...video, uri: video.sourceURL || `file://${video.path}` }
- ])
+ if (video.assets?.[0]) {
+ return resolve(video.assets)
} else {
return reject()
}
@@ -189,10 +97,6 @@ const mediaSelector = async ({
cancelButtonIndex: mediaType ? 1 : 2
},
async buttonIndex => {
- if (!(await checkLibraryPermission())) {
- return reject()
- }
-
switch (mediaType) {
case 'photo':
if (buttonIndex === 0) {
diff --git a/src/components/mediaTransformation.ts b/src/components/mediaTransformation.ts
deleted file mode 100644
index 29bb542d..00000000
--- a/src/components/mediaTransformation.ts
+++ /dev/null
@@ -1,149 +0,0 @@
-import { store } from '@root/store'
-import { getInstanceConfigurationMediaAttachments } from '@utils/slices/instancesSlice'
-import { Action, manipulateAsync, SaveFormat } from 'expo-image-manipulator'
-import i18next from 'i18next'
-import { Platform } from 'react-native'
-import ImagePicker from 'react-native-image-crop-picker'
-
-export interface Props {
- type: 'image' | 'video'
- uri: string // This can be pure path or uri starting with file://
- mime?: string
- transform: {
- imageFormat?: SaveFormat.JPEG | SaveFormat.PNG
- resize?: boolean
- width?: number
- height?: number
- }
-}
-
-const getFileExtension = (uri: string) => {
- const extension = uri.split('.').pop()
- // Using mime type standard of jpeg
- return extension === 'jpg' ? 'jpeg' : extension
-}
-
-const mediaTransformation = async ({
- type,
- uri,
- mime,
- transform
-}: Props): Promise<{
- uri: string
- mime: string
- width: number
- height: number
-}> => {
- const configurationMediaAttachments =
- getInstanceConfigurationMediaAttachments(store.getState())
-
- const fileExtension = getFileExtension(uri)
-
- switch (type) {
- case 'image':
- if (mime === 'image/gif' || fileExtension === 'gif') {
- return Promise.reject('GIFs should not be transformed')
- }
- let targetFormat: SaveFormat.JPEG | SaveFormat.PNG = SaveFormat.JPEG
-
- const supportedImageTypes =
- configurationMediaAttachments.supported_mime_types.filter(mime =>
- mime.startsWith('image/')
- )
-
- // @ts-ignore
- const transformations: Action[] = [
- !transform.resize && (transform.width || transform.height)
- ? {
- resize: { width: transform.width, height: transform.height }
- }
- : null
- ].filter(t => !!t)
-
- if (mime) {
- if (
- mime !== `image/${fileExtension}` ||
- !supportedImageTypes.includes(mime)
- ) {
- targetFormat = transform.imageFormat || SaveFormat.JPEG
- } else {
- targetFormat = mime.split('/').pop() as any
- }
- } else {
- if (!fileExtension) {
- return Promise.reject('Unable to get file extension')
- }
- if (!supportedImageTypes.includes(`image/${fileExtension}`)) {
- targetFormat = transform.imageFormat || SaveFormat.JPEG
- } else {
- targetFormat = fileExtension as any
- }
- }
-
- const converted = await manipulateAsync(uri, transformations, {
- base64: false,
- compress: Platform.OS === 'ios' ? 0.8 : 1,
- format: targetFormat
- })
-
- if (transform.resize) {
- const resized = await ImagePicker.openCropper({
- mediaType: 'photo',
- path: converted.uri,
- width: transform.width,
- height: transform.height,
- cropperChooseText: i18next.t('common:buttons.apply'),
- cropperCancelText: i18next.t('common:buttons.cancel'),
- hideBottomControls: true
- })
- if (!resized) {
- return Promise.reject('Resize failed')
- } else {
- return {
- uri: resized.path,
- mime: resized.mime,
- width: resized.width,
- height: resized.height
- }
- }
- } else {
- return {
- uri: converted.uri,
- mime: transform.imageFormat || SaveFormat.JPEG,
- width: converted.width,
- height: converted.height
- }
- }
- case 'video':
- const supportedVideoTypes =
- configurationMediaAttachments.supported_mime_types.filter(mime =>
- mime.startsWith('video/')
- )
-
- if (mime) {
- if (mime !== `video/${fileExtension}`) {
- console.warn('Video mime type and file extension does not match')
- }
- if (!supportedVideoTypes.includes(mime)) {
- return Promise.reject('Video file type is not supported')
- }
- } else {
- if (!fileExtension) {
- return Promise.reject('Unable to get file extension')
- }
- if (!supportedVideoTypes.includes(`video/${fileExtension}`)) {
- return Promise.reject('Video file type is not supported')
- }
- }
-
- return {
- uri: uri,
- mime: mime || `video/${fileExtension}`,
- width: 0,
- height: 0
- }
- break
- }
-}
-
-export default mediaTransformation
diff --git a/src/components/openLink.ts b/src/components/openLink.ts
index 3e0aff73..f30b0372 100644
--- a/src/components/openLink.ts
+++ b/src/components/openLink.ts
@@ -72,7 +72,6 @@ const openLink = async (url: string, navigation?: any) => {
// If an account can be found
const matchedAccount = url.match(matcherAccount)
- console.log(matchedAccount)
if (matchedAccount) {
// If the link in current instance
const instanceUrl = getInstanceUrl(store.getState())
diff --git a/src/i18n/de/components/contextMenu.json b/src/i18n/de/components/contextMenu.json
index b5b5f216..fac251f1 100644
--- a/src/i18n/de/components/contextMenu.json
+++ b/src/i18n/de/components/contextMenu.json
@@ -14,6 +14,10 @@
"action": "User melden"
}
},
+ "copy": {
+ "action": "",
+ "succeed": ""
+ },
"instance": {
"title": "",
"block": {
diff --git a/src/i18n/de/components/parse.json b/src/i18n/de/components/parse.json
index 571eac68..fc364f0e 100644
--- a/src/i18n/de/components/parse.json
+++ b/src/i18n/de/components/parse.json
@@ -1,9 +1,8 @@
{
"HTML": {
- "expanded": {
- "true": "Zusammenklappen {{hint}}",
- "false": "Ausklappen {{hint}}"
- },
- "defaultHint": "Artikel"
+ "accessibilityHint": "",
+ "expanded": "{{hint}}{{totalLines}}",
+ "totalLines": "",
+ "defaultHint": ""
}
}
\ No newline at end of file
diff --git a/src/i18n/de/screens/accountSelection.json b/src/i18n/de/screens/accountSelection.json
new file mode 100644
index 00000000..b16795a6
--- /dev/null
+++ b/src/i18n/de/screens/accountSelection.json
@@ -0,0 +1,6 @@
+{
+ "heading": "",
+ "content": {
+ "select_account": ""
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/de/screens/tabs.json b/src/i18n/de/screens/tabs.json
index 185cd5fd..59e3cfb2 100644
--- a/src/i18n/de/screens/tabs.json
+++ b/src/i18n/de/screens/tabs.json
@@ -78,9 +78,7 @@
}
},
"fontSize": {
- "showcase": "Beispieltröt",
"demo": "Dies ist ein Beispieltröt😊. Du kannst aus mehreren der unteren Möglichkeiten auswählen.
Diese Einstellung betrifft ausschließlich die Haupteinstellungen, nicht die Schriftgröße in anderen Bereichen der App.
",
- "availableSizes": "Verfügbare Größen",
"sizes": {
"S": "S",
"M": "M – Standard",
@@ -147,7 +145,8 @@
"group": "Gruppe {{index}}",
"label": "Kennzeichnung",
"content": "Inhalt"
- }
+ },
+ "mediaSelectionFailed": ""
},
"push": {
"notAvailable": "Dein Gerät unterstützt keine Push-Benachrichtigung",
diff --git a/src/i18n/en/_all.ts b/src/i18n/en/_all.ts
index 5f2a7a82..b86ba263 100644
--- a/src/i18n/en/_all.ts
+++ b/src/i18n/en/_all.ts
@@ -2,6 +2,7 @@ export default {
common: require('./common'),
screens: require('./screens'),
+ screenAccountSelection: require('./screens/accountSelection.json'),
screenActions: require('./screens/actions'),
screenAnnouncements: require('./screens/announcements'),
screenCompose: require('./screens/compose'),
diff --git a/src/i18n/en/components/contextMenu.json b/src/i18n/en/components/contextMenu.json
index cd410020..d7ba0c11 100644
--- a/src/i18n/en/components/contextMenu.json
+++ b/src/i18n/en/components/contextMenu.json
@@ -14,6 +14,10 @@
"action": "Report user"
}
},
+ "copy": {
+ "action": "Copy toot",
+ "succeed": "Copied"
+ },
"instance": {
"title": "Instance action",
"block": {
diff --git a/src/i18n/en/components/parse.json b/src/i18n/en/components/parse.json
index 9932ccc2..2305906a 100644
--- a/src/i18n/en/components/parse.json
+++ b/src/i18n/en/components/parse.json
@@ -1,9 +1,8 @@
{
"HTML": {
- "expanded": {
- "true": "Fold {{hint}}",
- "false": "Expand {{hint}}"
- },
- "defaultHint": "article"
+ "accessibilityHint": "Tap to expand or collapse content",
+ "expanded": "{{hint}}{{totalLines}}",
+ "totalLines": " ({{count}} lines)",
+ "defaultHint": "Long toot"
}
}
\ No newline at end of file
diff --git a/src/i18n/en/components/timeline.json b/src/i18n/en/components/timeline.json
index f622a093..066eade6 100644
--- a/src/i18n/en/components/timeline.json
+++ b/src/i18n/en/components/timeline.json
@@ -81,7 +81,7 @@
"accessibilityHint": "Tap to go to {{name}}'s page"
},
"content": {
- "expandHint": "hidden content"
+ "expandHint": "Hidden content"
},
"filtered": "Filtered",
"fullConversation": "Read conversations",
diff --git a/src/i18n/en/screens/accountSelection.json b/src/i18n/en/screens/accountSelection.json
new file mode 100644
index 00000000..ddd360eb
--- /dev/null
+++ b/src/i18n/en/screens/accountSelection.json
@@ -0,0 +1,6 @@
+{
+ "heading": "Share to ...",
+ "content": {
+ "select_account": "Select account"
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/en/screens/tabs.json b/src/i18n/en/screens/tabs.json
index 8f652234..33a37a35 100644
--- a/src/i18n/en/screens/tabs.json
+++ b/src/i18n/en/screens/tabs.json
@@ -78,9 +78,7 @@
}
},
"fontSize": {
- "showcase": "Example toot",
"demo": "This is a demo toot😊. You can choose from several options from below.
This setting only affects the main content of toots, but not other font sizes.
",
- "availableSizes": "Available sizes",
"sizes": {
"S": "S",
"M": "M - Default",
@@ -147,7 +145,8 @@
"group": "Group {{index}}",
"label": "Label",
"content": "Content"
- }
+ },
+ "mediaSelectionFailed": "Image processing failed. Please try again."
},
"push": {
"notAvailable": "Your phone does not support tooot's push notification",
diff --git a/src/i18n/it/components/contextMenu.json b/src/i18n/it/components/contextMenu.json
index 6b86a431..0c4b851c 100644
--- a/src/i18n/it/components/contextMenu.json
+++ b/src/i18n/it/components/contextMenu.json
@@ -14,6 +14,10 @@
"action": "Segnala utente"
}
},
+ "copy": {
+ "action": "",
+ "succeed": ""
+ },
"instance": {
"title": "Azione sull'istanza",
"block": {
diff --git a/src/i18n/it/components/parse.json b/src/i18n/it/components/parse.json
index 8f98a863..fc364f0e 100644
--- a/src/i18n/it/components/parse.json
+++ b/src/i18n/it/components/parse.json
@@ -1,9 +1,8 @@
{
"HTML": {
- "expanded": {
- "true": "Richiudi {{hint}}",
- "false": "Espandi {{hint}}"
- },
- "defaultHint": "toot"
+ "accessibilityHint": "",
+ "expanded": "{{hint}}{{totalLines}}",
+ "totalLines": "",
+ "defaultHint": ""
}
}
\ No newline at end of file
diff --git a/src/i18n/it/screens/accountSelection.json b/src/i18n/it/screens/accountSelection.json
new file mode 100644
index 00000000..b16795a6
--- /dev/null
+++ b/src/i18n/it/screens/accountSelection.json
@@ -0,0 +1,6 @@
+{
+ "heading": "",
+ "content": {
+ "select_account": ""
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/it/screens/tabs.json b/src/i18n/it/screens/tabs.json
index 02414793..1fc1a049 100644
--- a/src/i18n/it/screens/tabs.json
+++ b/src/i18n/it/screens/tabs.json
@@ -78,9 +78,7 @@
}
},
"fontSize": {
- "showcase": "Toot di esempio",
"demo": "Questo toot è un esempio 😺️. Puoi scegliere diverse opzioni di grandezza del testo qui sotto.
Questa impostazione si applica solo al testo dei toot, non anche agli altri testi della app.
",
- "availableSizes": "Dimensioni testo",
"sizes": {
"S": "S",
"M": "M - Predefinito",
@@ -147,7 +145,8 @@
"group": "Gruppo {{index}}",
"label": "Etichetta",
"content": "Contenuto"
- }
+ },
+ "mediaSelectionFailed": ""
},
"push": {
"notAvailable": "Il tuo dispositivo non supporta le notifiche push per tooot",
diff --git a/src/i18n/ja/common.json b/src/i18n/ja/common.json
new file mode 100644
index 00000000..d17849b2
--- /dev/null
+++ b/src/i18n/ja/common.json
@@ -0,0 +1,22 @@
+{
+ "buttons": {
+ "OK": "",
+ "apply": "",
+ "cancel": ""
+ },
+ "customEmoji": {
+ "accessibilityLabel": ""
+ },
+ "message": {
+ "success": {
+ "message": ""
+ },
+ "warning": {
+ "message": ""
+ },
+ "error": {
+ "message": ""
+ }
+ },
+ "separator": ""
+}
\ No newline at end of file
diff --git a/src/i18n/ja/components/contextMenu.json b/src/i18n/ja/components/contextMenu.json
new file mode 100644
index 00000000..ba398d8a
--- /dev/null
+++ b/src/i18n/ja/components/contextMenu.json
@@ -0,0 +1,76 @@
+{
+ "accessibilityHint": "",
+ "account": {
+ "title": "",
+ "mute": {
+ "action_false": "",
+ "action_true": ""
+ },
+ "block": {
+ "action_false": "",
+ "action_true": ""
+ },
+ "reports": {
+ "action": ""
+ }
+ },
+ "copy": {
+ "action": "",
+ "succeed": ""
+ },
+ "instance": {
+ "title": "",
+ "block": {
+ "action": "",
+ "alert": {
+ "title": "",
+ "message": "",
+ "buttons": {
+ "confirm": ""
+ }
+ }
+ }
+ },
+ "share": {
+ "status": {
+ "action": ""
+ },
+ "account": {
+ "action": ""
+ }
+ },
+ "status": {
+ "title": "",
+ "edit": {
+ "action": ""
+ },
+ "delete": {
+ "action": "",
+ "alert": {
+ "title": "",
+ "message": "",
+ "buttons": {
+ "confirm": ""
+ }
+ }
+ },
+ "deleteEdit": {
+ "action": "",
+ "alert": {
+ "title": "",
+ "message": "",
+ "buttons": {
+ "confirm": ""
+ }
+ }
+ },
+ "mute": {
+ "action_false": "",
+ "action_true": ""
+ },
+ "pin": {
+ "action_false": "",
+ "action_true": ""
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/ja/components/emojis.json b/src/i18n/ja/components/emojis.json
new file mode 100644
index 00000000..9e26dfee
--- /dev/null
+++ b/src/i18n/ja/components/emojis.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/src/i18n/ja/components/instance.json b/src/i18n/ja/components/instance.json
new file mode 100644
index 00000000..3f2cd6e8
--- /dev/null
+++ b/src/i18n/ja/components/instance.json
@@ -0,0 +1,30 @@
+{
+ "server": {
+ "textInput": {
+ "placeholder": ""
+ },
+ "button": "",
+ "information": {
+ "name": "",
+ "accounts": "",
+ "statuses": "",
+ "domains": ""
+ },
+ "disclaimer": {
+ "base": ""
+ },
+ "terms": {
+ "base": ""
+ }
+ },
+ "update": {
+ "alert": {
+ "title": "",
+ "message": "",
+ "buttons": {
+ "cancel": "",
+ "continue": ""
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/ja/components/mediaSelector.json b/src/i18n/ja/components/mediaSelector.json
new file mode 100644
index 00000000..a57c70b5
--- /dev/null
+++ b/src/i18n/ja/components/mediaSelector.json
@@ -0,0 +1,18 @@
+{
+ "title": "",
+ "options": {
+ "image": "",
+ "image_max": "",
+ "video": "",
+ "video_max": ""
+ },
+ "library": {
+ "alert": {
+ "title": "",
+ "message": "",
+ "buttons": {
+ "settings": ""
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/ja/components/parse.json b/src/i18n/ja/components/parse.json
new file mode 100644
index 00000000..fc364f0e
--- /dev/null
+++ b/src/i18n/ja/components/parse.json
@@ -0,0 +1,8 @@
+{
+ "HTML": {
+ "accessibilityHint": "",
+ "expanded": "{{hint}}{{totalLines}}",
+ "totalLines": "",
+ "defaultHint": ""
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/ja/components/relationship.json b/src/i18n/ja/components/relationship.json
new file mode 100644
index 00000000..ccf2aa7b
--- /dev/null
+++ b/src/i18n/ja/components/relationship.json
@@ -0,0 +1,16 @@
+{
+ "follow": {
+ "function": ""
+ },
+ "block": {
+ "function": ""
+ },
+ "button": {
+ "error": "",
+ "blocked_by": "",
+ "blocking": "",
+ "following": "",
+ "requested": "",
+ "default": ""
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/ja/components/timeline.json b/src/i18n/ja/components/timeline.json
new file mode 100644
index 00000000..e7dcf23e
--- /dev/null
+++ b/src/i18n/ja/components/timeline.json
@@ -0,0 +1,147 @@
+{
+ "empty": {
+ "error": {
+ "message": "",
+ "button": ""
+ },
+ "success": {
+ "message": ""
+ }
+ },
+ "end": {
+ "message": ""
+ },
+ "lookback": {
+ "message": ""
+ },
+ "refresh": {
+ "fetchPreviousPage": "",
+ "refetch": ""
+ },
+ "shared": {
+ "actioned": {
+ "pinned": "",
+ "favourite": "",
+ "status": "",
+ "follow": "",
+ "follow_request": "",
+ "poll": "",
+ "reblog": {
+ "default": "",
+ "notification": ""
+ },
+ "update": ""
+ },
+ "actions": {
+ "reply": {
+ "accessibilityLabel": ""
+ },
+ "reblogged": {
+ "accessibilityLabel": "",
+ "function": ""
+ },
+ "favourited": {
+ "accessibilityLabel": "",
+ "function": ""
+ },
+ "bookmarked": {
+ "accessibilityLabel": "",
+ "function": ""
+ }
+ },
+ "actionsUsers": {
+ "reblogged_by": {
+ "accessibilityLabel": "",
+ "accessibilityHint": "",
+ "text": ""
+ },
+ "favourited_by": {
+ "accessibilityLabel": "",
+ "accessibilityHint": "",
+ "text": ""
+ },
+ "history": {
+ "accessibilityLabel": "",
+ "accessibilityHint": "",
+ "text_one": "",
+ "text_other": ""
+ }
+ },
+ "attachment": {
+ "sensitive": {
+ "button": ""
+ },
+ "unsupported": {
+ "text": "",
+ "button": ""
+ }
+ },
+ "avatar": {
+ "accessibilityLabel": "",
+ "accessibilityHint": ""
+ },
+ "content": {
+ "expandHint": ""
+ },
+ "filtered": "",
+ "fullConversation": "",
+ "translate": {
+ "default": "",
+ "succeed": "",
+ "failed": "",
+ "source_not_supported": "",
+ "target_not_supported": ""
+ },
+ "header": {
+ "shared": {
+ "account": {
+ "name": {
+ "accessibilityHint": ""
+ },
+ "account": {
+ "accessibilityHint": ""
+ }
+ },
+ "application": "",
+ "edited": {
+ "accessibilityLabel": ""
+ },
+ "muted": {
+ "accessibilityLabel": ""
+ },
+ "visibility": {
+ "direct": {
+ "accessibilityLabel": ""
+ },
+ "private": {
+ "accessibilityLabel": ""
+ }
+ }
+ },
+ "conversation": {
+ "withAccounts": "",
+ "delete": {
+ "function": ""
+ }
+ }
+ },
+ "poll": {
+ "meta": {
+ "button": {
+ "vote": "",
+ "refresh": ""
+ },
+ "count": {
+ "voters_one": "",
+ "voters_other": "",
+ "votes_one": "",
+ "votes_other": ""
+ },
+ "expiration": {
+ "expired": "",
+ "until": ""
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/ja/screens.json b/src/i18n/ja/screens.json
new file mode 100644
index 00000000..59b67261
--- /dev/null
+++ b/src/i18n/ja/screens.json
@@ -0,0 +1,18 @@
+{
+ "screenshot": {
+ "title": "",
+ "message": "",
+ "button": ""
+ },
+ "localCorrupt": {
+ "message": ""
+ },
+ "pushError": {
+ "message": "",
+ "description": ""
+ },
+ "shareError": {
+ "imageNotSupported": "",
+ "videoNotSupported": ""
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/ja/screens/accountSelection.json b/src/i18n/ja/screens/accountSelection.json
new file mode 100644
index 00000000..b16795a6
--- /dev/null
+++ b/src/i18n/ja/screens/accountSelection.json
@@ -0,0 +1,6 @@
+{
+ "heading": "",
+ "content": {
+ "select_account": ""
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/ja/screens/actions.json b/src/i18n/ja/screens/actions.json
new file mode 100644
index 00000000..55e9959c
--- /dev/null
+++ b/src/i18n/ja/screens/actions.json
@@ -0,0 +1,20 @@
+{
+ "content": {
+ "altText": {
+ "heading": ""
+ },
+ "notificationsFilter": {
+ "heading": "",
+ "content": {
+ "follow": "",
+ "follow_request": "",
+ "favourite": "",
+ "reblog": "",
+ "mention": "",
+ "poll": "",
+ "status": "",
+ "update": ""
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/ja/screens/announcements.json b/src/i18n/ja/screens/announcements.json
new file mode 100644
index 00000000..95737a45
--- /dev/null
+++ b/src/i18n/ja/screens/announcements.json
@@ -0,0 +1,10 @@
+{
+ "heading": "",
+ "content": {
+ "published": "",
+ "button": {
+ "read": "",
+ "unread": ""
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/ja/screens/compose.json b/src/i18n/ja/screens/compose.json
new file mode 100644
index 00000000..ceb1afd4
--- /dev/null
+++ b/src/i18n/ja/screens/compose.json
@@ -0,0 +1,179 @@
+{
+ "heading": {
+ "left": {
+ "button": "",
+ "alert": {
+ "title": "",
+ "buttons": {
+ "save": "",
+ "delete": "",
+ "cancel": ""
+ }
+ }
+ },
+ "right": {
+ "button": {
+ "default": "",
+ "conversation": "",
+ "reply": "",
+ "deleteEdit": "",
+ "edit": "",
+ "share": ""
+ },
+ "alert": {
+ "default": {
+ "title": "",
+ "button": ""
+ },
+ "removeReply": {
+ "title": "",
+ "description": "",
+ "cancel": "",
+ "confirm": ""
+ }
+ }
+ }
+ },
+ "content": {
+ "root": {
+ "header": {
+ "postingAs": "",
+ "spoilerInput": {
+ "placeholder": ""
+ },
+ "textInput": {
+ "placeholder": "",
+ "keyboardImage": {
+ "exceedMaximum": {
+ "title": "",
+ "OK": ""
+ }
+ }
+ }
+ },
+ "footer": {
+ "attachments": {
+ "sensitive": "",
+ "remove": {
+ "accessibilityLabel": ""
+ },
+ "edit": {
+ "accessibilityLabel": ""
+ },
+ "upload": {
+ "accessibilityLabel": ""
+ }
+ },
+ "emojis": {
+ "accessibilityHint": ""
+ },
+ "poll": {
+ "option": {
+ "placeholder": {
+ "accessibilityLabel": "",
+ "single": "",
+ "multiple": ""
+ }
+ },
+ "quantity": {
+ "reduce": {
+ "accessibilityLabel": "",
+ "accessibilityHint": ""
+ },
+ "increase": {
+ "accessibilityLabel": "",
+ "accessibilityHint": ""
+ }
+ },
+ "multiple": {
+ "heading": "",
+ "options": {
+ "single": "",
+ "multiple": "",
+ "cancel": ""
+ }
+ },
+ "expiration": {
+ "heading": "",
+ "options": {
+ "300": "",
+ "1800": "",
+ "3600": "",
+ "21600": "",
+ "86400": "",
+ "259200": "",
+ "604800": "",
+ "cancel": ""
+ }
+ }
+ }
+ },
+ "actions": {
+ "attachment": {
+ "accessibilityLabel": "",
+ "accessibilityHint": "",
+ "failed": {
+ "alert": {
+ "title": "",
+ "button": ""
+ }
+ }
+ },
+ "poll": {
+ "accessibilityLabel": "",
+ "accessibilityHint": ""
+ },
+ "visibility": {
+ "accessibilityLabel": "",
+ "title": "",
+ "options": {
+ "public": "",
+ "unlisted": "",
+ "private": "",
+ "direct": "",
+ "cancel": ""
+ }
+ },
+ "spoiler": {
+ "accessibilityLabel": ""
+ },
+ "emoji": {
+ "accessibilityLabel": "",
+ "accessibilityHint": ""
+ }
+ },
+ "drafts_one": "",
+ "drafts_other": ""
+ },
+ "editAttachment": {
+ "header": {
+ "title": "",
+ "right": {
+ "accessibilityLabel": "",
+ "failed": {
+ "title": "",
+ "button": ""
+ }
+ }
+ },
+ "content": {
+ "altText": {
+ "heading": "",
+ "placeholder": ""
+ },
+ "imageFocus": ""
+ }
+ },
+ "draftsList": {
+ "header": {
+ "title": ""
+ },
+ "warning": "",
+ "content": {
+ "accessibilityHint": "",
+ "textEmpty": ""
+ },
+ "checkAttachment": ""
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/ja/screens/imageViewer.json b/src/i18n/ja/screens/imageViewer.json
new file mode 100644
index 00000000..ad2b495c
--- /dev/null
+++ b/src/i18n/ja/screens/imageViewer.json
@@ -0,0 +1,17 @@
+{
+ "content": {
+ "actions": {
+ "accessibilityLabel": "",
+ "accessibilityHint": ""
+ },
+ "options": {
+ "save": "",
+ "share": "",
+ "cancel": ""
+ },
+ "save": {
+ "succeed": "",
+ "failed": ""
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/ja/screens/tabs.json b/src/i18n/ja/screens/tabs.json
new file mode 100644
index 00000000..7d6ca206
--- /dev/null
+++ b/src/i18n/ja/screens/tabs.json
@@ -0,0 +1,353 @@
+{
+ "tabs": {
+ "local": {
+ "name": ""
+ },
+ "public": {
+ "name": "",
+ "segments": {
+ "left": "",
+ "right": ""
+ }
+ },
+ "notifications": {
+ "name": ""
+ },
+ "me": {
+ "name": ""
+ }
+ },
+ "common": {
+ "search": {
+ "accessibilityLabel": "",
+ "accessibilityHint": ""
+ }
+ },
+ "notifications": {
+ "filter": {
+ "accessibilityLabel": "",
+ "accessibilityHint": ""
+ }
+ },
+ "me": {
+ "stacks": {
+ "bookmarks": {
+ "name": ""
+ },
+ "conversations": {
+ "name": ""
+ },
+ "favourites": {
+ "name": ""
+ },
+ "fontSize": {
+ "name": ""
+ },
+ "language": {
+ "name": ""
+ },
+ "lists": {
+ "name": ""
+ },
+ "list": {
+ "name": ""
+ },
+ "push": {
+ "name": ""
+ },
+ "profile": {
+ "name": ""
+ },
+ "profileName": {
+ "name": ""
+ },
+ "profileNote": {
+ "name": ""
+ },
+ "profileFields": {
+ "name": ""
+ },
+ "settings": {
+ "name": ""
+ },
+ "webSettings": {
+ "name": ""
+ },
+ "switch": {
+ "name": ""
+ }
+ },
+ "fontSize": {
+ "demo": "",
+ "sizes": {
+ "S": "",
+ "M": "",
+ "L": "",
+ "XL": "",
+ "XXL": ""
+ }
+ },
+ "profile": {
+ "cancellation": {
+ "title": "",
+ "message": "",
+ "buttons": {
+ "cancel": "",
+ "discard": ""
+ }
+ },
+ "feedback": {
+ "succeed": "",
+ "failed": ""
+ },
+ "root": {
+ "name": {
+ "title": ""
+ },
+ "avatar": {
+ "title": "",
+ "description": ""
+ },
+ "header": {
+ "title": "",
+ "description": ""
+ },
+ "note": {
+ "title": ""
+ },
+ "fields": {
+ "title": "",
+ "total_one": "",
+ "total_other": ""
+ },
+ "visibility": {
+ "title": "",
+ "options": {
+ "public": "",
+ "unlisted": "",
+ "private": "",
+ "cancel": ""
+ }
+ },
+ "sensitive": {
+ "title": ""
+ },
+ "lock": {
+ "title": "",
+ "description": ""
+ },
+ "bot": {
+ "title": "",
+ "description": ""
+ }
+ },
+ "fields": {
+ "group": "",
+ "label": "",
+ "content": ""
+ },
+ "mediaSelectionFailed": ""
+ },
+ "push": {
+ "notAvailable": "",
+ "enable": {
+ "direct": "",
+ "settings": ""
+ },
+ "global": {
+ "heading": "",
+ "description": ""
+ },
+ "decode": {
+ "heading": "",
+ "description": ""
+ },
+ "default": {
+ "heading": ""
+ },
+ "follow": {
+ "heading": ""
+ },
+ "follow_request": {
+ "heading": ""
+ },
+ "favourite": {
+ "heading": ""
+ },
+ "reblog": {
+ "heading": ""
+ },
+ "mention": {
+ "heading": ""
+ },
+ "poll": {
+ "heading": ""
+ },
+ "status": {
+ "heading": ""
+ },
+ "howitworks": ""
+ },
+ "root": {
+ "announcements": {
+ "content": {
+ "unread": "",
+ "read": "",
+ "empty": ""
+ }
+ },
+ "push": {
+ "content": {
+ "enabled": "",
+ "disabled": ""
+ }
+ },
+ "update": {
+ "title": ""
+ },
+ "logout": {
+ "button": "",
+ "alert": {
+ "title": "",
+ "message": "",
+ "buttons": {
+ "logout": "",
+ "cancel": ""
+ }
+ }
+ }
+ },
+ "settings": {
+ "fontsize": {
+ "heading": "",
+ "content": {
+ "S": "",
+ "M": "",
+ "L": "",
+ "XL": "",
+ "XXL": ""
+ }
+ },
+ "language": {
+ "heading": "",
+ "options": {
+ "cancel": ""
+ }
+ },
+ "theme": {
+ "heading": "",
+ "options": {
+ "auto": "",
+ "light": "",
+ "dark": "",
+ "cancel": ""
+ }
+ },
+ "darkTheme": {
+ "heading": "",
+ "options": {
+ "lighter": "",
+ "darker": "",
+ "cancel": ""
+ }
+ },
+ "browser": {
+ "heading": "",
+ "options": {
+ "internal": "",
+ "external": "",
+ "cancel": ""
+ }
+ },
+ "staticEmoji": {
+ "heading": "",
+ "description": ""
+ },
+ "feedback": {
+ "heading": ""
+ },
+ "support": {
+ "heading": ""
+ },
+ "review": {
+ "heading": ""
+ },
+ "contact": {
+ "heading": ""
+ },
+ "analytics": {
+ "heading": "",
+ "description": ""
+ },
+ "version": "",
+ "instanceVersion": ""
+ },
+ "switch": {
+ "existing": "",
+ "new": ""
+ }
+ },
+ "shared": {
+ "account": {
+ "actions": {
+ "accessibilityLabel": "",
+ "accessibilityHint": ""
+ },
+ "followed_by": "",
+ "moved": "",
+ "created_at": "",
+ "summary": {
+ "statuses_count": "",
+ "following_count": "",
+ "followers_count": ""
+ },
+ "toots": {
+ "default": "",
+ "all": ""
+ }
+ },
+ "attachments": {
+ "name": ""
+ },
+ "search": {
+ "header": {
+ "prefix": "",
+ "placeholder": ""
+ },
+ "empty": {
+ "general": "",
+ "advanced": {
+ "header": "",
+ "example": {
+ "account": "",
+ "hashtag": "",
+ "statusLink": "",
+ "accountLink": ""
+ }
+ }
+ },
+ "sections": {
+ "accounts": "",
+ "hashtags": "",
+ "statuses": ""
+ },
+ "notFound": ""
+ },
+ "toot": {
+ "name": ""
+ },
+ "users": {
+ "accounts": {
+ "following": "",
+ "followers": ""
+ },
+ "statuses": {
+ "reblogged_by": "",
+ "favourited_by": ""
+ }
+ },
+ "history": {
+ "name": ""
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/ko/components/contextMenu.json b/src/i18n/ko/components/contextMenu.json
index 4b25d130..9f88f338 100644
--- a/src/i18n/ko/components/contextMenu.json
+++ b/src/i18n/ko/components/contextMenu.json
@@ -14,6 +14,10 @@
"action": "사용자 신고"
}
},
+ "copy": {
+ "action": "",
+ "succeed": ""
+ },
"instance": {
"title": "",
"block": {
diff --git a/src/i18n/ko/components/parse.json b/src/i18n/ko/components/parse.json
index ff5d8d24..fc364f0e 100644
--- a/src/i18n/ko/components/parse.json
+++ b/src/i18n/ko/components/parse.json
@@ -1,9 +1,8 @@
{
"HTML": {
- "expanded": {
- "true": "{{hint}} 접기",
- "false": "{{hint}} 펼치기"
- },
- "defaultHint": "글"
+ "accessibilityHint": "",
+ "expanded": "{{hint}}{{totalLines}}",
+ "totalLines": "",
+ "defaultHint": ""
}
}
\ No newline at end of file
diff --git a/src/i18n/ko/screens/accountSelection.json b/src/i18n/ko/screens/accountSelection.json
new file mode 100644
index 00000000..b16795a6
--- /dev/null
+++ b/src/i18n/ko/screens/accountSelection.json
@@ -0,0 +1,6 @@
+{
+ "heading": "",
+ "content": {
+ "select_account": ""
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/ko/screens/tabs.json b/src/i18n/ko/screens/tabs.json
index fdb34a76..90804d1b 100644
--- a/src/i18n/ko/screens/tabs.json
+++ b/src/i18n/ko/screens/tabs.json
@@ -78,9 +78,7 @@
}
},
"fontSize": {
- "showcase": "예시 툿",
"demo": "데모 툿이에요😊. 아래의 여러 옵션 중에서 선택할 수 있어요.
이 설정은 툿의 메인 내용에만 적용되고, 다른 폰트 크기에 영향을 미치지 않아요.
",
- "availableSizes": "사용할 수 있는 크기",
"sizes": {
"S": "작게",
"M": "중간 - 기본값",
@@ -147,7 +145,8 @@
"group": "그룹 {{index}}",
"label": "라벨",
"content": "내용"
- }
+ },
+ "mediaSelectionFailed": ""
},
"push": {
"notAvailable": "이 기기는 tooot의 푸시 알림을 지원하지 않아요",
diff --git a/src/i18n/pt_BR/components/contextMenu.json b/src/i18n/pt_BR/components/contextMenu.json
index fb858fa9..87bc4c52 100644
--- a/src/i18n/pt_BR/components/contextMenu.json
+++ b/src/i18n/pt_BR/components/contextMenu.json
@@ -14,6 +14,10 @@
"action": "Denunciar usuário"
}
},
+ "copy": {
+ "action": "",
+ "succeed": ""
+ },
"instance": {
"title": "Ação da Instância",
"block": {
diff --git a/src/i18n/pt_BR/components/parse.json b/src/i18n/pt_BR/components/parse.json
index 606d1a46..4b07729b 100644
--- a/src/i18n/pt_BR/components/parse.json
+++ b/src/i18n/pt_BR/components/parse.json
@@ -1,9 +1,8 @@
{
"HTML": {
- "expanded": {
- "true": "Fechar {{hint}}",
- "false": "Expandir {{hint}}"
- },
- "defaultHint": "artigo"
+ "accessibilityHint": "Toque para expandir ou recolher conteúdo",
+ "expanded": "{{hint}}{{totalLines}}",
+ "totalLines": "",
+ "defaultHint": ""
}
}
\ No newline at end of file
diff --git a/src/i18n/pt_BR/components/timeline.json b/src/i18n/pt_BR/components/timeline.json
index 7550e747..c5f3f967 100644
--- a/src/i18n/pt_BR/components/timeline.json
+++ b/src/i18n/pt_BR/components/timeline.json
@@ -81,7 +81,7 @@
"accessibilityHint": "Toque para ir à página de {{name}}"
},
"content": {
- "expandHint": "conteúdo oculto"
+ "expandHint": "Conteúdo oculto"
},
"filtered": "Filtrado",
"fullConversation": "Ler conversas",
diff --git a/src/i18n/pt_BR/screens/accountSelection.json b/src/i18n/pt_BR/screens/accountSelection.json
new file mode 100644
index 00000000..b16795a6
--- /dev/null
+++ b/src/i18n/pt_BR/screens/accountSelection.json
@@ -0,0 +1,6 @@
+{
+ "heading": "",
+ "content": {
+ "select_account": ""
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/pt_BR/screens/tabs.json b/src/i18n/pt_BR/screens/tabs.json
index 8581178c..66fc604e 100644
--- a/src/i18n/pt_BR/screens/tabs.json
+++ b/src/i18n/pt_BR/screens/tabs.json
@@ -78,9 +78,7 @@
}
},
"fontSize": {
- "showcase": "Exemplo de toot",
"demo": "Esta é uma demonstração também😊. Você pode escolher entre várias opções abaixo.
Esta configuração afeta apenas o conteúdo principal dos toots, mas não os tamanhos de outra fonte.
",
- "availableSizes": "Tamanhos disponíveis",
"sizes": {
"S": "P",
"M": "M - Padrão",
@@ -147,7 +145,8 @@
"group": "Grupo {{index}}",
"label": "Rótulo",
"content": "Conteúdo"
- }
+ },
+ "mediaSelectionFailed": ""
},
"push": {
"notAvailable": "Seu telefone não suporta notificação de envio de tooot",
diff --git a/src/i18n/vi/components/contextMenu.json b/src/i18n/vi/components/contextMenu.json
index d99cb59f..b54ab9aa 100644
--- a/src/i18n/vi/components/contextMenu.json
+++ b/src/i18n/vi/components/contextMenu.json
@@ -14,6 +14,10 @@
"action": "Báo cáo"
}
},
+ "copy": {
+ "action": "",
+ "succeed": ""
+ },
"instance": {
"title": "Hành động máy chủ",
"block": {
diff --git a/src/i18n/vi/components/parse.json b/src/i18n/vi/components/parse.json
index ccfb69d0..fc364f0e 100644
--- a/src/i18n/vi/components/parse.json
+++ b/src/i18n/vi/components/parse.json
@@ -1,9 +1,8 @@
{
"HTML": {
- "expanded": {
- "true": "Cuộn {{hint}}",
- "false": "Mở {{hint}}"
- },
- "defaultHint": "Tút"
+ "accessibilityHint": "",
+ "expanded": "{{hint}}{{totalLines}}",
+ "totalLines": "",
+ "defaultHint": ""
}
}
\ No newline at end of file
diff --git a/src/i18n/vi/components/timeline.json b/src/i18n/vi/components/timeline.json
index 63f09362..4b1c863c 100644
--- a/src/i18n/vi/components/timeline.json
+++ b/src/i18n/vi/components/timeline.json
@@ -81,7 +81,7 @@
"accessibilityHint": "Đến trang của {{name}}"
},
"content": {
- "expandHint": "nội dung ẩn"
+ "expandHint": "Nội dung ẩn"
},
"filtered": "Đã lọc",
"fullConversation": "Xem thêm",
diff --git a/src/i18n/vi/screens/accountSelection.json b/src/i18n/vi/screens/accountSelection.json
new file mode 100644
index 00000000..b16795a6
--- /dev/null
+++ b/src/i18n/vi/screens/accountSelection.json
@@ -0,0 +1,6 @@
+{
+ "heading": "",
+ "content": {
+ "select_account": ""
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/vi/screens/tabs.json b/src/i18n/vi/screens/tabs.json
index 166c2188..f095b624 100644
--- a/src/i18n/vi/screens/tabs.json
+++ b/src/i18n/vi/screens/tabs.json
@@ -78,9 +78,7 @@
}
},
"fontSize": {
- "showcase": "Xem trước",
"demo": "Đây là một tút mẫu 😊 Bạn có thể chọn một trong nhiều lựa chọn bên dưới.
Tùy chọn này chỉ áp dụng cho nội dung tút chứ không ảnh hưởng những phần tử khác của app.
",
- "availableSizes": "Kích cỡ",
"sizes": {
"S": "S",
"M": "M - Mặc định",
@@ -147,7 +145,8 @@
"group": "Mục {{index}}",
"label": "Nhãn",
"content": "Nội dung"
- }
+ },
+ "mediaSelectionFailed": ""
},
"push": {
"notAvailable": "Điện thoại của bạn chưa bật thông báo đẩy",
diff --git a/src/i18n/zh-Hans/components/contextMenu.json b/src/i18n/zh-Hans/components/contextMenu.json
index f2b033ef..cd6339a6 100644
--- a/src/i18n/zh-Hans/components/contextMenu.json
+++ b/src/i18n/zh-Hans/components/contextMenu.json
@@ -14,6 +14,10 @@
"action": "举报用户"
}
},
+ "copy": {
+ "action": "复制嘟文",
+ "succeed": "已复制"
+ },
"instance": {
"title": "实例操作",
"block": {
diff --git a/src/i18n/zh-Hans/components/parse.json b/src/i18n/zh-Hans/components/parse.json
index f141f891..dc86c41a 100644
--- a/src/i18n/zh-Hans/components/parse.json
+++ b/src/i18n/zh-Hans/components/parse.json
@@ -1,9 +1,8 @@
{
"HTML": {
- "expanded": {
- "true": "折叠{{hint}}",
- "false": "展开{{hint}}"
- },
- "defaultHint": "全文"
+ "accessibilityHint": "点击展开或折叠内容",
+ "expanded": "{{hint}}{{totalLines}}",
+ "totalLines": " ({{count}} 行)",
+ "defaultHint": "长嘟文"
}
}
\ No newline at end of file
diff --git a/src/i18n/zh-Hans/screens/accountSelection.json b/src/i18n/zh-Hans/screens/accountSelection.json
new file mode 100644
index 00000000..49a8ec4a
--- /dev/null
+++ b/src/i18n/zh-Hans/screens/accountSelection.json
@@ -0,0 +1,6 @@
+{
+ "heading": "分享到...",
+ "content": {
+ "select_account": "选择帐号"
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/zh-Hans/screens/tabs.json b/src/i18n/zh-Hans/screens/tabs.json
index 1f968e41..2a3f661d 100644
--- a/src/i18n/zh-Hans/screens/tabs.json
+++ b/src/i18n/zh-Hans/screens/tabs.json
@@ -78,9 +78,7 @@
}
},
"fontSize": {
- "showcase": "嘟文示例",
"demo": "这是一条测试用的嘟文😊。以下是可供选择的字号,从小号至超大号。
这个设置仅会调整嘟文的正文字号,不影响其它字号。
",
- "availableSizes": "可选字号",
"sizes": {
"S": "小号",
"M": "默认",
@@ -147,7 +145,8 @@
"group": "第 {{index}} 组",
"label": "标签",
"content": "内容"
- }
+ },
+ "mediaSelectionFailed": "图片处理失败,请重试"
},
"push": {
"notAvailable": "您的手机不支持tooot推送通知",
diff --git a/src/i18n/zh-Hant/components/contextMenu.json b/src/i18n/zh-Hant/components/contextMenu.json
index bcf2b253..ba398d8a 100644
--- a/src/i18n/zh-Hant/components/contextMenu.json
+++ b/src/i18n/zh-Hant/components/contextMenu.json
@@ -14,6 +14,10 @@
"action": ""
}
},
+ "copy": {
+ "action": "",
+ "succeed": ""
+ },
"instance": {
"title": "",
"block": {
diff --git a/src/i18n/zh-Hant/components/parse.json b/src/i18n/zh-Hant/components/parse.json
index df93b2df..fc364f0e 100644
--- a/src/i18n/zh-Hant/components/parse.json
+++ b/src/i18n/zh-Hant/components/parse.json
@@ -1,9 +1,8 @@
{
"HTML": {
- "expanded": {
- "true": "收起{{hint}}",
- "false": "展開{{hint}}"
- },
- "defaultHint": "全文"
+ "accessibilityHint": "",
+ "expanded": "{{hint}}{{totalLines}}",
+ "totalLines": "",
+ "defaultHint": ""
}
}
\ No newline at end of file
diff --git a/src/i18n/zh-Hant/screens/accountSelection.json b/src/i18n/zh-Hant/screens/accountSelection.json
new file mode 100644
index 00000000..b16795a6
--- /dev/null
+++ b/src/i18n/zh-Hant/screens/accountSelection.json
@@ -0,0 +1,6 @@
+{
+ "heading": "",
+ "content": {
+ "select_account": ""
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/zh-Hant/screens/tabs.json b/src/i18n/zh-Hant/screens/tabs.json
index bf70a873..0ba7ce83 100644
--- a/src/i18n/zh-Hant/screens/tabs.json
+++ b/src/i18n/zh-Hant/screens/tabs.json
@@ -78,9 +78,7 @@
}
},
"fontSize": {
- "showcase": "嘟文範例",
"demo": "",
- "availableSizes": "",
"sizes": {
"S": "",
"M": "",
@@ -147,7 +145,8 @@
"group": "",
"label": "",
"content": ""
- }
+ },
+ "mediaSelectionFailed": ""
},
"push": {
"notAvailable": "",
diff --git a/src/screens/AccountSelection.tsx b/src/screens/AccountSelection.tsx
new file mode 100644
index 00000000..ff5e99aa
--- /dev/null
+++ b/src/screens/AccountSelection.tsx
@@ -0,0 +1,163 @@
+import AccountButton from '@components/AccountButton'
+import CustomText from '@components/Text'
+import navigationRef from '@helpers/navigationRef'
+import { RootStackScreenProps } from '@utils/navigation/navigators'
+import { getInstances } from '@utils/slices/instancesSlice'
+import { StyleConstants } from '@utils/styles/constants'
+import { useTheme } from '@utils/styles/ThemeManager'
+import * as VideoThumbnails from 'expo-video-thumbnails'
+import React, { useEffect, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { FlatList, Image, ScrollView, View } from 'react-native'
+import { SafeAreaProvider } from 'react-native-safe-area-context'
+import { useSelector } from 'react-redux'
+
+const Share = ({
+ text,
+ media
+}: {
+ text?: string | undefined
+ media?:
+ | {
+ uri: string
+ mime: string
+ }[]
+ | undefined
+}) => {
+ const { colors } = useTheme()
+
+ const [images, setImages] = useState([])
+ useEffect(() => {
+ const prepareThumbs = async (media: { uri: string; mime: string }[]) => {
+ const thumbs: string[] = []
+ for (const m of media) {
+ if (m.mime.startsWith('image/')) {
+ thumbs.push(m.uri)
+ } else if (m.mime.startsWith('video/')) {
+ const { uri } = await VideoThumbnails.getThumbnailAsync(m.uri)
+ thumbs.push(uri)
+ }
+ }
+ setImages(thumbs)
+ }
+ if (media) {
+ prepareThumbs(media)
+ }
+ }, [])
+
+ if (text) {
+ return (
+
+ )
+ }
+ if (media) {
+ return (
+
+ (
+
+ )}
+ ItemSeparatorComponent={() => (
+
+ )}
+ />
+
+ )
+ }
+
+ return null
+}
+
+// Only needed when data incoming into the app when there are multiple accounts
+const ScreenAccountSelection = ({
+ route: {
+ params: { share }
+ }
+}: RootStackScreenProps<'Screen-AccountSelection'>) => {
+ const { colors } = useTheme()
+ const { t } = useTranslation('screenAccountSelection')
+
+ const instances = useSelector(getInstances, () => true)
+
+ return (
+
+
+
+ {share ? : null}
+
+ {t('content.select_account')}
+
+
+ {instances.length
+ ? instances
+ .slice()
+ .sort((a, b) =>
+ `${a.uri}${a.account.acct}`.localeCompare(
+ `${b.uri}${b.account.acct}`
+ )
+ )
+ .map((instance, index) => {
+ return (
+ {
+ navigationRef.navigate('Screen-Compose', {
+ type: 'share',
+ ...share
+ })
+ }}
+ />
+ )
+ })
+ : null}
+
+
+
+
+ )
+}
+
+export default ScreenAccountSelection
diff --git a/src/screens/Announcements.tsx b/src/screens/Announcements.tsx
index e38df48c..2b04312b 100644
--- a/src/screens/Announcements.tsx
+++ b/src/screens/Announcements.tsx
@@ -15,8 +15,15 @@ import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useCallback, useEffect, useState } from 'react'
import { Trans, useTranslation } from 'react-i18next'
-import { FormattedRelativeTime } from 'react-intl'
-import { Dimensions, Platform, Pressable, StyleSheet, View } from 'react-native'
+import {
+ Dimensions,
+ NativeScrollEvent,
+ NativeSyntheticEvent,
+ Platform,
+ Pressable,
+ StyleSheet,
+ View
+} from 'react-native'
import { Circle } from 'react-native-animated-spinkit'
import FastImage from 'react-native-fast-image'
import { FlatList, ScrollView } from 'react-native-gesture-handler'
@@ -92,9 +99,7 @@ const ScreenAnnouncements: React.FC<
>
- ]}
+ components={[]}
/>
{
+ }: NativeSyntheticEvent) => {
setIndex(Math.floor(x / width))
},
[]
diff --git a/src/screens/Compose.tsx b/src/screens/Compose.tsx
index d0695c9d..3a7aa3ab 100644
--- a/src/screens/Compose.tsx
+++ b/src/screens/Compose.tsx
@@ -150,7 +150,7 @@ const ScreenCompose: React.FC> = ({
for (const m of params.media) {
uploadAttachment({
composeDispatch,
- media: { ...m, width: 100, height: 100 }
+ media: { uri: m.uri, fileName: 'temp.jpg', type: m.mime }
})
}
}
diff --git a/src/screens/Compose/DraftsList/Root.tsx b/src/screens/Compose/DraftsList/Root.tsx
index 3c1abed3..12c44384 100644
--- a/src/screens/Compose/DraftsList/Root.tsx
+++ b/src/screens/Compose/DraftsList/Root.tsx
@@ -47,10 +47,6 @@ const ComposeDraftsListRoot: React.FC = ({ timestamp }) => {
const [checkingAttachments, setCheckingAttachments] = useState(false)
- const removeDraft = useCallback(ts => {
- dispatch(removeInstanceDraft(ts))
- }, [])
-
const renderItem = useCallback(
({ item }: { item: ComposeStateDraft }) => {
return (
@@ -144,7 +140,7 @@ const ComposeDraftsListRoot: React.FC = ({ timestamp }) => {
}}
source={{
uri:
- attachment.local?.local_thumbnail ||
+ attachment.local?.thumbnail ||
attachment.remote?.preview_url
}}
/>
@@ -157,38 +153,6 @@ const ComposeDraftsListRoot: React.FC = ({ timestamp }) => {
},
[theme]
)
- const renderHiddenItem = useCallback(
- ({ item }) => (
- removeDraft(item.timestamp)}
- children={
-
- }
- />
- }
- />
- ),
- [theme]
- )
return (
<>
@@ -220,7 +184,35 @@ const ComposeDraftsListRoot: React.FC = ({ timestamp }) => {
(
+ dispatch(removeInstanceDraft(item.timestamp))}
+ children={
+
+ }
+ />
+ }
+ />
+ )}
disableRightSwipe={true}
rightOpenValue={-actionWidth}
// previewRowKey={
diff --git a/src/screens/Compose/EditAttachment/Root.tsx b/src/screens/Compose/EditAttachment/Root.tsx
index bff60bd9..24e89f3f 100644
--- a/src/screens/Compose/EditAttachment/Root.tsx
+++ b/src/screens/Compose/EditAttachment/Root.tsx
@@ -35,7 +35,7 @@ const ComposeEditAttachmentRoot: React.FC = ({ index }) => {
video.local
? ({
url: video.local.uri,
- preview_url: video.local.local_thumbnail,
+ preview_url: video.local.thumbnail,
blurhash: video.remote?.blurhash
} as Mastodon.AttachmentVideo)
: (video.remote as Mastodon.AttachmentVideo)
diff --git a/src/screens/Compose/Root.tsx b/src/screens/Compose/Root.tsx
index f2270d8a..5afeaf54 100644
--- a/src/screens/Compose/Root.tsx
+++ b/src/screens/Compose/Root.tsx
@@ -4,13 +4,7 @@ import { useSearchQuery } from '@utils/queryHooks/search'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import { chunk, forEach, groupBy, sortBy } from 'lodash'
-import React, {
- useCallback,
- useContext,
- useEffect,
- useMemo,
- useRef
-} from 'react'
+import React, { useContext, useEffect, useMemo, useRef } from 'react'
import {
AccessibilityInfo,
findNodeHandle,
@@ -147,35 +141,25 @@ const ComposeRoot = React.memo(
}
}, [isFetching])
- const listItem = useCallback(
- ({ item }) => (
-
- ),
- [composeState]
- )
-
- const ListFooter = useCallback(
- () => (
-
- ),
- []
- )
-
return (
(
+
+ )}
ListEmptyComponent={listEmpty}
keyboardShouldPersistTaps='always'
ListHeaderComponent={ComposeRootHeader}
- ListFooterComponent={ListFooter}
+ ListFooterComponent={() => (
+
+ )}
ItemSeparatorComponent={ComponentSeparator}
// @ts-ignore
data={data ? data[composeState.tag?.type] : undefined}
diff --git a/src/screens/Compose/Root/Footer/Attachments.tsx b/src/screens/Compose/Root/Footer/Attachments.tsx
index 8df70266..da5c7496 100644
--- a/src/screens/Compose/Root/Footer/Attachments.tsx
+++ b/src/screens/Compose/Root/Footer/Attachments.tsx
@@ -56,9 +56,12 @@ const ComposeAttachments: React.FC = ({ accessibleRefAttachments }) => {
})
}, [composeState.attachments.sensitive])
- const calculateWidth = useCallback(item => {
+ const calculateWidth = useCallback((item: ExtendedAttachment) => {
if (item.local) {
- return (item.local.width / item.local.height) * DEFAULT_HEIGHT
+ return (
+ ((item.local.width || 100) / (item.local.height || 100)) *
+ DEFAULT_HEIGHT
+ )
} else {
if (item.remote) {
if (item.remote.meta.original.aspect) {
@@ -135,7 +138,7 @@ const ComposeAttachments: React.FC = ({ accessibleRefAttachments }) => {
{item.remote?.meta?.original?.duration ? (
diff --git a/src/screens/Compose/Root/Footer/Emojis.tsx b/src/screens/Compose/Root/Footer/Emojis.tsx
index 552d755d..eb6ee6b2 100644
--- a/src/screens/Compose/Root/Footer/Emojis.tsx
+++ b/src/screens/Compose/Root/Footer/Emojis.tsx
@@ -42,22 +42,6 @@ const ComposeEmojis: React.FC = ({ accessibleRefEmojis }) => {
}
}, [composeState.emoji.active])
- const listHeader = useCallback(
- ({ section: { title } }) => (
-
- {title}
-
- ),
- []
- )
-
const listItem = useCallback(
({ index, item }: { item: Mastodon.Emoji[]; index: number }) => {
return (
@@ -155,7 +139,18 @@ const ComposeEmojis: React.FC = ({ accessibleRefEmojis }) => {
keyboardShouldPersistTaps='always'
sections={composeState.emoji.emojis || []}
keyExtractor={item => item[0].shortcode}
- renderSectionHeader={listHeader}
+ renderSectionHeader={({ section: { title } }) => (
+
+ {title}
+
+ )}
renderItem={listItem}
windowSize={2}
/>
diff --git a/src/screens/Compose/Root/Footer/addAttachment.ts b/src/screens/Compose/Root/Footer/addAttachment.ts
index 63e11904..86104c42 100644
--- a/src/screens/Compose/Root/Footer/addAttachment.ts
+++ b/src/screens/Compose/Root/Footer/addAttachment.ts
@@ -7,7 +7,7 @@ import { ActionSheetOptions } from '@expo/react-native-action-sheet'
import i18next from 'i18next'
import apiInstance from '@api/instance'
import mediaSelector from '@components/mediaSelector'
-import { ImageOrVideo } from 'react-native-image-crop-picker'
+import { Asset } from 'react-native-image-picker'
export interface Props {
composeDispatch: Dispatch
@@ -22,46 +22,39 @@ export const uploadAttachment = async ({
media
}: {
composeDispatch: Dispatch
- media: { uri: string } & Pick
+ media: Required>
}) => {
const hash = await Crypto.digestStringAsync(
Crypto.CryptoDigestAlgorithm.SHA256,
media.uri + Math.random()
)
- switch (media.mime.split('/')[0]) {
+ switch (media.type.split('/')[0]) {
case 'image':
composeDispatch({
type: 'attachment/upload/start',
payload: {
- local: { ...media, type: 'image', local_thumbnail: media.uri, hash },
+ local: { ...media, thumbnail: media.uri, hash },
uploading: true
}
})
break
case 'video':
VideoThumbnails.getThumbnailAsync(media.uri)
- .then(({ uri, width, height }) =>
+ .then(({ uri, width, height }) => {
composeDispatch({
type: 'attachment/upload/start',
payload: {
- local: {
- ...media,
- type: 'video',
- local_thumbnail: uri,
- hash,
- width,
- height
- },
+ local: { ...media, thumbnail: uri, hash, width, height },
uploading: true
}
})
- )
+ })
.catch(() =>
composeDispatch({
type: 'attachment/upload/start',
payload: {
- local: { ...media, type: 'video', hash },
+ local: { ...media, hash },
uploading: true
}
})
@@ -71,7 +64,7 @@ export const uploadAttachment = async ({
composeDispatch({
type: 'attachment/upload/start',
payload: {
- local: { ...media, type: 'unknown', hash },
+ local: { ...media, hash },
uploading: true
}
})
@@ -102,8 +95,8 @@ export const uploadAttachment = async ({
const formData = new FormData()
formData.append('file', {
uri: media.uri,
- name: media.uri.match(new RegExp(/.*\/(.*)/))?.[1] || 'file.jpg',
- type: media.mime
+ name: media.fileName,
+ type: media.type
} as any)
return apiInstance({
@@ -140,7 +133,8 @@ const chooseAndUploadAttachment = async ({
showActionSheetWithOptions
})
for (const media of result) {
- uploadAttachment({ composeDispatch, media })
+ const requiredMedia = media as Required
+ uploadAttachment({ composeDispatch, media: requiredMedia })
await new Promise(res => setTimeout(res, 500))
}
}
diff --git a/src/screens/Compose/Root/Header/SpoilerInput.tsx b/src/screens/Compose/Root/Header/SpoilerInput.tsx
index 231d7db5..e5794fda 100644
--- a/src/screens/Compose/Root/Header/SpoilerInput.tsx
+++ b/src/screens/Compose/Root/Header/SpoilerInput.tsx
@@ -1,9 +1,12 @@
import CustomText from '@components/Text'
+import { getSettingsFontsize } from '@utils/slices/settingsSlice'
import { StyleConstants } from '@utils/styles/constants'
+import { adaptiveScale } from '@utils/styles/scaling'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useContext } from 'react'
import { useTranslation } from 'react-i18next'
import { TextInput } from 'react-native'
+import { useSelector } from 'react-redux'
import formatText from '../../formatText'
import ComposeContext from '../../utils/createContext'
@@ -12,6 +15,16 @@ const ComposeSpoilerInput: React.FC = () => {
const { t } = useTranslation('screenCompose')
const { colors, mode } = useTheme()
+ const adaptiveFontsize = useSelector(getSettingsFontsize)
+ const adaptedFontsize = adaptiveScale(
+ StyleConstants.Font.Size.M,
+ adaptiveFontsize
+ )
+ const adaptedLineheight = adaptiveScale(
+ StyleConstants.Font.LineHeight.M,
+ adaptiveFontsize
+ )
+
return (
{
marginRight: StyleConstants.Spacing.Global.PagePadding,
borderBottomWidth: 0.5,
color: colors.primaryDefault,
- borderBottomColor: colors.border
+ borderBottomColor: colors.border,
+ fontSize: adaptedFontsize,
+ lineHeight: adaptedLineheight
}}
autoCapitalize='none'
autoCorrect={false}
diff --git a/src/screens/Compose/Root/Header/TextInput.tsx b/src/screens/Compose/Root/Header/TextInput.tsx
index e148cbca..f107cebf 100644
--- a/src/screens/Compose/Root/Header/TextInput.tsx
+++ b/src/screens/Compose/Root/Header/TextInput.tsx
@@ -1,7 +1,9 @@
import CustomText from '@components/Text'
import PasteInput, { PastedFile } from '@mattermost/react-native-paste-input'
import { getInstanceConfigurationStatusMaxAttachments } from '@utils/slices/instancesSlice'
+import { getSettingsFontsize } from '@utils/slices/settingsSlice'
import { StyleConstants } from '@utils/styles/constants'
+import { adaptiveScale } from '@utils/styles/scaling'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useContext } from 'react'
import { useTranslation } from 'react-i18next'
@@ -21,6 +23,16 @@ const ComposeTextInput: React.FC = () => {
() => true
)
+ const adaptiveFontsize = useSelector(getSettingsFontsize)
+ const adaptedFontsize = adaptiveScale(
+ StyleConstants.Font.Size.M,
+ adaptiveFontsize
+ )
+ const adaptedLineheight = adaptiveScale(
+ StyleConstants.Font.LineHeight.M,
+ adaptiveFontsize
+ )
+
return (
{
marginLeft: StyleConstants.Spacing.Global.PagePadding,
marginRight: StyleConstants.Spacing.Global.PagePadding,
color: colors.primaryDefault,
- borderBottomColor: colors.border
+ borderBottomColor: colors.border,
+ fontSize: adaptedFontsize,
+ lineHeight: adaptedLineheight
}}
autoFocus
enablesReturnKeyAutomatically
@@ -87,15 +101,7 @@ const ComposeTextInput: React.FC = () => {
}
for (const file of files) {
- uploadAttachment({
- composeDispatch,
- media: {
- uri: file.uri,
- mime: file.type,
- width: 100,
- height: 100
- }
- })
+ uploadAttachment({ composeDispatch, media: file })
}
}}
>
diff --git a/src/screens/Compose/utils/types.d.ts b/src/screens/Compose/utils/types.d.ts
index 586be113..3b89b956 100644
--- a/src/screens/Compose/utils/types.d.ts
+++ b/src/screens/Compose/utils/types.d.ts
@@ -1,12 +1,8 @@
-import { ImageOrVideo } from 'react-native-image-crop-picker'
+import { Asset } from 'react-native-image-picker'
export type ExtendedAttachment = {
remote?: Mastodon.Attachment
- local?: { uri: string } & Pick & {
- type: 'image' | 'video' | 'unknown'
- local_thumbnail?: string
- hash?: string
- }
+ local?: Asset & { thumbnail?: string; hash: string }
uploading?: boolean
}
@@ -121,10 +117,7 @@ export type ComposeAction =
}
| {
type: 'attachment/upload/end'
- payload: {
- remote: Mastodon.Attachment
- local: { uri: string } & Pick
- }
+ payload: { remote: Mastodon.Attachment; local: Asset }
}
| {
type: 'attachment/upload/fail'
diff --git a/src/screens/ImageViewer/hooks/usePanResponder.ts b/src/screens/ImageViewer/hooks/usePanResponder.ts
index d4ed1fe1..69f0eb9a 100644
--- a/src/screens/ImageViewer/hooks/usePanResponder.ts
+++ b/src/screens/ImageViewer/hooks/usePanResponder.ts
@@ -50,11 +50,9 @@ const usePanResponder = ({
onLongPress,
delayLongPress,
onRequestClose
-}: Props): Readonly<[
- GestureResponderHandlers,
- Animated.Value,
- Animated.ValueXY
-]> => {
+}: Props): Readonly<
+ [GestureResponderHandlers, Animated.Value, Animated.ValueXY]
+> => {
let numberInitialTouches = 1
let initialTouches: NativeTouchEvent[] = []
let currentScale = initialScale
@@ -137,6 +135,7 @@ const usePanResponder = ({
if (gestureState.numberActiveTouches > 1) return
+ // @ts-ignore
longPressHandlerRef = setTimeout(onLongPress, delayLongPress)
},
onStart: (
@@ -150,6 +149,7 @@ const usePanResponder = ({
const tapTS = Date.now()
!timer &&
+ // @ts-ignore
(timer = setTimeout(() => onRequestClose(), DOUBLE_TAP_DELAY + 50))
// Handle double tap event by calculating diff between first and second taps timestamps
@@ -158,6 +158,7 @@ const usePanResponder = ({
)
if (doubleTapToZoomEnabled && isDoubleTapPerformed) {
+ // @ts-ignore
clearTimeout(timer)
const isScaled = currentTranslate.x !== initialTranslate.x // currentScale !== initialScale;
const { pageX: touchX, pageY: touchY } = event.nativeEvent.touches[0]
@@ -291,9 +292,8 @@ const usePanResponder = ({
if (isTapGesture && currentScale > initialScale) {
const { x, y } = currentTranslate
const { dx, dy } = gestureState
- const [topBound, leftBound, bottomBound, rightBound] = getBounds(
- currentScale
- )
+ const [topBound, leftBound, bottomBound, rightBound] =
+ getBounds(currentScale)
let nextTranslateX = x + dx
let nextTranslateY = y + dy
@@ -357,9 +357,8 @@ const usePanResponder = ({
if (tmpTranslate) {
const { x, y } = tmpTranslate
- const [topBound, leftBound, bottomBound, rightBound] = getBounds(
- currentScale
- )
+ const [topBound, leftBound, bottomBound, rightBound] =
+ getBounds(currentScale)
let nextTranslateX = x
let nextTranslateY = y
diff --git a/src/screens/ImageViewer/utils.ts b/src/screens/ImageViewer/utils.ts
index 54703ac5..c75a8ae8 100644
--- a/src/screens/ImageViewer/utils.ts
+++ b/src/screens/ImageViewer/utils.ts
@@ -44,6 +44,7 @@ export const getImageStyles = (
const transform = translate.getTranslateTransform()
if (scale) {
+ // @ts-ignore
transform.push({ scale }, { perspective: new Animated.Value(1000) })
}
diff --git a/src/screens/ImagesViewer.tsx b/src/screens/ImagesViewer.tsx
index 23dfb816..555c5353 100644
--- a/src/screens/ImagesViewer.tsx
+++ b/src/screens/ImagesViewer.tsx
@@ -2,13 +2,9 @@ import analytics from '@components/analytics'
import { HeaderCenter, HeaderLeft, HeaderRight } from '@components/Header'
import { Message } from '@components/Message'
import { useActionSheet } from '@expo/react-native-action-sheet'
-import { NativeStackNavigationProp } from '@react-navigation/native-stack'
-import {
- RootStackParamList,
- RootStackScreenProps
-} from '@utils/navigation/navigators'
+import { RootStackScreenProps } from '@utils/navigation/navigators'
import { useTheme } from '@utils/styles/ThemeManager'
-import React, { RefObject, useCallback, useRef, useState } from 'react'
+import React, { useCallback, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Platform, Share, StatusBar, View } from 'react-native'
import FlashMessage from 'react-native-flash-message'
diff --git a/src/screens/Tabs.tsx b/src/screens/Tabs.tsx
index 0c18965e..6efb3266 100644
--- a/src/screens/Tabs.tsx
+++ b/src/screens/Tabs.tsx
@@ -1,10 +1,7 @@
import GracefullyImage from '@components/GracefullyImage'
import haptics from '@components/haptics'
import Icon from '@components/Icon'
-import {
- BottomTabNavigationOptions,
- createBottomTabNavigator
-} from '@react-navigation/bottom-tabs'
+import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'
import { useAppDispatch } from '@root/store'
import {
RootStackScreenProps,
@@ -15,10 +12,7 @@ import {
getInstanceAccount,
getInstanceActive
} from '@utils/slices/instancesSlice'
-import {
- getVersionUpdate,
- retriveVersionLatest
-} from '@utils/slices/appSlice'
+import { getVersionUpdate, retriveVersionLatest } from '@utils/slices/appSlice'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useCallback, useEffect, useMemo } from 'react'
import { Platform } from 'react-native'
@@ -32,7 +26,7 @@ const Tab = createBottomTabNavigator()
const ScreenTabs = React.memo(
({ navigation }: RootStackScreenProps<'Screen-Tabs'>) => {
- const { colors, theme } = useTheme()
+ const { colors } = useTheme()
const instanceActive = useSelector(getInstanceActive)
const instanceAccount = useSelector(
@@ -40,57 +34,6 @@ const ScreenTabs = React.memo(
(prev, next) => prev?.avatarStatic === next?.avatarStatic
)
- const screenOptions = useCallback(
- ({ route }): BottomTabNavigationOptions => ({
- headerShown: false,
- tabBarActiveTintColor: colors.primaryDefault,
- tabBarInactiveTintColor: colors.secondary,
- tabBarShowLabel: false,
- ...(Platform.OS === 'android' && { tabBarHideOnKeyboard: true }),
- tabBarStyle: { display: instanceActive !== -1 ? 'flex' : 'none' },
- tabBarIcon: ({
- focused,
- color,
- size
- }: {
- focused: boolean
- color: string
- size: number
- }) => {
- switch (route.name) {
- case 'Tab-Local':
- return
- case 'Tab-Public':
- return
- case 'Tab-Compose':
- return
- case 'Tab-Notifications':
- return
- case 'Tab-Me':
- return (
-
- )
- default:
- return
- }
- }
- }),
- [instanceAccount?.avatarStatic, instanceActive, theme]
- )
-
const composeListeners = useMemo(
() => ({
tabPress: (e: any) => {
@@ -132,7 +75,53 @@ const ScreenTabs = React.memo(
return (
({
+ headerShown: false,
+ tabBarActiveTintColor: colors.primaryDefault,
+ tabBarInactiveTintColor: colors.secondary,
+ tabBarShowLabel: false,
+ ...(Platform.OS === 'android' && { tabBarHideOnKeyboard: true }),
+ tabBarStyle: { display: instanceActive !== -1 ? 'flex' : 'none' },
+ tabBarIcon: ({
+ focused,
+ color,
+ size
+ }: {
+ focused: boolean
+ color: string
+ size: number
+ }) => {
+ switch (route.name) {
+ case 'Tab-Local':
+ return
+ case 'Tab-Public':
+ return
+ case 'Tab-Compose':
+ return
+ case 'Tab-Notifications':
+ return
+ case 'Tab-Me':
+ return (
+
+ )
+ default:
+ return
+ }
+ }
+ })}
>
diff --git a/src/screens/Tabs/Local.tsx b/src/screens/Tabs/Local.tsx
index 53cadbb2..2b2ae681 100644
--- a/src/screens/Tabs/Local.tsx
+++ b/src/screens/Tabs/Local.tsx
@@ -7,64 +7,101 @@ import {
ScreenTabsScreenProps,
TabLocalStackParamList
} from '@utils/navigation/navigators'
+import { useListsQuery } from '@utils/queryHooks/lists'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
-import React, { useCallback, useMemo } from 'react'
+import layoutAnimation from '@utils/styles/layoutAnimation'
+import React, { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
-import { Platform } from 'react-native'
+import ContextMenu from 'react-native-context-menu-view'
import TabSharedRoot from './Shared/Root'
const Stack = createNativeStackNavigator()
const TabLocal = React.memo(
({ navigation }: ScreenTabsScreenProps<'Tab-Local'>) => {
- const { t, i18n } = useTranslation('screenTabs')
+ const { t } = useTranslation('screenTabs')
- const screenOptionsRoot = useMemo(
- () => ({
- title: t('tabs.local.name'),
- ...(Platform.OS === 'android' && {
- headerCenter: () =>
- }),
- headerRight: () => (
- {
- analytics('search_tap', { page: 'Local' })
- navigation.navigate('Tab-Local', {
- screen: 'Tab-Shared-Search',
- params: { text: undefined }
- })
- }}
- />
- )
- }),
- [i18n.language]
- )
+ const { data: lists } = useListsQuery({})
+ useEffect(() => {
+ layoutAnimation()
+ }, [lists?.length])
- const queryKey: QueryKeyTimeline = ['Timeline', { page: 'Following' }]
- const renderItem = useCallback(
- ({ item }) => ,
- []
- )
- const children = useCallback(
- () => (
-
- ),
- []
- )
+ const [queryKey, setQueryKey] = useState([
+ 'Timeline',
+ { page: 'Following' }
+ ])
return (
(
+ ({
+ id: list.id,
+ title: list.title,
+ disabled:
+ queryKey[1].page === 'List' &&
+ queryKey[1].list === list.id
+ }))
+ ]
+ : undefined
+ }
+ onPress={({ nativeEvent: { id } }) => {
+ id.length
+ ? setQueryKey(['Timeline', { page: 'List', list: id }])
+ : setQueryKey(['Timeline', { page: 'Following' }])
+ }}
+ children={
+ 0}
+ content={
+ queryKey[1].page === 'List' && queryKey[1].list?.length
+ ? lists?.find(list => list.id === queryKey[1].list)
+ ?.title
+ : t('tabs.local.name')
+ }
+ />
+ }
+ />
+ ),
+ headerRight: () => (
+ {
+ analytics('search_tap', { page: 'Local' })
+ navigation.navigate('Tab-Local', {
+ screen: 'Tab-Shared-Search',
+ params: { text: undefined }
+ })
+ }}
+ />
+ )
+ }}
+ children={() => (
+ (
+
+ )
+ }}
+ />
+ )}
/>
{TabSharedRoot({ Stack })}
diff --git a/src/screens/Tabs/Me/Bookmarks.tsx b/src/screens/Tabs/Me/Bookmarks.tsx
index aad868e8..a6bdd1f2 100644
--- a/src/screens/Tabs/Me/Bookmarks.tsx
+++ b/src/screens/Tabs/Me/Bookmarks.tsx
@@ -1,16 +1,22 @@
import Timeline from '@components/Timeline'
import TimelineDefault from '@components/Timeline/Default'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
-import React, { useCallback } from 'react'
+import React from 'react'
const TabMeBookmarks = React.memo(
() => {
const queryKey: QueryKeyTimeline = ['Timeline', { page: 'Bookmarks' }]
- const renderItem = useCallback(
- ({ item }) => ,
- []
+
+ return (
+ (
+
+ )
+ }}
+ />
)
- return
},
() => true
)
diff --git a/src/screens/Tabs/Me/Cconversations.tsx b/src/screens/Tabs/Me/Cconversations.tsx
index 65eecd6d..48d2410e 100644
--- a/src/screens/Tabs/Me/Cconversations.tsx
+++ b/src/screens/Tabs/Me/Cconversations.tsx
@@ -1,19 +1,22 @@
import Timeline from '@components/Timeline'
import TimelineConversation from '@components/Timeline/Conversation'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
-import React, { useCallback } from 'react'
+import React from 'react'
const TabMeConversations = React.memo(
() => {
const queryKey: QueryKeyTimeline = ['Timeline', { page: 'Conversations' }]
- const renderItem = useCallback(
- ({ item }) => (
-
- ),
- []
- )
- return
+ return (
+ (
+
+ )
+ }}
+ />
+ )
},
() => true
)
diff --git a/src/screens/Tabs/Me/Favourites.tsx b/src/screens/Tabs/Me/Favourites.tsx
index fe799f19..c712fe4a 100644
--- a/src/screens/Tabs/Me/Favourites.tsx
+++ b/src/screens/Tabs/Me/Favourites.tsx
@@ -1,17 +1,22 @@
import Timeline from '@components/Timeline'
import TimelineDefault from '@components/Timeline/Default'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
-import React, { useCallback } from 'react'
+import React from 'react'
const TabMeFavourites = React.memo(
() => {
const queryKey: QueryKeyTimeline = ['Timeline', { page: 'Favourites' }]
- const renderItem = useCallback(
- ({ item }) => ,
- []
- )
- return
+ return (
+ (
+
+ )
+ }}
+ />
+ )
},
() => true
)
diff --git a/src/screens/Tabs/Me/ListsList.tsx b/src/screens/Tabs/Me/ListsList.tsx
index ad94eb04..3c76cf85 100644
--- a/src/screens/Tabs/Me/ListsList.tsx
+++ b/src/screens/Tabs/Me/ListsList.tsx
@@ -2,7 +2,7 @@ import Timeline from '@components/Timeline'
import TimelineDefault from '@components/Timeline/Default'
import { TabMeStackScreenProps } from '@utils/navigation/navigators'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
-import React, { useCallback } from 'react'
+import React from 'react'
const TabMeListsList: React.FC> = ({
route: {
@@ -10,12 +10,17 @@ const TabMeListsList: React.FC> = ({
}
}) => {
const queryKey: QueryKeyTimeline = ['Timeline', { page: 'List', list }]
- const renderItem = useCallback(
- ({ item }) => ,
- []
- )
- return
+ return (
+ (
+
+ )
+ }}
+ />
+ )
}
export default TabMeListsList
diff --git a/src/screens/Tabs/Me/Profile/Root/AvatarHeader.tsx b/src/screens/Tabs/Me/Profile/Root/AvatarHeader.tsx
index 23d83b9e..227f5d17 100644
--- a/src/screens/Tabs/Me/Profile/Root/AvatarHeader.tsx
+++ b/src/screens/Tabs/Me/Profile/Root/AvatarHeader.tsx
@@ -1,5 +1,6 @@
import mediaSelector from '@components/mediaSelector'
import { MenuRow } from '@components/Menu'
+import { displayMessage } from '@components/Message'
import { useActionSheet } from '@expo/react-native-action-sheet'
import { useProfileMutation, useProfileQuery } from '@utils/queryHooks/profile'
import { useTheme } from '@utils/styles/ThemeManager'
@@ -37,6 +38,15 @@ const ProfileAvatarHeader: React.FC = ({ type, messageRef }) => {
? { width: 400, height: 400 }
: { width: 1500, height: 500 }
})
+ if (!image[0].uri) {
+ displayMessage({
+ ref: messageRef,
+ message: t('screenTabs:me.profile.mediaSelectionFailed'),
+ theme: theme,
+ type: 'error'
+ })
+ return
+ }
mutation.mutate({
theme,
messageRef,
diff --git a/src/screens/Tabs/Me/Settings/Analytics.tsx b/src/screens/Tabs/Me/Settings/Analytics.tsx
index 7701564b..580cd530 100644
--- a/src/screens/Tabs/Me/Settings/Analytics.tsx
+++ b/src/screens/Tabs/Me/Settings/Analytics.tsx
@@ -42,7 +42,7 @@ const SettingsAnalytics: React.FC = () => {
color: colors.secondary
}}
>
- {t('me.settings.version', { version: Constants.manifest?.version })}
+ {t('me.settings.version', { version: Constants.expoConfig?.version })}
-
- {t('me.fontSize.showcase')}
-
-
-
-
-
-
-
- {t('me.fontSize.availableSizes')}
-
{sizesDemo}
@@ -185,6 +148,26 @@ const TabMeSettingsFontsize: React.FC<
style={{ marginHorizontal: StyleConstants.Spacing.S }}
/>
+
+
+
+
+
)
}
diff --git a/src/screens/Tabs/Me/Switch.tsx b/src/screens/Tabs/Me/Switch.tsx
index b345ff98..80c90384 100644
--- a/src/screens/Tabs/Me/Switch.tsx
+++ b/src/screens/Tabs/Me/Switch.tsx
@@ -1,11 +1,6 @@
-import analytics from '@components/analytics'
-import Button from '@components/Button'
-import haptics from '@components/haptics'
+import AccountButton from '@components/AccountButton'
import ComponentInstance from '@components/Instance'
import CustomText from '@components/Text'
-import { useNavigation } from '@react-navigation/native'
-import initQuery from '@utils/initQuery'
-import { InstanceLatest } from '@utils/migrations/instances/migration'
import { getInstanceActive, getInstances } from '@utils/slices/instancesSlice'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
@@ -15,35 +10,6 @@ import { KeyboardAvoidingView, Platform, StyleSheet, View } from 'react-native'
import { ScrollView } from 'react-native-gesture-handler'
import { useSelector } from 'react-redux'
-interface Props {
- instance: InstanceLatest
- selected?: boolean
-}
-
-const AccountButton: React.FC = ({ instance, selected = false }) => {
- const navigation = useNavigation()
-
- return (
-