This commit is contained in:
xmflsct 2022-12-17 23:21:56 +01:00
parent 3691b19a87
commit c59690fcb9
9 changed files with 65 additions and 41 deletions

View File

@ -1,10 +1 @@
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

View File

@ -1,10 +1 @@
toooting愉快此版本包括以下改进和修复
- 增加乌克兰语Slava Ukraini
- 自动识别发嘟语言
- 记住上次公共时间轴选项
- 显示编辑历史的差异
- 关注列表可隐藏转嘟和回复
- 新增管理员推送通知
- 支持嘟文右到左文字
- 修复过滤整词功能
- 修复平板不能删除草稿

View File

@ -1,6 +1,6 @@
{
"name": "tooot",
"version": "4.7.0",
"version": "4.7.1",
"description": "tooot for Mastodon",
"author": "xmflsct <me@xmflsct.com>",
"license": "GPL-3.0-or-later",

View File

@ -64,6 +64,7 @@ const TimelineDefault: React.FC<Props> = ({
content: '',
complete: false
})
const detectedLanguage = useRef<string>(status.language || '')
const filtered = queryKey && shouldFilter({ copiableContent, status, queryKey })
if (queryKey && filtered && !highlighted) {
@ -139,6 +140,7 @@ const TimelineDefault: React.FC<Props> = ({
ownAccount,
spoilerHidden,
copiableContent,
detectedLanguage,
highlighted,
inThread: queryKey?.[1].page === 'Toot',
disableDetails,

View File

@ -14,6 +14,7 @@ type ContextType = {
content: string
complete: boolean
}>
detectedLanguage?: React.MutableRefObject<string>
highlighted?: boolean
inThread?: boolean

View File

@ -11,7 +11,7 @@ import { StyleSheet, View } from 'react-native'
import StatusContext from './Context'
const TimelineFeedback = () => {
const { status, highlighted } = useContext(StatusContext)
const { status, highlighted, detectedLanguage } = useContext(StatusContext)
if (!status || !highlighted) return null
const { t } = useTranslation('componentTimeline')
@ -80,7 +80,12 @@ const TimelineFeedback = () => {
accessibilityHint={t('shared.actionsUsers.history.accessibilityHint')}
accessibilityRole='button'
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', {
count: data.length - 1

View File

@ -13,7 +13,7 @@ import { Circle } from 'react-native-animated-spinkit'
import StatusContext from './Context'
const TimelineTranslate = () => {
const { status, highlighted, copiableContent } = useContext(StatusContext)
const { status, highlighted, copiableContent, detectedLanguage } = useContext(StatusContext)
if (!status || !highlighted) return null
const { t } = useTranslation('componentTimeline')
@ -38,14 +38,19 @@ const TimelineTranslate = () => {
? [copiableContent?.current.content]
: backupTextProcessing()
const [detectedLanguage, setDetectedLanguage] = useState<{
const [detected, setDetected] = useState<{
language: string
confidence: number
}>({ language: status.language || '', confidence: 0 })
useEffect(() => {
const detect = async () => {
const result = await detectLanguage(text.join('\n\n'))
result && setDetectedLanguage(result)
if (result) {
setDetected(result)
if (detectedLanguage) {
detectedLanguage.current = result.language
}
}
}
detect()
}, [])
@ -57,7 +62,7 @@ const TimelineTranslate = () => {
const [enabled, setEnabled] = useState(false)
const { refetch, data, isFetching, isSuccess, isError } = useTranslateQuery({
source: detectedLanguage.language,
source: detected.language,
target: targetLanguage,
text,
options: { enabled }
@ -66,9 +71,9 @@ const TimelineTranslate = () => {
const devView = () => {
return __DEV__ ? (
<CustomText fontStyle='S' style={{ color: colors.secondary }}>{` Source: ${
detectedLanguage?.language
detected?.language
}; Confidence: ${
detectedLanguage?.confidence.toString().slice(0, 5) || 'null'
detected?.confidence.toString().slice(0, 5) || 'null'
}; Target: ${targetLanguage}`}</CustomText>
) : null
}
@ -78,13 +83,13 @@ const TimelineTranslate = () => {
}
if (
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()
}
if (
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()
}

View File

@ -11,25 +11,45 @@ import { TabSharedStackScreenProps } from '@utils/navigation/navigators'
import { useStatusHistory } from '@utils/queryHooks/statusesHistory'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import { diffWords } from 'diff'
import { diffChars, diffWords } from 'diff'
import React, { useEffect } from 'react'
import { useTranslation } from 'react-i18next'
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<{
withoutBoundary: boolean
item: Mastodon.StatusHistory
prevItem?: Mastodon.StatusHistory
}> = ({ item, prevItem }) => {
}> = ({ withoutBoundary, item, prevItem }) => {
const { colors } = useTheme()
const changesSpoiler = diffWords(
removeHTML(prevItem?.spoiler_text || item.spoiler_text || ''),
removeHTML(item.spoiler_text || '')
)
const changesContent = diffWords(
removeHTML(prevItem?.content || item.content),
removeHTML(item.content)
)
const changesSpoiler = withoutBoundary
? diffChars(
removeHTML(prevItem?.spoiler_text || item.spoiler_text || ''),
removeHTML(item.spoiler_text || '')
)
: diffWords(
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 (
// @ts-ignore
@ -91,7 +111,7 @@ const ContentView: React.FC<{
const TabSharedHistory: React.FC<TabSharedStackScreenProps<'Tab-Shared-History'>> = ({
navigation,
route: {
params: { id }
params: { id, detectedLanguage }
}
}) => {
const { t } = useTranslation('screenTabs')
@ -106,12 +126,20 @@ const TabSharedHistory: React.FC<TabSharedStackScreenProps<'Tab-Shared-History'>
const dataReversed = data ? [...data].reverse() : []
const withoutBoundary = !!SCRIPTS_WITHOUT_BOUNDARIES.filter(script =>
detectedLanguage?.toLocaleLowerCase().startsWith(script)
).length
return (
<FlatList
style={{ flex: 1, minHeight: '100%' }}
data={dataReversed}
renderItem={({ item, index }) => (
<ContentView item={item} prevItem={dataReversed[index + 1]} />
<ContentView
withoutBoundary={withoutBoundary}
item={item}
prevItem={dataReversed[index + 1]}
/>
)}
ItemSeparatorComponent={ComponentSeparator}
/>

View File

@ -103,6 +103,7 @@ export type TabSharedStackParamList = {
}
'Tab-Shared-History': {
id: Mastodon.Status['id']
detectedLanguage: string
}
'Tab-Shared-Search': undefined
'Tab-Shared-Toot': {