This commit is contained in:
Zhiyuan Zheng 2020-12-18 00:00:45 +01:00
parent b679b56a0e
commit 7be25ae516
No known key found for this signature in database
GPG Key ID: 078A93AB607D85E0
13 changed files with 144 additions and 78 deletions

View File

@ -74,7 +74,7 @@ const renderNode = ({
)
}
} else {
const domain = href.split(new RegExp(/:\/\/(.*?)\//))
const domain = href.split(new RegExp(/:\/\/(.[^\/]+)/))
return (
<Text
key={index}

View File

@ -19,7 +19,6 @@ export interface Props {
toot?: Mastodon.Status
account?: string
disableRefresh?: boolean
scrollEnabled?: boolean
}
const Timeline: React.FC<Props> = ({
@ -28,8 +27,7 @@ const Timeline: React.FC<Props> = ({
list,
toot,
account,
disableRefresh = false,
scrollEnabled = true
disableRefresh = false
}) => {
setFocusHandler(handleFocus => {
const handleAppStateChange = (appState: string) => {
@ -160,7 +158,6 @@ const Timeline: React.FC<Props> = ({
renderItem={flRenderItem}
onEndReached={flOnEndReach}
keyExtractor={flKeyExtrator}
scrollEnabled={scrollEnabled} // For timeline in Account view
ListFooterComponent={flFooter}
ListEmptyComponent={flItemEmptyComponent}
ItemSeparatorComponent={flItemSeparatorComponent}

View File

@ -44,7 +44,7 @@ const TimelineDefault: React.FC<Props> = ({
const tootOnPress = useCallback(
() =>
!isRemotePublic &&
navigation.navigate('Screen-Shared-Toot', {
navigation.push('Screen-Shared-Toot', {
toot: actualStatus
}),
[]

View File

@ -1,7 +1,7 @@
import React, { useCallback } from 'react'
import { Image, Pressable, StyleSheet } from 'react-native'
import { useNavigation } from '@react-navigation/native'
import { StyleConstants } from '@utils/styles/constants'
import { useNavigation } from '@react-navigation/native'
export interface Props {
queryKey?: App.QueryKey
@ -13,7 +13,7 @@ const TimelineAvatar: React.FC<Props> = ({ queryKey, account }) => {
// Need to fix go back root
const onPress = useCallback(() => {
queryKey &&
navigation.navigate('Screen-Shared-Account', {
navigation.push('Screen-Shared-Account', {
id: account.id
})
}, [])

View File

@ -1,5 +1,5 @@
import React, { useRef } from 'react'
import { ScrollView } from 'react-native'
import React, { useRef, useState } from 'react'
import { Animated, ScrollView } from 'react-native'
import { useSelector } from 'react-redux'
import { getLocalUrl } from '@utils/slices/instancesSlice'
@ -10,6 +10,8 @@ import Collections from '@screens/Me/Root/Collections'
import Settings from '@screens/Me/Root/Settings'
import Logout from '@screens/Me/Root/Logout'
import { useScrollToTop } from '@react-navigation/native'
import { AccountState } from '../Shared/Account'
import AccountNav from '../Shared/Account/Nav'
const ScreenMeRoot: React.FC = () => {
const localRegistered = useSelector(getLocalUrl)
@ -17,13 +19,34 @@ const ScreenMeRoot: React.FC = () => {
const scrollRef = useRef<ScrollView>(null)
useScrollToTop(scrollRef)
const scrollY = useRef(new Animated.Value(0)).current
const [data, setData] = useState<Mastodon.Account>()
return (
<ScrollView ref={scrollRef} keyboardShouldPersistTaps='handled'>
{localRegistered ? <MyInfo /> : <Login />}
{localRegistered && <Collections />}
<Settings />
{localRegistered && <Logout />}
</ScrollView>
<>
{localRegistered && data ? (
<AccountNav
accountState={{ headerRatio: 0.4 } as AccountState}
scrollY={scrollY}
account={data}
/>
) : null}
<ScrollView
ref={scrollRef}
keyboardShouldPersistTaps='handled'
bounces={false}
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { y: scrollY } } }],
{ useNativeDriver: false }
)}
scrollEventThrottle={8}
>
{localRegistered ? <MyInfo setData={setData} /> : <Login />}
{localRegistered && <Collections />}
<Settings />
{localRegistered && <Logout />}
</ScrollView>
</>
)
}

View File

@ -1,4 +1,4 @@
import React from 'react'
import React, { useEffect } from 'react'
import { useQuery } from 'react-query'
import { accountFetch } from '@utils/fetches/accountFetch'
@ -6,14 +6,28 @@ import AccountHeader from '@screens/Shared/Account/Header'
import AccountInformation from '@screens/Shared/Account/Information'
import { useSelector } from 'react-redux'
import { getLocalAccountId } from '@utils/slices/instancesSlice'
import { AccountState } from '@root/screens/Shared/Account'
const MyInfo: React.FC = () => {
export interface Props {
setData: React.Dispatch<React.SetStateAction<Mastodon.Account | undefined>>
}
const MyInfo: React.FC<Props> = ({ setData }) => {
const localAccountId = useSelector(getLocalAccountId)
const { data } = useQuery(['Account', { id: localAccountId }], accountFetch)
useEffect(() => {
if (data) {
setData(data)
}
}, [data])
return (
<>
<AccountHeader uri={data?.header} limitHeight />
<AccountHeader
accountState={{ headerRatio: 0.4 } as AccountState}
account={data}
limitHeight
/>
<AccountInformation account={data} />
</>
)

View File

@ -1,4 +1,4 @@
import React, { createContext, Dispatch, useReducer, useRef } from 'react'
import React, { useReducer, useRef } from 'react'
import { Animated, ScrollView } from 'react-native'
// import * as relationshipsSlice from 'src/stacks/common/relationshipsSlice'
@ -62,11 +62,6 @@ const accountReducer = (
throw new Error('Unexpected action')
}
}
type ContextType = {
accountState: AccountState
accountDispatch: Dispatch<AccountAction>
}
export const AccountContext = createContext<ContextType>({} as ContextType)
const ScreenSharedAccount: React.FC<Props> = ({
route: {
@ -83,23 +78,38 @@ const ScreenSharedAccount: React.FC<Props> = ({
)
return (
<AccountContext.Provider value={{ accountState, accountDispatch }}>
<AccountNav scrollY={scrollY} account={data} />
<AccountSegmentedControl scrollY={scrollY} />
<>
<AccountNav
accountState={accountState}
scrollY={scrollY}
account={data}
/>
<AccountSegmentedControl
accountState={accountState}
accountDispatch={accountDispatch}
scrollY={scrollY}
/>
<ScrollView
contentContainerStyle={{ zIndex: 99 }}
bounces={false}
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { y: scrollY } } }],
{ useNativeDriver: false }
)}
scrollEventThrottle={16}
scrollEventThrottle={8}
>
<AccountHeader uri={data?.header} />
<AccountInformation account={data} />
<AccountToots id={id} />
<AccountHeader
accountState={accountState}
accountDispatch={accountDispatch}
account={data}
/>
<AccountInformation accountDispatch={accountDispatch} account={data} />
<AccountToots
accountState={accountState}
accountDispatch={accountDispatch}
id={id}
/>
</ScrollView>
</AccountContext.Provider>
</>
)
}

View File

@ -1,25 +1,39 @@
import React, { useContext, useEffect, useRef } from 'react'
import React, { Dispatch, useEffect, useRef, useState } from 'react'
import { Animated, Dimensions, Image, StyleSheet } from 'react-native'
import { AccountContext } from '../Account'
import { AccountAction, AccountState } from '../Account'
export interface Props {
uri?: Mastodon.Account['header']
accountState: AccountState
accountDispatch?: Dispatch<AccountAction>
account?: Mastodon.Account
limitHeight?: boolean
}
const AccountHeader: React.FC<Props> = ({ uri, limitHeight = false }) => {
const { accountState, accountDispatch } = useContext(AccountContext)
const AccountHeader: React.FC<Props> = ({
accountState,
accountDispatch,
account,
limitHeight = false
}) => {
const [imageShown, setImageShown] = useState(true)
useEffect(() => {
if (uri) {
if (uri.includes('/headers/original/missing.png')) {
if (account?.header) {
if (account.header.includes('/headers/original/missing.png')) {
animateNewSize(accountState.headerRatio)
} else {
if (account.header !== account.header_static) {
setImageShown(false)
}
Image.getSize(
uri,
account.header,
(width, height) => {
if (!limitHeight) {
accountDispatch({ type: 'headerRatio', payload: height / width })
accountDispatch &&
accountDispatch({
type: 'headerRatio',
payload: height / width
})
}
animateNewSize(
limitHeight ? accountState.headerRatio : height / width
@ -30,10 +44,12 @@ const AccountHeader: React.FC<Props> = ({ uri, limitHeight = false }) => {
}
)
}
} else {
animateNewSize(accountState.headerRatio)
}
}, [uri])
}, [account])
const theImage = imageShown ? (
<Image source={{ uri: account?.header }} style={styles.image} />
) : null
const windowWidth = Dimensions.get('window').width
const imageHeight = useRef(
@ -44,12 +60,16 @@ const AccountHeader: React.FC<Props> = ({ uri, limitHeight = false }) => {
toValue: windowWidth * ratio,
duration: 350,
useNativeDriver: false
}).start()
}).start(({ finished }) => {
if (finished) {
setImageShown(true)
}
})
}
return (
<Animated.View style={[styles.imageContainer, { height: imageHeight }]}>
<Image source={{ uri: uri }} style={styles.image} />
{theImage}
</Animated.View>
)
}

View File

@ -1,4 +1,4 @@
import React, { createRef, useContext, useEffect, useState } from 'react'
import React, { createRef, Dispatch, useEffect, useState } from 'react'
import { Animated, Image, StyleSheet, Text, View } from 'react-native'
import { createShimmerPlaceholder } from 'react-native-shimmer-placeholder'
import { Feather } from '@expo/vector-icons'
@ -9,14 +9,14 @@ import { StyleConstants } from '@utils/styles/constants'
import { useTranslation } from 'react-i18next'
import Emojis from '@components/Timelines/Timeline/Shared/Emojis'
import { LinearGradient } from 'expo-linear-gradient'
import { AccountContext } from '../Account'
import { AccountAction } from '../Account'
export interface Props {
accountDispatch?: Dispatch<AccountAction>
account: Mastodon.Account | undefined
}
const AccountInformation: React.FC<Props> = ({ account }) => {
const { accountDispatch } = useContext(AccountContext)
const AccountInformation: React.FC<Props> = ({ accountDispatch, account }) => {
const { t } = useTranslation('sharedAccount')
const { theme } = useTheme()
const [avatarLoaded, setAvatarLoaded] = useState(false)
@ -48,6 +48,7 @@ const AccountInformation: React.FC<Props> = ({ account }) => {
<View
style={styles.information}
onLayout={({ nativeEvent }) =>
accountDispatch &&
accountDispatch({
type: 'informationLayout',
payload: {

View File

@ -1,18 +1,18 @@
import Emojis from '@root/components/Timelines/Timeline/Shared/Emojis'
import { StyleConstants } from '@root/utils/styles/constants'
import { useTheme } from '@root/utils/styles/ThemeManager'
import React, { useContext } from 'react'
import React from 'react'
import { Animated, Dimensions, StyleSheet, Text, View } from 'react-native'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { AccountContext } from '../Account'
import { AccountState } from '../Account'
export interface Props {
accountState: AccountState
scrollY: Animated.Value
account: Mastodon.Account | undefined
}
const AccountNav: React.FC<Props> = ({ scrollY, account }) => {
const { accountState } = useContext(AccountContext)
const AccountNav: React.FC<Props> = ({ accountState, scrollY, account }) => {
const { theme } = useTheme()
const headerHeight = useSafeAreaInsets().top + 44

View File

@ -1,18 +1,23 @@
import SegmentedControl from '@react-native-community/segmented-control'
import { StyleConstants } from '@root/utils/styles/constants'
import { useTheme } from '@root/utils/styles/ThemeManager'
import React, { useContext } from 'react'
import React, { Dispatch } from 'react'
import { useTranslation } from 'react-i18next'
import { Animated, StyleSheet } from 'react-native'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { AccountContext } from '../Account'
import { AccountAction, AccountState } from '../Account'
export interface Props {
accountState: AccountState
accountDispatch: Dispatch<AccountAction>
scrollY: Animated.Value
}
const AccountSegmentedControl: React.FC<Props> = ({ scrollY }) => {
const { accountState, accountDispatch } = useContext(AccountContext)
const AccountSegmentedControl: React.FC<Props> = ({
accountState,
accountDispatch,
scrollY
}) => {
const { t } = useTranslation('sharedAccount')
const { mode, theme } = useTheme()
@ -69,12 +74,10 @@ const AccountSegmentedControl: React.FC<Props> = ({ scrollY }) => {
const styles = StyleSheet.create({
base: {
...StyleSheet.absoluteFillObject,
position: 'absolute',
left: 0,
right: 0,
zIndex: 99,
borderTopWidth: StyleSheet.hairlineWidth,
padding: StyleConstants.Spacing.Global.PagePadding
padding: StyleConstants.Spacing.Global.PagePadding,
paddingBottom: StyleConstants.Spacing.Global.PagePadding * 3
}
})

View File

@ -1,32 +1,29 @@
import React, { useCallback, useContext, useState } from 'react'
import React, { Dispatch, useCallback, useState } from 'react'
import { Dimensions, StyleSheet } from 'react-native'
import { TabView, SceneMap } from 'react-native-tab-view'
import { SceneMap, TabView } from 'react-native-tab-view'
import Timeline from '@components/Timelines/Timeline'
import { AccountContext } from '../Account'
import { AccountAction, AccountState } from '../Account'
import { StyleConstants } from '@root/utils/styles/constants'
export interface Props {
accountState: AccountState
accountDispatch: Dispatch<AccountAction>
id: Mastodon.Account['id']
}
const AccountToots: React.FC<Props> = ({ id }) => {
const { accountState, accountDispatch } = useContext(AccountContext)
const AccountToots: React.FC<Props> = ({
accountState,
accountDispatch,
id
}) => {
const [routes] = useState([
{ key: 'Account_Default' },
{ key: 'Account_All' },
{ key: 'Account_Media' }
])
const singleScene = useCallback(
({ route }) => (
<Timeline
page={route.key}
account={id}
disableRefresh
scrollEnabled={false}
/>
),
({ route }) => <Timeline page={route.key} account={id} disableRefresh />,
[]
)
const renderScene = SceneMap({

View File

@ -51,6 +51,7 @@ const ScreenSharedWebview: React.FC<Props> = ({
{() => (
<>
<WebView
allowsBackForwardNavigationGestures
ref={webview}
source={{ uri }}
decelerationRate='normal'