添加同步历史列表

This commit is contained in:
lyswhut 2023-02-20 17:58:24 +08:00
parent 59cc117143
commit 90a0f548c2
5 changed files with 115 additions and 75 deletions

View File

@ -254,6 +254,7 @@
"setting_sync_enbale": "Enable sync", "setting_sync_enbale": "Enable sync",
"setting_sync_history": "History address", "setting_sync_history": "History address",
"setting_sync_history_empty": "Nothing here", "setting_sync_history_empty": "Nothing here",
"setting_sync_history_title": "Connection history",
"setting_sync_host_label": "Synchronization service IP address", "setting_sync_host_label": "Synchronization service IP address",
"setting_sync_host_tip": "Please enter the synchronization service IP address", "setting_sync_host_tip": "Please enter the synchronization service IP address",
"setting_sync_port_label": "Synchronization service port number", "setting_sync_port_label": "Synchronization service port number",

View File

@ -1,4 +1,4 @@
import ChoosePath, { ChoosePathType } from '@/components/common/ChoosePath' import ChoosePath, { type ChoosePathType } from '@/components/common/ChoosePath'
import { LXM_FILE_EXT_RXP } from '@/config/constant' import { LXM_FILE_EXT_RXP } from '@/config/constant'
import React, { forwardRef, useImperativeHandle, useRef, useState } from 'react' import React, { forwardRef, useImperativeHandle, useRef, useState } from 'react'
import { InteractionManager } from 'react-native' import { InteractionManager } from 'react-native'

View File

@ -1,97 +1,142 @@
import React, { memo, useRef, useState, useEffect, useCallback } from 'react' import React, { memo, useRef, useState, useCallback, useImperativeHandle, forwardRef } from 'react'
import { View, TouchableOpacity, ScrollView } from 'react-native' import { View, TouchableOpacity, ScrollView } from 'react-native'
// import { gzip, ungzip } from 'pako' // import { gzip, ungzip } from 'pako'
import { Icon } from '@/components/common/Icon' import { Icon } from '@/components/common/Icon'
import Button from '../components/Button' import Button from '../components/Button'
import { useTranslation } from '@/plugins/i18n' import { getSyncHostHistory, removeSyncHostHistory, setSyncHost } from '@/utils/data'
import { createStyle, getSyncHostHistory, removeSyncHostHistory, setSyncHost } from '@/utils/tools' import Popup, { type PopupType } from '@/components/common/Popup'
import Popup from '@/components/common/Popup'
import { BorderWidths } from '@/theme' import { BorderWidths } from '@/theme'
import Text from '@/components/common/Text' import Text from '@/components/common/Text'
import { useTheme } from '@/store/theme/hook'
import { useI18n } from '@/lang'
import { useSettingValue } from '@/store/setting/hook'
import { createStyle } from '@/utils/tools'
const HistoryListItem = ({ item, index, remove, setHostInfo }) => { type SyncHistoryItem = Awaited<ReturnType<typeof getSyncHostHistory>>[number]
const theme = useGetter('common', 'theme')
const HistoryListItem = ({ item, index, onRemove, onSelect }: {
item: SyncHistoryItem
index: number
onRemove: (index: number) => void
onSelect: (index: number) => void
}) => {
const theme = useTheme()
const handleSetHost = () => { const handleSetHost = () => {
setHostInfo({ onSelect(index)
host: item.host, // setHostInfo({
port: item.port, // host: item.host,
}) // port: item.port,
setSyncHost({ // })
host: item.host, // setSyncHost({
port: item.port, // host: item.host,
}) // port: item.port,
// })
} }
const handleRemove = () => { const handleRemove = () => {
remove(index) onRemove(index)
} }
return ( return (
<View style={{ ...styles.listItem, borderBottomColor: theme.borderColor }}> <View style={{ ...styles.listItem, borderBottomColor: theme['c-border-background'] }}>
<TouchableOpacity style={styles.listName} onPress={handleSetHost}> <TouchableOpacity style={styles.listName} onPress={handleSetHost}>
<Text numberOfLines={1}>{item.host}</Text> <Text numberOfLines={1}>{item.host}</Text>
<Text color={theme['c-font-label']} numberOfLines={1}>{item.port}</Text> <Text color={theme['c-font-label']} numberOfLines={1}>{item.port}</Text>
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity onPress={handleRemove} style={styles.listMoreBtn}> <TouchableOpacity onPress={handleRemove} style={styles.listBtn}>
<Icon name="remove" style={{ color: theme.normal35 }} size={16} /> <Icon name="remove" color={theme['c-font-label']} size={12} />
</TouchableOpacity> </TouchableOpacity>
</View> </View>
) )
} }
const HistoryList = ({ visible, setHostInfo }) => {
const [list, setList] = useState([])
const isUnmountedRef = useRef(true)
const theme = useGetter('common', 'theme')
const { t } = useTranslation()
const getHistory = () => { interface HistoryListProps {
getSyncHostHistory().then(historyList => { onSelect: (item: SyncHistoryItem) => void
if (isUnmountedRef.current) return }
setList([...historyList]) interface HistoryListType {
show: () => void
}
const HistoryList = forwardRef<HistoryListType, HistoryListProps>(({ onSelect }, ref) => {
const popupRef = useRef<PopupType>(null)
const [visible, setVisible] = useState(false)
const [list, setList] = useState<SyncHistoryItem[]>([])
// const isUnmountedRef = useRef(true)
const theme = useTheme()
const t = useI18n()
const handleShow = () => {
popupRef.current?.setVisible(true)
requestAnimationFrame(() => {
void getSyncHostHistory().then(historyList => {
setList([...historyList])
})
}) })
} }
useImperativeHandle(ref, () => ({
show() {
if (visible) handleShow()
else {
setVisible(true)
requestAnimationFrame(() => {
handleShow()
})
}
},
}))
useEffect(() => { const handleSelect = useCallback((index: number) => {
if (!visible) return popupRef.current?.setVisible(false)
getHistory() onSelect(list[index])
}, [visible]) }, [list, onSelect])
useEffect(() => { const handleRemove = useCallback((index: number) => {
isUnmountedRef.current = false void removeSyncHostHistory(index)
return () => {
isUnmountedRef.current = true
}
}, [])
const handleRemove = useCallback((index) => {
removeSyncHostHistory(index)
const newList = [...list] const newList = [...list]
newList.splice(index, 1) newList.splice(index, 1)
setList(newList) setList(newList)
}, [list]) }, [list])
return (
<ScrollView style={styles.list}>
{
list.length
? list.map((item, index) => <HistoryListItem item={item} index={index} remove={handleRemove} key={`${item.host}:${item.port}`} setHostInfo={setHostInfo} />)
: <Text style={styles.tipText} color={theme['c-font-label']}>{t('setting_sync_history_empty')}</Text>
}
</ScrollView>
)
}
export default memo(({ setHostInfo, isWaiting }) => { return (
const { t } = useTranslation() visible
const [visible, setVisible] = useState(false) ? (
const isEnableSync = useGetter('common', 'isEnableSync') <Popup ref={popupRef} title={t('setting_sync_history_title')}>
<ScrollView style={styles.list}>
{
list.length
? list.map((item, index) => (
<HistoryListItem
item={item}
index={index}
onRemove={handleRemove}
key={`${item.host}:${item.port}`}
onSelect={handleSelect}
/>
))
: <Text style={styles.tipText} color={theme['c-font-label']}>{t('setting_sync_history_empty')}</Text>
}
</ScrollView>
</Popup>
)
: null
)
})
export default memo(({ setHostInfo, isWaiting }: {
setHostInfo: (hostInfo: { host: string, port: string }) => void
isWaiting: boolean
}) => {
const t = useI18n()
const isEnableSync = useSettingValue('sync.enable')
const listRef = useRef<HistoryListType>(null)
const showPopup = () => { const showPopup = () => {
setVisible(true) listRef.current?.show()
} }
const hidePopup = () => { const handleSelect = (item: SyncHistoryItem) => {
setVisible(false) setHostInfo(item)
void setSyncHost(item)
} }
return ( return (
@ -99,21 +144,12 @@ export default memo(({ setHostInfo, isWaiting }) => {
<View style={styles.btn}> <View style={styles.btn}>
<Button disabled={isWaiting || isEnableSync} onPress={showPopup}>{t('setting_sync_history')}</Button> <Button disabled={isWaiting || isEnableSync} onPress={showPopup}>{t('setting_sync_history')}</Button>
</View> </View>
<Popup <HistoryList ref={listRef} onSelect={handleSelect} />
visible={visible}
hide={hidePopup}
title={t('setting_sync_history_title')}
>
<HistoryList visible={visible} setHostInfo={setHostInfo} />
</Popup>
</> </>
) )
}) })
const styles = createStyle({ const styles = createStyle({
cacheSize: {
marginBottom: 5,
},
btn: { btn: {
flexDirection: 'row', flexDirection: 'row',
marginLeft: 25, marginLeft: 25,
@ -126,17 +162,20 @@ const styles = createStyle({
list: { list: {
flexShrink: 1, flexShrink: 1,
flexGrow: 0, flexGrow: 0,
paddingLeft: 10, paddingLeft: 15,
paddingRight: 10, paddingRight: 15,
}, },
listItem: { listItem: {
flexDirection: 'row', flexDirection: 'row',
alignItems: 'center', alignItems: 'center',
paddingTop: 5, paddingTop: 8,
paddingBottom: 5, paddingBottom: 8,
borderBottomWidth: BorderWidths.normal, borderBottomWidth: BorderWidths.normal,
}, },
listName: { listName: {
flex: 1, flex: 1,
}, },
listBtn: {
padding: 5,
},
}) })

View File

@ -2,7 +2,7 @@ import React, { memo, useState } from 'react'
import Section from '../components/Section' import Section from '../components/Section'
import IsEnable from './IsEnable' import IsEnable from './IsEnable'
// import History from './History' import History from './History'
import { useI18n } from '@/lang' import { useI18n } from '@/lang'
// import SyncHost from './SyncHost' // import SyncHost from './SyncHost'
@ -15,7 +15,7 @@ export default memo(() => {
return ( return (
<Section title={t('setting_sync')}> <Section title={t('setting_sync')}>
<IsEnable hostInfo={hostInfo} setHostInfo={setHostInfo} isWaiting={isWaiting} setIsWaiting={setIsWaiting} /> <IsEnable hostInfo={hostInfo} setHostInfo={setHostInfo} isWaiting={isWaiting} setIsWaiting={setIsWaiting} />
{/* <History setHostInfo={setHostInfo} isWaiting={isWaiting} /> */} <History setHostInfo={setHostInfo} isWaiting={isWaiting} />
</Section> </Section>
) )
}) })

2
src/types/sync.d.ts vendored
View File

@ -1,4 +1,4 @@
import { io } from 'socket.io-client' import { type io } from 'socket.io-client'
declare global { declare global {
namespace LX { namespace LX {