Skip to content

Commit

Permalink
- [帖子] 优化了条目媒体块获取数据和渲染
Browse files Browse the repository at this point in the history
  • Loading branch information
czy0729 committed Jul 5, 2023
1 parent ffc7847 commit 3c32cb1
Show file tree
Hide file tree
Showing 10 changed files with 330 additions and 152 deletions.
95 changes: 56 additions & 39 deletions src/components/render-html/a/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
* @Author: czy0729
* @Date: 2022-05-13 05:12:53
* @Last Modified by: czy0729
* @Last Modified time: 2023-03-02 18:36:49
* @Last Modified time: 2023-07-06 07:33:47
*/
import React from 'react'
import { observer } from 'mobx-react'
import React, { useEffect, useState } from 'react'
import { useObserver } from 'mobx-react'
import { rakuenStore } from '@stores'
import { matchBgmLink } from '@utils'
import { Text } from '../../text'
Expand All @@ -16,42 +16,59 @@ function A({ style, attrs = {}, passProps, children, onPress, ...other }: Props)
const { matchLink, acSearch } = rakuenStore.setting
const { href } = attrs
const { route, params = {}, app } = matchBgmLink(href) || {}
const onLinkPress = () => onPress(null, href)

let el: JSX.Element
const args = {
style,
passProps,
params,
href,
onPress,
onLinkPress
}

if (app && route === 'Subject') {
if (acSearch) el = getACSearch(args)
} else if (matchLink) {
if (route === 'Subject') {
el = getSubject(args)
} else if (route === 'Topic') {
if (params?.topicId !== 'group/350677') el = getTopic(args)
} else if (route === 'Mono') {
el = getMono(args)

const [el, setEl] = useState<JSX.Element>(null)
useEffect(() => {
const onLinkPress = () => onPress(null, href)
const args = {
style,
passProps,
params,
href,
onPress,
onLinkPress
}
}
if (el) return el

return (
<Text
style={style || this.styles.a}
selectable
underline
{...other}
onPress={onLinkPress}
>
{filterChildren(children)}
</Text>
)

;(async () => {
if (app && route === 'Subject') {
if (acSearch) setEl(getACSearch(args))
return
}

if (matchLink) {
if (route === 'Subject') {
setEl(await getSubject(args, setEl))
return
}

if (route === 'Topic') {
if (params?.topicId !== 'group/350677') setEl(await getTopic(args))
return
}

if (route === 'Mono') {
setEl(await getMono(args))
}
}
})()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])

return useObserver(() => {
if (el) return el

return (
<Text
style={style}
selectable
underline
{...other}
onPress={() => onPress(null, href)}
>
{filterChildren(children)}
</Text>
)
})
}

export default observer(A)
export default A
78 changes: 78 additions & 0 deletions src/components/render-html/a/subject/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* @Author: czy0729
* @Date: 2023-07-06 07:36:09
* @Last Modified by: czy0729
* @Last Modified time: 2023-07-06 07:45:32
*/
import React from 'react'
import { View } from 'react-native'
import { observer } from 'mobx-react'
import { _, systemStore } from '@stores'
import { HTMLDecode } from '@utils'
import { Touchable } from '../../../touchable'
import { Flex } from '../../../flex'
import { Text } from '../../../text'
import { Iconfont } from '../../../iconfont'
import { Cover } from '../../../cover'
import Rank from '../rank'
import { memoStyles } from '../styles'

function Subject({
text,
href,
image,
name,
name_cn,
rating,
rank,
air_date,
onLinkPress
}) {
const styles = memoStyles()
const top = HTMLDecode(name_cn || name || text || '')
const bottom = HTMLDecode(
text !== top && text !== href ? text : name || name_cn || ''
)
const showScore = !systemStore.setting.hideScore && !!rating?.score
const showBottom = bottom && bottom !== top
return (
<View style={styles.wrap}>
<Touchable animate onPress={onLinkPress}>
<Flex style={styles.body}>
<Cover src={image} size={40} radius={_.radiusXs} />
<View style={_.ml.sm}>
<Text style={styles.top} size={12} bold numberOfLines={2} selectable>
{top}
{!!air_date && air_date !== '0000-00-00' && (
<Text size={10} lineHeight={12} type='sub' bold>
{' '}
{String(air_date).slice(0, 7)}
</Text>
)}
</Text>
{(showScore || showBottom) && (
<Flex style={_.mt.sm}>
{showScore && (
<Flex style={_.mr.xs}>
<Rank value={rank} />
<Iconfont name='md-star' size={10} color={_.colorWarning} />
<Text style={_.ml.xxs} type='sub' size={10} bold>
{rating?.score}
</Text>
{!!rating?.total && (
<Text style={_.ml.xs} type='sub' size={10} bold>
({rating?.total})
</Text>
)}
</Flex>
)}
</Flex>
)}
</View>
</Flex>
</Touchable>
</View>
)
}

export default observer(Subject)
150 changes: 50 additions & 100 deletions src/components/render-html/a/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,32 @@
* @Author: czy0729
* @Date: 2022-05-13 05:32:07
* @Last Modified by: czy0729
* @Last Modified time: 2023-04-11 12:58:33
* @Last Modified time: 2023-07-06 07:43:18
*/
import React from 'react'
import { View } from 'react-native'
import { _, systemStore, subjectStore, rakuenStore, userStore } from '@stores'
import { runAfter, HTMLDecode, navigationReference } from '@utils'
import { IOS, API_COVER, API_AVATAR } from '@constants'
import { ReactNode } from '@types'
import { _, subjectStore, rakuenStore } from '@stores'
import { runAfter, navigationReference } from '@utils'
import { IOS, API_AVATAR } from '@constants'
import { Fn, ReactNode } from '@types'
import { Touchable } from '../../touchable'
import { Flex } from '../../flex'
import { Text } from '../../text'
import { Iconfont } from '../../iconfont'
import { Cover } from '../../cover'
import { Avatar } from '../../avatar'
import { fetchMediaQueue } from '../utils'
import ACText from './ac-text'
import Rank from './rank'
import Subject from './subject'
import { memoStyles } from './styles'

/** @todo 待优化, 安卓Text中一定要过滤非文字节点 */
/** @todo 待优化, 安卓 Text 中一定要过滤非文字节点 */
export function filterChildren(
children: ReactNode | ReactNode[]
): ReactNode | ReactNode[] {
if (IOS) return children

const childrens = React.Children.toArray(children)
const data = React.Children.toArray(children).filter(
const data = childrens.filter(
item =>
// @ts-expect-error
item?.type?.displayName === 'Text'
Expand All @@ -45,7 +44,7 @@ export function filterChildren(
}

/** 获取 html 根节点文字 */
export function getRawChildrenText(passProps) {
export function getRawChildrenText(passProps: any) {
try {
const text = passProps?.rawChildren?.[0]?.data
if (text) return text
Expand Down Expand Up @@ -85,103 +84,54 @@ export function getACSearch({ style, passProps, params, onPress }) {
}

/** 条目媒体块 */
export function getSubject({ passProps, params, href, onLinkPress }) {
const text = getRawChildrenText(passProps)
if (text) {
export async function getSubject(
{ passProps, params, href, onLinkPress },
render?: Fn
) {
try {
const text = getRawChildrenText(passProps)
if (!text) return

const { subjectId } = params
const subject = subjectStore.subject(subjectId)
const {
images = {
common: undefined
},
name,
name_cn,
rating = {
score: undefined,
total: undefined
},
rank,
_loaded
} = subject
let { air_date } = subject
if (!_loaded) {
const subject = await subjectStore.getSubjectSnapshot(subjectId)

// 等待列队请求媒体信息
if (!subject?._loaded) {
setTimeout(() => {
runAfter(() => fetchMediaQueue('subject', subjectId))
fetchMediaQueue('subject', subjectId, async result => {
// 主动渲染组件
if (result && typeof render === 'function') {
render(await getSubject({ passProps, params, href, onLinkPress }))
}
})
}, 2000)
} else {
const { score } = rating
const image = images.common
if (image) {
const styles = memoStyles()
const top = HTMLDecode(name_cn || name || text || '')
const bottom = HTMLDecode(
text !== top && text !== href ? text : name || name_cn || ''
)
const showScore = !systemStore.setting.hideScore && !!score
const showBottom = bottom && bottom !== top
if (air_date === '0000-00-00') air_date = ''
return (
<View style={styles.wrap}>
<Touchable animate onPress={onLinkPress}>
<Flex style={styles.body}>
<Cover
src={API_COVER(subjectId)}
size={48}
radius={_.radiusSm}
headers={userStore.requestHeaders}
/>
<View style={_.ml.sm}>
<Text style={styles.top} size={11} bold numberOfLines={2} selectable>
{top}{' '}
{!!air_date && (
<Text size={9} lineHeight={11} type='sub' bold>
{String(air_date).slice(0, 7)}
</Text>
)}
</Text>
{(showScore || showBottom) && (
<Flex style={_.mt.sm}>
{showScore && (
<Flex style={_.mr.xs}>
<Rank value={rank} />
<Iconfont name='md-star' size={10} color={_.colorWarning} />
<Text style={_.ml.xxs} type='sub' size={10} bold>
{score}
</Text>
{!!rating.total && (
<Text style={_.ml.xs} type='sub' size={10} bold>
({rating.total})
</Text>
)}
</Flex>
)}
{/* {showBottom && (
<Text
style={styles.bottom}
type='sub'
size={10}
bold
numberOfLines={1}
selectable
>
{showScore && '· '}
{bottom}
</Text>
)} */}
</Flex>
)}
</View>
</Flex>
</Touchable>
</View>
)
}
return
}

const { images, name, name_cn, rating, rank, air_date } = subject
const image = images?.common
if (!image) return

return (
<Subject
text={text}
href={href}
image={image}
name={name}
name_cn={name_cn}
rating={rating}
rank={rank}
air_date={air_date}
onLinkPress={onLinkPress}
/>
)
} catch (error) {
console.error('render-html', 'a', 'utils', 'getSubject', error)
}
}

/** 帖子媒体块 */
export function getTopic({ passProps, params, onLinkPress }) {
export async function getTopic({ passProps, params, onLinkPress }) {
const text = getRawChildrenText(passProps)
if (text) {
const { topicId } = params
Expand Down Expand Up @@ -239,7 +189,7 @@ export function getTopic({ passProps, params, onLinkPress }) {
}

/** 人物媒体块 */
export function getMono({ passProps, params, onLinkPress }) {
export async function getMono({ passProps, params, onLinkPress }) {
const text = getRawChildrenText(passProps)
if (text) {
const { monoId } = params
Expand Down
Loading

0 comments on commit 3c32cb1

Please sign in to comment.