Skip to content

Commit

Permalink
新增动态背景,默认关闭,启用后将使用当前歌曲封面做APP背景
Browse files Browse the repository at this point in the history
  • Loading branch information
lyswhut committed Dec 17, 2023
1 parent 647721b commit 47a1657
Show file tree
Hide file tree
Showing 11 changed files with 126 additions and 23 deletions.
1 change: 1 addition & 0 deletions publish/changeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
- 新增长按收藏列表名自动跳转列表顶部的功能
- 新增实验性的添加本地歌曲到我的收藏支持,与PC端类似,在我的收藏的列表菜单中选择歌曲目录,将添加所选目录下的所有歌曲,目前支持mp3/flac/ogg/wav格式
- 新增歌曲标签编辑功能,允许编辑本地源且文件歌曲存在的歌曲标签信息
- 新增动态背景,默认关闭,启用后将使用当前歌曲封面做APP背景

### 优化

Expand Down
70 changes: 66 additions & 4 deletions src/components/PageContent.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
// import { useEffect, useState } from 'react'
import { View } from 'react-native'
import { Image, View } from 'react-native'
import { useTheme } from '@/store/theme/hook'
import ImageBackground from '@/components/common/ImageBackground'
import { useWindowSize } from '@/utils/hooks'
import { useEffect, useMemo, useState } from 'react'
import playerState from '@/store/player/state'
import settingState from '@/store/setting/state'

interface Props {
children: React.ReactNode
Expand All @@ -12,6 +15,7 @@ interface Props {
export default ({ children }: Props) => {
const theme = useTheme()
const windowSize = useWindowSize()
const [pic, setPic] = useState<string | null | undefined>(settingState.setting['theme.dynamicBg'] ? playerState.musicInfo.pic : null)
// const [wh, setWH] = useState<{ width: number | string, height: number | string }>({ width: '100%', height: Dimensions.get('screen').height })

// 固定宽高度 防止弹窗键盘时大小改变导致背景被缩放
Expand All @@ -32,17 +36,75 @@ export default ({ children }: Props) => {
// }
// console.log('render page content')

return (
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) {
console.log('picUpdated', playerState.musicInfo.pic)
pic = playerState.musicInfo.pic
if (!isDynamicBg) return
void Image.prefetch(playerState.musicInfo.pic).then(() => {
if (pic != playerState.musicInfo.pic || isUnmounted) return
setPic(playerState.musicInfo.pic)
}).catch(() => {
if (isUnmounted) return
setPic(null)
})
} else if (playerState.loadErrorPicUrl == pic) {
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(() => (
<View style={{ flex: 1, overflow: 'hidden' }}>
<ImageBackground
style={{ position: 'absolute', left: 0, top: 0, height: windowSize.height, width: windowSize.width, backgroundColor: theme['c-content-background'] }}
url={theme['bg-image']}
source={theme['bg-image']}
resizeMode="cover"
>
</ImageBackground>
<View style={{ flex: 1, flexDirection: 'column', backgroundColor: theme['c-main-background'] }}>
{children}
</View>
</View>
)
), [children, theme, windowSize.height, windowSize.width])
const picComponent = useMemo(() => (
<View style={{ flex: 1, overflow: 'hidden' }}>
<ImageBackground
style={{ position: 'absolute', left: 0, top: 0, height: windowSize.height, width: windowSize.width, backgroundColor: theme['c-content-background'] }}
source={{ uri: pic! }}
resizeMode="cover"
blurRadius={30}
>
<View style={{ flex: 1, flexDirection: 'column', backgroundColor: theme['c-content-background'], opacity: 0.8 }}></View>
</ImageBackground>
<View style={{ flex: 1, flexDirection: 'column' }}>
{children}
</View>
</View>
), [children, pic, theme, windowSize.height, windowSize.width])

return pic ? picComponent : themeComponent
}
25 changes: 13 additions & 12 deletions src/components/common/ImageBackground.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ import { forwardRef } from 'react'
import {
View,
StyleSheet,
Image,
} from 'react-native'
import type { ViewProps } from 'react-native'
import Image, { type ImageProps } from './Image'
import type { ImageBackgroundProps as _ImageBackgroundProps } from 'react-native'


/**
Expand Down Expand Up @@ -45,32 +45,32 @@ import Image, { type ImageProps } from './Image'

export type ImageBackgroundType = View

export type ImageSourceType = string | number

export interface ImageBackgroundProps extends Omit<ImageProps, 'style'> {
style: ViewProps['style']
imageStyle?: ImageProps['style']
export interface ImageBackgroundProps extends Omit<_ImageBackgroundProps, 'source'> {
source?: _ImageBackgroundProps['source'] | null
}

export default forwardRef<ImageBackgroundType, ImageBackgroundProps>(({
export default forwardRef<View, ImageBackgroundProps>(({
children,
style,
imageStyle,
url,
imageRef,
importantForAccessibility,
source,
...props
}, ref) => {
const flattenedStyle = StyleSheet.flatten(style)
return (
<View
accessibilityIgnoresInvertColors={true}
importantForAccessibility={'no'}
importantForAccessibility={importantForAccessibility}
ref={ref}
style={style}>
{
url == null ? null : (
source == null ? null : (
<Image
{...props}
url={url}
source={source}
importantForAccessibility={importantForAccessibility}
style={[
StyleSheet.absoluteFill,
{
Expand All @@ -86,6 +86,7 @@ export default forwardRef<ImageBackgroundType, ImageBackgroundProps>(({
},
imageStyle,
]}
ref={imageRef}
/>
)
}
Expand Down
1 change: 1 addition & 0 deletions src/config/defaultSetting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ const defaultSetting: LX.AppSetting = {
'theme.lightId': 'green',
'theme.darkId': 'black',
'theme.hideBgDark': false,
'theme.dynamicBg': false,
}


Expand Down
1 change: 1 addition & 0 deletions src/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@
"setting_basic_startup_auto_play": "Play music automatically after startup",
"setting_basic_theme": "Theme",
"setting_basic_theme_auto_theme": "Follow the system light and dark mode to switch themes",
"setting_basic_theme_dynamic_bg": "Use dynamic backgrounds",
"setting_basic_theme_hide_bg_dark": "Hide black theme",
"setting_basic_theme_more_btn_show": "Expand themes",
"setting_dislike_list_input_tip": "song name@artist name\nSong name\n@ singer name",
Expand Down
1 change: 1 addition & 0 deletions src/lang/zh_cn.json
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@
"setting_basic_startup_auto_play": "启动后自动播放音乐",
"setting_basic_theme": "主题颜色",
"setting_basic_theme_auto_theme": "跟随系统亮、暗模式切换主题",
"setting_basic_theme_dynamic_bg": "使用动态背景",
"setting_basic_theme_hide_bg_dark": "隐藏黑色主题背景",
"setting_basic_theme_more_btn_show": "更多主题",
"setting_dislike_list_input_tip": "歌曲名@歌手名\n歌曲名\n@歌手名",
Expand Down
30 changes: 30 additions & 0 deletions src/screens/Home/Views/Setting/settings/Theme/IsDynamicBg.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { memo } from 'react'
import { View } from 'react-native'

import CheckBoxItem from '../../components/CheckBoxItem'
import { createStyle } from '@/utils/tools'
import { useI18n } from '@/lang'
import { updateSetting } from '@/core/common'
import { useSettingValue } from '@/store/setting/hook'

export default memo(() => {
const t = useI18n()
const isDynamicBg = useSettingValue('theme.dynamicBg')
const setIsDynamicBg = (isDynamicBg: boolean) => {
updateSetting({ 'theme.dynamicBg': isDynamicBg })
}


return (
<View style={styles.content}>
<CheckBoxItem check={isDynamicBg} label={t('setting_basic_theme_dynamic_bg')} onChange={setIsDynamicBg} />
</View>
)
})

const styles = createStyle({
content: {
marginTop: 5,
// marginBottom: 15,
},
})
8 changes: 4 additions & 4 deletions src/screens/Home/Views/Setting/settings/Theme/Theme.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { memo, useCallback, useEffect, useMemo, useState } from 'react'
import { View, TouchableOpacity, InteractionManager } from 'react-native'
import { View, TouchableOpacity, InteractionManager, type ImageSourcePropType } from 'react-native'
import { setTheme } from '@/core/theme'
import { useI18n } from '@/lang'
import { useSettingValue } from '@/store/setting/hook'
Expand All @@ -11,7 +11,7 @@ import Text from '@/components/common/Text'
import { createStyle } from '@/utils/tools'
import { scaleSizeH } from '@/utils/pixelRatio'
import { Icon } from '@/components/common/Icon'
import ImageBackground, { type ImageSourceType } from '@/components/common/ImageBackground'
import ImageBackground from '@/components/common/ImageBackground'

const useActive = (id: string) => {
const activeThemeId = useSettingValue('theme.id')
Expand All @@ -24,7 +24,7 @@ const ThemeItem = ({ id, name, color, image, setTheme, showAll }: {
name: string
color: string
showAll: boolean
image?: ImageSourceType
image?: ImageSourcePropType
setTheme: (id: string) => void
}) => {
const theme = useTheme()
Expand All @@ -38,7 +38,7 @@ const ThemeItem = ({ id, name, color, image, setTheme, showAll }: {
image
? <ImageBackground style={{ ...styles.imageContent, width: scaleSizeH(IMAGE_HEIGHT), backgroundColor: color }}
imageStyle={{ borderRadius: 4 }}
url={image} />
source={image} />
: <View style={{ ...styles.imageContent, width: scaleSizeH(IMAGE_HEIGHT), backgroundColor: color }}></View>
}
</View>
Expand Down
2 changes: 2 additions & 0 deletions src/screens/Home/Views/Setting/settings/Theme/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import { memo } from 'react'
import Theme from './Theme'
import IsAutoTheme from './IsAutoTheme'
import IsHideBgDark from './IsHideBgDark'
import IsDynamicBg from './IsDynamicBg'
// import { useI18n } from '@/lang/i18n'

export default memo(() => {
return (
<>
<Theme />
<IsAutoTheme />
<IsDynamicBg />
<IsHideBgDark />
</>
)
Expand Down
5 changes: 5 additions & 0 deletions src/types/app_setting.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ declare global {
*/
'theme.hideBgDark': boolean

/**
* 动态背景
*/
'theme.dynamicBg': boolean

/**
* 启动时自动播放歌曲
*/
Expand Down
5 changes: 2 additions & 3 deletions src/types/theme.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { ImageSourceType } from '@/components/common/ImageBackground'

import type { ImageSourcePropType } from 'react-native'

declare global {
namespace LX {
Expand Down Expand Up @@ -280,7 +279,7 @@ declare global {
'c-list-header-border-bottom': string
'c-content-background': string
'c-border-background': string
'bg-image'?: ImageSourceType
'bg-image'?: ImageSourcePropType
}

interface Theme {
Expand Down

0 comments on commit 47a1657

Please sign in to comment.