mirror of
https://github.com/tooot-app/app
synced 2025-03-06 12:37:44 +01:00
My lists are done
This commit is contained in:
parent
1ad67e67ac
commit
6a5d9e7fb8
@ -37,6 +37,7 @@
|
||||
"react-native-render-html": "^4.2.4",
|
||||
"react-native-safe-area-context": "3.1.4",
|
||||
"react-native-screens": "~2.10.1",
|
||||
"react-native-shimmer-placeholder": "^2.0.6",
|
||||
"react-native-toast-message": "^1.3.4",
|
||||
"react-native-web": "~0.13.7",
|
||||
"react-native-webview": "10.7.0",
|
||||
|
3
src/@types/app.d.ts
vendored
3
src/@types/app.d.ts
vendored
@ -11,6 +11,9 @@ declare namespace App {
|
||||
| 'Account_Default'
|
||||
| 'Account_All'
|
||||
| 'Account_Media'
|
||||
| 'Conversations'
|
||||
| 'Bookmarks'
|
||||
| 'Favourites'
|
||||
|
||||
type QueryKey = [
|
||||
Pages,
|
||||
|
12
src/@types/mastodon.d.ts
vendored
12
src/@types/mastodon.d.ts
vendored
@ -136,6 +136,13 @@ declare namespace Mastodon {
|
||||
blurhash: string
|
||||
}
|
||||
|
||||
type Conversation = {
|
||||
id: string
|
||||
accounts: Account[]
|
||||
unread: boolean
|
||||
last_status?: Status
|
||||
}
|
||||
|
||||
type Emoji = {
|
||||
// Base
|
||||
shortcode: string
|
||||
@ -151,6 +158,11 @@ declare namespace Mastodon {
|
||||
verified_at?: string
|
||||
}
|
||||
|
||||
type List = {
|
||||
id: string
|
||||
title: string
|
||||
}
|
||||
|
||||
type Mention = {
|
||||
// Base
|
||||
id: string
|
||||
|
@ -57,7 +57,6 @@ export const Index: React.FC = () => {
|
||||
<Tab.Screen name='Screen-Public' component={ScreenPublic} />
|
||||
<Tab.Screen
|
||||
name='Screen-Post'
|
||||
component={() => <></>}
|
||||
listeners={({ navigation, route }) => ({
|
||||
tabPress: e => {
|
||||
e.preventDefault()
|
||||
@ -70,8 +69,13 @@ export const Index: React.FC = () => {
|
||||
})
|
||||
}
|
||||
})}
|
||||
>
|
||||
{() => <></>}
|
||||
</Tab.Screen>
|
||||
<Tab.Screen
|
||||
name='Screen-Notifications'
|
||||
component={ScreenNotifications}
|
||||
/>
|
||||
<Tab.Screen name='Screen-Notifications' component={ScreenNotifications} />
|
||||
<Tab.Screen name='Screen-Me' component={ScreenMe} />
|
||||
</Tab.Navigator>
|
||||
|
||||
|
5
src/components/Menu.tsx
Normal file
5
src/components/Menu.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import MenuContainer from './Menu/Container'
|
||||
import MenuHeader from './Menu/Header'
|
||||
import MenuItem from './Menu/Item'
|
||||
|
||||
export { MenuContainer, MenuHeader, MenuItem }
|
8
src/components/Menu/Container.tsx
Normal file
8
src/components/Menu/Container.tsx
Normal file
@ -0,0 +1,8 @@
|
||||
import React from 'react'
|
||||
import { View } from 'react-native'
|
||||
|
||||
const MenuContainer: React.FC = ({ ...props }) => {
|
||||
return <View>{props.children}</View>
|
||||
}
|
||||
|
||||
export default MenuContainer
|
20
src/components/Menu/Header.tsx
Normal file
20
src/components/Menu/Header.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import React from 'react'
|
||||
import { StyleSheet, Text } from 'react-native'
|
||||
|
||||
export interface Props {
|
||||
heading: string
|
||||
}
|
||||
|
||||
const MenuHeader: React.FC<Props> = ({ heading }) => {
|
||||
return <Text style={styles.header}>{heading}</Text>
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
header: {
|
||||
marginTop: 12,
|
||||
paddingLeft: 12,
|
||||
paddingRight: 12
|
||||
}
|
||||
})
|
||||
|
||||
export default MenuHeader
|
70
src/components/Menu/Item.tsx
Normal file
70
src/components/Menu/Item.tsx
Normal file
@ -0,0 +1,70 @@
|
||||
import React from 'react'
|
||||
import { Pressable, StyleSheet, Text, View } from 'react-native'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import { Feather } from '@expo/vector-icons'
|
||||
|
||||
export interface Props {
|
||||
icon?: string
|
||||
title: string
|
||||
navigateTo?: string
|
||||
navigateToParams?: {}
|
||||
}
|
||||
|
||||
const Core: React.FC<Props> = ({ icon, title, navigateTo }) => {
|
||||
return (
|
||||
<View style={styles.core}>
|
||||
{icon && <Feather name={icon} size={24} style={styles.iconLeading} />}
|
||||
<Text>{title}</Text>
|
||||
{navigateTo && (
|
||||
<Feather
|
||||
name='chevron-right'
|
||||
size={24}
|
||||
color='lightgray'
|
||||
style={styles.iconNavigation}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const MenuItem: React.FC<Props> = ({ ...props }) => {
|
||||
const navigation = useNavigation()
|
||||
|
||||
return props.navigateTo ? (
|
||||
<Pressable
|
||||
style={styles.base}
|
||||
onPress={() => {
|
||||
navigation.navigate(props.navigateTo!, props.navigateToParams)
|
||||
}}
|
||||
>
|
||||
<Core {...props} />
|
||||
</Pressable>
|
||||
) : (
|
||||
<View style={styles.base}>
|
||||
<Core {...props} />
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
base: {
|
||||
height: 50,
|
||||
borderBottomColor: 'lightgray',
|
||||
borderBottomWidth: 1
|
||||
},
|
||||
core: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingLeft: 12,
|
||||
paddingRight: 12
|
||||
},
|
||||
iconLeading: {
|
||||
marginRight: 8
|
||||
},
|
||||
iconNavigation: {
|
||||
marginLeft: 'auto'
|
||||
}
|
||||
})
|
||||
|
||||
export default MenuItem
|
@ -14,7 +14,7 @@ const Avatar: React.FC<Props> = ({ uri, id }) => {
|
||||
<Pressable
|
||||
style={styles.avatar}
|
||||
onPress={() => {
|
||||
navigation.navigate('Account', {
|
||||
navigation.navigate('Screen-Shared-Account', {
|
||||
id: id
|
||||
})
|
||||
}}
|
||||
|
66
src/components/Status/HeaderConversation.tsx
Normal file
66
src/components/Status/HeaderConversation.tsx
Normal file
@ -0,0 +1,66 @@
|
||||
import React from 'react'
|
||||
import { StyleSheet, Text, View } from 'react-native'
|
||||
|
||||
import relativeTime from 'src/utils/relativeTime'
|
||||
import Emojis from './Emojis'
|
||||
|
||||
export interface Props {
|
||||
account: Mastodon.Account
|
||||
created_at?: Mastodon.Status['created_at']
|
||||
}
|
||||
|
||||
const HeaderConversation: React.FC<Props> = ({ account, created_at }) => {
|
||||
return (
|
||||
<View>
|
||||
<View style={styles.nameAndDate}>
|
||||
<View style={styles.name}>
|
||||
{account.emojis ? (
|
||||
<Emojis
|
||||
content={account.display_name || account.username}
|
||||
emojis={account.emojis}
|
||||
dimension={14}
|
||||
/>
|
||||
) : (
|
||||
<Text numberOfLines={1}>
|
||||
{account.display_name || account.username}
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
{created_at && (
|
||||
<View>
|
||||
<Text style={styles.created_at}>{relativeTime(created_at)}</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
<Text style={styles.account} numberOfLines={1}>
|
||||
@{account.acct}
|
||||
</Text>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
nameAndDate: {
|
||||
width: '100%',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between'
|
||||
},
|
||||
name: {
|
||||
flexDirection: 'row',
|
||||
marginRight: 8,
|
||||
fontWeight: '900'
|
||||
},
|
||||
created_at: {
|
||||
fontSize: 12,
|
||||
lineHeight: 12,
|
||||
marginTop: 8,
|
||||
marginBottom: 8,
|
||||
marginRight: 8
|
||||
},
|
||||
account: {
|
||||
lineHeight: 14,
|
||||
flexShrink: 1
|
||||
}
|
||||
})
|
||||
|
||||
export default HeaderConversation
|
@ -45,7 +45,9 @@ const TootNotification: React.FC<Props> = ({ notification, queryKey }) => {
|
||||
/>
|
||||
<Pressable
|
||||
onPress={() =>
|
||||
navigation.navigate('Toot', { toot: notification.id })
|
||||
navigation.navigate('Screen-Shared-Toot', {
|
||||
toot: notification.id
|
||||
})
|
||||
}
|
||||
>
|
||||
{notification.status ? (
|
||||
|
73
src/components/TimelineConversation.tsx
Normal file
73
src/components/TimelineConversation.tsx
Normal file
@ -0,0 +1,73 @@
|
||||
import React, { useMemo } from 'react'
|
||||
import { Pressable, StyleSheet, View } from 'react-native'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
|
||||
import Avatar from './Status/Avatar'
|
||||
import HeaderConversation from './Status/HeaderConversation'
|
||||
import Content from './Status/Content'
|
||||
|
||||
export interface Props {
|
||||
item: Mastodon.Conversation
|
||||
}
|
||||
// Unread and mark as unread
|
||||
const TimelineConversation: React.FC<Props> = ({ item }) => {
|
||||
const navigation = useNavigation()
|
||||
|
||||
const statusView = useMemo(() => {
|
||||
return (
|
||||
<View style={styles.statusView}>
|
||||
<View style={styles.status}>
|
||||
<Avatar uri={item.accounts[0].avatar} id={item.accounts[0].id} />
|
||||
<View style={styles.details}>
|
||||
<HeaderConversation
|
||||
account={item.accounts[0]}
|
||||
created_at={item.last_status?.created_at}
|
||||
/>
|
||||
{/* Can pass toot info to next page to speed up performance */}
|
||||
<Pressable
|
||||
onPress={() =>
|
||||
item.last_status &&
|
||||
navigation.navigate('Screen-Shared-Toot', {
|
||||
toot: item.last_status.id
|
||||
})
|
||||
}
|
||||
>
|
||||
{item.last_status ? (
|
||||
<Content
|
||||
content={item.last_status.content}
|
||||
emojis={item.last_status.emojis}
|
||||
mentions={item.last_status.mentions}
|
||||
spoiler_text={item.last_status.spoiler_text}
|
||||
// tags={actualStatus.tags}
|
||||
// style={{ flex: 1 }}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Pressable>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}, [item])
|
||||
|
||||
return statusView
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
statusView: {
|
||||
flex: 1,
|
||||
flexDirection: 'column',
|
||||
padding: 12
|
||||
},
|
||||
status: {
|
||||
flex: 1,
|
||||
flexDirection: 'row'
|
||||
},
|
||||
details: {
|
||||
flex: 1,
|
||||
flexGrow: 1
|
||||
}
|
||||
})
|
||||
|
||||
export default TimelineConversation
|
@ -12,23 +12,23 @@ import Card from './Status/Card'
|
||||
import ActionsStatus from './Status/ActionsStatus'
|
||||
|
||||
export interface Props {
|
||||
status: Mastodon.Status
|
||||
item: Mastodon.Status
|
||||
queryKey: App.QueryKey
|
||||
}
|
||||
|
||||
const StatusInTimeline: React.FC<Props> = ({ status, queryKey }) => {
|
||||
const TimelineDefault: React.FC<Props> = ({ item, queryKey }) => {
|
||||
const navigation = useNavigation()
|
||||
|
||||
let actualStatus = status.reblog ? status.reblog : status
|
||||
let actualStatus = item.reblog ? item.reblog : item
|
||||
|
||||
const statusView = useMemo(() => {
|
||||
return (
|
||||
<View style={styles.statusView}>
|
||||
{status.reblog && (
|
||||
{item.reblog && (
|
||||
<Actioned
|
||||
action='reblog'
|
||||
name={status.account.display_name || status.account.username}
|
||||
emojis={status.account.emojis}
|
||||
name={item.account.display_name || item.account.username}
|
||||
emojis={item.account.emojis}
|
||||
/>
|
||||
)}
|
||||
<View style={styles.status}>
|
||||
@ -47,13 +47,15 @@ const StatusInTimeline: React.FC<Props> = ({ status, queryKey }) => {
|
||||
}
|
||||
emojis={actualStatus.account.emojis}
|
||||
account={actualStatus.account.acct}
|
||||
created_at={status.created_at}
|
||||
application={status.application}
|
||||
created_at={item.created_at}
|
||||
application={item.application}
|
||||
/>
|
||||
{/* Can pass toot info to next page to speed up performance */}
|
||||
<Pressable
|
||||
onPress={() =>
|
||||
navigation.navigate('Toot', { toot: actualStatus.id })
|
||||
navigation.navigate('Screen-Shared-Toot', {
|
||||
toot: actualStatus.id
|
||||
})
|
||||
}
|
||||
>
|
||||
{actualStatus.content ? (
|
||||
@ -83,7 +85,7 @@ const StatusInTimeline: React.FC<Props> = ({ status, queryKey }) => {
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}, [status])
|
||||
}, [item])
|
||||
|
||||
return statusView
|
||||
}
|
||||
@ -104,4 +106,4 @@ const styles = StyleSheet.create({
|
||||
}
|
||||
})
|
||||
|
||||
export default StatusInTimeline
|
||||
export default TimelineDefault
|
@ -2,14 +2,66 @@ import React from 'react'
|
||||
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
|
||||
|
||||
import ScreenMeRoot from 'src/screens/Me/Root'
|
||||
import ScreenMeConversations from './Me/Cconversations'
|
||||
import ScreenMeBookmarks from './Me/Bookmarks'
|
||||
import ScreenMeFavourites from './Me/Favourites'
|
||||
import ScreenMeLists from './Me/Lists'
|
||||
import sharedScreens from 'src/screens/Shared/sharedScreens'
|
||||
import ScreenMeListsList from './Me/Root/Lists/List'
|
||||
|
||||
const Stack = createNativeStackNavigator()
|
||||
|
||||
const ScreenMe: React.FC = () => {
|
||||
return (
|
||||
<Stack.Navigator>
|
||||
<Stack.Screen name='Screen-Me-Root' component={ScreenMeRoot} />
|
||||
<Stack.Navigator
|
||||
screenOptions={{
|
||||
headerTitle: 'test'
|
||||
}}
|
||||
>
|
||||
<Stack.Screen
|
||||
name='Screen-Me-Root'
|
||||
component={ScreenMeRoot}
|
||||
options={{
|
||||
headerTranslucent: true,
|
||||
headerStyle: { backgroundColor: 'rgba(255, 255, 255, 0)' },
|
||||
headerCenter: () => <></>
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name='Screen-Me-Conversations'
|
||||
component={ScreenMeConversations}
|
||||
options={{
|
||||
headerTitle: '对话'
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name='Screen-Me-Bookmarks'
|
||||
component={ScreenMeBookmarks}
|
||||
options={{
|
||||
headerTitle: '书签'
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name='Screen-Me-Favourites'
|
||||
component={ScreenMeFavourites}
|
||||
options={{
|
||||
headerTitle: '书签'
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name='Screen-Me-Lists'
|
||||
component={ScreenMeLists}
|
||||
options={{
|
||||
headerTitle: '书签'
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name='Screen-Me-Lists-List'
|
||||
component={ScreenMeListsList}
|
||||
options={{
|
||||
headerTitle: '书签'
|
||||
}}
|
||||
/>
|
||||
|
||||
{sharedScreens(Stack)}
|
||||
</Stack.Navigator>
|
||||
|
9
src/screens/Me/Bookmarks.tsx
Normal file
9
src/screens/Me/Bookmarks.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import React from 'react'
|
||||
|
||||
import Timeline from 'src/screens/Timelines/Timeline'
|
||||
|
||||
const ScreenMeBookmarks: React.FC = () => {
|
||||
return <Timeline page='Bookmarks' />
|
||||
}
|
||||
|
||||
export default ScreenMeBookmarks
|
9
src/screens/Me/Cconversations.tsx
Normal file
9
src/screens/Me/Cconversations.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import React from 'react'
|
||||
|
||||
import Timeline from 'src/screens/Timelines/Timeline'
|
||||
|
||||
const ScreenMeConversations: React.FC = () => {
|
||||
return <Timeline page='Conversations' />
|
||||
}
|
||||
|
||||
export default ScreenMeConversations
|
9
src/screens/Me/Favourites.tsx
Normal file
9
src/screens/Me/Favourites.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import React from 'react'
|
||||
|
||||
import Timeline from 'src/screens/Timelines/Timeline'
|
||||
|
||||
const ScreenMeFavourites: React.FC = () => {
|
||||
return <Timeline page='Favourites' />
|
||||
}
|
||||
|
||||
export default ScreenMeFavourites
|
41
src/screens/Me/Lists.tsx
Normal file
41
src/screens/Me/Lists.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
import React from 'react'
|
||||
import { ActivityIndicator, Text } from 'react-native'
|
||||
import { useQuery } from 'react-query'
|
||||
import { MenuContainer, MenuHeader, MenuItem } from 'src/components/Menu'
|
||||
|
||||
import { listsFetch } from 'src/utils/fetches/listsFetch'
|
||||
|
||||
const ScreenMeLists: React.FC = () => {
|
||||
const { status, data } = useQuery(['Lists'], listsFetch)
|
||||
|
||||
let lists
|
||||
switch (status) {
|
||||
case 'loading':
|
||||
lists = <ActivityIndicator />
|
||||
break
|
||||
case 'error':
|
||||
lists = <Text>载入错误</Text>
|
||||
break
|
||||
case 'success':
|
||||
lists = data?.map(d => (
|
||||
<MenuItem
|
||||
icon='list'
|
||||
title={d.title}
|
||||
navigateTo='Screen-Me-Lists-List'
|
||||
navigateToParams={{
|
||||
list: d.id
|
||||
}}
|
||||
/>
|
||||
))
|
||||
break
|
||||
}
|
||||
|
||||
return (
|
||||
<MenuContainer>
|
||||
<MenuHeader heading='我的列表' />
|
||||
{lists}
|
||||
</MenuContainer>
|
||||
)
|
||||
}
|
||||
|
||||
export default ScreenMeLists
|
@ -1,17 +1,33 @@
|
||||
import React from 'react'
|
||||
import { View } from 'react-native'
|
||||
import { ScrollView } from 'react-native'
|
||||
import { useSelector } from 'react-redux'
|
||||
|
||||
import { RootState } from 'src/store'
|
||||
import { RootState, store } from 'src/store'
|
||||
import { getLocalAccountId } from 'src/utils/slices/instancesSlice'
|
||||
|
||||
import Login from './Root/Login'
|
||||
import MyInfo from './Root/MyInfo'
|
||||
import MyCollections from './Root/MyCollections'
|
||||
import Settings from './Root/Settings'
|
||||
|
||||
const ScreenMeRoot: React.FC = () => {
|
||||
const localRegistered = useSelector(
|
||||
(state: RootState) => state.instances.local.url
|
||||
)
|
||||
|
||||
return <View>{localRegistered ? <></> : <Login />}</View>
|
||||
return (
|
||||
<ScrollView>
|
||||
{localRegistered ? (
|
||||
<MyInfo id={getLocalAccountId(store.getState())!} />
|
||||
) : (
|
||||
<Login />
|
||||
)}
|
||||
{localRegistered && (
|
||||
<MyCollections id={getLocalAccountId(store.getState())!} />
|
||||
)}
|
||||
<Settings />
|
||||
</ScrollView>
|
||||
)
|
||||
}
|
||||
|
||||
export default ScreenMeRoot
|
||||
|
23
src/screens/Me/Root/Lists/List.tsx
Normal file
23
src/screens/Me/Root/Lists/List.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import React from 'react'
|
||||
|
||||
import Timeline from 'src/screens/Timelines/Timeline'
|
||||
|
||||
// Show remote hashtag? Only when private, show local version?
|
||||
|
||||
export interface Props {
|
||||
route: {
|
||||
params: {
|
||||
list: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const ScreenMeListsList: React.FC<Props> = ({
|
||||
route: {
|
||||
params: { list }
|
||||
}
|
||||
}) => {
|
||||
return <Timeline page='List' list={list} />
|
||||
}
|
||||
|
||||
export default ScreenMeListsList
|
@ -76,7 +76,6 @@ const Login: React.FC = () => {
|
||||
clientSecret: applicationData?.clientSecret,
|
||||
scopes: ['read', 'write', 'follow', 'push'],
|
||||
redirectUri: 'exp://127.0.0.1:19000'
|
||||
// usePKCE: false
|
||||
},
|
||||
{
|
||||
authorizationEndpoint: `https://${instance}/oauth/authorize`
|
||||
|
20
src/screens/Me/Root/MyCollections.tsx
Normal file
20
src/screens/Me/Root/MyCollections.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import React from 'react'
|
||||
import { MenuContainer, MenuHeader, MenuItem } from 'src/components/Menu'
|
||||
|
||||
export interface Props {
|
||||
id: Mastodon.Account['id']
|
||||
}
|
||||
|
||||
const MyInfo: React.FC<Props> = ({ id }) => {
|
||||
return (
|
||||
<MenuContainer>
|
||||
<MenuHeader heading='我的东西' />
|
||||
<MenuItem icon='mail' title='私信' navigateTo='Screen-Me-Conversations' />
|
||||
<MenuItem icon='bookmark' title='书签' navigateTo='Screen-Me-Bookmarks' />
|
||||
<MenuItem icon='star' title='喜欢' navigateTo='Screen-Me-Favourites' />
|
||||
<MenuItem icon='list' title='列表' navigateTo='Screen-Me-Lists' />
|
||||
</MenuContainer>
|
||||
)
|
||||
}
|
||||
|
||||
export default MyInfo
|
23
src/screens/Me/Root/MyInfo.tsx
Normal file
23
src/screens/Me/Root/MyInfo.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import React from 'react'
|
||||
import { useQuery } from 'react-query'
|
||||
|
||||
import { accountFetch } from 'src/utils/fetches/accountFetch'
|
||||
import AccountHeader from 'src/screens/Shared/Account/Header'
|
||||
import AccountInformation from 'src/screens/Shared/Account/Information'
|
||||
|
||||
export interface Props {
|
||||
id: Mastodon.Account['id']
|
||||
}
|
||||
|
||||
const MyInfo: React.FC<Props> = ({ id }) => {
|
||||
const { data } = useQuery(['Account', { id }], accountFetch)
|
||||
|
||||
return (
|
||||
<>
|
||||
<AccountHeader uri={data?.header} limitHeight />
|
||||
<AccountInformation account={data} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default MyInfo
|
13
src/screens/Me/Root/Settings.tsx
Normal file
13
src/screens/Me/Root/Settings.tsx
Normal file
@ -0,0 +1,13 @@
|
||||
import React from 'react'
|
||||
import { MenuContainer, MenuHeader, MenuItem } from 'src/components/Menu'
|
||||
|
||||
const Settings: React.FC = () => {
|
||||
return (
|
||||
<MenuContainer>
|
||||
<MenuHeader heading='设置' />
|
||||
<MenuItem icon='settings' title='设置' navigateTo='Local' />
|
||||
</MenuContainer>
|
||||
)
|
||||
}
|
||||
|
||||
export default Settings
|
@ -1,185 +1,16 @@
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import {
|
||||
Dimensions,
|
||||
FlatList,
|
||||
Image,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
Text,
|
||||
View
|
||||
} from 'react-native'
|
||||
import SegmentedControl from '@react-native-community/segmented-control'
|
||||
import { Feather } from '@expo/vector-icons'
|
||||
import React from 'react'
|
||||
import { ScrollView } from 'react-native'
|
||||
|
||||
// import * as relationshipsSlice from 'src/stacks/common/relationshipsSlice'
|
||||
|
||||
import ParseContent from 'src/components/ParseContent'
|
||||
import Timeline from 'src/screens/Timelines/Timeline'
|
||||
import { useQuery } from 'react-query'
|
||||
import { accountFetch } from '../../utils/fetches/accountFetch'
|
||||
import AccountToots from './Account/Toots'
|
||||
import AccountHeader from './Account/Header'
|
||||
import AccountInformation from './Account/Information'
|
||||
|
||||
// Moved account example: https://m.cmx.im/web/accounts/27812
|
||||
|
||||
const Header = ({
|
||||
uri,
|
||||
size
|
||||
}: {
|
||||
uri: string
|
||||
size: { width: number; height: number }
|
||||
}) => {
|
||||
if (uri) {
|
||||
const heightRatio = size ? size.height / size.width : 1 / 2
|
||||
return (
|
||||
<Image
|
||||
source={{ uri: uri }}
|
||||
style={[
|
||||
styles.header,
|
||||
{
|
||||
height:
|
||||
Dimensions.get('window').width *
|
||||
(heightRatio > 0.5 ? 1 / 2 : heightRatio)
|
||||
}
|
||||
]}
|
||||
/>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
styles.header,
|
||||
{ height: Dimensions.get('window').width * (1 / 3) }
|
||||
]}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const Information = ({
|
||||
account,
|
||||
emojis
|
||||
}: {
|
||||
account: Mastodon.Account
|
||||
emojis: Mastodon.Emoji[]
|
||||
}) => {
|
||||
return (
|
||||
<View style={styles.information}>
|
||||
{/* <Text>Moved or not: {account.moved}</Text> */}
|
||||
<Image source={{ uri: account.avatar }} style={styles.avatar} />
|
||||
|
||||
<Text style={styles.display_name}>
|
||||
{account.display_name || account.username}
|
||||
{account.bot && (
|
||||
<Feather name='hard-drive' style={styles.display_name} />
|
||||
)}
|
||||
</Text>
|
||||
<Text style={styles.account}>
|
||||
{account.acct}
|
||||
{account.locked && <Feather name='lock' />}
|
||||
</Text>
|
||||
|
||||
{account.fields &&
|
||||
account.fields.map((field, index) => (
|
||||
<View key={index} style={{ flex: 1, flexDirection: 'row' }}>
|
||||
<Text style={{ width: '30%', alignSelf: 'center' }}>
|
||||
<ParseContent content={field.name} emojis={emojis} showFullLink />{' '}
|
||||
{field.verified_at && <Feather name='check-circle' />}
|
||||
</Text>
|
||||
<Text style={{ width: '70%' }}>
|
||||
<ParseContent
|
||||
content={field.value}
|
||||
emojis={emojis}
|
||||
showFullLink
|
||||
/>
|
||||
</Text>
|
||||
</View>
|
||||
))}
|
||||
{account.note && <ParseContent content={account.note} emojis={emojis} />}
|
||||
<Text>
|
||||
加入时间{' '}
|
||||
{new Date(account.created_at).toLocaleDateString('zh-CN', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric'
|
||||
})}
|
||||
</Text>
|
||||
|
||||
<Text>Toots: {account.statuses_count}</Text>
|
||||
<Text>Followers: {account.followers_count}</Text>
|
||||
<Text>Following: {account.following_count}</Text>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const Toots = ({ account }: { account: string }) => {
|
||||
const [segment, setSegment] = useState(0)
|
||||
const [segmentManuallyTriggered, setSegmentManuallyTriggered] = useState(
|
||||
false
|
||||
)
|
||||
const horizontalPaging = useRef<any>()
|
||||
|
||||
const pages: ['Account_Default', 'Account_All', 'Account_Media'] = [
|
||||
'Account_Default',
|
||||
'Account_All',
|
||||
'Account_Media'
|
||||
]
|
||||
|
||||
return (
|
||||
<>
|
||||
<SegmentedControl
|
||||
values={['嘟嘟', '嘟嘟和回复', '媒体']}
|
||||
selectedIndex={segment}
|
||||
onChange={({ nativeEvent }) => {
|
||||
setSegmentManuallyTriggered(true)
|
||||
setSegment(nativeEvent.selectedSegmentIndex)
|
||||
horizontalPaging.current.scrollToIndex({
|
||||
index: nativeEvent.selectedSegmentIndex
|
||||
})
|
||||
}}
|
||||
style={{ width: '100%', height: 30 }}
|
||||
/>
|
||||
<FlatList
|
||||
style={{ width: Dimensions.get('window').width, height: '100%' }}
|
||||
data={pages}
|
||||
keyExtractor={page => page}
|
||||
renderItem={({ item, index }) => {
|
||||
return (
|
||||
<View style={{ width: Dimensions.get('window').width }}>
|
||||
<Timeline
|
||||
key={index}
|
||||
page={item}
|
||||
account={account}
|
||||
disableRefresh
|
||||
scrollEnabled={false}
|
||||
/>
|
||||
</View>
|
||||
)
|
||||
}}
|
||||
ref={horizontalPaging}
|
||||
bounces={false}
|
||||
getItemLayout={(data, index) => ({
|
||||
length: Dimensions.get('window').width,
|
||||
offset: Dimensions.get('window').width * index,
|
||||
index
|
||||
})}
|
||||
horizontal
|
||||
onMomentumScrollEnd={() => {
|
||||
setSegmentManuallyTriggered(false)
|
||||
}}
|
||||
onScroll={({ nativeEvent }) =>
|
||||
!segmentManuallyTriggered &&
|
||||
setSegment(
|
||||
nativeEvent.contentOffset.x <= Dimensions.get('window').width / 3
|
||||
? 0
|
||||
: 1
|
||||
)
|
||||
}
|
||||
pagingEnabled
|
||||
showsHorizontalScrollIndicator={false}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export interface Props {
|
||||
route: {
|
||||
params: {
|
||||
@ -193,68 +24,17 @@ const ScreenSharedAccount: React.FC<Props> = ({
|
||||
params: { id }
|
||||
}
|
||||
}) => {
|
||||
const { isLoading, isFetchingMore, isError, isSuccess, data } = useQuery(
|
||||
['Account', { id }],
|
||||
accountFetch
|
||||
)
|
||||
const { data } = useQuery(['Account', { id }], accountFetch)
|
||||
|
||||
// const stateRelationships = useSelector(relationshipsState)
|
||||
interface isHeaderImageSize {
|
||||
width: number
|
||||
height: number
|
||||
}
|
||||
const [headerImageSize, setHeaderImageSize] = useState<
|
||||
isHeaderImageSize | undefined
|
||||
>(undefined)
|
||||
|
||||
useEffect(() => {
|
||||
if (isSuccess && data.header) {
|
||||
Image.getSize(data.header, (width, height) => {
|
||||
setHeaderImageSize({ width, height })
|
||||
})
|
||||
} else {
|
||||
setHeaderImageSize({ width: 3, height: 1 })
|
||||
}
|
||||
}, [data, isSuccess])
|
||||
|
||||
// add emoji support
|
||||
return isSuccess && headerImageSize ? (
|
||||
<ScrollView>
|
||||
{headerImageSize && (
|
||||
<Header
|
||||
uri={data.header}
|
||||
size={{
|
||||
width: headerImageSize.width,
|
||||
height: headerImageSize.height
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<Information account={data} emojis={data.emojis} />
|
||||
<Toots account={id} />
|
||||
return (
|
||||
<ScrollView bounces={false}>
|
||||
<AccountHeader uri={data?.header} />
|
||||
<AccountInformation account={data} />
|
||||
<AccountToots id={id} />
|
||||
</ScrollView>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
header: {
|
||||
width: '100%',
|
||||
backgroundColor: 'gray'
|
||||
},
|
||||
information: { marginTop: -30, paddingLeft: 12, paddingRight: 12 },
|
||||
avatar: {
|
||||
width: 90,
|
||||
height: 90
|
||||
},
|
||||
display_name: {
|
||||
fontSize: 18,
|
||||
fontWeight: 'bold',
|
||||
marginTop: 12
|
||||
},
|
||||
account: {
|
||||
marginTop: 4
|
||||
}
|
||||
})
|
||||
|
||||
export default ScreenSharedAccount
|
||||
|
61
src/screens/Shared/Account/Header.tsx
Normal file
61
src/screens/Shared/Account/Header.tsx
Normal file
@ -0,0 +1,61 @@
|
||||
import React, { useEffect, useRef } from 'react'
|
||||
import { Animated, Dimensions, Image, StyleSheet } from 'react-native'
|
||||
|
||||
export interface Props {
|
||||
uri: Mastodon.Account['header']
|
||||
limitHeight?: boolean
|
||||
}
|
||||
|
||||
const limitRatio = 0.4
|
||||
|
||||
const AccountHeader: React.FC<Props> = ({ uri, limitHeight = false }) => {
|
||||
console.log(uri)
|
||||
useEffect(() => {
|
||||
if (uri) {
|
||||
if (uri.includes('/headers/original/missing.png')) {
|
||||
animateNewSize(limitRatio)
|
||||
} else {
|
||||
Image.getSize(
|
||||
uri,
|
||||
(width, height) => {
|
||||
animateNewSize(limitHeight ? limitRatio : height / width)
|
||||
},
|
||||
() => {
|
||||
animateNewSize(limitRatio)
|
||||
}
|
||||
)
|
||||
}
|
||||
} else {
|
||||
animateNewSize(limitRatio)
|
||||
}
|
||||
}, [uri])
|
||||
|
||||
const windowWidth = Dimensions.get('window').width
|
||||
const imageHeight = useRef(new Animated.Value(windowWidth * limitRatio))
|
||||
.current
|
||||
const animateNewSize = (ratio: number) => {
|
||||
Animated.timing(imageHeight, {
|
||||
toValue: windowWidth * ratio,
|
||||
duration: 350,
|
||||
useNativeDriver: false
|
||||
}).start()
|
||||
}
|
||||
|
||||
return (
|
||||
<Animated.View style={[styles.imageContainer, { height: imageHeight }]}>
|
||||
<Image source={{ uri: uri }} style={styles.image} />
|
||||
</Animated.View>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
imageContainer: {
|
||||
backgroundColor: 'lightgray'
|
||||
},
|
||||
image: {
|
||||
width: '100%',
|
||||
height: '100%'
|
||||
}
|
||||
})
|
||||
|
||||
export default AccountHeader
|
95
src/screens/Shared/Account/Information.tsx
Normal file
95
src/screens/Shared/Account/Information.tsx
Normal file
@ -0,0 +1,95 @@
|
||||
import React, { useState } from 'react'
|
||||
import { Image, StyleSheet, Text, View } from 'react-native'
|
||||
import ShimmerPlaceholder from 'react-native-shimmer-placeholder'
|
||||
import { Feather } from '@expo/vector-icons'
|
||||
|
||||
import ParseContent from 'src/components/ParseContent'
|
||||
|
||||
export interface Props {
|
||||
account: Mastodon.Account | undefined
|
||||
}
|
||||
|
||||
const AccountInformation: React.FC<Props> = ({ account }) => {
|
||||
const [avatarLoaded, setAvatarLoaded] = useState(false)
|
||||
|
||||
// add emoji support
|
||||
return (
|
||||
<View style={styles.information}>
|
||||
{/* <Text>Moved or not: {account.moved}</Text> */}
|
||||
<ShimmerPlaceholder visible={avatarLoaded} width={90} height={90}>
|
||||
<Image
|
||||
source={{ uri: account?.avatar }}
|
||||
style={styles.avatar}
|
||||
onLoadEnd={() => setAvatarLoaded(true)}
|
||||
/>
|
||||
</ShimmerPlaceholder>
|
||||
|
||||
<Text style={styles.display_name}>
|
||||
{account?.display_name || account?.username}
|
||||
{account?.bot && (
|
||||
<Feather name='hard-drive' style={styles.display_name} />
|
||||
)}
|
||||
</Text>
|
||||
<Text style={styles.account}>
|
||||
{account?.acct}
|
||||
{account?.locked && <Feather name='lock' />}
|
||||
</Text>
|
||||
|
||||
{account?.fields &&
|
||||
account.fields.map((field, index) => (
|
||||
<View key={index} style={{ flex: 1, flexDirection: 'row' }}>
|
||||
<Text style={{ width: '30%', alignSelf: 'center' }}>
|
||||
<ParseContent
|
||||
content={field.name}
|
||||
emojis={account.emojis}
|
||||
showFullLink
|
||||
/>{' '}
|
||||
{field.verified_at && <Feather name='check-circle' />}
|
||||
</Text>
|
||||
<Text style={{ width: '70%' }}>
|
||||
<ParseContent
|
||||
content={field.value}
|
||||
emojis={account.emojis}
|
||||
showFullLink
|
||||
/>
|
||||
</Text>
|
||||
</View>
|
||||
))}
|
||||
{account?.note && (
|
||||
<ParseContent content={account.note} emojis={account.emojis} />
|
||||
)}
|
||||
{account?.created_at && (
|
||||
<Text>
|
||||
加入时间{' '}
|
||||
{new Date(account.created_at).toLocaleDateString('zh-CN', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric'
|
||||
})}
|
||||
</Text>
|
||||
)}
|
||||
|
||||
<Text>Toots: {account?.statuses_count}</Text>
|
||||
<Text>Followers: {account?.followers_count}</Text>
|
||||
<Text>Following: {account?.following_count}</Text>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
information: { marginTop: -30, paddingLeft: 12, paddingRight: 12 },
|
||||
avatar: {
|
||||
width: 90,
|
||||
height: 90
|
||||
},
|
||||
display_name: {
|
||||
fontSize: 18,
|
||||
fontWeight: 'bold',
|
||||
marginTop: 12
|
||||
},
|
||||
account: {
|
||||
marginTop: 4
|
||||
}
|
||||
})
|
||||
|
||||
export default AccountInformation
|
81
src/screens/Shared/Account/Toots.tsx
Normal file
81
src/screens/Shared/Account/Toots.tsx
Normal file
@ -0,0 +1,81 @@
|
||||
import React, { useRef, useState } from 'react'
|
||||
import { Dimensions, FlatList, View } from 'react-native'
|
||||
import SegmentedControl from '@react-native-community/segmented-control'
|
||||
|
||||
import Timeline from 'src/screens/Timelines/Timeline'
|
||||
|
||||
export interface Props {
|
||||
id: Mastodon.Account['id']
|
||||
}
|
||||
|
||||
const AccountToots: React.FC<Props> = ({ id }) => {
|
||||
const [segment, setSegment] = useState(0)
|
||||
const [segmentManuallyTriggered, setSegmentManuallyTriggered] = useState(
|
||||
false
|
||||
)
|
||||
const horizontalPaging = useRef<any>()
|
||||
|
||||
const pages: ['Account_Default', 'Account_All', 'Account_Media'] = [
|
||||
'Account_Default',
|
||||
'Account_All',
|
||||
'Account_Media'
|
||||
]
|
||||
|
||||
return (
|
||||
<>
|
||||
<SegmentedControl
|
||||
values={['嘟嘟', '嘟嘟和回复', '媒体']}
|
||||
selectedIndex={segment}
|
||||
onChange={({ nativeEvent }) => {
|
||||
setSegmentManuallyTriggered(true)
|
||||
setSegment(nativeEvent.selectedSegmentIndex)
|
||||
horizontalPaging.current.scrollToIndex({
|
||||
index: nativeEvent.selectedSegmentIndex
|
||||
})
|
||||
}}
|
||||
style={{ width: '100%', height: 30 }}
|
||||
/>
|
||||
<FlatList
|
||||
style={{ width: Dimensions.get('window').width, height: '100%' }}
|
||||
data={pages}
|
||||
keyExtractor={page => page}
|
||||
renderItem={({ item, index }) => {
|
||||
return (
|
||||
<View style={{ width: Dimensions.get('window').width }}>
|
||||
<Timeline
|
||||
key={index}
|
||||
page={item}
|
||||
account={id}
|
||||
disableRefresh
|
||||
scrollEnabled={false}
|
||||
/>
|
||||
</View>
|
||||
)
|
||||
}}
|
||||
ref={horizontalPaging}
|
||||
bounces={false}
|
||||
getItemLayout={(data, index) => ({
|
||||
length: Dimensions.get('window').width,
|
||||
offset: Dimensions.get('window').width * index,
|
||||
index
|
||||
})}
|
||||
horizontal
|
||||
onMomentumScrollEnd={() => {
|
||||
setSegmentManuallyTriggered(false)
|
||||
}}
|
||||
onScroll={({ nativeEvent }) =>
|
||||
!segmentManuallyTriggered &&
|
||||
setSegment(
|
||||
nativeEvent.contentOffset.x <= Dimensions.get('window').width / 3
|
||||
? 0
|
||||
: 1
|
||||
)
|
||||
}
|
||||
pagingEnabled
|
||||
showsHorizontalScrollIndicator={false}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default AccountToots
|
@ -5,8 +5,27 @@ import ScreenSharedHashtag from 'src/screens/Shared/Hashtag'
|
||||
import ScreenSharedToot from 'src/screens/Shared/Toot'
|
||||
import ScreenSharedWebview from 'src/screens/Shared/Webview'
|
||||
import PostToot from 'src/screens/Shared/Compose'
|
||||
import { TypedNavigator } from '@react-navigation/native'
|
||||
import { NativeStackNavigationOptions } from 'react-native-screens/lib/typescript'
|
||||
import {
|
||||
NativeStackNavigationEventMap,
|
||||
NativeStackNavigatorProps
|
||||
} from 'react-native-screens/lib/typescript/types'
|
||||
|
||||
const sharedScreens = (Stack: any) => {
|
||||
const sharedScreens = (
|
||||
Stack: TypedNavigator<
|
||||
Record<string, object | undefined>,
|
||||
any,
|
||||
NativeStackNavigationOptions,
|
||||
NativeStackNavigationEventMap,
|
||||
({
|
||||
initialRouteName,
|
||||
children,
|
||||
screenOptions,
|
||||
...rest
|
||||
}: NativeStackNavigatorProps) => JSX.Element
|
||||
>
|
||||
) => {
|
||||
return [
|
||||
<Stack.Screen
|
||||
key='Screen-Shared-Account'
|
||||
@ -15,7 +34,7 @@ const sharedScreens = (Stack: any) => {
|
||||
options={{
|
||||
headerTranslucent: true,
|
||||
headerStyle: { backgroundColor: 'rgba(255, 255, 255, 0)' },
|
||||
headerCenter: () => {}
|
||||
headerCenter: () => <></>
|
||||
}}
|
||||
/>,
|
||||
<Stack.Screen
|
||||
|
@ -3,7 +3,8 @@ import { ActivityIndicator, AppState, FlatList, Text, View } from 'react-native'
|
||||
import { setFocusHandler, useInfiniteQuery } from 'react-query'
|
||||
|
||||
import StatusInNotifications from 'src/components/StatusInNotifications'
|
||||
import StatusInTimeline from 'src/components/StatusInTimeline'
|
||||
import TimelineDefault from 'src/components/TimelineDefault'
|
||||
import TimelineConversation from 'src/components/TimelineConversation'
|
||||
import { timelineFetch } from 'src/utils/fetches/timelineFetch'
|
||||
|
||||
// Opening nesting hashtag pages
|
||||
@ -37,10 +38,7 @@ const Timeline: React.FC<Props> = ({
|
||||
return () => AppState.removeEventListener('change', handleAppStateChange)
|
||||
})
|
||||
|
||||
const queryKey: App.QueryKey = [
|
||||
page,
|
||||
{ page, hashtag, list, toot, account }
|
||||
]
|
||||
const queryKey: App.QueryKey = [page, { page, hashtag, list, toot, account }]
|
||||
const {
|
||||
isLoading,
|
||||
isFetchingMore,
|
||||
@ -50,9 +48,7 @@ const Timeline: React.FC<Props> = ({
|
||||
fetchMore
|
||||
} = useInfiniteQuery(queryKey, timelineFetch)
|
||||
const flattenData = data ? data.flatMap(d => [...d?.toots]) : []
|
||||
// if (page==='Toot'){
|
||||
// console.log(data)
|
||||
// }
|
||||
// const flattenPointer = data ? data.flatMap(d => [d?.pointer]) : []
|
||||
|
||||
let content
|
||||
if (!isSuccess) {
|
||||
@ -67,18 +63,30 @@ const Timeline: React.FC<Props> = ({
|
||||
scrollEnabled={scrollEnabled} // For timeline in Account view
|
||||
data={flattenData}
|
||||
keyExtractor={({ id }) => id}
|
||||
renderItem={({ item, index, separators }) =>
|
||||
page === 'Notifications' ? (
|
||||
<StatusInNotifications
|
||||
key={index}
|
||||
notification={item}
|
||||
queryKey={queryKey}
|
||||
/>
|
||||
) : (
|
||||
<StatusInTimeline key={index} status={item} queryKey={queryKey} />
|
||||
)
|
||||
}
|
||||
// {...(state.pointer && { initialScrollIndex: state.pointer })}
|
||||
renderItem={({ item, index, separators }) => {
|
||||
switch (page) {
|
||||
case 'Conversations':
|
||||
return <TimelineConversation key={index} item={item} />
|
||||
case 'Notifications':
|
||||
return (
|
||||
<StatusInNotifications
|
||||
key={index}
|
||||
notification={item}
|
||||
queryKey={queryKey}
|
||||
/>
|
||||
)
|
||||
default:
|
||||
return (
|
||||
<TimelineDefault
|
||||
key={index}
|
||||
item={item}
|
||||
queryKey={queryKey}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}}
|
||||
// require getItemLayout
|
||||
// {...(flattenPointer[0] && { initialScrollIndex: flattenPointer[0] })}
|
||||
{...(!disableRefresh && {
|
||||
onRefresh: () =>
|
||||
fetchMore(
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { configureStore } from '@reduxjs/toolkit'
|
||||
import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit'
|
||||
import { persistReducer, persistStore } from 'redux-persist'
|
||||
import createSecureStore from 'redux-persist-expo-securestore'
|
||||
|
||||
@ -14,7 +14,12 @@ const instancesPersistConfig = {
|
||||
const store = configureStore({
|
||||
reducer: {
|
||||
instances: persistReducer(instancesPersistConfig, instancesSlice)
|
||||
}
|
||||
},
|
||||
middleware: getDefaultMiddleware({
|
||||
serializableCheck: {
|
||||
ignoredActions: ['persist/PERSIST']
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
let persistor = persistStore(store)
|
||||
|
10
src/utils/fetches/listsFetch.ts
Normal file
10
src/utils/fetches/listsFetch.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import client from 'src/api/client'
|
||||
|
||||
export const listsFetch = async () => {
|
||||
const res = await client({
|
||||
method: 'get',
|
||||
instance: 'local',
|
||||
endpoint: 'lists'
|
||||
})
|
||||
return Promise.resolve(res.body)
|
||||
}
|
@ -47,7 +47,7 @@ export const timelineFetch = async (
|
||||
endpoint: 'timelines/home',
|
||||
query
|
||||
})
|
||||
return Promise.resolve({ toots: res.body })
|
||||
return Promise.resolve({ toots: res.body, pointer: null })
|
||||
|
||||
case 'Local':
|
||||
query.local = 'true'
|
||||
@ -57,7 +57,7 @@ export const timelineFetch = async (
|
||||
endpoint: 'timelines/public',
|
||||
query
|
||||
})
|
||||
return Promise.resolve({ toots: res.body })
|
||||
return Promise.resolve({ toots: res.body, pointer: null })
|
||||
|
||||
case 'LocalPublic':
|
||||
res = await client({
|
||||
@ -66,7 +66,7 @@ export const timelineFetch = async (
|
||||
endpoint: 'timelines/public',
|
||||
query
|
||||
})
|
||||
return Promise.resolve({ toots: res.body })
|
||||
return Promise.resolve({ toots: res.body, pointer: null })
|
||||
|
||||
case 'RemotePublic':
|
||||
res = await client({
|
||||
@ -75,7 +75,7 @@ export const timelineFetch = async (
|
||||
endpoint: 'timelines/public',
|
||||
query
|
||||
})
|
||||
return Promise.resolve({ toots: res.body })
|
||||
return Promise.resolve({ toots: res.body, pointer: null })
|
||||
|
||||
case 'Notifications':
|
||||
res = await client({
|
||||
@ -84,7 +84,7 @@ export const timelineFetch = async (
|
||||
endpoint: 'notifications',
|
||||
query
|
||||
})
|
||||
return Promise.resolve({ toots: res.body })
|
||||
return Promise.resolve({ toots: res.body, pointer: null })
|
||||
|
||||
case 'Account_Default':
|
||||
res = await client({
|
||||
@ -105,7 +105,7 @@ export const timelineFetch = async (
|
||||
}
|
||||
})
|
||||
toots = uniqBy([...toots, ...res.body], 'id')
|
||||
return Promise.resolve({ toots: toots })
|
||||
return Promise.resolve({ toots: toots, pointer: null })
|
||||
|
||||
case 'Account_All':
|
||||
res = await client({
|
||||
@ -114,7 +114,7 @@ export const timelineFetch = async (
|
||||
endpoint: `accounts/${account}/statuses`,
|
||||
query
|
||||
})
|
||||
return Promise.resolve({ toots: res.body })
|
||||
return Promise.resolve({ toots: res.body, pointer: null })
|
||||
|
||||
case 'Account_Media':
|
||||
res = await client({
|
||||
@ -125,7 +125,7 @@ export const timelineFetch = async (
|
||||
only_media: 'true'
|
||||
}
|
||||
})
|
||||
return Promise.resolve({ toots: res.body })
|
||||
return Promise.resolve({ toots: res.body, pointer: null })
|
||||
|
||||
case 'Hashtag':
|
||||
res = await client({
|
||||
@ -134,18 +134,43 @@ export const timelineFetch = async (
|
||||
endpoint: `timelines/tag/${hashtag}`,
|
||||
query
|
||||
})
|
||||
return Promise.resolve({ toots: res.body })
|
||||
return Promise.resolve({ toots: res.body, pointer: null })
|
||||
|
||||
// case 'List':
|
||||
// res = await client({
|
||||
// method: 'get',
|
||||
// instance: 'local',
|
||||
// endpoint: `timelines/list/${list}`,
|
||||
// query
|
||||
// })
|
||||
// return {
|
||||
// toots: res.body
|
||||
// }
|
||||
case 'Conversations':
|
||||
res = await client({
|
||||
method: 'get',
|
||||
instance: 'local',
|
||||
endpoint: `conversations`,
|
||||
query
|
||||
})
|
||||
return Promise.resolve({ toots: res.body, pointer: null })
|
||||
|
||||
case 'Bookmarks':
|
||||
res = await client({
|
||||
method: 'get',
|
||||
instance: 'local',
|
||||
endpoint: `bookmarks`,
|
||||
query
|
||||
})
|
||||
return Promise.resolve({ toots: res.body, pointer: null })
|
||||
|
||||
case 'Favourites':
|
||||
res = await client({
|
||||
method: 'get',
|
||||
instance: 'local',
|
||||
endpoint: `favourites`,
|
||||
query
|
||||
})
|
||||
return Promise.resolve({ toots: res.body, pointer: null })
|
||||
|
||||
case 'List':
|
||||
res = await client({
|
||||
method: 'get',
|
||||
instance: 'local',
|
||||
endpoint: `timelines/list/${list}`,
|
||||
query
|
||||
})
|
||||
return Promise.resolve({ toots: res.body, pointer: null })
|
||||
|
||||
case 'Toot':
|
||||
const current = await client({
|
||||
@ -168,6 +193,6 @@ export const timelineFetch = async (
|
||||
})
|
||||
|
||||
default:
|
||||
console.error('First time fetching timeline error')
|
||||
console.error('Page is not provided')
|
||||
}
|
||||
}
|
||||
|
@ -5039,6 +5039,11 @@ react-native-screens@~2.10.1:
|
||||
resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-2.10.1.tgz#06d22fae87ef0ce51c616c34a199726db1403b95"
|
||||
integrity sha512-Z2kKSk4AwWRQNCBmTjViuBQK0/Lx0jc25TZptn/2gKYUCOuVRvCekoA26u0Tsb3BIQ8tWDsZW14OwDlFUXW1aw==
|
||||
|
||||
react-native-shimmer-placeholder@^2.0.6:
|
||||
version "2.0.6"
|
||||
resolved "https://registry.yarnpkg.com/react-native-shimmer-placeholder/-/react-native-shimmer-placeholder-2.0.6.tgz#a6626d955945edb1aa01f8863f3e039a738d53d1"
|
||||
integrity sha512-eq0Jxi/j/WseijfSeNjoAsaz1164XUCDvKpG/+My+c5YeVMfjTnl9SwoVAIr9uOpuDXXia67j8xME+eFJZvBXw==
|
||||
|
||||
react-native-toast-message@^1.3.4:
|
||||
version "1.3.4"
|
||||
resolved "https://registry.yarnpkg.com/react-native-toast-message/-/react-native-toast-message-1.3.4.tgz#19ea1c5d3ad8e9d12f7550c4719a9e0258dca6bd"
|
||||
|
Loading…
x
Reference in New Issue
Block a user