mirror of https://github.com/tooot-app/app
Fixed #119 and translation
This commit is contained in:
parent
0517d2fae2
commit
0190b35b57
|
@ -1,5 +1,5 @@
|
||||||
# [tooot](https://tooot.app/) app for Mastodon
|
# [tooot](https://tooot.app/) app for Mastodon
|
||||||
|
|
||||||
[![GPL-3.0](https://img.shields.io/github/license/tooot-app/push?style=flat-square)](LICENSE) ![GitHub issues](https://img.shields.io/github/issues/tooot-app/app?style=flat-square) ![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/tooot-app/app?include_prereleases&style=flat-square) ![Code Climate maintainability](https://img.shields.io/codeclimate/maintainability/tooot-app/app?style=flat-square) [![Crowdin](https://badges.crowdin.net/tooot/localized.svg)](https://crowdin.tooot.app/project/tooot)
|
[![GPL-3.0](https://img.shields.io/github/license/tooot-app/push)](LICENSE) ![GitHub issues](https://img.shields.io/github/issues/tooot-app/app) ![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/tooot-app/app?include_prereleases&style=flat-square) ![Code Climate maintainability](https://img.shields.io/codeclimate/maintainability/tooot-app/app) [![Crowdin](https://badges.crowdin.net/tooot/localized.svg)](https://crowdin.tooot.app/project/tooot)
|
||||||
|
|
||||||
![GitHub Workflow Status](https://img.shields.io/github/workflow/status/tooot-app/app/build?style=flat-square) ![GitHub Workflow Status (branch)](https://img.shields.io/github/workflow/status/tooot-app/app/build/candidate?label=build%20candidate&style=flat-square) ![GitHub Workflow Status (branch)](https://img.shields.io/github/workflow/status/tooot-app/app/build/release?label=build%20release&style=flat-square)
|
![GitHub Workflow Status](https://img.shields.io/github/workflow/status/tooot-app/app/build) ![GitHub Workflow Status (branch)](https://img.shields.io/github/workflow/status/tooot-app/app/build/candidate?label=build%20candidate&style=flat-square) ![GitHub Workflow Status (branch)](https://img.shields.io/github/workflow/status/tooot-app/app/build/release?label=build%20release&style=flat-square)
|
||||||
|
|
|
@ -19,6 +19,7 @@ public class BasePackageList {
|
||||||
new expo.modules.font.FontLoaderPackage(),
|
new expo.modules.font.FontLoaderPackage(),
|
||||||
new expo.modules.haptics.HapticsPackage(),
|
new expo.modules.haptics.HapticsPackage(),
|
||||||
new expo.modules.imageloader.ImageLoaderPackage(),
|
new expo.modules.imageloader.ImageLoaderPackage(),
|
||||||
|
new expo.modules.imagemanipulator.ImageManipulatorPackage(),
|
||||||
new expo.modules.imagepicker.ImagePickerPackage(),
|
new expo.modules.imagepicker.ImagePickerPackage(),
|
||||||
new expo.modules.keepawake.KeepAwakePackage(),
|
new expo.modules.keepawake.KeepAwakePackage(),
|
||||||
new expo.modules.localization.LocalizationPackage(),
|
new expo.modules.localization.LocalizationPackage(),
|
||||||
|
|
|
@ -825,7 +825,7 @@ SPEC CHECKSUMS:
|
||||||
EXVideoThumbnails: cd257fc6e07884a704a5674d362a6410933acb68
|
EXVideoThumbnails: cd257fc6e07884a704a5674d362a6410933acb68
|
||||||
EXWebBrowser: 0b466c50e5ff61c9758095d49d5081e3229d77ac
|
EXWebBrowser: 0b466c50e5ff61c9758095d49d5081e3229d77ac
|
||||||
FBLazyVector: 7b423f9e248eae65987838148c36eec1dbfe0b53
|
FBLazyVector: 7b423f9e248eae65987838148c36eec1dbfe0b53
|
||||||
FBReactNativeSpec: be55984d4a593b4ef281ead81139cdfb1812d259
|
FBReactNativeSpec: 5058d1917c80dca4b9ed89bdf94385315939ab80
|
||||||
Firebase: cd2ab85eec8170dc260186159f21072ecb679ad5
|
Firebase: cd2ab85eec8170dc260186159f21072ecb679ad5
|
||||||
FirebaseAnalytics: f3f8f75de34fe04141a69bb1c4bd7e24a80178e1
|
FirebaseAnalytics: f3f8f75de34fe04141a69bb1c4bd7e24a80178e1
|
||||||
FirebaseCore: ac35d680a0bf32319a59966a1478e0741536b97b
|
FirebaseCore: ac35d680a0bf32319a59966a1478e0741536b97b
|
||||||
|
|
|
@ -346,7 +346,7 @@
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = tooot/tooot.entitlements;
|
CODE_SIGN_ENTITLEMENTS = tooot/tooot.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Distribution";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
CURRENT_PROJECT_VERSION = 2102022230;
|
CURRENT_PROJECT_VERSION = 2102022230;
|
||||||
DEVELOPMENT_TEAM = 8EGBLQ2MA6;
|
DEVELOPMENT_TEAM = 8EGBLQ2MA6;
|
||||||
|
@ -366,7 +366,7 @@
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.xmflsct.app.tooot;
|
PRODUCT_BUNDLE_IDENTIFIER = com.xmflsct.app.tooot;
|
||||||
PRODUCT_NAME = tooot;
|
PRODUCT_NAME = tooot;
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "match Development com.xmflsct.app.tooot";
|
PROVISIONING_PROFILE_SPECIFIER = "match AdHoc com.xmflsct.app.tooot";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "tooot-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "tooot-Bridging-Header.h";
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
declare namespace Translate {
|
|
||||||
type Detect = {
|
|
||||||
confidence: number
|
|
||||||
language: string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Language = {
|
|
||||||
code: string
|
|
||||||
name: string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Translate = {
|
|
||||||
translatedText: string
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -74,7 +74,11 @@ const apiGeneral = async <T = unknown>({
|
||||||
// The request was made but no response was received
|
// The request was made but no response was received
|
||||||
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
|
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
|
||||||
// http.ClientRequest in node.js
|
// http.ClientRequest in node.js
|
||||||
console.error(ctx.bold(' API general '), ctx.bold('request'), error)
|
console.error(
|
||||||
|
ctx.bold(' API general '),
|
||||||
|
ctx.bold('request'),
|
||||||
|
error.request
|
||||||
|
)
|
||||||
return Promise.reject()
|
return Promise.reject()
|
||||||
} else {
|
} else {
|
||||||
console.error(
|
console.error(
|
||||||
|
|
|
@ -76,7 +76,7 @@ const MenuRow: React.FC<Props> = ({
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<View>
|
<View style={{ flex: 1 }}>
|
||||||
<View style={styles.core}>
|
<View style={styles.core}>
|
||||||
<View style={styles.front}>
|
<View style={styles.front}>
|
||||||
{iconFront && (
|
{iconFront && (
|
||||||
|
|
|
@ -164,6 +164,7 @@ export interface Props {
|
||||||
expandHint?: string
|
expandHint?: string
|
||||||
highlighted?: boolean
|
highlighted?: boolean
|
||||||
disableDetails?: boolean
|
disableDetails?: boolean
|
||||||
|
selectable?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const ParseHTML = React.memo(
|
const ParseHTML = React.memo(
|
||||||
|
@ -178,7 +179,8 @@ const ParseHTML = React.memo(
|
||||||
numberOfLines = 10,
|
numberOfLines = 10,
|
||||||
expandHint,
|
expandHint,
|
||||||
highlighted = false,
|
highlighted = false,
|
||||||
disableDetails = false
|
disableDetails = false,
|
||||||
|
selectable = false
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const adaptiveFontsize = useSelector(getSettingsFontsize)
|
const adaptiveFontsize = useSelector(getSettingsFontsize)
|
||||||
const adaptedFontsize = adaptiveScale(
|
const adaptedFontsize = adaptiveScale(
|
||||||
|
@ -255,6 +257,7 @@ const ParseHTML = React.memo(
|
||||||
numberOfLines={
|
numberOfLines={
|
||||||
expandAllow ? (expanded ? 999 : numberOfLines) : undefined
|
expandAllow ? (expanded ? 999 : numberOfLines) : undefined
|
||||||
}
|
}
|
||||||
|
selectable={selectable}
|
||||||
/>
|
/>
|
||||||
{expandAllow ? (
|
{expandAllow ? (
|
||||||
<Pressable
|
<Pressable
|
||||||
|
|
|
@ -32,6 +32,7 @@ const TimelineContent = React.memo(
|
||||||
numberOfLines={999}
|
numberOfLines={999}
|
||||||
highlighted={highlighted}
|
highlighted={highlighted}
|
||||||
disableDetails={disableDetails}
|
disableDetails={disableDetails}
|
||||||
|
selectable={highlighted}
|
||||||
/>
|
/>
|
||||||
<ParseHTML
|
<ParseHTML
|
||||||
content={status.content}
|
content={status.content}
|
||||||
|
@ -44,6 +45,7 @@ const TimelineContent = React.memo(
|
||||||
expandHint={t('shared.content.expandHint')}
|
expandHint={t('shared.content.expandHint')}
|
||||||
highlighted={highlighted}
|
highlighted={highlighted}
|
||||||
disableDetails={disableDetails}
|
disableDetails={disableDetails}
|
||||||
|
selectable={highlighted}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
|
@ -56,6 +58,7 @@ const TimelineContent = React.memo(
|
||||||
tags={status.tags}
|
tags={status.tags}
|
||||||
numberOfLines={highlighted ? 999 : numberOfLines}
|
numberOfLines={highlighted ? 999 : numberOfLines}
|
||||||
disableDetails={disableDetails}
|
disableDetails={disableDetails}
|
||||||
|
selectable={highlighted}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -1,32 +1,16 @@
|
||||||
|
import analytics from '@components/analytics'
|
||||||
|
import { ParseHTML } from '@components/Parse'
|
||||||
import { useTranslateQuery } from '@utils/queryHooks/translate'
|
import { useTranslateQuery } from '@utils/queryHooks/translate'
|
||||||
|
import { getInstanceUri } from '@utils/slices/instancesSlice'
|
||||||
import { getSettingsLanguage } from '@utils/slices/settingsSlice'
|
import { getSettingsLanguage } from '@utils/slices/settingsSlice'
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import htmlparser2 from 'htmlparser2-without-node-native'
|
|
||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Pressable, StyleSheet, Text } from 'react-native'
|
import { Pressable, StyleSheet, Text } from 'react-native'
|
||||||
import { Circle } from 'react-native-animated-spinkit'
|
import { Circle } from 'react-native-animated-spinkit'
|
||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux'
|
||||||
|
|
||||||
const availableLanguages = [
|
|
||||||
'en',
|
|
||||||
'ar',
|
|
||||||
'zh',
|
|
||||||
'fr',
|
|
||||||
'de',
|
|
||||||
'hi',
|
|
||||||
'ga',
|
|
||||||
'it',
|
|
||||||
'ja',
|
|
||||||
'ko',
|
|
||||||
'pl',
|
|
||||||
'pt',
|
|
||||||
'ru',
|
|
||||||
'es',
|
|
||||||
'tr'
|
|
||||||
]
|
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
highlighted: boolean
|
highlighted: boolean
|
||||||
status: Mastodon.Status
|
status: Mastodon.Status
|
||||||
|
@ -45,48 +29,31 @@ const TimelineTranslate = React.memo(
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
|
|
||||||
const tootLanguage = status.language.slice(0, 2)
|
const tootLanguage = status.language.slice(0, 2)
|
||||||
if (!availableLanguages.includes(tootLanguage)) {
|
|
||||||
return (
|
|
||||||
<Text
|
|
||||||
style={{
|
|
||||||
...StyleConstants.FontStyle.M,
|
|
||||||
color: theme.disabled
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('shared.translate.unavailable')}
|
|
||||||
</Text>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const settingsLanguage = useSelector(getSettingsLanguage, () => true)
|
const settingsLanguage = useSelector(getSettingsLanguage)
|
||||||
|
|
||||||
if (settingsLanguage.includes(tootLanguage)) {
|
if (settingsLanguage.includes(tootLanguage)) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
let emojisRemoved = status.spoiler_text
|
let text = status.spoiler_text
|
||||||
? status.spoiler_text.concat(status.content)
|
? [status.spoiler_text, status.content]
|
||||||
: status.content
|
: [status.content]
|
||||||
if (status.emojis) {
|
|
||||||
|
for (const i in text) {
|
||||||
for (const emoji of status.emojis) {
|
for (const emoji of status.emojis) {
|
||||||
emojisRemoved = emojisRemoved.replaceAll(`:${emoji.shortcode}:`, '')
|
text[i] = text[i].replaceAll(`:${emoji.shortcode}:`, '')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let cleaned = ''
|
const instanceUri = useSelector(getInstanceUri)
|
||||||
const parser = new htmlparser2.Parser({
|
|
||||||
ontext (text: string) {
|
|
||||||
cleaned = cleaned.concat(text)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
parser.write(emojisRemoved)
|
|
||||||
parser.end()
|
|
||||||
|
|
||||||
const [enabled, setEnabled] = useState(false)
|
const [enabled, setEnabled] = useState(false)
|
||||||
const { refetch, data, isLoading, isSuccess, isError } = useTranslateQuery({
|
const { refetch, data, isLoading, isSuccess, isError } = useTranslateQuery({
|
||||||
toot: cleaned,
|
instance: instanceUri!,
|
||||||
|
id: status.id,
|
||||||
source: status.language,
|
source: status.language,
|
||||||
target: settingsLanguage.slice(0, 2),
|
target: settingsLanguage,
|
||||||
|
text,
|
||||||
options: { enabled }
|
options: { enabled }
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -97,9 +64,15 @@ const TimelineTranslate = React.memo(
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
if (!isSuccess) {
|
if (!isSuccess) {
|
||||||
|
analytics('timeline_shared_translate_retry', {
|
||||||
|
language: status.language
|
||||||
|
})
|
||||||
refetch()
|
refetch()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
analytics('timeline_shared_translate', {
|
||||||
|
language: status.language
|
||||||
|
})
|
||||||
setEnabled(true)
|
setEnabled(true)
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
@ -109,15 +82,21 @@ const TimelineTranslate = React.memo(
|
||||||
...StyleConstants.FontStyle.M,
|
...StyleConstants.FontStyle.M,
|
||||||
color:
|
color:
|
||||||
isLoading || isSuccess
|
isLoading || isSuccess
|
||||||
? theme.disabled
|
? theme.secondary
|
||||||
: isError
|
: isError
|
||||||
? theme.red
|
? theme.red
|
||||||
: theme.blue
|
: theme.blue
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{isError
|
{isError
|
||||||
? t('shared.translate.error')
|
? t('shared.translate.failed')
|
||||||
|
: isSuccess
|
||||||
|
? t('shared.translate.succeed', {
|
||||||
|
provider: data?.provider,
|
||||||
|
source: data?.sourceLanguage
|
||||||
|
})
|
||||||
: t('shared.translate.default')}
|
: t('shared.translate.default')}
|
||||||
|
{__DEV__ ? ` Source: ${status.language}` : undefined}
|
||||||
</Text>
|
</Text>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<Circle
|
<Circle
|
||||||
|
@ -127,15 +106,17 @@ const TimelineTranslate = React.memo(
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
</Pressable>
|
</Pressable>
|
||||||
{data ? (
|
{data
|
||||||
<Text
|
? data.text.map((d, i) => (
|
||||||
style={{
|
<ParseHTML
|
||||||
...StyleConstants.FontStyle.M,
|
key={i}
|
||||||
color: theme.primaryDefault
|
content={d}
|
||||||
}}
|
size={'M'}
|
||||||
children={data}
|
numberOfLines={999}
|
||||||
/>
|
selectable
|
||||||
) : null}
|
/>
|
||||||
|
))
|
||||||
|
: null}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
|
@ -76,8 +76,8 @@
|
||||||
"fullConversation": "Read conversations",
|
"fullConversation": "Read conversations",
|
||||||
"translate": {
|
"translate": {
|
||||||
"default": "Translate",
|
"default": "Translate",
|
||||||
"error": "Try to translate again",
|
"succeed": "Translated by {{provider}} from {{source}}",
|
||||||
"unavailable": "Language not supported"
|
"failed": "Translation failed"
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
"shared": {
|
"shared": {
|
||||||
|
|
|
@ -87,6 +87,7 @@ const ScreenAnnouncements: React.FC<ScreenAnnouncementsProp> = ({
|
||||||
emojis={item.emojis}
|
emojis={item.emojis}
|
||||||
mentions={item.mentions}
|
mentions={item.mentions}
|
||||||
numberOfLines={999}
|
numberOfLines={999}
|
||||||
|
selectable
|
||||||
/>
|
/>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
{item.reactions?.length ? (
|
{item.reactions?.length ? (
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import analytics from '@components/analytics'
|
||||||
import { MenuContainer, MenuRow } from '@components/Menu'
|
import { MenuContainer, MenuRow } from '@components/Menu'
|
||||||
import { displayMessage } from '@components/Message'
|
import { displayMessage } from '@components/Message'
|
||||||
import { useActionSheet } from '@expo/react-native-action-sheet'
|
import { useActionSheet } from '@expo/react-native-action-sheet'
|
||||||
|
@ -40,6 +41,12 @@ const TabMeProfileRoot: React.FC<StackScreenProps<
|
||||||
async buttonIndex => {
|
async buttonIndex => {
|
||||||
switch (buttonIndex) {
|
switch (buttonIndex) {
|
||||||
case 0:
|
case 0:
|
||||||
|
analytics('me_profile_visibility', {
|
||||||
|
current: t(
|
||||||
|
`me.profile.root.visibility.options.${data?.source.privacy}`
|
||||||
|
),
|
||||||
|
new: 'public'
|
||||||
|
})
|
||||||
mutateAsync({ type: 'source[privacy]', data: 'public' })
|
mutateAsync({ type: 'source[privacy]', data: 'public' })
|
||||||
.then(() => dispatch(updateAccountPreferences()))
|
.then(() => dispatch(updateAccountPreferences()))
|
||||||
.catch(err =>
|
.catch(err =>
|
||||||
|
@ -55,6 +62,12 @@ const TabMeProfileRoot: React.FC<StackScreenProps<
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
case 1:
|
case 1:
|
||||||
|
analytics('me_profile_visibility', {
|
||||||
|
current: t(
|
||||||
|
`me.profile.root.visibility.options.${data?.source.privacy}`
|
||||||
|
),
|
||||||
|
new: 'unlisted'
|
||||||
|
})
|
||||||
mutateAsync({ type: 'source[privacy]', data: 'unlisted' })
|
mutateAsync({ type: 'source[privacy]', data: 'unlisted' })
|
||||||
.then(() => dispatch(updateAccountPreferences()))
|
.then(() => dispatch(updateAccountPreferences()))
|
||||||
.catch(err =>
|
.catch(err =>
|
||||||
|
@ -70,6 +83,12 @@ const TabMeProfileRoot: React.FC<StackScreenProps<
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
case 2:
|
case 2:
|
||||||
|
analytics('me_profile_visibility', {
|
||||||
|
current: t(
|
||||||
|
`me.profile.root.visibility.options.${data?.source.privacy}`
|
||||||
|
),
|
||||||
|
new: 'unlisted'
|
||||||
|
})
|
||||||
mutateAsync({ type: 'source[privacy]', data: 'private' })
|
mutateAsync({ type: 'source[privacy]', data: 'private' })
|
||||||
.then(() => dispatch(updateAccountPreferences()))
|
.then(() => dispatch(updateAccountPreferences()))
|
||||||
.catch(err =>
|
.catch(err =>
|
||||||
|
@ -87,10 +106,14 @@ const TabMeProfileRoot: React.FC<StackScreenProps<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}, [])
|
}, [data?.source.privacy])
|
||||||
|
|
||||||
const onPressSensitive = useCallback(() => {
|
const onPressSensitive = useCallback(() => {
|
||||||
if (data?.source.sensitive === undefined) {
|
if (data?.source.sensitive === undefined) {
|
||||||
|
analytics('me_profile_sensitive', {
|
||||||
|
current: undefined,
|
||||||
|
new: true
|
||||||
|
})
|
||||||
mutateAsync({ type: 'source[sensitive]', data: true })
|
mutateAsync({ type: 'source[sensitive]', data: true })
|
||||||
.then(() => dispatch(updateAccountPreferences()))
|
.then(() => dispatch(updateAccountPreferences()))
|
||||||
.catch(err =>
|
.catch(err =>
|
||||||
|
@ -105,6 +128,10 @@ const TabMeProfileRoot: React.FC<StackScreenProps<
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
analytics('me_profile_sensitive', {
|
||||||
|
current: data.source.sensitive,
|
||||||
|
new: !data.source.sensitive
|
||||||
|
})
|
||||||
mutateAsync({
|
mutateAsync({
|
||||||
type: 'source[sensitive]',
|
type: 'source[sensitive]',
|
||||||
data: !data.source.sensitive
|
data: !data.source.sensitive
|
||||||
|
@ -126,6 +153,10 @@ const TabMeProfileRoot: React.FC<StackScreenProps<
|
||||||
|
|
||||||
const onPressLock = useCallback(() => {
|
const onPressLock = useCallback(() => {
|
||||||
if (data?.locked === undefined) {
|
if (data?.locked === undefined) {
|
||||||
|
analytics('me_profile_lock', {
|
||||||
|
current: undefined,
|
||||||
|
new: true
|
||||||
|
})
|
||||||
mutateAsync({ type: 'locked', data: true }).catch(err =>
|
mutateAsync({ type: 'locked', data: true }).catch(err =>
|
||||||
displayMessage({
|
displayMessage({
|
||||||
ref: messageRef,
|
ref: messageRef,
|
||||||
|
@ -138,6 +169,10 @@ const TabMeProfileRoot: React.FC<StackScreenProps<
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
analytics('me_profile_lock', {
|
||||||
|
current: data.locked,
|
||||||
|
new: !data.locked
|
||||||
|
})
|
||||||
mutateAsync({ type: 'locked', data: !data.locked }).catch(err =>
|
mutateAsync({ type: 'locked', data: !data.locked }).catch(err =>
|
||||||
displayMessage({
|
displayMessage({
|
||||||
ref: messageRef,
|
ref: messageRef,
|
||||||
|
@ -154,6 +189,10 @@ const TabMeProfileRoot: React.FC<StackScreenProps<
|
||||||
|
|
||||||
const onPressBot = useCallback(() => {
|
const onPressBot = useCallback(() => {
|
||||||
if (data?.bot === undefined) {
|
if (data?.bot === undefined) {
|
||||||
|
analytics('me_profile_bot', {
|
||||||
|
current: undefined,
|
||||||
|
new: true
|
||||||
|
})
|
||||||
mutateAsync({ type: 'bot', data: true }).catch(err =>
|
mutateAsync({ type: 'bot', data: true }).catch(err =>
|
||||||
displayMessage({
|
displayMessage({
|
||||||
ref: messageRef,
|
ref: messageRef,
|
||||||
|
@ -166,6 +205,10 @@ const TabMeProfileRoot: React.FC<StackScreenProps<
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
analytics('me_profile_bot', {
|
||||||
|
current: data.bot,
|
||||||
|
new: !data.bot
|
||||||
|
})
|
||||||
mutateAsync({ type: 'bot', data: !data?.bot }).catch(err =>
|
mutateAsync({ type: 'bot', data: !data?.bot }).catch(err =>
|
||||||
displayMessage({
|
displayMessage({
|
||||||
ref: messageRef,
|
ref: messageRef,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import analytics from '@components/analytics'
|
||||||
import Button from '@components/Button'
|
import Button from '@components/Button'
|
||||||
import { MenuContainer, MenuRow } from '@components/Menu'
|
import { MenuContainer, MenuRow } from '@components/Menu'
|
||||||
import { updateInstancePush } from '@utils/slices/instances/updatePush'
|
import { updateInstancePush } from '@utils/slices/instances/updatePush'
|
||||||
|
@ -67,7 +68,11 @@ const TabMePush: React.FC = () => {
|
||||||
!pushEnabled || !instancePush.global.value || isLoading
|
!pushEnabled || !instancePush.global.value || isLoading
|
||||||
}
|
}
|
||||||
switchValue={instancePush?.alerts[alert].value}
|
switchValue={instancePush?.alerts[alert].value}
|
||||||
switchOnValueChange={() =>
|
switchOnValueChange={() => {
|
||||||
|
analytics(`me_push_${alert}`, {
|
||||||
|
current: instancePush?.alerts[alert].value,
|
||||||
|
new: !instancePush?.alerts[alert].value
|
||||||
|
})
|
||||||
dispatch(
|
dispatch(
|
||||||
updateInstancePushAlert({
|
updateInstancePushAlert({
|
||||||
changed: alert,
|
changed: alert,
|
||||||
|
@ -80,7 +85,7 @@ const TabMePush: React.FC = () => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}}
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
: null
|
: null
|
||||||
|
@ -103,10 +108,12 @@ const TabMePush: React.FC = () => {
|
||||||
}}
|
}}
|
||||||
onPress={async () => {
|
onPress={async () => {
|
||||||
if (pushCanAskAgain) {
|
if (pushCanAskAgain) {
|
||||||
|
analytics('me_push_enabled_dialogue')
|
||||||
const result = await Notifications.requestPermissionsAsync()
|
const result = await Notifications.requestPermissionsAsync()
|
||||||
setPushEnabled(result.granted)
|
setPushEnabled(result.granted)
|
||||||
setPushCanAskAgain(result.canAskAgain)
|
setPushCanAskAgain(result.canAskAgain)
|
||||||
} else {
|
} else {
|
||||||
|
analytics('me_push_enabled_setting')
|
||||||
Linking.openSettings()
|
Linking.openSettings()
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
@ -124,9 +131,13 @@ const TabMePush: React.FC = () => {
|
||||||
switchValue={
|
switchValue={
|
||||||
pushEnabled === false ? false : instancePush?.global.value
|
pushEnabled === false ? false : instancePush?.global.value
|
||||||
}
|
}
|
||||||
switchOnValueChange={() =>
|
switchOnValueChange={() => {
|
||||||
|
analytics('me_push_global', {
|
||||||
|
current: instancePush?.global.value,
|
||||||
|
new: !instancePush?.global.value
|
||||||
|
})
|
||||||
dispatch(updateInstancePush(!instancePush?.global.value))
|
dispatch(updateInstancePush(!instancePush?.global.value))
|
||||||
}
|
}}
|
||||||
/>
|
/>
|
||||||
</MenuContainer>
|
</MenuContainer>
|
||||||
<MenuContainer>
|
<MenuContainer>
|
||||||
|
@ -138,16 +149,21 @@ const TabMePush: React.FC = () => {
|
||||||
!pushEnabled || !instancePush?.global.value || isLoading
|
!pushEnabled || !instancePush?.global.value || isLoading
|
||||||
}
|
}
|
||||||
switchValue={instancePush?.decode.value}
|
switchValue={instancePush?.decode.value}
|
||||||
switchOnValueChange={() =>
|
switchOnValueChange={() => {
|
||||||
|
analytics('me_push_decode', {
|
||||||
|
current: instancePush?.decode.value,
|
||||||
|
new: !instancePush?.decode.value
|
||||||
|
})
|
||||||
dispatch(updateInstancePushDecode(!instancePush?.decode.value))
|
dispatch(updateInstancePushDecode(!instancePush?.decode.value))
|
||||||
}
|
}}
|
||||||
/>
|
/>
|
||||||
<MenuRow
|
<MenuRow
|
||||||
title={t('me.push.howitworks')}
|
title={t('me.push.howitworks')}
|
||||||
iconBack='ExternalLink'
|
iconBack='ExternalLink'
|
||||||
onPress={() =>
|
onPress={() => {
|
||||||
|
analytics('me_push_howitworks')
|
||||||
WebBrowser.openBrowserAsync('https://tooot.app/how-push-works')
|
WebBrowser.openBrowserAsync('https://tooot.app/how-push-works')
|
||||||
}
|
}}
|
||||||
/>
|
/>
|
||||||
</MenuContainer>
|
</MenuContainer>
|
||||||
<MenuContainer>{alerts}</MenuContainer>
|
<MenuContainer>{alerts}</MenuContainer>
|
||||||
|
|
|
@ -34,6 +34,7 @@ const AccountInformationFields = React.memo(
|
||||||
emojis={account.emojis}
|
emojis={account.emojis}
|
||||||
showFullLink
|
showFullLink
|
||||||
numberOfLines={5}
|
numberOfLines={5}
|
||||||
|
selectable
|
||||||
/>
|
/>
|
||||||
{field.verified_at ? (
|
{field.verified_at ? (
|
||||||
<Icon
|
<Icon
|
||||||
|
@ -51,6 +52,7 @@ const AccountInformationFields = React.memo(
|
||||||
emojis={account.emojis}
|
emojis={account.emojis}
|
||||||
showFullLink
|
showFullLink
|
||||||
numberOfLines={5}
|
numberOfLines={5}
|
||||||
|
selectable
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -28,7 +28,7 @@ const AccountInformationNote = React.memo(
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.note}>
|
<View style={styles.note}>
|
||||||
<ParseHTML content={account.note!} size={'M'} emojis={account.emojis} />
|
<ParseHTML content={account.note!} size={'M'} emojis={account.emojis} selectable />
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,39 +1,55 @@
|
||||||
import apiGeneral from '@api/general'
|
import apiGeneral from '@api/general'
|
||||||
import { AxiosError } from 'axios'
|
import { AxiosError } from 'axios'
|
||||||
import { Constants } from 'react-native-unimodules'
|
import { Buffer } from 'buffer'
|
||||||
|
import Constants from 'expo-constants'
|
||||||
import { useQuery, UseQueryOptions } from 'react-query'
|
import { useQuery, UseQueryOptions } from 'react-query'
|
||||||
|
|
||||||
|
type Translations = {
|
||||||
|
provider: string
|
||||||
|
sourceLanguage: string
|
||||||
|
text: string[]
|
||||||
|
}
|
||||||
|
|
||||||
export type QueryKeyTranslate = [
|
export type QueryKeyTranslate = [
|
||||||
'Translate',
|
'Translate',
|
||||||
{ toot: string; source: string; target: string }
|
{
|
||||||
|
instance: string
|
||||||
|
id: string
|
||||||
|
source: string
|
||||||
|
target: string
|
||||||
|
text: string[]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const queryFunction = async ({ queryKey }: { queryKey: QueryKeyTranslate }) => {
|
export const TRANSLATE_SERVER = __DEV__
|
||||||
const { toot, source, target } = queryKey[1]
|
? 'testtranslate.tooot.app'
|
||||||
|
: 'translate.tooot.app'
|
||||||
|
|
||||||
const res = await apiGeneral<Translate.Translate>({
|
const queryFunction = async ({ queryKey }: { queryKey: QueryKeyTranslate }) => {
|
||||||
domain: 'translate.tooot.app',
|
const key = Constants.manifest.extra?.translateKey
|
||||||
method: 'post',
|
if (!key) {
|
||||||
url: 'translate',
|
return Promise.reject()
|
||||||
params: {
|
}
|
||||||
api_key: Constants.manifest?.extra?.translateKey,
|
|
||||||
q: toot,
|
const { instance, id, source, target, text } = queryKey[1]
|
||||||
source,
|
|
||||||
target
|
const res = await apiGeneral<Translations>({
|
||||||
|
domain: TRANSLATE_SERVER,
|
||||||
|
method: 'get',
|
||||||
|
url: `v1/translate/${instance}/${id}/${target}`,
|
||||||
|
headers: {
|
||||||
|
key,
|
||||||
|
original: Buffer.from(JSON.stringify({ source, text })).toString('base64')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return res.body.translatedText
|
return res.body
|
||||||
}
|
}
|
||||||
|
|
||||||
const useTranslateQuery = ({
|
const useTranslateQuery = ({
|
||||||
options,
|
options,
|
||||||
...queryKeyParams
|
...queryKeyParams
|
||||||
}: QueryKeyTranslate[1] & {
|
}: QueryKeyTranslate[1] & {
|
||||||
options?: UseQueryOptions<
|
options?: UseQueryOptions<Translations, AxiosError, Translations>
|
||||||
Translate.Translate['translatedText'],
|
|
||||||
AxiosError,
|
|
||||||
Translate.Translate['translatedText']
|
|
||||||
>
|
|
||||||
}) => {
|
}) => {
|
||||||
const queryKey: QueryKeyTranslate = ['Translate', { ...queryKeyParams }]
|
const queryKey: QueryKeyTranslate = ['Translate', { ...queryKeyParams }]
|
||||||
return useQuery(queryKey, queryFunction, options)
|
return useQuery(queryKey, queryFunction, options)
|
||||||
|
|
Loading…
Reference in New Issue