优化使用体验

This commit is contained in:
lyswhut 2023-03-26 18:33:40 +08:00
parent 309d426aa8
commit 31a8b5c67e
21 changed files with 381 additions and 40 deletions

View File

@ -37,7 +37,7 @@ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
# your application. You should enable this flag either if you want
# to write custom TurboModules/Fabric components OR use libraries that
# are providing them.
newArchEnabled=false
newArchEnabled=true
# Use this property to enable or disable the Hermes JS engine.
# If set to false, you will be using JSC instead.

View File

@ -1,3 +1,8 @@
### 修复
### 优化
- 修复在线列表翻页问题
- 竖屏下的首页允许滑动切换页面恢复v0.x.x的切页操作
- 优化更新语言、主题设置时的流畅度
### 其他
- 启用新架构

View File

@ -24,6 +24,7 @@ export interface ListProps {
onPlayList?: (index: number) => void
progressViewOffset?: number
ListHeaderComponent?: FlatListType['ListEmptyComponent']
checkHomePagerIdle: boolean
}
export interface ListType {
setList: (list: LX.Music.MusicInfoOnline[], showSource?: boolean) => void
@ -46,6 +47,7 @@ const List = forwardRef<ListType, ListProps>(({
onPlayList,
progressViewOffset,
ListHeaderComponent,
checkHomePagerIdle,
}, ref) => {
// const t = useI18n()
const theme = useTheme()
@ -139,6 +141,8 @@ const List = forwardRef<ListType, ListProps>(({
}
const handlePress = (item: LX.Music.MusicInfoOnline, index: number) => {
requestAnimationFrame(() => {
if (checkHomePagerIdle && !global.lx.homePagerIdle) return
if (isMultiSelectModeRef.current) {
handleSelect(item, index)
} else {
@ -149,6 +153,7 @@ const List = forwardRef<ListType, ListProps>(({
handlePlay(currentList[index])
}
}
})
}
const handleLongPress = (item: LX.Music.MusicInfoOnline, index: number) => {

View File

@ -15,6 +15,7 @@ export interface OnlineListProps {
onPlayList?: ListProps['onPlayList']
progressViewOffset?: ListProps['progressViewOffset']
ListHeaderComponent?: ListProps['ListHeaderComponent']
checkHomePagerIdle?: boolean
}
export interface OnlineListType {
setList: (list: LX.Music.MusicInfoOnline[], showSource?: boolean) => void
@ -27,6 +28,7 @@ export default forwardRef<OnlineListType, OnlineListProps>(({
onPlayList,
progressViewOffset,
ListHeaderComponent,
checkHomePagerIdle = false,
}, ref) => {
const listRef = useRef<ListType>(null)
const multipleModeBarRef = useRef<MultipleModeBarType>(null)
@ -86,6 +88,7 @@ export default forwardRef<OnlineListType, OnlineListProps>(({
onPlayList={onPlayList}
progressViewOffset={progressViewOffset}
ListHeaderComponent={ListHeaderComponent}
checkHomePagerIdle={checkHomePagerIdle}
/>
<MultipleModeBar
ref={multipleModeBarRef}

View File

@ -1,4 +1,4 @@
import React, { forwardRef, useCallback, useRef, useState } from 'react'
import React, { forwardRef, useCallback, useImperativeHandle, useRef, useState } from 'react'
import { DrawerLayoutAndroid, type DrawerLayoutAndroidProps, View, type LayoutChangeEvent } from 'react-native'
// import { getWindowSise } from '@/utils/tools'
import { usePageVisible } from '@/store/common/hook'
@ -10,18 +10,43 @@ interface Props extends DrawerLayoutAndroidProps {
widthPercentageMax?: number
}
const DrawerLayoutFixed = forwardRef<DrawerLayoutAndroid, Props>(({ visibleNavNames, widthPercentage, widthPercentageMax, children, ...props }, ref) => {
export interface DrawerLayoutFixedType {
openDrawer: () => void
closeDrawer: () => void
fixWidth: () => void
}
const DrawerLayoutFixed = forwardRef<DrawerLayoutFixedType, Props>(({ visibleNavNames, widthPercentage, widthPercentageMax, children, ...props }, ref) => {
const drawerLayoutRef = useRef<DrawerLayoutAndroid>(null)
const [w, setW] = useState<number | string>('100%')
const [drawerWidth, setDrawerWidth] = useState(0)
const changedRef = useRef({ width: 0, changed: false })
// 修复 DrawerLayoutAndroid 在导航到其他屏幕再返回后无法打开的问题
usePageVisible(visibleNavNames, useCallback((visible) => {
if (!visible || !changedRef.current.width) return
const fixDrawerWidth = useCallback(() => {
if (!changedRef.current.width) return
changedRef.current.changed = true
// console.log('usePageVisible', visible, changedRef.current.width)
setW(changedRef.current.width - 1)
}, []))
}, [])
// 修复 DrawerLayoutAndroid 在导航到其他屏幕再返回后无法打开的问题
usePageVisible(visibleNavNames, useCallback((visible) => {
if (!visible || !changedRef.current.width) return
fixDrawerWidth()
}, [fixDrawerWidth]))
useImperativeHandle(ref, () => ({
openDrawer() {
drawerLayoutRef.current?.openDrawer()
},
closeDrawer() {
drawerLayoutRef.current?.closeDrawer()
},
fixWidth() {
fixDrawerWidth()
},
}), [fixDrawerWidth])
const handleLayout = useCallback((e: LayoutChangeEvent) => {
// console.log('handleLayout', e.nativeEvent.layout.width, changedRef.current.width)
@ -51,7 +76,7 @@ const DrawerLayoutFixed = forwardRef<DrawerLayoutAndroid, Props>(({ visibleNavNa
style={{ width: w, flex: 1 }}
>
<DrawerLayoutAndroid
ref={ref}
ref={drawerLayoutRef}
keyboardDismissMode="on-drag"
drawerWidth={drawerWidth}
{...props}

View File

@ -55,6 +55,8 @@ global.lx = {
settingActiveId: 'basic',
homePagerIdle: true,
// syncKeyInfo: initValue as LX.Sync.KeyInfo,
// windowInfo: {

View File

@ -40,7 +40,10 @@ export const updateSetting = (setting: Partial<LX.AppSetting>) => {
export const setLanguage = (locale: Parameters<typeof applyLanguage>[0]) => {
updateSetting({ 'common.langId': locale })
global.state_event.languageChanged(locale)
requestAnimationFrame(() => {
applyLanguage(locale)
})
}

View File

@ -1,6 +1,6 @@
import { setNavActiveId } from '@/core/common'
import Event from './Event'
import commonState from '@/store/common/state'
import commonState, { type InitState as CommonState } from '@/store/common/state'
import { type Source as SonglistSource } from '@/store/songlist/state'
import { type SearchType } from '@/store/search/state'
@ -162,6 +162,10 @@ export class AppEvent extends Event {
this.emit('changeMenuVisible', visible)
}
homeNavPagerChanged(id: CommonState['navActiveId']) {
this.emit('homeNavPagerChanged', id)
}
/**
*
* @param type

View File

@ -3,6 +3,7 @@ import type { InitState as CommonState } from '@/store/common/state'
import type { InitState as ListState } from '@/store/list/state'
import type { InitState as PlayerState } from '@/store/player/state'
import type { InitState as VersionState } from '@/store/version/state'
import { type I18n } from '@/lang'
// {
@ -19,6 +20,10 @@ export class StateEvent extends Event {
this.emit('configUpdated', keys, setting)
}
languageChanged(locale: I18n['locale']) {
this.emit('languageChanged', locale)
}
fontSizeUpdated(size: number) {
this.emit('fontSizeUpdated', size)
}

View File

@ -40,7 +40,7 @@ const hookTools = {
}
const useI18n = () => {
const [locale, updateLocale] = useState(i18n.locale)
const [locale, updateLocale] = useState(i18n?.locale ?? 'en_us')
// console.log('hook run')
useEffect(() => {
const hook: Hook = (locale) => {

View File

@ -4,7 +4,7 @@ import Aside from './Aside'
import PlayerBar from '../components/PlayerBar'
import StatusBar from '@/components/common/StatusBar'
import Header from './Header'
import Main from '../components/Main'
import Main from './Main'
import { createStyle } from '@/utils/tools'
const styles = createStyle({

View File

@ -1,18 +1,17 @@
import React, { useEffect, useRef } from 'react'
import { type DrawerLayoutAndroid } from 'react-native'
// import { getWindowSise, onDimensionChange } from '@/utils/tools'
import DrawerNav from './DrawerNav'
import Header from './Header'
import Main from '../components/Main'
import Main from './Main'
import { useSettingValue } from '@/store/setting/hook'
import { COMPONENT_IDS } from '@/config/constant'
import DrawerLayoutFixed from '@/components/common/DrawerLayoutFixed'
import DrawerLayoutFixed, { type DrawerLayoutFixedType } from '@/components/common/DrawerLayoutFixed'
import { scaleSizeW } from '@/utils/pixelRatio'
const MAX_WIDTH = scaleSizeW(300)
const Content = () => {
const drawer = useRef<DrawerLayoutAndroid>(null)
const drawer = useRef<DrawerLayoutFixedType>(null)
const drawerLayoutPosition = useSettingValue('common.drawerLayoutPosition')
useEffect(() => {

View File

@ -0,0 +1,262 @@
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { View } from 'react-native'
import Search from '../Views/Search'
import SongList from '../Views/SongList'
import Mylist from '../Views/Mylist'
import Leaderboard from '../Views/Leaderboard'
import Setting from '../Views/Setting'
import commonState, { type InitState as CommonState } from '@/store/common/state'
import { createStyle } from '@/utils/tools'
import PagerView, { type PageScrollStateChangedNativeEvent, type PagerViewOnPageSelectedEvent } from 'react-native-pager-view'
import { setNavActiveId } from '@/core/common'
const SearchPage = () => {
const [visible, setVisible] = useState(commonState.navActiveId == 'nav_search')
const component = useMemo(() => <Search />, [])
useEffect(() => {
const handleNavIdUpdate = (id: CommonState['navActiveId']) => {
if (id == 'nav_search') setVisible(true)
}
const handleHide = () => {
setVisible(false)
}
global.state_event.on('navActiveIdUpdated', handleNavIdUpdate)
global.state_event.on('themeUpdated', handleHide)
global.state_event.on('languageChanged', handleHide)
return () => {
global.state_event.off('navActiveIdUpdated', handleNavIdUpdate)
global.state_event.off('themeUpdated', handleHide)
global.state_event.off('languageChanged', handleHide)
}
}, [])
return visible ? component : null
}
const SongListPage = () => {
const [visible, setVisible] = useState(commonState.navActiveId == 'nav_songlist')
const component = useMemo(() => <SongList />, [])
useEffect(() => {
const handleNavIdUpdate = (id: CommonState['navActiveId']) => {
if (id == 'nav_songlist') setVisible(true)
}
const handleHide = () => {
setVisible(false)
}
global.state_event.on('navActiveIdUpdated', handleNavIdUpdate)
global.state_event.on('themeUpdated', handleHide)
global.state_event.on('languageChanged', handleHide)
return () => {
global.state_event.off('navActiveIdUpdated', handleNavIdUpdate)
global.state_event.off('themeUpdated', handleHide)
global.state_event.off('languageChanged', handleHide)
}
}, [])
return visible ? component : null
// return activeId == 1 || activeId == 0 ? SongList : null
}
const LeaderboardPage = () => {
const [visible, setVisible] = useState(commonState.navActiveId == 'nav_top')
const component = useMemo(() => <Leaderboard />, [])
useEffect(() => {
const handleNavIdUpdate = (id: CommonState['navActiveId']) => {
if (id == 'nav_top') setVisible(true)
}
const handleHide = () => {
setVisible(false)
}
global.state_event.on('navActiveIdUpdated', handleNavIdUpdate)
global.state_event.on('themeUpdated', handleHide)
global.state_event.on('languageChanged', handleHide)
return () => {
global.state_event.off('navActiveIdUpdated', handleNavIdUpdate)
global.state_event.off('themeUpdated', handleHide)
global.state_event.off('languageChanged', handleHide)
}
}, [])
return visible ? component : null
}
const MylistPage = () => {
const [visible, setVisible] = useState(commonState.navActiveId == 'nav_love')
const component = useMemo(() => <Mylist />, [])
useEffect(() => {
const handleNavIdUpdate = (id: CommonState['navActiveId']) => {
if (id == 'nav_love') setVisible(true)
}
const handleHide = () => {
setVisible(false)
}
global.state_event.on('navActiveIdUpdated', handleNavIdUpdate)
global.state_event.on('themeUpdated', handleHide)
global.state_event.on('languageChanged', handleHide)
return () => {
global.state_event.off('navActiveIdUpdated', handleNavIdUpdate)
global.state_event.off('themeUpdated', handleHide)
global.state_event.off('languageChanged', handleHide)
}
}, [])
return visible ? component : null
}
const SettingPage = () => {
const [visible, setVisible] = useState(commonState.navActiveId == 'nav_setting')
const component = useMemo(() => <Setting />, [])
useEffect(() => {
const handleNavIdUpdate = (id: CommonState['navActiveId']) => {
if (id == 'nav_setting') setVisible(true)
}
global.state_event.on('navActiveIdUpdated', handleNavIdUpdate)
return () => {
global.state_event.off('navActiveIdUpdated', handleNavIdUpdate)
}
}, [])
return visible ? component : null
}
const viewMap = {
nav_search: 0,
nav_songlist: 1,
nav_top: 2,
nav_love: 3,
nav_setting: 4,
}
const indexMap = [
'nav_search',
'nav_songlist',
'nav_top',
'nav_love',
'nav_setting',
] as const
const Main = () => {
const pagerViewRef = useRef<PagerView>(null)
let activeIndexRef = useRef(viewMap[commonState.navActiveId])
// const isScrollingRef = useRef(false)
// const scrollPositionRef = useRef(-1)
// const handlePageScroll = useCallback(({ nativeEvent }) => {
// console.log(nativeEvent.offset, activeIndexRef.current)
// // if (activeIndexRef.current == -1) return
// // if (nativeEvent.offset == 0) {
// // isScrollingRef.current = false
// // const index = nativeEvent.position
// // if (activeIndexRef.current == index) return
// // activeIndexRef.current = index
// // setNavActiveIndex(index)
// // } else if (!isScrollingRef.current) {
// // isScrollingRef.current = true
// // }
// }, [setNavActiveIndex])
const onPageSelected = useCallback(({ nativeEvent }: PagerViewOnPageSelectedEvent) => {
// console.log(nativeEvent)
activeIndexRef.current = nativeEvent.position
if (activeIndexRef.current != viewMap[commonState.navActiveId]) {
setNavActiveId(indexMap[activeIndexRef.current])
}
global.app_event.homeNavPagerChanged(indexMap[activeIndexRef.current])
}, [])
const onPageScrollStateChanged = useCallback(({ nativeEvent }: PageScrollStateChangedNativeEvent) => {
// console.log(nativeEvent)
const idle = nativeEvent.pageScrollState == 'idle'
if (global.lx.homePagerIdle != idle) global.lx.homePagerIdle = idle
// if (nativeEvent.pageScrollState != 'idle') return
// if (scrollPositionRef.current != commonState.navActiveIndex) {
// setNavActiveIndex(scrollPositionRef.current)
// }
// if (activeIndexRef.current == -1) return
// if (nativeEvent.offset == 0) {
// isScrollingRef.current = false
// const index = nativeEvent.position
// if (activeIndexRef.current == index) return
// activeIndexRef.current = index
// setNavActiveIndex(index)
// } else if (!isScrollingRef.current) {
// isScrollingRef.current = true
// }
}, [])
useEffect(() => {
const handleUpdate = (id: CommonState['navActiveId']) => {
const index = viewMap[id]
if (activeIndexRef.current == index) return
activeIndexRef.current = index
pagerViewRef.current?.setPageWithoutAnimation(index)
}
// window.requestAnimationFrame(() => pagerViewRef.current && pagerViewRef.current.setPage(activeIndexRef.current))
global.state_event.on('navActiveIdUpdated', handleUpdate)
return () => {
global.state_event.off('navActiveIdUpdated', handleUpdate)
}
}, [])
const component = useMemo(() => (
<PagerView ref={pagerViewRef}
initialPage={activeIndexRef.current}
// onPageScroll={handlePageScroll}
offscreenPageLimit={1}
onPageSelected={onPageSelected}
onPageScrollStateChanged={onPageScrollStateChanged}
style={styles.pagerView}
>
<View collapsable={false} key="nav_search" style={styles.pageStyle}>
<SearchPage />
</View>
<View collapsable={false} key="nav_songlist" style={styles.pageStyle}>
<SongListPage />
</View>
<View collapsable={false} key="nav_top" style={styles.pageStyle}>
<LeaderboardPage />
</View>
<View collapsable={false} key="nav_love" style={styles.pageStyle}>
<MylistPage />
</View>
<View collapsable={false} key="nav_setting" style={styles.pageStyle}>
<SettingPage />
</View>
{/* <View collapsable={false} key="nav_search" style={styles.pageStyle}>
<Search />
</View>
<View collapsable={false} key="nav_songlist" style={styles.pageStyle}>
<SongList />
</View>
<View collapsable={false} key="nav_top" style={styles.pageStyle}>
<Leaderboard />
</View>
<View collapsable={false} key="nav_love" style={styles.pageStyle}>
<Mylist />
</View>
<View collapsable={false} key="nav_setting" style={styles.pageStyle}>
<Setting />
</View> */}
</PagerView>
), [onPageScrollStateChanged, onPageSelected])
return component
}
const styles = createStyle({
pagerView: {
flex: 1,
overflow: 'hidden',
},
pageStyle: {
// alignItems: 'center',
// padding: 20,
},
})
export default Main

View File

@ -89,6 +89,7 @@ export default forwardRef<MusicListType, {}>((props, ref) => {
onPlayList={handlePlayList}
onRefresh={handleRefresh}
onLoadMore={handleLoadMore}
checkHomePagerIdle
/>
})

View File

@ -212,11 +212,16 @@ const List = forwardRef<ListType, ListProps>(({ onShowMenu, onMuiltSelectMode, o
}
const handlePress = (item: LX.Music.MusicInfo, index: number) => {
// console.log(global.lx.homePagerIdle)
requestAnimationFrame(() => {
// console.log(global.lx.homePagerIdle)
if (!global.lx.homePagerIdle) return
if (isMultiSelectModeRef.current) {
handleSelect(item, index)
} else {
handlePlay(index)
}
})
}
const handleLongPress = (item: LX.Music.MusicInfo, index: number) => {

View File

@ -1,21 +1,24 @@
import React, { useEffect, useRef } from 'react'
import { type DrawerLayoutAndroid } from 'react-native'
import settingState from '@/store/setting/state'
import MusicList from './MusicList'
import MyList from './MyList'
import { useTheme } from '@/store/theme/hook'
import DrawerLayoutFixed from '@/components/common/DrawerLayoutFixed'
import DrawerLayoutFixed, { type DrawerLayoutFixedType } from '@/components/common/DrawerLayoutFixed'
import { COMPONENT_IDS } from '@/config/constant'
import { scaleSizeW } from '@/utils/pixelRatio'
import type { InitState as CommonState } from '@/store/common/state'
const MAX_WIDTH = scaleSizeW(400)
export default () => {
const drawer = useRef<DrawerLayoutAndroid>(null)
const drawer = useRef<DrawerLayoutFixedType>(null)
const theme = useTheme()
// const [width, setWidth] = useState(0)
useEffect(() => {
const handleFixDrawer = (id: CommonState['navActiveId']) => {
if (id == 'nav_love') drawer.current?.fixWidth()
}
const changeVisible = (visible: boolean) => {
if (visible) {
requestAnimationFrame(() => {
@ -25,8 +28,10 @@ export default () => {
drawer.current?.closeDrawer()
}
}
// setWidth(getWindowSise().width * 0.82)
global.app_event.on('homeNavPagerChanged', handleFixDrawer)
global.app_event.on('changeLoveListVisible', changeVisible)
// 就放旋转屏幕后的宽度没有更新的问题
@ -38,6 +43,7 @@ export default () => {
// })
return () => {
global.app_event.off('homeNavPagerChanged', handleFixDrawer)
global.app_event.off('changeLoveListVisible', changeVisible)
// changeEvent.remove()
}

View File

@ -82,6 +82,7 @@ export default forwardRef<MusicListType, {}>((props, ref) => {
ref={listRef}
onRefresh={handleRefresh}
onLoadMore={handleLoadMore}
checkHomePagerIdle
/>
})

View File

@ -1,20 +1,23 @@
import React, { useEffect, useRef } from 'react'
import { type DrawerLayoutAndroid } from 'react-native'
import settingState from '@/store/setting/state'
import Content from './Content'
import TagList from './TagList'
import { useTheme } from '@/store/theme/hook'
import DrawerLayoutFixed from '@/components/common/DrawerLayoutFixed'
import DrawerLayoutFixed, { type DrawerLayoutFixedType } from '@/components/common/DrawerLayoutFixed'
import { COMPONENT_IDS } from '@/config/constant'
import { scaleSizeW } from '@/utils/pixelRatio'
import type { InitState as CommonState } from '@/store/common/state'
const MAX_WIDTH = scaleSizeW(560)
export default () => {
const drawer = useRef<DrawerLayoutAndroid>(null)
const drawer = useRef<DrawerLayoutFixedType>(null)
const theme = useTheme()
useEffect(() => {
const handleFixDrawer = (id: CommonState['navActiveId']) => {
if (id == 'nav_songlist') drawer.current?.fixWidth()
}
const handleShow = () => {
requestAnimationFrame(() => {
drawer.current?.openDrawer()
@ -24,10 +27,12 @@ export default () => {
drawer.current?.closeDrawer()
}
global.app_event.on('homeNavPagerChanged', handleFixDrawer)
global.app_event.on('showSonglistTagList', handleShow)
global.app_event.on('hideSonglistTagList', handleHide)
return () => {
global.app_event.off('homeNavPagerChanged', handleFixDrawer)
global.app_event.off('showSonglistTagList', handleShow)
global.app_event.off('hideSonglistTagList', handleHide)
}

View File

@ -9,9 +9,14 @@ export default memo(({ children }: {
const [theme, setTheme] = useState(themeState.theme)
useEffect(() => {
global.state_event.on('themeUpdated', setTheme)
const handleUpdateTheme = (theme: LX.ActiveTheme) => {
requestAnimationFrame(() => {
setTheme(theme)
})
}
global.state_event.on('themeUpdated', handleUpdateTheme)
return () => {
global.state_event.off('themeUpdated', setTheme)
global.state_event.off('themeUpdated', handleUpdateTheme)
}
}, [])

5
src/types/app.d.ts vendored
View File

@ -38,6 +38,11 @@ interface GlobalData {
settingActiveId: SettingScreenIds
/**
*
*/
homePagerIdle: boolean
// windowInfo: {
// screenW: number
// screenH: number