优化背景切换逻辑

This commit is contained in:
lyswhut 2023-12-23 13:13:33 +08:00
parent 8367758113
commit 634ebe71e9
15 changed files with 124 additions and 94 deletions

12
package-lock.json generated
View File

@ -25,7 +25,7 @@
"react-native-fast-image": "^8.6.3", "react-native-fast-image": "^8.6.3",
"react-native-file-system": "github:lyswhut/react-native-file-system#291582cd202053246458bf9376efe27fbb75afb6", "react-native-file-system": "github:lyswhut/react-native-file-system#291582cd202053246458bf9376efe27fbb75afb6",
"react-native-fs": "^2.20.0", "react-native-fs": "^2.20.0",
"react-native-local-media-metadata": "github:lyswhut/react-native-local-media-metadata#35d7df1f68f19492749a9ea0541f02be77c0a675", "react-native-local-media-metadata": "github:lyswhut/react-native-local-media-metadata#fbf7c7d07475c6adb398b05653fa3cadc722d4ea",
"react-native-navigation": "^7.37.2", "react-native-navigation": "^7.37.2",
"react-native-pager-view": "^6.2.3", "react-native-pager-view": "^6.2.3",
"react-native-quick-base64": "^2.0.8", "react-native-quick-base64": "^2.0.8",
@ -9014,8 +9014,8 @@
}, },
"node_modules/react-native-local-media-metadata": { "node_modules/react-native-local-media-metadata": {
"version": "0.1.0", "version": "0.1.0",
"resolved": "git+ssh://git@github.com/lyswhut/react-native-local-media-metadata.git#35d7df1f68f19492749a9ea0541f02be77c0a675", "resolved": "git+ssh://git@github.com/lyswhut/react-native-local-media-metadata.git#fbf7c7d07475c6adb398b05653fa3cadc722d4ea",
"integrity": "sha512-Gbf8yuVQIWOAuJ4JQ5cRL9QNMePqsiPiSVw+e11ZfwKnZtpCtiwbgTixCjWpIcIyRsURNBz+3UJwQl2fPx6FWQ==", "integrity": "sha512-HIjzXi0t/70NoDn91wS/A0SiusPpKF1aJPXXZ1e8BMf5TyepOwzRWDezvz8tvymsb52caY7DesgUWS1Tv2m29A==",
"license": "MIT", "license": "MIT",
"workspaces": [ "workspaces": [
"example" "example"
@ -17217,9 +17217,9 @@
} }
}, },
"react-native-local-media-metadata": { "react-native-local-media-metadata": {
"version": "git+ssh://git@github.com/lyswhut/react-native-local-media-metadata.git#35d7df1f68f19492749a9ea0541f02be77c0a675", "version": "git+ssh://git@github.com/lyswhut/react-native-local-media-metadata.git#fbf7c7d07475c6adb398b05653fa3cadc722d4ea",
"integrity": "sha512-Gbf8yuVQIWOAuJ4JQ5cRL9QNMePqsiPiSVw+e11ZfwKnZtpCtiwbgTixCjWpIcIyRsURNBz+3UJwQl2fPx6FWQ==", "integrity": "sha512-HIjzXi0t/70NoDn91wS/A0SiusPpKF1aJPXXZ1e8BMf5TyepOwzRWDezvz8tvymsb52caY7DesgUWS1Tv2m29A==",
"from": "react-native-local-media-metadata@github:lyswhut/react-native-local-media-metadata#35d7df1f68f19492749a9ea0541f02be77c0a675", "from": "react-native-local-media-metadata@github:lyswhut/react-native-local-media-metadata#fbf7c7d07475c6adb398b05653fa3cadc722d4ea",
"requires": {} "requires": {}
}, },
"react-native-navigation": { "react-native-navigation": {

View File

@ -59,7 +59,7 @@
"react-native-fast-image": "^8.6.3", "react-native-fast-image": "^8.6.3",
"react-native-file-system": "github:lyswhut/react-native-file-system#291582cd202053246458bf9376efe27fbb75afb6", "react-native-file-system": "github:lyswhut/react-native-file-system#291582cd202053246458bf9376efe27fbb75afb6",
"react-native-fs": "^2.20.0", "react-native-fs": "^2.20.0",
"react-native-local-media-metadata": "github:lyswhut/react-native-local-media-metadata#35d7df1f68f19492749a9ea0541f02be77c0a675", "react-native-local-media-metadata": "github:lyswhut/react-native-local-media-metadata#fbf7c7d07475c6adb398b05653fa3cadc722d4ea",
"react-native-navigation": "^7.37.2", "react-native-navigation": "^7.37.2",
"react-native-pager-view": "^6.2.3", "react-native-pager-view": "^6.2.3",
"react-native-quick-base64": "^2.0.8", "react-native-quick-base64": "^2.0.8",

View File

@ -1,29 +1,24 @@
// import { useEffect, useState } from 'react' // import { useEffect, useState } from 'react'
import { Image, View } from 'react-native' import { View } from 'react-native'
import { useTheme } from '@/store/theme/hook' import { useTheme } from '@/store/theme/hook'
import ImageBackground from '@/components/common/ImageBackground' import ImageBackground from '@/components/common/ImageBackground'
import { useWindowSize } from '@/utils/hooks' import { useWindowSize } from '@/utils/hooks'
import { useEffect, useMemo, useState } from 'react' import { useMemo } from 'react'
import playerState from '@/store/player/state'
import settingState from '@/store/setting/state'
import { scaleSizeAbsHR } from '@/utils/pixelRatio' import { scaleSizeAbsHR } from '@/utils/pixelRatio'
import { defaultHeaders } from './common/Image' import { defaultHeaders } from './common/Image'
import SizeView from './SizeView' import SizeView from './SizeView'
import { useBgPic } from '@/store/common/hook'
interface Props { interface Props {
children: React.ReactNode children: React.ReactNode
} }
const formatUri = <T extends string | null>(url: T) => { const BLUR_RADIUS = Math.max(scaleSizeAbsHR(18), 10)
return (typeof url == 'string' && url.startsWith('/')) ? `file://${url}` : url
}
const BLUR_RADIUS = Math.max(scaleSizeAbsHR(24), 10)
export default ({ children }: Props) => { export default ({ children }: Props) => {
const theme = useTheme() const theme = useTheme()
const windowSize = useWindowSize() const windowSize = useWindowSize()
const [pic, setPic] = useState<string | null | undefined>(settingState.setting['theme.dynamicBg'] ? playerState.musicInfo.pic : null) const pic = useBgPic()
// const [wh, setWH] = useState<{ width: number | string, height: number | string }>({ width: '100%', height: Dimensions.get('screen').height }) // const [wh, setWH] = useState<{ width: number | string, height: number | string }>({ width: '100%', height: Dimensions.get('screen').height })
// 固定宽高度 防止弹窗键盘时大小改变导致背景被缩放 // 固定宽高度 防止弹窗键盘时大小改变导致背景被缩放
@ -44,49 +39,6 @@ export default ({ children }: Props) => {
// } // }
// console.log('render page content') // console.log('render page content')
useEffect(() => {
let pic = playerState.musicInfo.pic
let isUnmounted = false
let isDynamicBg = settingState.setting['theme.dynamicBg']
const handlePicUpdate = () => {
if (playerState.musicInfo.pic && playerState.musicInfo.pic != playerState.loadErrorPicUrl) {
// if (playerState.musicInfo.pic != playerState.loadErrorPicUrl) {
// console.log('picUpdated', playerState.musicInfo.pic)
pic = playerState.musicInfo.pic
if (!isDynamicBg) return
void Image.prefetch(formatUri(playerState.musicInfo.pic)).then(() => {
if (pic != playerState.musicInfo.pic || isUnmounted) return
setPic(playerState.musicInfo.pic)
}).catch(() => {
if (isUnmounted) return
setPic(null)
})
}
// } else {
// if (!isDynamicBg) return
// setPic(null)
// }
}
const handleConfigUpdate = (keys: Array<keyof LX.AppSetting>, setting: Partial<LX.AppSetting>) => {
if (!keys.includes('theme.dynamicBg')) return
isDynamicBg = setting['theme.dynamicBg']!
if (isDynamicBg) {
if (playerState.musicInfo.pic) {
pic = playerState.musicInfo.pic
// console.log(pic)
setPic(pic)
}
} else setPic(null)
}
global.state_event.on('playerMusicInfoChanged', handlePicUpdate)
global.state_event.on('configUpdated', handleConfigUpdate)
return () => {
isUnmounted = true
global.state_event.off('playerMusicInfoChanged', handlePicUpdate)
global.state_event.off('configUpdated', handleConfigUpdate)
}
}, [])
const themeComponent = useMemo(() => ( const themeComponent = useMemo(() => (
<View style={{ flex: 1, overflow: 'hidden' }}> <View style={{ flex: 1, overflow: 'hidden' }}>
<ImageBackground <ImageBackground
@ -105,11 +57,11 @@ export default ({ children }: Props) => {
<View style={{ flex: 1, overflow: 'hidden' }}> <View style={{ flex: 1, overflow: 'hidden' }}>
<ImageBackground <ImageBackground
style={{ position: 'absolute', left: 0, top: 0, height: windowSize.height, width: windowSize.width, backgroundColor: theme['c-content-background'] }} style={{ position: 'absolute', left: 0, top: 0, height: windowSize.height, width: windowSize.width, backgroundColor: theme['c-content-background'] }}
source={{ uri: formatUri(pic!), headers: defaultHeaders }} source={{ uri: pic!, headers: defaultHeaders }}
resizeMode="cover" resizeMode="cover"
blurRadius={BLUR_RADIUS} blurRadius={BLUR_RADIUS}
> >
<View style={{ flex: 1, flexDirection: 'column', backgroundColor: theme['c-content-background'], opacity: 0.8 }}></View> <View style={{ flex: 1, flexDirection: 'column', backgroundColor: theme['c-content-background'], opacity: 0.76 }}></View>
</ImageBackground> </ImageBackground>
<View style={{ flex: 1, flexDirection: 'column' }}> <View style={{ flex: 1, flexDirection: 'column' }}>
{children} {children}

View File

@ -94,3 +94,7 @@ export default forwardRef<View, ImageBackgroundProps>(({
</View> </View>
) )
}) })
export const prefetch = async(url: string) => {
return Image.prefetch(url)
}

View File

@ -46,7 +46,7 @@ export default ({ isHome }: { isHome: boolean }) => {
return ( return (
<TouchableOpacity onLongPress={handleLongPress} onPress={handlePress} activeOpacity={0.7} > <TouchableOpacity onLongPress={handleLongPress} onPress={handlePress} activeOpacity={0.7} >
<Image url={musicInfo.pic} cache={false} nativeID={NAV_SHEAR_NATIVE_IDS.playDetail_pic} style={styles.image} onError={handleError} /> <Image url={musicInfo.pic} nativeID={NAV_SHEAR_NATIVE_IDS.playDetail_pic} style={styles.image} onError={handleError} />
</TouchableOpacity> </TouchableOpacity>
) )
} }

View File

@ -108,3 +108,7 @@ export const requestStoragePermission = async() => {
await setSelectedManagedFolder(uri.path) await setSelectedManagedFolder(uri.path)
return true return true
} }
export const setBgPic = (pic: string | null) => {
commonActions.setBgPic(pic)
}

71
src/core/init/common.ts Normal file
View File

@ -0,0 +1,71 @@
// import musicSdk from '@/utils/musicSdk'
// import commonActions from '@/store/common/action'
import playerState from '@/store/player/state'
import { prefetch } from '@/components/common/ImageBackground'
import { setBgPic } from '@/core/common'
// const handleUpdateSourceNmaes = () => {
// const prefix = settingState.setting['common.sourceNameType'] == 'real' ? 'source_' : 'source_alias_'
// const sourceNames: Record<LX.OnlineSource | 'all', string> = {
// kw: 'kw',
// tx: 'tx',
// kg: 'kg',
// mg: 'mg',
// wy: 'wy',
// // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
// all: global.i18n.t(prefix + 'all' as any),
// }
// for (const { id } of musicSdk.sources) {
// // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
// sourceNames[id as LX.OnlineSource] = global.i18n.t(prefix + id as any)
// }
// commonActions.setSourceNames(sourceNames)
// }
const formatUri = <T extends string | null>(url: T) => {
return (typeof url == 'string' && url.startsWith('/')) ? `file://${url}` : url
}
export default async(setting: LX.AppSetting) => {
// const handleConfigUpdated = (keys: Array<keyof LX.AppSetting>, setting: Partial<LX.AppSetting>) => {
// // if (keys.includes('common.sourceNameType')) handleUpdateSourceNmaes()
// handleConfigUpdate(keys, setting)
// }
let pic = playerState.musicInfo.pic
let isDynamicBg = setting['theme.dynamicBg']
const handleUpdatePic = (pic: string) => {
if (!pic) return
const picUrl = formatUri(pic)
void prefetch(picUrl).then(() => {
if (pic != playerState.musicInfo.pic) return
setBgPic(picUrl)
})
}
const handlePicUpdate = () => {
if (playerState.musicInfo.pic && playerState.musicInfo.pic != playerState.loadErrorPicUrl) {
// if (playerState.musicInfo.pic != playerState.loadErrorPicUrl) {
console.log('picUpdated', playerState.musicInfo.pic)
pic = playerState.musicInfo.pic
if (!isDynamicBg) return
handleUpdatePic(pic)
// .catch(() => {
// if (pic != playerState.musicInfo.pic) return
// setBgPic(null)
// })
}
// } else {
// if (!isDynamicBg) return
// setPic(null)
// }
}
const handleConfigUpdate = (keys: Array<keyof LX.AppSetting>, setting: Partial<LX.AppSetting>) => {
if (!keys.includes('theme.dynamicBg')) return
isDynamicBg = setting['theme.dynamicBg']!
if (isDynamicBg) {
if (pic) handleUpdatePic(pic)
} else setBgPic(null)
}
handlePicUpdate()
global.state_event.on('playerMusicInfoChanged', handlePicUpdate)
global.state_event.on('configUpdated', handleConfigUpdate)
}

View File

@ -6,7 +6,7 @@ import initUserApi from './userApi'
import initPlayer from './player' import initPlayer from './player'
import dataInit from './dataInit' import dataInit from './dataInit'
import initSync from './sync' import initSync from './sync'
// import syncSetting from './syncSetting' import initCommonState from './common'
import { setApiSource } from '@/core/apiSource' import { setApiSource } from '@/core/apiSource'
import commonActions from '@/store/common/action' import commonActions from '@/store/common/action'
import settingState from '@/store/setting/state' import settingState from '@/store/setting/state'
@ -55,6 +55,10 @@ export default async() => {
bootLog('Player inited.') bootLog('Player inited.')
await dataInit(setting) await dataInit(setting)
bootLog('Data inited.') bootLog('Data inited.')
await dataInit(setting)
bootLog('Data inited.')
await initCommonState(setting)
bootLog('Common State inited.')
void initSync(setting) void initSync(setting)
bootLog('Sync inited.') bootLog('Sync inited.')

View File

@ -1,28 +0,0 @@
import musicSdk from '@/utils/musicSdk'
import commonActions from '@/store/common/action'
import settingState from '@/store/setting/state'
const handleUpdateSourceNmaes = () => {
const prefix = settingState.setting['common.sourceNameType'] == 'real' ? 'source_' : 'source_alias_'
const sourceNames: Record<LX.OnlineSource | 'all', string> = {
kw: 'kw',
tx: 'tx',
kg: 'kg',
mg: 'mg',
wy: 'wy',
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
all: global.i18n.t(prefix + 'all' as any),
}
for (const { id } of musicSdk.sources) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
sourceNames[id as LX.OnlineSource] = global.i18n.t(prefix + id as any)
}
commonActions.setSourceNames(sourceNames)
}
export default () => {
const handleConfigUpdated = (keys: Array<keyof LX.AppSetting>) => {
if (keys.includes('common.sourceNameType')) handleUpdateSourceNmaes()
}
global.state_event.on('configUpdated', handleConfigUpdated)
}

View File

@ -40,6 +40,10 @@ export class StateEvent extends Event {
this.emit('themeUpdated', theme) this.emit('themeUpdated', theme)
} }
bgPicUpdated(bgPic: string | null) {
this.emit('bgPicUpdated', bgPic)
}
playerMusicInfoChanged(musicInfo: PlayerState['musicInfo']) { playerMusicInfoChanged(musicInfo: PlayerState['musicInfo']) {
this.emit('playerMusicInfoChanged', musicInfo) this.emit('playerMusicInfoChanged', musicInfo)
} }

View File

@ -32,7 +32,7 @@ export default memo(({ componentId }: { componentId: string }) => {
return ( return (
<View style={{ ...styles.container, height: contentHeight }}> <View style={{ ...styles.container, height: contentHeight }}>
<View style={{ ...styles.content, elevation: animated ? 3 : 0 }}> <View style={{ ...styles.content, elevation: animated ? 3 : 0 }}>
<Image url={musicInfo.pic} cache={false} nativeID={NAV_SHEAR_NATIVE_IDS.playDetail_pic} style={{ <Image url={musicInfo.pic} nativeID={NAV_SHEAR_NATIVE_IDS.playDetail_pic} style={{
width: imgWidth, width: imgWidth,
height: imgWidth, height: imgWidth,
borderRadius: 2, borderRadius: 2,

View File

@ -35,7 +35,7 @@ export default ({ componentId }: { componentId: string }) => {
return ( return (
<View style={styles.container}> <View style={styles.container}>
<View style={{ ...styles.content, elevation: animated ? 3 : 0 }}> <View style={{ ...styles.content, elevation: animated ? 3 : 0 }}>
<Image url={musicInfo.pic} cache={false} nativeID={NAV_SHEAR_NATIVE_IDS.playDetail_pic} style={style} /> <Image url={musicInfo.pic} nativeID={NAV_SHEAR_NATIVE_IDS.playDetail_pic} style={style} />
</View> </View>
</View> </View>
) )

View File

@ -29,6 +29,10 @@ export default {
setLastNavActiveId(id: InitState['navActiveId']) { setLastNavActiveId(id: InitState['navActiveId']) {
state.lastNavActiveId = id state.lastNavActiveId = id
}, },
setBgPic(pic: string | null) {
state.bgPic = pic
global.state_event.bgPicUpdated(pic)
},
setSourceNames(names: InitState['sourceNames']) { setSourceNames(names: InitState['sourceNames']) {
state.sourceNames = names state.sourceNames = names
global.state_event.sourceNamesUpdated(names) global.state_event.sourceNamesUpdated(names)

View File

@ -96,6 +96,19 @@ export const useNavActiveId = () => {
return value return value
} }
export const useBgPic = () => {
const [value, update] = useState(state.bgPic)
useEffect(() => {
global.state_event.on('bgPicUpdated', update)
return () => {
global.state_event.off('bgPicUpdated', update)
}
}, [])
return value
}
export const useSourceNames = () => { export const useSourceNames = () => {
const [value, update] = useState(state.sourceNames) const [value, update] = useState(state.sourceNames)

View File

@ -8,6 +8,7 @@ export interface InitState {
navActiveId: NAV_ID_Type navActiveId: NAV_ID_Type
lastNavActiveId: NAV_ID_Type lastNavActiveId: NAV_ID_Type
sourceNames: Record<LX.OnlineSource | 'all', string> sourceNames: Record<LX.OnlineSource | 'all', string>
bgPic: string | null
} }
const initData = {} const initData = {}
@ -19,6 +20,7 @@ const state: InitState = {
navActiveId: 'nav_search', navActiveId: 'nav_search',
lastNavActiveId: 'nav_search', lastNavActiveId: 'nav_search',
sourceNames: initData as InitState['sourceNames'], sourceNames: initData as InitState['sourceNames'],
bgPic: null,
} }