1import React, {useMemo, useState} from 'react'; 2import {StyleSheet, View} from 'react-native'; 3import rpx from '@/utils/rpx'; 4import ThemeText from '@/components/base/themeText'; 5import useColors from '@/hooks/useColors'; 6import {TouchableWithoutFeedback} from 'react-native-gesture-handler'; 7import MusicSheet from '@/core/musicSheet'; 8import {FlashList} from '@shopify/flash-list'; 9import ListItem from '@/components/base/listItem'; 10import {ROUTE_PATH, useNavigate} from '@/entry/router'; 11import {ImgAsset} from '@/constants/assetsConst'; 12import {showDialog} from '@/components/dialogs/useDialog'; 13import Toast from '@/utils/toast'; 14import Empty from '@/components/base/empty'; 15import IconButton from '@/components/base/iconButton'; 16import {showPanel} from '@/components/panels/usePanel'; 17import {localPluginPlatform} from '@/constants/commonConst'; 18 19export default function Sheets() { 20 const [index, setIndex] = useState(0); 21 const colors = useColors(); 22 const navigate = useNavigate(); 23 24 const allSheets = MusicSheet.useSheets(); 25 const staredSheets = MusicSheet.useStarredMusicSheet(); 26 27 const selectedTabTextStyle = useMemo(() => { 28 return [ 29 styles.selectTabText, 30 { 31 borderBottomColor: colors.primary, 32 }, 33 ]; 34 }, [colors]); 35 36 return ( 37 <> 38 <View style={styles.subTitleContainer}> 39 <TouchableWithoutFeedback 40 style={styles.tabContainer} 41 accessible 42 accessibilityLabel={`我的歌单,共${allSheets.length}个`} 43 onPress={() => { 44 setIndex(0); 45 }}> 46 <ThemeText 47 accessible={false} 48 fontSize="title" 49 style={[ 50 styles.tabText, 51 index === 0 ? selectedTabTextStyle : null, 52 ]}> 53 我的歌单 54 </ThemeText> 55 <ThemeText 56 accessible={false} 57 fontColor="textSecondary" 58 fontSize="subTitle" 59 style={styles.tabText}> 60 {' '} 61 ({allSheets.length}) 62 </ThemeText> 63 </TouchableWithoutFeedback> 64 <TouchableWithoutFeedback 65 style={styles.tabContainer} 66 accessible 67 accessibilityLabel={`收藏歌单,共${staredSheets.length}个`} 68 onPress={() => { 69 setIndex(1); 70 }}> 71 <ThemeText 72 fontSize="title" 73 accessible={false} 74 style={[ 75 styles.tabText, 76 index === 1 ? selectedTabTextStyle : null, 77 ]}> 78 收藏歌单 79 </ThemeText> 80 <ThemeText 81 fontColor="textSecondary" 82 fontSize="subTitle" 83 accessible={false} 84 style={styles.tabText}> 85 {' '} 86 ({staredSheets.length}) 87 </ThemeText> 88 </TouchableWithoutFeedback> 89 <View style={styles.more}> 90 <IconButton 91 name="plus" 92 sizeType="normal" 93 accessibilityLabel="新建歌单" 94 onPress={() => { 95 showPanel('NewMusicSheet'); 96 }} 97 /> 98 </View> 99 </View> 100 <FlashList 101 ListEmptyComponent={<Empty />} 102 data={(index === 0 ? allSheets : staredSheets) ?? []} 103 estimatedItemSize={ListItem.Size.big} 104 renderItem={({item: sheet}) => { 105 const isLocalSheet = !( 106 sheet.platform && sheet.platform !== localPluginPlatform 107 ); 108 109 return ( 110 <ListItem 111 key={`${sheet.id}`} 112 heightType="big" 113 withHorizonalPadding 114 onPress={() => { 115 if (isLocalSheet) { 116 navigate(ROUTE_PATH.LOCAL_SHEET_DETAIL, { 117 id: sheet.id, 118 }); 119 } else { 120 navigate(ROUTE_PATH.PLUGIN_SHEET_DETAIL, { 121 sheetInfo: sheet, 122 }); 123 } 124 }}> 125 <ListItem.ListItemImage 126 uri={sheet.coverImg ?? sheet.artwork} 127 fallbackImg={ImgAsset.albumDefault} 128 maskIcon={ 129 sheet.id === MusicSheet.defaultSheet.id 130 ? 'heart' 131 : null 132 } 133 /> 134 <ListItem.Content 135 title={sheet.title} 136 description={ 137 isLocalSheet 138 ? `${sheet.musicList?.length ?? '-'}首` 139 : `${sheet.artist}` 140 } 141 /> 142 {sheet.id !== MusicSheet.defaultSheet.id ? ( 143 <ListItem.ListItemIcon 144 position="right" 145 icon="trash-can-outline" 146 onPress={() => { 147 showDialog('SimpleDialog', { 148 title: '删除歌单', 149 content: `确定删除歌单「${sheet.title}」吗?`, 150 onOk: async () => { 151 if (isLocalSheet) { 152 await MusicSheet.removeSheet( 153 sheet.id, 154 ); 155 Toast.success('已删除'); 156 } else { 157 await MusicSheet.unstarMusicSheet( 158 sheet, 159 ); 160 Toast.success('已取消收藏'); 161 } 162 }, 163 }); 164 }} 165 /> 166 ) : null} 167 </ListItem> 168 ); 169 }} 170 nestedScrollEnabled 171 /> 172 </> 173 ); 174} 175 176const styles = StyleSheet.create({ 177 subTitleContainer: { 178 paddingHorizontal: rpx(24), 179 flexDirection: 'row', 180 alignItems: 'flex-start', 181 marginBottom: rpx(12), 182 }, 183 subTitleLeft: { 184 flexDirection: 'row', 185 }, 186 tabContainer: { 187 flexDirection: 'row', 188 marginRight: rpx(32), 189 }, 190 191 tabText: { 192 lineHeight: rpx(64), 193 }, 194 selectTabText: { 195 borderBottomWidth: rpx(6), 196 fontWeight: 'bold', 197 }, 198 more: { 199 height: rpx(64), 200 marginTop: rpx(3), 201 flexGrow: 1, 202 flexDirection: 'row', 203 justifyContent: 'flex-end', 204 }, 205}); 206