mirror of
https://github.com/tooot-app/app
synced 2025-02-22 14:47:43 +01:00
Fixed #566
This commit is contained in:
parent
3691b19a87
commit
c59690fcb9
@ -1,10 +1 @@
|
|||||||
Enjoy toooting! This version includes following improvements and fixes:
|
Enjoy toooting! This version includes following improvements and fixes:
|
||||||
- Added Ukrainian (Slava Ukraini)
|
|
||||||
- Automatic setting detected language when tooting
|
|
||||||
- Remember public timeline type selection
|
|
||||||
- Show diffing of edit history
|
|
||||||
- Allow hiding boosts and replies in home timeline
|
|
||||||
- Support toot in RTL languages
|
|
||||||
- Added notification for admins
|
|
||||||
- Fix whole word filter matching
|
|
||||||
- Fix tablet cannot delete toot drafts
|
|
||||||
|
@ -1,10 +1 @@
|
|||||||
toooting愉快!此版本包括以下改进和修复:
|
toooting愉快!此版本包括以下改进和修复:
|
||||||
- 增加乌克兰语(Slava Ukraini)
|
|
||||||
- 自动识别发嘟语言
|
|
||||||
- 记住上次公共时间轴选项
|
|
||||||
- 显示编辑历史的差异
|
|
||||||
- 关注列表可隐藏转嘟和回复
|
|
||||||
- 新增管理员推送通知
|
|
||||||
- 支持嘟文右到左文字
|
|
||||||
- 修复过滤整词功能
|
|
||||||
- 修复平板不能删除草稿
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "tooot",
|
"name": "tooot",
|
||||||
"version": "4.7.0",
|
"version": "4.7.1",
|
||||||
"description": "tooot for Mastodon",
|
"description": "tooot for Mastodon",
|
||||||
"author": "xmflsct <me@xmflsct.com>",
|
"author": "xmflsct <me@xmflsct.com>",
|
||||||
"license": "GPL-3.0-or-later",
|
"license": "GPL-3.0-or-later",
|
||||||
|
@ -64,6 +64,7 @@ const TimelineDefault: React.FC<Props> = ({
|
|||||||
content: '',
|
content: '',
|
||||||
complete: false
|
complete: false
|
||||||
})
|
})
|
||||||
|
const detectedLanguage = useRef<string>(status.language || '')
|
||||||
|
|
||||||
const filtered = queryKey && shouldFilter({ copiableContent, status, queryKey })
|
const filtered = queryKey && shouldFilter({ copiableContent, status, queryKey })
|
||||||
if (queryKey && filtered && !highlighted) {
|
if (queryKey && filtered && !highlighted) {
|
||||||
@ -139,6 +140,7 @@ const TimelineDefault: React.FC<Props> = ({
|
|||||||
ownAccount,
|
ownAccount,
|
||||||
spoilerHidden,
|
spoilerHidden,
|
||||||
copiableContent,
|
copiableContent,
|
||||||
|
detectedLanguage,
|
||||||
highlighted,
|
highlighted,
|
||||||
inThread: queryKey?.[1].page === 'Toot',
|
inThread: queryKey?.[1].page === 'Toot',
|
||||||
disableDetails,
|
disableDetails,
|
||||||
|
@ -14,6 +14,7 @@ type ContextType = {
|
|||||||
content: string
|
content: string
|
||||||
complete: boolean
|
complete: boolean
|
||||||
}>
|
}>
|
||||||
|
detectedLanguage?: React.MutableRefObject<string>
|
||||||
|
|
||||||
highlighted?: boolean
|
highlighted?: boolean
|
||||||
inThread?: boolean
|
inThread?: boolean
|
||||||
|
@ -11,7 +11,7 @@ import { StyleSheet, View } from 'react-native'
|
|||||||
import StatusContext from './Context'
|
import StatusContext from './Context'
|
||||||
|
|
||||||
const TimelineFeedback = () => {
|
const TimelineFeedback = () => {
|
||||||
const { status, highlighted } = useContext(StatusContext)
|
const { status, highlighted, detectedLanguage } = useContext(StatusContext)
|
||||||
if (!status || !highlighted) return null
|
if (!status || !highlighted) return null
|
||||||
|
|
||||||
const { t } = useTranslation('componentTimeline')
|
const { t } = useTranslation('componentTimeline')
|
||||||
@ -80,7 +80,12 @@ const TimelineFeedback = () => {
|
|||||||
accessibilityHint={t('shared.actionsUsers.history.accessibilityHint')}
|
accessibilityHint={t('shared.actionsUsers.history.accessibilityHint')}
|
||||||
accessibilityRole='button'
|
accessibilityRole='button'
|
||||||
style={[styles.text, { marginRight: 0, color: colors.blue }]}
|
style={[styles.text, { marginRight: 0, color: colors.blue }]}
|
||||||
onPress={() => navigation.push('Tab-Shared-History', { id: status.id })}
|
onPress={() =>
|
||||||
|
navigation.push('Tab-Shared-History', {
|
||||||
|
id: status.id,
|
||||||
|
detectedLanguage: detectedLanguage?.current || status.language || ''
|
||||||
|
})
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{t('shared.actionsUsers.history.text', {
|
{t('shared.actionsUsers.history.text', {
|
||||||
count: data.length - 1
|
count: data.length - 1
|
||||||
|
@ -13,7 +13,7 @@ import { Circle } from 'react-native-animated-spinkit'
|
|||||||
import StatusContext from './Context'
|
import StatusContext from './Context'
|
||||||
|
|
||||||
const TimelineTranslate = () => {
|
const TimelineTranslate = () => {
|
||||||
const { status, highlighted, copiableContent } = useContext(StatusContext)
|
const { status, highlighted, copiableContent, detectedLanguage } = useContext(StatusContext)
|
||||||
if (!status || !highlighted) return null
|
if (!status || !highlighted) return null
|
||||||
|
|
||||||
const { t } = useTranslation('componentTimeline')
|
const { t } = useTranslation('componentTimeline')
|
||||||
@ -38,14 +38,19 @@ const TimelineTranslate = () => {
|
|||||||
? [copiableContent?.current.content]
|
? [copiableContent?.current.content]
|
||||||
: backupTextProcessing()
|
: backupTextProcessing()
|
||||||
|
|
||||||
const [detectedLanguage, setDetectedLanguage] = useState<{
|
const [detected, setDetected] = useState<{
|
||||||
language: string
|
language: string
|
||||||
confidence: number
|
confidence: number
|
||||||
}>({ language: status.language || '', confidence: 0 })
|
}>({ language: status.language || '', confidence: 0 })
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const detect = async () => {
|
const detect = async () => {
|
||||||
const result = await detectLanguage(text.join('\n\n'))
|
const result = await detectLanguage(text.join('\n\n'))
|
||||||
result && setDetectedLanguage(result)
|
if (result) {
|
||||||
|
setDetected(result)
|
||||||
|
if (detectedLanguage) {
|
||||||
|
detectedLanguage.current = result.language
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
detect()
|
detect()
|
||||||
}, [])
|
}, [])
|
||||||
@ -57,7 +62,7 @@ const TimelineTranslate = () => {
|
|||||||
|
|
||||||
const [enabled, setEnabled] = useState(false)
|
const [enabled, setEnabled] = useState(false)
|
||||||
const { refetch, data, isFetching, isSuccess, isError } = useTranslateQuery({
|
const { refetch, data, isFetching, isSuccess, isError } = useTranslateQuery({
|
||||||
source: detectedLanguage.language,
|
source: detected.language,
|
||||||
target: targetLanguage,
|
target: targetLanguage,
|
||||||
text,
|
text,
|
||||||
options: { enabled }
|
options: { enabled }
|
||||||
@ -66,9 +71,9 @@ const TimelineTranslate = () => {
|
|||||||
const devView = () => {
|
const devView = () => {
|
||||||
return __DEV__ ? (
|
return __DEV__ ? (
|
||||||
<CustomText fontStyle='S' style={{ color: colors.secondary }}>{` Source: ${
|
<CustomText fontStyle='S' style={{ color: colors.secondary }}>{` Source: ${
|
||||||
detectedLanguage?.language
|
detected?.language
|
||||||
}; Confidence: ${
|
}; Confidence: ${
|
||||||
detectedLanguage?.confidence.toString().slice(0, 5) || 'null'
|
detected?.confidence.toString().slice(0, 5) || 'null'
|
||||||
}; Target: ${targetLanguage}`}</CustomText>
|
}; Target: ${targetLanguage}`}</CustomText>
|
||||||
) : null
|
) : null
|
||||||
}
|
}
|
||||||
@ -78,13 +83,13 @@ const TimelineTranslate = () => {
|
|||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
Platform.OS === 'ios' &&
|
Platform.OS === 'ios' &&
|
||||||
Localization.locale.slice(0, 2).includes(detectedLanguage.language.slice(0, 2))
|
Localization.locale.slice(0, 2).includes(detected.language.slice(0, 2))
|
||||||
) {
|
) {
|
||||||
return devView()
|
return devView()
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
Platform.OS === 'android' &&
|
Platform.OS === 'android' &&
|
||||||
settingsLanguage?.slice(0, 2).includes(detectedLanguage.language.slice(0, 2))
|
settingsLanguage?.slice(0, 2).includes(detected.language.slice(0, 2))
|
||||||
) {
|
) {
|
||||||
return devView()
|
return devView()
|
||||||
}
|
}
|
||||||
|
@ -11,25 +11,45 @@ import { TabSharedStackScreenProps } from '@utils/navigation/navigators'
|
|||||||
import { useStatusHistory } from '@utils/queryHooks/statusesHistory'
|
import { useStatusHistory } from '@utils/queryHooks/statusesHistory'
|
||||||
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 { diffWords } from 'diff'
|
import { diffChars, diffWords } from 'diff'
|
||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { FlatList, View } from 'react-native'
|
import { FlatList, View } from 'react-native'
|
||||||
|
|
||||||
|
const SCRIPTS_WITHOUT_BOUNDARIES = [
|
||||||
|
'my',
|
||||||
|
'zh',
|
||||||
|
'ja',
|
||||||
|
'kar',
|
||||||
|
'km',
|
||||||
|
'lp',
|
||||||
|
'phag',
|
||||||
|
'pwo',
|
||||||
|
'kar',
|
||||||
|
'lana',
|
||||||
|
'th',
|
||||||
|
'bo'
|
||||||
|
]
|
||||||
|
|
||||||
const ContentView: React.FC<{
|
const ContentView: React.FC<{
|
||||||
|
withoutBoundary: boolean
|
||||||
item: Mastodon.StatusHistory
|
item: Mastodon.StatusHistory
|
||||||
prevItem?: Mastodon.StatusHistory
|
prevItem?: Mastodon.StatusHistory
|
||||||
}> = ({ item, prevItem }) => {
|
}> = ({ withoutBoundary, item, prevItem }) => {
|
||||||
const { colors } = useTheme()
|
const { colors } = useTheme()
|
||||||
|
|
||||||
const changesSpoiler = diffWords(
|
const changesSpoiler = withoutBoundary
|
||||||
removeHTML(prevItem?.spoiler_text || item.spoiler_text || ''),
|
? diffChars(
|
||||||
removeHTML(item.spoiler_text || '')
|
removeHTML(prevItem?.spoiler_text || item.spoiler_text || ''),
|
||||||
)
|
removeHTML(item.spoiler_text || '')
|
||||||
const changesContent = diffWords(
|
)
|
||||||
removeHTML(prevItem?.content || item.content),
|
: diffWords(
|
||||||
removeHTML(item.content)
|
removeHTML(prevItem?.spoiler_text || item.spoiler_text || ''),
|
||||||
)
|
removeHTML(item.spoiler_text || '')
|
||||||
|
)
|
||||||
|
const changesContent = withoutBoundary
|
||||||
|
? diffChars(removeHTML(prevItem?.content || item.content), removeHTML(item.content))
|
||||||
|
: diffWords(removeHTML(prevItem?.content || item.content), removeHTML(item.content))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -91,7 +111,7 @@ const ContentView: React.FC<{
|
|||||||
const TabSharedHistory: React.FC<TabSharedStackScreenProps<'Tab-Shared-History'>> = ({
|
const TabSharedHistory: React.FC<TabSharedStackScreenProps<'Tab-Shared-History'>> = ({
|
||||||
navigation,
|
navigation,
|
||||||
route: {
|
route: {
|
||||||
params: { id }
|
params: { id, detectedLanguage }
|
||||||
}
|
}
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation('screenTabs')
|
const { t } = useTranslation('screenTabs')
|
||||||
@ -106,12 +126,20 @@ const TabSharedHistory: React.FC<TabSharedStackScreenProps<'Tab-Shared-History'>
|
|||||||
|
|
||||||
const dataReversed = data ? [...data].reverse() : []
|
const dataReversed = data ? [...data].reverse() : []
|
||||||
|
|
||||||
|
const withoutBoundary = !!SCRIPTS_WITHOUT_BOUNDARIES.filter(script =>
|
||||||
|
detectedLanguage?.toLocaleLowerCase().startsWith(script)
|
||||||
|
).length
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FlatList
|
<FlatList
|
||||||
style={{ flex: 1, minHeight: '100%' }}
|
style={{ flex: 1, minHeight: '100%' }}
|
||||||
data={dataReversed}
|
data={dataReversed}
|
||||||
renderItem={({ item, index }) => (
|
renderItem={({ item, index }) => (
|
||||||
<ContentView item={item} prevItem={dataReversed[index + 1]} />
|
<ContentView
|
||||||
|
withoutBoundary={withoutBoundary}
|
||||||
|
item={item}
|
||||||
|
prevItem={dataReversed[index + 1]}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
ItemSeparatorComponent={ComponentSeparator}
|
ItemSeparatorComponent={ComponentSeparator}
|
||||||
/>
|
/>
|
||||||
|
@ -103,6 +103,7 @@ export type TabSharedStackParamList = {
|
|||||||
}
|
}
|
||||||
'Tab-Shared-History': {
|
'Tab-Shared-History': {
|
||||||
id: Mastodon.Status['id']
|
id: Mastodon.Status['id']
|
||||||
|
detectedLanguage: string
|
||||||
}
|
}
|
||||||
'Tab-Shared-Search': undefined
|
'Tab-Shared-Search': undefined
|
||||||
'Tab-Shared-Toot': {
|
'Tab-Shared-Toot': {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user