mirror of
https://github.com/ikun0014/lx-music-mobile.git
synced 2025-05-23 22:37:41 +08:00
202 lines
5.7 KiB
JavaScript
202 lines
5.7 KiB
JavaScript
import React, { useCallback, useMemo, memo, useState, useRef, useEffect } from 'react'
|
|
import { View, StyleSheet, Text, ScrollView, TouchableOpacity } from 'react-native'
|
|
import Dialog from '@/components/common/Dialog'
|
|
import Button from '@/components/common/Button'
|
|
import { useGetter, useDispatch } from '@/store'
|
|
import { useTranslation } from '@/plugins/i18n'
|
|
import { useDimensions } from '@/utils/hooks'
|
|
import { BorderWidths } from '@/theme'
|
|
import Input from '@/components/common/Input'
|
|
import { toast } from '@/utils/tools'
|
|
|
|
const ListItem = ({ list, onPress, musicInfo, width }) => {
|
|
const theme = useGetter('common', 'theme')
|
|
const isExists = useMemo(() => {
|
|
return list.list.some(s => s.songmid == musicInfo.songmid)
|
|
}, [list, musicInfo])
|
|
|
|
return (
|
|
<View style={{ ...styles.listItem, width: width }}>
|
|
<Button
|
|
style={{ ...styles.button, backgroundColor: theme.secondary45, borderColor: theme.secondary45, opacity: isExists ? 0.6 : 1 }}
|
|
onPress={() => { onPress(list, isExists) }}
|
|
>
|
|
<Text numberOfLines={1} style={{ fontSize: 12, color: isExists ? theme.secondary10 : theme.secondary }}>{list.name}</Text>
|
|
</Button>
|
|
</View>
|
|
)
|
|
}
|
|
|
|
const Title = ({ musicInfo, isMove }) => {
|
|
const theme = useGetter('common', 'theme')
|
|
const { t } = useTranslation()
|
|
return (
|
|
musicInfo
|
|
? <Text style={{ ...styles.title, color: theme.normal }}>{t(isMove ? 'list_add_title_first_move' : 'list_add_title_first_add')} <Text style={{ color: theme.secondary }} >{musicInfo.name}</Text> {t('list_add_title_last')}</Text>
|
|
: null
|
|
)
|
|
}
|
|
|
|
const CreateUserList = ({ isEdit, hideEdit }) => {
|
|
const [text, setText] = useState('')
|
|
const inputRef = useRef()
|
|
const { t } = useTranslation()
|
|
const theme = useGetter('common', 'theme')
|
|
const createUserList = useDispatch('list', 'createUserList')
|
|
|
|
useEffect(() => {
|
|
if (isEdit) {
|
|
setText('')
|
|
global.requestAnimationFrame(() => {
|
|
inputRef.current.focus()
|
|
})
|
|
}
|
|
}, [isEdit])
|
|
|
|
const handleSubmitEditing = () => {
|
|
hideEdit()
|
|
const name = text.trim()
|
|
if (!name.length) return
|
|
createUserList({ name })
|
|
}
|
|
|
|
return isEdit
|
|
? (
|
|
<View style={styles.imputContainer}>
|
|
<Input
|
|
placeholder={t('list_create_input_placeholder')}
|
|
value={text}
|
|
onChangeText={setText}
|
|
ref={inputRef}
|
|
onBlur={handleSubmitEditing}
|
|
onSubmitEditing={handleSubmitEditing}
|
|
style={{ ...styles.input, backgroundColor: theme.secondary45 }}
|
|
/>
|
|
</View>
|
|
)
|
|
: null
|
|
}
|
|
|
|
export default memo(({ visible, hideModal, musicInfo, listId, isMove = false }) => {
|
|
const allList = useGetter('list', 'allList')
|
|
const addMusicToList = useDispatch('list', 'listAdd')
|
|
const moveMusicToList = useDispatch('list', 'listMove')
|
|
const { window } = useDimensions()
|
|
const theme = useGetter('common', 'theme')
|
|
const [isEdit, setIsEdit] = useState(false)
|
|
const { t } = useTranslation()
|
|
|
|
const itemWidth = useMemo(() => {
|
|
let w = window.width * 0.9 - 20
|
|
let n = 1
|
|
while (true) {
|
|
if (w / n < 100 + n * 30 || n > 9) return parseInt(w / n)
|
|
n++
|
|
}
|
|
}, [window])
|
|
|
|
const handleSelect = useCallback((list, isExists) => {
|
|
if (isMove) {
|
|
moveMusicToList({
|
|
fromId: listId,
|
|
toId: list.id,
|
|
musicInfo,
|
|
})
|
|
toast(t('list_edit_action_tip_move_success'))
|
|
hideModal()
|
|
} else {
|
|
if (isExists) {
|
|
toast(t('list_edit_action_tip_exist'))
|
|
} else {
|
|
addMusicToList({
|
|
musicInfo,
|
|
id: list.id,
|
|
})
|
|
toast(t('list_edit_action_tip_add_success'))
|
|
hideModal()
|
|
}
|
|
}
|
|
}, [addMusicToList, hideModal, isMove, listId, moveMusicToList, musicInfo, t])
|
|
|
|
const hideEdit = useCallback(() => {
|
|
setIsEdit(false)
|
|
}, [])
|
|
|
|
useEffect(() => {
|
|
if (!visible) {
|
|
hideEdit()
|
|
}
|
|
}, [hideEdit, visible])
|
|
|
|
return (
|
|
<Dialog visible={visible} hideDialog={hideModal}>
|
|
<Title musicInfo={musicInfo} isMove={isMove} />
|
|
<View style={{ flexShrink: 1 }} onStartShouldSetResponder={() => true}>
|
|
<ScrollView style={{ flexGrow: 0 }}>
|
|
<View style={{ ...styles.list }}>
|
|
{ allList.map(list => <ListItem key={list.id} list={list} musicInfo={musicInfo} onPress={handleSelect} width={itemWidth} />) }
|
|
<View style={{ ...styles.listItem, width: itemWidth }}>
|
|
<TouchableOpacity
|
|
style={{ ...styles.button, borderColor: theme.secondary20, borderStyle: 'dashed' }}
|
|
onPress={() => setIsEdit(true)}>
|
|
<Text numberOfLines={1} style={{ fontSize: 12, color: theme.secondary }}>{t('list_create')}</Text>
|
|
</TouchableOpacity>
|
|
{
|
|
isEdit
|
|
? <CreateUserList isEdit={isEdit} hideEdit={hideEdit} />
|
|
: null
|
|
}
|
|
</View>
|
|
</View>
|
|
</ScrollView>
|
|
</View>
|
|
</Dialog>
|
|
)
|
|
})
|
|
|
|
const styles = StyleSheet.create({
|
|
title: {
|
|
textAlign: 'center',
|
|
padding: 15,
|
|
},
|
|
list: {
|
|
paddingLeft: 15,
|
|
paddingRight: 5,
|
|
paddingBottom: 5,
|
|
flexDirection: 'row',
|
|
flexWrap: 'wrap',
|
|
// backgroundColor: 'rgba(0,0,0,0.2)'
|
|
},
|
|
listItem: {
|
|
// width: '50%',
|
|
paddingRight: 10,
|
|
},
|
|
button: {
|
|
paddingTop: 8,
|
|
paddingBottom: 8,
|
|
paddingLeft: 10,
|
|
paddingRight: 10,
|
|
marginRight: 10,
|
|
marginBottom: 10,
|
|
borderRadius: 4,
|
|
width: '100%',
|
|
alignItems: 'center',
|
|
borderWidth: BorderWidths.normal2,
|
|
},
|
|
imputContainer: {
|
|
position: 'absolute',
|
|
top: 0,
|
|
left: 0,
|
|
width: '100%',
|
|
height: '100%',
|
|
paddingBottom: 10,
|
|
// backgroundColor: 'rgba(0,0,0,0.2)',
|
|
},
|
|
input: {
|
|
flex: 1,
|
|
fontSize: 12,
|
|
borderRadius: 4,
|
|
textAlign: 'center',
|
|
},
|
|
})
|