mirror of
https://github.com/ikun0014/lx-music-mobile.git
synced 2025-07-03 07:12:10 +08:00
修复加载某些图片导致APP卡死的问题
This commit is contained in:
parent
8352ca7803
commit
5cf9863f9f
@ -1,9 +1,18 @@
|
||||
import { Image as _Image } from 'react-native'
|
||||
import { useTheme } from '@/store/theme/hook'
|
||||
import { BorderRadius } from '@/theme'
|
||||
import { createStyle } from '@/utils/tools'
|
||||
import { memo, useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { View, type ViewProps, Image as _Image, StyleSheet } from 'react-native'
|
||||
import FastImage, { type FastImageProps } from 'react-native-fast-image'
|
||||
import Text from './Text'
|
||||
import { useLayout } from '@/utils/hooks'
|
||||
export type { OnLoadEvent } from 'react-native-fast-image'
|
||||
|
||||
export interface ImageProps extends Omit<FastImageProps, 'source'> {
|
||||
url?: string | number
|
||||
export interface ImageProps extends ViewProps {
|
||||
style: FastImageProps['style']
|
||||
url?: string | number | null
|
||||
resizeMode?: FastImageProps['resizeMode']
|
||||
onError?: (url: string | number) => void
|
||||
}
|
||||
|
||||
|
||||
@ -11,26 +20,69 @@ const defaultHeaders = {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
|
||||
}
|
||||
|
||||
const Image = ({ url, resizeMode = FastImage.resizeMode.cover, ...props }: ImageProps) => {
|
||||
const EmptyPic = memo(({ style, nativeID }: { style: ImageProps['style'], nativeID: ImageProps['nativeID'] }) => {
|
||||
const theme = useTheme()
|
||||
const { onLayout, width } = useLayout()
|
||||
const size = width * 0.36
|
||||
|
||||
return (
|
||||
<View style={StyleSheet.compose({ ...styles.emptyPic, backgroundColor: theme['c-primary-light-900-alpha-200'], gap: size * 0.1 }, style)} onLayout={onLayout} nativeID={nativeID}>
|
||||
<Text size={size} color={theme['c-primary-light-400-alpha-200']}>L</Text>
|
||||
<Text size={size} color={theme['c-primary-light-400-alpha-200']} style={styles.text}>X</Text>
|
||||
</View>
|
||||
)
|
||||
})
|
||||
|
||||
const Image = memo(({ url, resizeMode = FastImage.resizeMode.cover, style, onError, nativeID }: ImageProps) => {
|
||||
const [isError, setError] = useState(false)
|
||||
const handleError = useCallback(() => {
|
||||
setError(true)
|
||||
onError?.(url!)
|
||||
}, [onError, url])
|
||||
useEffect(() => {
|
||||
setError(false)
|
||||
}, [url])
|
||||
let uri = typeof url == 'number'
|
||||
? _Image.resolveAssetSource(url).uri
|
||||
: url?.startsWith('/')
|
||||
? 'file://' + url
|
||||
: url
|
||||
const showDefault = useMemo(() => !uri || isError, [isError, uri])
|
||||
return (
|
||||
<FastImage
|
||||
{...props}
|
||||
source={{
|
||||
uri,
|
||||
headers: defaultHeaders,
|
||||
priority: FastImage.priority.normal,
|
||||
}}
|
||||
resizeMode={resizeMode}
|
||||
/>
|
||||
showDefault ? <EmptyPic style={style} nativeID={nativeID} />
|
||||
: (
|
||||
<FastImage
|
||||
style={style}
|
||||
source={{
|
||||
uri: uri!,
|
||||
headers: defaultHeaders,
|
||||
priority: FastImage.priority.normal,
|
||||
}}
|
||||
onError={handleError}
|
||||
resizeMode={resizeMode}
|
||||
nativeID={nativeID}
|
||||
/>
|
||||
)
|
||||
)
|
||||
}
|
||||
}, (prevProps, nextProps) => {
|
||||
return prevProps.url == nextProps.url &&
|
||||
prevProps.style == nextProps.style &&
|
||||
prevProps.nativeID == nextProps.nativeID
|
||||
})
|
||||
|
||||
export const getSize = (uri: string, success: (width: number, height: number) => void, failure?: (error: any) => void) => {
|
||||
_Image.getSize(uri, success, failure)
|
||||
}
|
||||
export default Image
|
||||
|
||||
const styles = createStyle({
|
||||
emptyPic: {
|
||||
borderRadius: BorderRadius.normal,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
text: {
|
||||
paddingLeft: 2,
|
||||
},
|
||||
})
|
||||
|
@ -56,7 +56,6 @@ export default forwardRef<ImageBackgroundType, ImageBackgroundProps>(({
|
||||
children,
|
||||
style,
|
||||
imageStyle,
|
||||
importantForAccessibility,
|
||||
url,
|
||||
...props
|
||||
}, ref) => {
|
||||
@ -64,7 +63,7 @@ export default forwardRef<ImageBackgroundType, ImageBackgroundProps>(({
|
||||
return (
|
||||
<View
|
||||
accessibilityIgnoresInvertColors={true}
|
||||
importantForAccessibility={importantForAccessibility}
|
||||
importantForAccessibility={'no'}
|
||||
ref={ref}
|
||||
style={style}>
|
||||
{
|
||||
@ -72,7 +71,6 @@ export default forwardRef<ImageBackgroundType, ImageBackgroundProps>(({
|
||||
<Image
|
||||
{...props}
|
||||
url={url}
|
||||
importantForAccessibility={importantForAccessibility}
|
||||
style={[
|
||||
StyleSheet.absoluteFill,
|
||||
{
|
||||
|
@ -1,42 +1,22 @@
|
||||
import { memo } from 'react'
|
||||
import { View, TouchableOpacity } from 'react-native'
|
||||
import { StyleSheet, TouchableOpacity } from 'react-native'
|
||||
import { navigations } from '@/navigation'
|
||||
import { usePlayerMusicInfo } from '@/store/player/hook'
|
||||
import { useTheme } from '@/store/theme/hook'
|
||||
import { scaleSizeH } from '@/utils/pixelRatio'
|
||||
import { createStyle } from '@/utils/tools'
|
||||
import { BorderRadius } from '@/theme'
|
||||
import commonState from '@/store/common/state'
|
||||
import playerState from '@/store/player/state'
|
||||
import Text from '@/components/common/Text'
|
||||
import { LIST_IDS, NAV_SHEAR_NATIVE_IDS } from '@/config/constant'
|
||||
import Image from '@/components/common/Image'
|
||||
import { useCallback } from 'react'
|
||||
import { setLoadErrorPicUrl, setMusicInfo } from '@/core/player/playInfo'
|
||||
|
||||
const PIC_HEIGHT = scaleSizeH(46)
|
||||
|
||||
const styles = createStyle({
|
||||
// content: {
|
||||
// marginBottom: 3,
|
||||
// },/
|
||||
emptyPic: {
|
||||
borderRadius: BorderRadius.normal,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
const styles = StyleSheet.create({
|
||||
image: {
|
||||
width: PIC_HEIGHT,
|
||||
height: PIC_HEIGHT,
|
||||
borderRadius: 2,
|
||||
},
|
||||
text: {
|
||||
paddingLeft: 2,
|
||||
},
|
||||
})
|
||||
|
||||
const EmptyPic = memo(() => {
|
||||
const theme = useTheme()
|
||||
return (
|
||||
<View nativeID={NAV_SHEAR_NATIVE_IDS.playDetail_pic} style={{ ...styles.emptyPic, width: PIC_HEIGHT, height: PIC_HEIGHT, backgroundColor: theme['c-primary-light-900-alpha-200'] }}>
|
||||
<Text size={20} color={theme['c-primary-light-400-alpha-200']}>L</Text>
|
||||
<Text size={20} color={theme['c-primary-light-400-alpha-200']} style={styles.text}>X</Text>
|
||||
</View>
|
||||
)
|
||||
})
|
||||
|
||||
export default ({ isHome }: { isHome: boolean }) => {
|
||||
@ -57,23 +37,16 @@ export default ({ isHome }: { isHome: boolean }) => {
|
||||
global.app_event.jumpListPosition()
|
||||
}
|
||||
|
||||
// console.log('render pic')
|
||||
const handleError = useCallback((url: string | number) => {
|
||||
setLoadErrorPicUrl(url as string)
|
||||
setMusicInfo({
|
||||
pic: null,
|
||||
})
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<TouchableOpacity onLongPress={handleLongPress} onPress={handlePress} activeOpacity={0.7} >
|
||||
{
|
||||
musicInfo.pic
|
||||
? (
|
||||
<Image url={musicInfo.pic} nativeID={NAV_SHEAR_NATIVE_IDS.playDetail_pic} style={{
|
||||
// ...styles.playInfoImg,
|
||||
// backgroundColor: theme.primary,
|
||||
width: PIC_HEIGHT,
|
||||
height: PIC_HEIGHT,
|
||||
borderRadius: 2,
|
||||
}} />
|
||||
)
|
||||
: <EmptyPic />
|
||||
}
|
||||
<Image url={musicInfo.pic} nativeID={NAV_SHEAR_NATIVE_IDS.playDetail_pic} style={styles.image} onError={handleError} />
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
|
@ -9,8 +9,11 @@ import { createStyle } from '@/utils/tools'
|
||||
import Text from '@/components/common/Text'
|
||||
import { COMPONENT_IDS } from '@/config/constant'
|
||||
import { usePageVisible } from '@/store/common/hook'
|
||||
import { scaleSizeH } from '@/utils/pixelRatio'
|
||||
|
||||
const FONT_SIZE = 13
|
||||
const PADDING_TOP_RAW = 3
|
||||
const PADDING_TOP = scaleSizeH(PADDING_TOP_RAW)
|
||||
|
||||
const PlayTimeCurrent = ({ timeStr }: { timeStr: string }) => {
|
||||
const theme = useTheme()
|
||||
@ -42,7 +45,9 @@ export default ({ isHome }: { isHome: boolean }) => {
|
||||
<Text size={FONT_SIZE} color={theme['c-500']}> / </Text>
|
||||
<PlayTimeMax timeStr={maxPlayTimeStr} />
|
||||
</View>
|
||||
<View style={[StyleSheet.absoluteFill, styles.progress]}><Progress progress={progress} duration={maxPlayTime} /></View>
|
||||
<View style={[StyleSheet.absoluteFill, styles.progress]}>
|
||||
<Progress progress={progress} duration={maxPlayTime} paddingTop={PADDING_TOP} />
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
@ -64,7 +69,7 @@ const styles = createStyle({
|
||||
// position: 'absolute',
|
||||
// width: '100%',
|
||||
// top: 0,
|
||||
paddingVertical: 2,
|
||||
paddingTop: PADDING_TOP_RAW,
|
||||
paddingHorizontal: 3,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
@ -78,5 +83,6 @@ const styles = createStyle({
|
||||
flexGrow: 1,
|
||||
flexShrink: 1,
|
||||
paddingRight: 5,
|
||||
// backgroundColor: '#ccc',
|
||||
},
|
||||
})
|
||||
|
@ -69,7 +69,8 @@ const styles = createStyle({
|
||||
container: {
|
||||
width: '100%',
|
||||
paddingHorizontal: 2,
|
||||
paddingBottom: 2,
|
||||
// paddingBottom: 4,
|
||||
// height: '50%',
|
||||
// backgroundColor: 'rgba(0, 0, 0, .1)',
|
||||
},
|
||||
})
|
||||
|
@ -48,8 +48,7 @@ const styles = createStyle({
|
||||
// marginTop: -progressContentPadding,
|
||||
// backgroundColor: 'rgba(0, 0, 0, .1)',
|
||||
// borderTopWidth: BorderWidths.normal2,
|
||||
paddingTop: 5,
|
||||
paddingBottom: 5,
|
||||
paddingVertical: 5,
|
||||
paddingLeft: 5,
|
||||
// backgroundColor: AppColors.primary,
|
||||
// backgroundColor: 'red',
|
||||
|
@ -67,9 +67,10 @@ const PreassBar = memo(({ onDragState, setDragProgress, onSetProgress }: {
|
||||
})
|
||||
|
||||
|
||||
const Progress = ({ progress, duration }: {
|
||||
const Progress = ({ progress, duration, paddingTop }: {
|
||||
progress: number
|
||||
duration: number
|
||||
paddingTop?: number
|
||||
}) => {
|
||||
// const { progress } = usePlayTimeBuffer()
|
||||
const theme = useTheme()
|
||||
@ -87,7 +88,7 @@ const Progress = ({ progress, duration }: {
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<View style={styles.progress}>
|
||||
<View style={{ ...styles.progress, paddingTop }}>
|
||||
<View style={{ flex: 1 }}>
|
||||
<DefaultBar />
|
||||
{/* <BufferedBar bufferedProgress={bufferedProgress} /> */}
|
||||
@ -120,7 +121,7 @@ const styles = createStyle({
|
||||
},
|
||||
progressBar: {
|
||||
height: '100%',
|
||||
borderRadius: 3,
|
||||
borderRadius: 2,
|
||||
},
|
||||
pressBar: {
|
||||
position: 'absolute',
|
||||
|
@ -10,6 +10,10 @@ export const setMusicInfo = (musicInfo: Partial<LX.Player.MusicInfo>) => {
|
||||
playerActions.setMusicInfo(musicInfo)
|
||||
}
|
||||
|
||||
export const setLoadErrorPicUrl = (url: string) => {
|
||||
playerActions.setLoadErrorPicUrl(url)
|
||||
}
|
||||
|
||||
export const setPlayListId = (listId: string | null) => {
|
||||
playerActions.setPlayListId(listId)
|
||||
}
|
||||
|
@ -151,7 +151,11 @@ const handleRestorePlay = async(restorePlayInfo: LX.Player.SavedPlayInfo) => {
|
||||
const playMusicInfo = playerState.playMusicInfo
|
||||
|
||||
void getPicPath({ musicInfo, listId: playMusicInfo.listId }).then((url: string) => {
|
||||
if (musicInfo.id != playMusicInfo.musicInfo?.id) return
|
||||
if (
|
||||
musicInfo.id != playMusicInfo.musicInfo?.id ||
|
||||
playerState.musicInfo.pic == url ||
|
||||
playerState.loadErrorPicUrl == url
|
||||
) return
|
||||
setMusicInfo({ pic: url })
|
||||
global.app_event.picUpdated()
|
||||
})
|
||||
@ -180,7 +184,10 @@ const debouncePlay = debounceBackgroundTimer((musicInfo: LX.Player.PlayMusic) =>
|
||||
setMusicUrl(musicInfo)
|
||||
|
||||
void getPicPath({ musicInfo, listId: playerState.playMusicInfo.listId }).then((url: string) => {
|
||||
if (musicInfo.id != playerState.playMusicInfo.musicInfo?.id) return
|
||||
if (
|
||||
musicInfo.id != playerState.playMusicInfo.musicInfo?.id ||
|
||||
playerState.musicInfo.pic == url ||
|
||||
playerState.loadErrorPicUrl == url) return
|
||||
setMusicInfo({ pic: url })
|
||||
global.app_event.picUpdated()
|
||||
})
|
||||
|
@ -19,7 +19,6 @@ const LIST_LOAD_LIMIT = 30
|
||||
*/
|
||||
export const setSelectListInfo = (info: ListInfoItem) => {
|
||||
songlistActions.clearListDetail()
|
||||
songlistActions.setSelectListInfo(info)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -13,6 +13,7 @@ import themeState from '@/store/theme/state'
|
||||
import { NAV_SHEAR_NATIVE_IDS } from '@/config/constant'
|
||||
import { getStatusBarStyle } from './utils'
|
||||
import { windowSizeTools } from '@/utils/windowSizeTools'
|
||||
import { type ListInfoItem } from '@/store/songlist/state'
|
||||
|
||||
// const store = getStore()
|
||||
// const getTheme = () => getter('common', 'theme')(store.getState())
|
||||
@ -211,7 +212,7 @@ export function pushPlayDetailScreen(componentId: string) {
|
||||
})
|
||||
})
|
||||
}
|
||||
export function pushSonglistDetailScreen(componentId: string, id: string) {
|
||||
export function pushSonglistDetailScreen(componentId: string, info: ListInfoItem) {
|
||||
const theme = themeState.theme
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
@ -219,6 +220,9 @@ export function pushSonglistDetailScreen(componentId: string, id: string) {
|
||||
void Navigation.push(componentId, {
|
||||
component: {
|
||||
name: SONGLIST_DETAIL_SCREEN,
|
||||
passProps: {
|
||||
info,
|
||||
},
|
||||
options: {
|
||||
topBar: {
|
||||
visible: false,
|
||||
@ -242,8 +246,8 @@ export function pushSonglistDetailScreen(componentId: string, id: string) {
|
||||
push: {
|
||||
sharedElementTransitions: [
|
||||
{
|
||||
fromId: `${NAV_SHEAR_NATIVE_IDS.songlistDetail_pic}_from_${id}`,
|
||||
toId: `${NAV_SHEAR_NATIVE_IDS.songlistDetail_pic}_to_${id}`,
|
||||
fromId: `${NAV_SHEAR_NATIVE_IDS.songlistDetail_pic}_from_${info.id}`,
|
||||
toId: `${NAV_SHEAR_NATIVE_IDS.songlistDetail_pic}_to_${info.id}`,
|
||||
interpolation: { type: 'spring' },
|
||||
},
|
||||
],
|
||||
@ -281,8 +285,8 @@ export function pushSonglistDetailScreen(componentId: string, id: string) {
|
||||
pop: {
|
||||
sharedElementTransitions: [
|
||||
{
|
||||
fromId: `${NAV_SHEAR_NATIVE_IDS.songlistDetail_pic}_to_${id}`,
|
||||
toId: `${NAV_SHEAR_NATIVE_IDS.songlistDetail_pic}_from_${id}`,
|
||||
fromId: `${NAV_SHEAR_NATIVE_IDS.songlistDetail_pic}_to_${info.id}`,
|
||||
toId: `${NAV_SHEAR_NATIVE_IDS.songlistDetail_pic}_from_${info.id}`,
|
||||
interpolation: { type: 'spring' },
|
||||
},
|
||||
],
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { memo, useState, useMemo, useCallback } from 'react'
|
||||
import { View } from 'react-native'
|
||||
import { StyleSheet, View } from 'react-native'
|
||||
import { BorderWidths } from '@/theme'
|
||||
import { Icon } from '@/components/common/Icon'
|
||||
import { createStyle } from '@/utils/tools'
|
||||
@ -65,7 +65,7 @@ const CommentFloor = memo(({ comment, isLast }: {
|
||||
<Image
|
||||
url={comment.avatar && !isAvatarError ? comment.avatar : defaultUser}
|
||||
onError={handleAvatarError}
|
||||
style={{ height: avatarWidth, width: avatarWidth, borderRadius: 4 }} />
|
||||
style={stylesRaw.avatar} />
|
||||
</View>
|
||||
<View style={styles.right}>
|
||||
<View style={styles.info}>
|
||||
@ -152,4 +152,12 @@ const styles = createStyle({
|
||||
},
|
||||
})
|
||||
|
||||
const stylesRaw = StyleSheet.create({
|
||||
avatar: {
|
||||
height: avatarWidth,
|
||||
width: avatarWidth,
|
||||
borderRadius: 4,
|
||||
},
|
||||
})
|
||||
|
||||
export default CommentFloor
|
||||
|
@ -69,12 +69,20 @@ const NewCommentPage = memo(({ activeId, musicInfo, onUpdateTotal }: {
|
||||
}
|
||||
})
|
||||
|
||||
const TABS = [
|
||||
'hot',
|
||||
'new',
|
||||
] as const
|
||||
const getMusicInfo = (musicInfo: LX.Player.PlayMusic | null) => {
|
||||
if (!musicInfo) return null
|
||||
return 'progress' in musicInfo ? musicInfo.metadata.musicInfo : musicInfo
|
||||
}
|
||||
export default memo(({ componentId }: {
|
||||
componentId: string
|
||||
}) => {
|
||||
const pagerViewRef = useRef<PagerView>(null)
|
||||
const [activeId, setActiveId] = useState<ActiveId>('hot')
|
||||
const [musicInfo, setMusicInfo] = useState<LX.Music.MusicInfo | null>(null)
|
||||
const [musicInfo, setMusicInfo] = useState<LX.Music.MusicInfo | null>(getMusicInfo(playerState.playMusicInfo.musicInfo))
|
||||
const t = useI18n()
|
||||
const theme = useTheme()
|
||||
const [total, setTotal] = useState({ hot: 0, new: 0 })
|
||||
@ -86,21 +94,21 @@ export default memo(({ componentId }: {
|
||||
|
||||
const tabs = useMemo(() => {
|
||||
return [
|
||||
{ id: 'hot', label: t('comment_tab_hot', { total: total.hot ? `(${total.hot})` : '' }) },
|
||||
{ id: 'new', label: t('comment_tab_new', { total: total.new ? `(${total.new})` : '' }) },
|
||||
{ id: TABS[0], label: t('comment_tab_hot', { total: total.hot ? `(${total.hot})` : '' }) },
|
||||
{ id: TABS[1], label: t('comment_tab_new', { total: total.new ? `(${total.new})` : '' }) },
|
||||
] as const
|
||||
}, [total, t])
|
||||
|
||||
const toggleTab = (id: ActiveId) => {
|
||||
const toggleTab = useCallback((id: ActiveId) => {
|
||||
setActiveId(id)
|
||||
pagerViewRef.current?.setPage(tabs.findIndex(tab => tab.id == id))
|
||||
}
|
||||
pagerViewRef.current?.setPage(TABS.findIndex(tab => tab == id))
|
||||
}, [])
|
||||
|
||||
const onPageSelected = ({ nativeEvent }: PagerViewOnPageSelectedEvent) => {
|
||||
setActiveId(tabs[nativeEvent.position].id)
|
||||
}
|
||||
const onPageSelected = useCallback(({ nativeEvent }: PagerViewOnPageSelectedEvent) => {
|
||||
setActiveId(TABS[nativeEvent.position])
|
||||
}, [])
|
||||
|
||||
const refreshComment = () => {
|
||||
const refreshComment = useCallback(() => {
|
||||
if (!playerState.playMusicInfo.musicInfo) return
|
||||
let playerMusicInfo = playerState.playMusicInfo.musicInfo
|
||||
if ('progress' in playerMusicInfo) playerMusicInfo = playerMusicInfo.metadata.musicInfo
|
||||
@ -110,7 +118,7 @@ export default memo(({ componentId }: {
|
||||
return
|
||||
}
|
||||
setMusicInfo(playerMusicInfo)
|
||||
}
|
||||
}, [musicInfo, t])
|
||||
|
||||
const setHotTotal = useCallback((total: number) => {
|
||||
setTotal(totalInfo => ({ ...totalInfo, hot: total }))
|
||||
@ -119,14 +127,35 @@ export default memo(({ componentId }: {
|
||||
setTotal(totalInfo => ({ ...totalInfo, new: total }))
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
setTimeout(() => {
|
||||
if (!playerState.playMusicInfo.musicInfo) return
|
||||
let playerMusicInfo = playerState.playMusicInfo.musicInfo
|
||||
if ('progress' in playerMusicInfo) playerMusicInfo = playerMusicInfo.metadata.musicInfo
|
||||
setMusicInfo(playerMusicInfo)
|
||||
}, 300)
|
||||
}, [])
|
||||
const commentComponent = useMemo(() => {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={{ ...styles.tabHeader, borderBottomColor: theme['c-border-background'], height: BAR_HEIGHT }}>
|
||||
<View style={styles.left}>
|
||||
{tabs.map(({ id, label }) => <HeaderItem id={id} label={label} key={id} isActive={activeId == id} onPress={toggleTab} />)}
|
||||
</View>
|
||||
<View>
|
||||
<TouchableOpacity onPress={refreshComment} style={{ ...styles.btn, width: BAR_HEIGHT }}>
|
||||
<Icon name="available_updates" size={20} color={theme['c-600']} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
<PagerView
|
||||
ref={pagerViewRef}
|
||||
onPageSelected={onPageSelected}
|
||||
// onPageScrollStateChanged={onPageScrollStateChanged}
|
||||
style={styles.pagerView}
|
||||
>
|
||||
<View collapsable={false} style={styles.pageStyle}>
|
||||
<HotCommentPage activeId={activeId} musicInfo={musicInfo as LX.Music.MusicInfoOnline} onUpdateTotal={setHotTotal} />
|
||||
</View>
|
||||
<View collapsable={false} style={styles.pageStyle}>
|
||||
<NewCommentPage activeId={activeId} musicInfo={musicInfo as LX.Music.MusicInfoOnline} onUpdateTotal={setNewTotal} />
|
||||
</View>
|
||||
</PagerView>
|
||||
</View>
|
||||
)
|
||||
}, [activeId, musicInfo, onPageSelected, refreshComment, setHotTotal, setNewTotal, tabs, theme, toggleTab])
|
||||
|
||||
return (
|
||||
<PageContent>
|
||||
@ -142,33 +171,7 @@ export default memo(({ componentId }: {
|
||||
<Text>{t('comment_not support')}</Text>
|
||||
</View>
|
||||
)
|
||||
: (
|
||||
<View style={styles.container}>
|
||||
<View style={{ ...styles.tabHeader, borderBottomColor: theme['c-border-background'], height: BAR_HEIGHT }}>
|
||||
<View style={styles.left}>
|
||||
{tabs.map(({ id, label }) => <HeaderItem id={id} label={label} key={id} isActive={activeId == id} onPress={toggleTab} />)}
|
||||
</View>
|
||||
<View>
|
||||
<TouchableOpacity onPress={refreshComment} style={{ ...styles.btn, width: BAR_HEIGHT }}>
|
||||
<Icon name="available_updates" size={20} color={theme['c-600']} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
<PagerView
|
||||
ref={pagerViewRef}
|
||||
onPageSelected={onPageSelected}
|
||||
// onPageScrollStateChanged={onPageScrollStateChanged}
|
||||
style={styles.pagerView}
|
||||
>
|
||||
<View collapsable={false} style={styles.pageStyle}>
|
||||
<HotCommentPage activeId={activeId} musicInfo={musicInfo} onUpdateTotal={setHotTotal} />
|
||||
</View>
|
||||
<View collapsable={false} style={styles.pageStyle}>
|
||||
<NewCommentPage activeId={activeId} musicInfo={musicInfo} onUpdateTotal={setNewTotal} />
|
||||
</View>
|
||||
</PagerView>
|
||||
</View>
|
||||
)
|
||||
: commentComponent
|
||||
}
|
||||
</>
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ import { useRef, forwardRef, useImperativeHandle } from 'react'
|
||||
import { type ListInfoItem } from '@/store/songlist/state'
|
||||
// import LoadingMask, { LoadingMaskType } from '@/components/common/LoadingMask'
|
||||
import List, { type ListProps, type ListType, type Status } from './List'
|
||||
import { setSelectListInfo } from '@/core/songlist'
|
||||
import { navigations } from '@/navigation'
|
||||
import commonState from '@/store/common/state'
|
||||
|
||||
@ -32,9 +31,7 @@ export default forwardRef<SonglistType, SonglistProps>(({
|
||||
}))
|
||||
|
||||
const handleOpenDetail = (item: ListInfoItem, index: number) => {
|
||||
// console.log(item)
|
||||
setSelectListInfo(item)
|
||||
navigations.pushSonglistDetailScreen(commonState.componentIds.home!, item.id)
|
||||
navigations.pushSonglistDetailScreen(commonState.componentIds.home!, item)
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -1,9 +1,6 @@
|
||||
import { memo, useState } from 'react'
|
||||
import { View } from 'react-native'
|
||||
// import { useLayout } from '@/utils/hooks'
|
||||
import { useTheme } from '@/store/theme/hook'
|
||||
import { BorderRadius } from '@/theme'
|
||||
import Text from '@/components/common/Text'
|
||||
import { usePlayerMusicInfo } from '@/store/player/hook'
|
||||
import { useWindowSize } from '@/utils/hooks'
|
||||
import { useNavigationComponentDidAppear } from '@/navigation'
|
||||
@ -15,16 +12,6 @@ import { BTN_WIDTH } from './MoreBtn/Btn'
|
||||
import { marginLeft } from './constant'
|
||||
import Image from '@/components/common/Image'
|
||||
|
||||
const EmptyPic = memo(({ width }: { width: number }) => {
|
||||
const theme = useTheme()
|
||||
const size = width * 0.2
|
||||
return (
|
||||
<View style={{ ...styles.emptyPic, width, height: width, backgroundColor: theme['c-primary-light-900-alpha-200'] }}>
|
||||
<Text size={size} color={theme['c-primary-light-400-alpha-200']}>L</Text>
|
||||
<Text size={size} color={theme['c-primary-light-400-alpha-200']} style={styles.text}>X</Text>
|
||||
</View>
|
||||
)
|
||||
})
|
||||
|
||||
export default memo(({ componentId }: { componentId: string }) => {
|
||||
const musicInfo = usePlayerMusicInfo()
|
||||
@ -44,18 +31,11 @@ export default memo(({ componentId }: { componentId: string }) => {
|
||||
return (
|
||||
<View style={{ ...styles.container, height: contentHeight }}>
|
||||
<View style={{ ...styles.content, elevation: animated ? 3 : 0 }}>
|
||||
{
|
||||
musicInfo.pic
|
||||
? (
|
||||
<Image url={musicInfo.pic} nativeID={NAV_SHEAR_NATIVE_IDS.playDetail_pic} style={{
|
||||
...styles.img,
|
||||
width: imgWidth,
|
||||
height: imgWidth,
|
||||
borderRadius: 2,
|
||||
}} />
|
||||
)
|
||||
: <EmptyPic width={imgWidth} />
|
||||
}
|
||||
<Image url={musicInfo.pic} nativeID={NAV_SHEAR_NATIVE_IDS.playDetail_pic} style={{
|
||||
width: imgWidth,
|
||||
height: imgWidth,
|
||||
borderRadius: 2,
|
||||
}} />
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
@ -75,17 +55,4 @@ const styles = createStyle({
|
||||
backgroundColor: 'rgba(0,0,0,0)',
|
||||
borderRadius: 4,
|
||||
},
|
||||
img: {
|
||||
borderRadius: 4,
|
||||
// opacity: 0,
|
||||
},
|
||||
emptyPic: {
|
||||
borderRadius: BorderRadius.normal,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
text: {
|
||||
paddingLeft: 2,
|
||||
},
|
||||
})
|
||||
|
@ -1,28 +1,15 @@
|
||||
import { memo, useState } from 'react'
|
||||
import { useMemo, useState } from 'react'
|
||||
import { View } from 'react-native'
|
||||
// import { useLayout } from '@/utils/hooks'
|
||||
import { createStyle } from '@/utils/tools'
|
||||
import { usePlayerMusicInfo } from '@/store/player/hook'
|
||||
import { useTheme } from '@/store/theme/hook'
|
||||
import { BorderRadius } from '@/theme'
|
||||
import { useWindowSize } from '@/utils/hooks'
|
||||
import Text from '@/components/common/Text'
|
||||
import { NAV_SHEAR_NATIVE_IDS } from '@/config/constant'
|
||||
import { useNavigationComponentDidAppear } from '@/navigation'
|
||||
import StatusBar from '@/components/common/StatusBar'
|
||||
import { HEADER_HEIGHT } from './components/Header'
|
||||
import Image from '@/components/common/Image'
|
||||
|
||||
const EmptyPic = memo(({ width }: { width: number }) => {
|
||||
const theme = useTheme()
|
||||
const size = width * 0.2
|
||||
return (
|
||||
<View style={{ ...styles.emptyPic, width, height: width, backgroundColor: theme['c-primary-light-900-alpha-200'] }}>
|
||||
<Text size={size} color={theme['c-primary-light-400-alpha-200']}>L</Text>
|
||||
<Text size={size} color={theme['c-primary-light-400-alpha-200']} style={styles.text}>X</Text>
|
||||
</View>
|
||||
)
|
||||
})
|
||||
|
||||
export default ({ componentId }: { componentId: string }) => {
|
||||
const musicInfo = usePlayerMusicInfo()
|
||||
@ -35,23 +22,19 @@ export default ({ componentId }: { componentId: string }) => {
|
||||
})
|
||||
// console.log('render pic')
|
||||
|
||||
const imgWidth = Math.min(winWidth * 0.8, (winHeight - StatusBar.currentHeight - HEADER_HEIGHT) * 0.5)
|
||||
const style = useMemo(() => {
|
||||
const imgWidth = Math.min(winWidth * 0.8, (winHeight - StatusBar.currentHeight - HEADER_HEIGHT) * 0.5)
|
||||
return {
|
||||
width: imgWidth,
|
||||
height: imgWidth,
|
||||
borderRadius: 2,
|
||||
}
|
||||
}, [winHeight, winWidth])
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={{ ...styles.content, elevation: animated ? 3 : 0 }}>
|
||||
{
|
||||
musicInfo.pic
|
||||
? (
|
||||
<Image url={musicInfo.pic} nativeID={NAV_SHEAR_NATIVE_IDS.playDetail_pic} style={{
|
||||
...styles.img,
|
||||
width: imgWidth,
|
||||
height: imgWidth,
|
||||
borderRadius: 2,
|
||||
}} />
|
||||
)
|
||||
: <EmptyPic width={imgWidth} />
|
||||
}
|
||||
<Image url={musicInfo.pic} nativeID={NAV_SHEAR_NATIVE_IDS.playDetail_pic} style={style} />
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
@ -70,17 +53,4 @@ const styles = createStyle({
|
||||
backgroundColor: 'rgba(0,0,0,0)',
|
||||
borderRadius: 4,
|
||||
},
|
||||
img: {
|
||||
borderRadius: 4,
|
||||
// opacity: 0,
|
||||
},
|
||||
emptyPic: {
|
||||
borderRadius: BorderRadius.normal,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
text: {
|
||||
paddingLeft: 2,
|
||||
},
|
||||
})
|
||||
|
@ -10,11 +10,13 @@ import Text from '@/components/common/Text'
|
||||
import { handleCollect, handlePlay } from './listAction'
|
||||
import songlistState from '@/store/songlist/state'
|
||||
import { useI18n } from '@/lang'
|
||||
import { useListInfo } from './state'
|
||||
// import { NAV_SHEAR_NATIVE_IDS } from '@/config/constant'
|
||||
|
||||
export default memo(() => {
|
||||
const theme = useTheme()
|
||||
const t = useI18n()
|
||||
const info = useListInfo()
|
||||
|
||||
const back = () => {
|
||||
void pop(commonState.componentIds.songlistDetail!)
|
||||
@ -22,12 +24,12 @@ export default memo(() => {
|
||||
|
||||
const handlePlayAll = () => {
|
||||
if (!songlistState.listDetailInfo.info.name) return
|
||||
void handlePlay(songlistState.selectListInfo.id, songlistState.selectListInfo.source, songlistState.listDetailInfo.list)
|
||||
void handlePlay(info.id, info.source, songlistState.listDetailInfo.list)
|
||||
}
|
||||
|
||||
const handleCollection = () => {
|
||||
if (!songlistState.listDetailInfo.info.name) return
|
||||
void handleCollect(songlistState.selectListInfo.id, songlistState.selectListInfo.source, songlistState.listDetailInfo.info.name || songlistState.selectListInfo.name)
|
||||
void handleCollect(info.id, info.source, songlistState.listDetailInfo.info.name || info.name)
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -9,8 +9,8 @@ import { useTheme } from '@/store/theme/hook'
|
||||
import Text from '@/components/common/Text'
|
||||
import { createStyle } from '@/utils/tools'
|
||||
import StatusBar from '@/components/common/StatusBar'
|
||||
import songlistState from '@/store/songlist/state'
|
||||
import Image from '@/components/common/Image'
|
||||
import { useListInfo } from './state'
|
||||
|
||||
const IMAGE_WIDTH = scaleSizeW(70)
|
||||
|
||||
@ -20,6 +20,7 @@ const Pic = ({ componentId, playCount, imgUrl }: {
|
||||
imgUrl?: string
|
||||
}) => {
|
||||
const [animated, setAnimated] = useState(false)
|
||||
const info = useListInfo()
|
||||
|
||||
useNavigationComponentDidAppear(componentId, () => {
|
||||
setAnimated(true)
|
||||
@ -27,7 +28,7 @@ const Pic = ({ componentId, playCount, imgUrl }: {
|
||||
|
||||
return (
|
||||
<View style={{ ...styles.listItemImg, width: IMAGE_WIDTH, height: IMAGE_WIDTH }}>
|
||||
<Image nativeID={`${NAV_SHEAR_NATIVE_IDS.songlistDetail_pic}_to_${songlistState.selectListInfo.id}`} url={imgUrl} style={{ flex: 1, justifyContent: 'flex-end', borderRadius: 4 }} />
|
||||
<Image nativeID={`${NAV_SHEAR_NATIVE_IDS.songlistDetail_pic}_to_${info.id}`} url={imgUrl} style={{ flex: 1, justifyContent: 'flex-end', borderRadius: 4 }} />
|
||||
{
|
||||
playCount && animated
|
||||
? <Text style={styles.playCount} numberOfLines={ 1 }>{playCount}</Text>
|
||||
@ -53,7 +54,8 @@ export interface DetailInfo {
|
||||
|
||||
export default forwardRef<HeaderType, HeaderProps>(({ componentId }: { componentId: string }, ref) => {
|
||||
const theme = useTheme()
|
||||
const [detailInfo, setDetailInfo] = useState<DetailInfo>({ name: '', desc: '', playCount: '' })
|
||||
const info = useListInfo()
|
||||
const [detailInfo, setDetailInfo] = useState<DetailInfo>({ name: '', desc: '', playCount: '', imgUrl: info.img })
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
setInfo(info) {
|
||||
|
@ -4,6 +4,7 @@ import { clearListDetail, getListDetail, setListDetail, setListDetailInfo } from
|
||||
import songlistState from '@/store/songlist/state'
|
||||
import { handlePlay } from './listAction'
|
||||
import Header, { type HeaderType } from './Header'
|
||||
import { useListInfo } from './state'
|
||||
|
||||
export interface MusicListProps {
|
||||
componentId: string
|
||||
@ -17,42 +18,45 @@ export default forwardRef<MusicListType, MusicListProps>(({ componentId }, ref)
|
||||
const listRef = useRef<OnlineListType>(null)
|
||||
const headerRef = useRef<HeaderType>(null)
|
||||
const isUnmountedRef = useRef(false)
|
||||
const info = useListInfo()
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
async loadList(source, id) {
|
||||
clearListDetail()
|
||||
const listDetailInfo = songlistState.listDetailInfo
|
||||
listRef.current?.setList([])
|
||||
if (listDetailInfo.id == id && listDetailInfo.source == source && listDetailInfo.list.length) {
|
||||
requestAnimationFrame(() => {
|
||||
listRef.current?.setList(listDetailInfo.list)
|
||||
headerRef.current?.setInfo({
|
||||
name: (songlistState.selectListInfo.name || listDetailInfo.info.name) ?? '',
|
||||
name: (info.name || listDetailInfo.info.name) ?? '',
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
||||
desc: songlistState.selectListInfo.desc || listDetailInfo.info.desc || '',
|
||||
playCount: (songlistState.selectListInfo.play_count ?? listDetailInfo.info.play_count) ?? '',
|
||||
imgUrl: songlistState.selectListInfo.img ?? listDetailInfo.info.img,
|
||||
desc: info.desc || listDetailInfo.info.desc || '',
|
||||
playCount: (info.play_count ?? listDetailInfo.info.play_count) ?? '',
|
||||
imgUrl: info.img ?? listDetailInfo.info.img,
|
||||
})
|
||||
})
|
||||
} else {
|
||||
listRef.current?.setStatus('loading')
|
||||
const page = 1
|
||||
setListDetailInfo(songlistState.selectListInfo.source, songlistState.selectListInfo.id)
|
||||
setListDetailInfo(info.source, info.id)
|
||||
headerRef.current?.setInfo({
|
||||
name: (songlistState.selectListInfo.name || listDetailInfo.info.name) ?? '',
|
||||
name: (info.name || listDetailInfo.info.name) ?? '',
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
||||
desc: songlistState.selectListInfo.desc || listDetailInfo.info.desc || '',
|
||||
playCount: (songlistState.selectListInfo.play_count ?? listDetailInfo.info.play_count) ?? '',
|
||||
imgUrl: songlistState.selectListInfo.img ?? listDetailInfo.info.img,
|
||||
desc: info.desc || listDetailInfo.info.desc || '',
|
||||
playCount: (info.play_count ?? listDetailInfo.info.play_count) ?? '',
|
||||
imgUrl: info.img ?? listDetailInfo.info.img,
|
||||
})
|
||||
return getListDetail(id, source, page).then((listDetail) => {
|
||||
const result = setListDetail(listDetail, id, page)
|
||||
if (isUnmountedRef.current) return
|
||||
requestAnimationFrame(() => {
|
||||
headerRef.current?.setInfo({
|
||||
name: (songlistState.selectListInfo.name || listDetailInfo.info.name) ?? '',
|
||||
name: (info.name || listDetailInfo.info.name) ?? '',
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
||||
desc: songlistState.selectListInfo.desc || listDetailInfo.info.desc || '',
|
||||
playCount: (songlistState.selectListInfo.play_count ?? listDetailInfo.info.play_count) ?? '',
|
||||
imgUrl: songlistState.selectListInfo.img ?? listDetailInfo.info.img,
|
||||
desc: info.desc || listDetailInfo.info.desc || '',
|
||||
playCount: (info.play_count ?? listDetailInfo.info.play_count) ?? '',
|
||||
imgUrl: info.img ?? listDetailInfo.info.img,
|
||||
})
|
||||
listRef.current?.setList(result.list)
|
||||
listRef.current?.setStatus(songlistState.listDetailInfo.maxPage <= page ? 'end' : 'idle')
|
||||
|
@ -5,11 +5,12 @@ import PageContent from '@/components/PageContent'
|
||||
import StatusBar from '@/components/common/StatusBar'
|
||||
import { setComponentId } from '@/core/common'
|
||||
import { COMPONENT_IDS } from '@/config/constant'
|
||||
import songlistState from '@/store/songlist/state'
|
||||
import { type ListInfoItem } from '@/store/songlist/state'
|
||||
import PlayerBar from '@/components/player/PlayerBar'
|
||||
import { ListInfoContext } from './state'
|
||||
|
||||
|
||||
export default ({ componentId }: { componentId: string }) => {
|
||||
export default ({ componentId, info }: { componentId: string, info: ListInfoItem }) => {
|
||||
const musicListRef = useRef<MusicListType>(null)
|
||||
const isUnmountedRef = useRef(false)
|
||||
|
||||
@ -18,7 +19,7 @@ export default ({ componentId }: { componentId: string }) => {
|
||||
|
||||
isUnmountedRef.current = false
|
||||
|
||||
musicListRef.current?.loadList(songlistState.selectListInfo.source, songlistState.selectListInfo.id)
|
||||
musicListRef.current?.loadList(info.source, info.id)
|
||||
|
||||
|
||||
return () => {
|
||||
@ -31,7 +32,9 @@ export default ({ componentId }: { componentId: string }) => {
|
||||
return (
|
||||
<PageContent>
|
||||
<StatusBar />
|
||||
<MusicList ref={musicListRef} componentId={componentId} />
|
||||
<ListInfoContext.Provider value={info}>
|
||||
<MusicList ref={musicListRef} componentId={componentId} />
|
||||
</ListInfoContext.Provider>
|
||||
<PlayerBar />
|
||||
</PageContent>
|
||||
)
|
||||
|
13
src/screens/SonglistDetail/state.ts
Normal file
13
src/screens/SonglistDetail/state.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { type ListInfoItem } from '@/store/songlist/state'
|
||||
import { createContext, useContext } from 'react'
|
||||
|
||||
export const ListInfoContext = createContext<ListInfoItem>({
|
||||
id: '',
|
||||
author: '',
|
||||
name: '',
|
||||
source: 'kw',
|
||||
})
|
||||
|
||||
export const useListInfo = () => {
|
||||
return useContext(ListInfoContext)
|
||||
}
|
@ -104,4 +104,7 @@ export default {
|
||||
|
||||
global.state_event.playTempPlayListChanged({ ...state.tempPlayList })
|
||||
},
|
||||
setLoadErrorPicUrl(url: string) {
|
||||
state.loadErrorPicUrl = url
|
||||
},
|
||||
}
|
||||
|
@ -24,6 +24,8 @@ export interface InitState {
|
||||
playedList: LX.Player.PlayMusicInfo[]
|
||||
tempPlayList: LX.Player.PlayMusicInfo[]
|
||||
|
||||
loadErrorPicUrl: string
|
||||
|
||||
|
||||
progress: {
|
||||
nowPlayTime: number
|
||||
@ -63,6 +65,7 @@ const state: InitState = {
|
||||
volume: 1,
|
||||
playRate: 1,
|
||||
statusText: '',
|
||||
loadErrorPicUrl: '',
|
||||
|
||||
playedList: [],
|
||||
tempPlayList: [],
|
||||
|
@ -1,4 +1,4 @@
|
||||
import type { TagInfo, ListDetailInfo, ListInfo, ListInfoItem, Source } from './state'
|
||||
import type { TagInfo, ListDetailInfo, ListInfo, Source } from './state'
|
||||
import state from './state'
|
||||
|
||||
export default {
|
||||
@ -58,13 +58,4 @@ export default {
|
||||
state.listDetailInfo.info = {}
|
||||
state.listDetailInfo.maxPage = 1
|
||||
},
|
||||
setSelectListInfo(info: ListInfoItem) {
|
||||
state.selectListInfo.author = info.author
|
||||
state.selectListInfo.desc = info.desc
|
||||
state.selectListInfo.id = info.id
|
||||
state.selectListInfo.img = info.img
|
||||
state.selectListInfo.name = info.name
|
||||
state.selectListInfo.play_count = info.play_count
|
||||
state.selectListInfo.source = info.source
|
||||
},
|
||||
}
|
||||
|
@ -79,7 +79,6 @@ export interface InitState {
|
||||
sortList: Partial<Record<Source, SortInfo[]>>
|
||||
tags: Tags
|
||||
listInfo: ListInfo
|
||||
selectListInfo: ListInfoItem
|
||||
listDetailInfo: ListDetailInfo
|
||||
}
|
||||
|
||||
@ -99,17 +98,6 @@ const state: InitState = {
|
||||
tagId: '',
|
||||
sortId: '',
|
||||
},
|
||||
selectListInfo: {
|
||||
play_count: '',
|
||||
id: '',
|
||||
author: '',
|
||||
name: '',
|
||||
time: '',
|
||||
img: '',
|
||||
// grade: basic.favorcnt / 10,
|
||||
desc: '',
|
||||
source: 'kw',
|
||||
},
|
||||
listDetailInfo: {
|
||||
list: [],
|
||||
id: '',
|
||||
|
Loading…
x
Reference in New Issue
Block a user