Rewrap pages in ScrollViews

This commit is contained in:
Nat 2022-05-16 17:10:06 -07:00
parent 52e8f8f59b
commit 985cbe6ca1
8 changed files with 138 additions and 85 deletions

View File

@ -1,5 +1,12 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { View, TextInput, Text, Dimensions } from "react-native"; import {
ScrollView,
TouchableOpacity,
View,
TextInput,
Text,
Dimensions
} from "react-native";
import { TabView, TabBar, SceneMap } from "react-native-tab-view"; import { TabView, TabBar, SceneMap } from "react-native-tab-view";
@ -142,24 +149,26 @@ const Discover = (props) => {
return ( return (
<> <>
{ state.loaded { state.loaded
? <> ? <ScrollView>
<TouchableWithoutFeedback <View style = { styles.form.container }>
onPress = { () => props.navigation.navigate("Search") }> <TextInput
<View style = { styles.form }> style = { styles.form.input }
<View style = { styles.searchBarContainer }> placeholder = "Search..."
<Text style = { styles.searchBar }> onPressIn = {
Search... () => props.navigation.navigate("Search")
</Text> }/>
</View> <TouchableOpacity
</View> style = { styles.form.submit }>
</TouchableWithoutFeedback> <Ionicons name="search" size={24} color="black" />
</TouchableOpacity>
</View>
<TabView <TabView
navigationState = { { index, routes } } navigationState = { { index, routes } }
renderScene = { renderScene } renderScene = { renderScene }
renderTabBar = { renderTabBar } renderTabBar = { renderTabBar }
onIndexChange = { setIndex } onIndexChange = { setIndex }
initialLayout = { { width: SCREEN_WIDTH } } /> initialLayout = { { width: SCREEN_WIDTH } } />
</> </ScrollView>
: <></> : <></>
} }
</> </>
@ -169,10 +178,25 @@ const Discover = (props) => {
const SCREEN_WIDTH = Dimensions.get("window").width; const SCREEN_WIDTH = Dimensions.get("window").width;
const styles = { const styles = {
form: { form: {
justifyContent: "center", container: {
backgroundColor: "white", flexDirection: "row",
padding: 20 justifyContent: "center",
backgroundColor: "white",
padding: 20,
},
input: {
flexGrow: 1,
padding: 10,
fontSize: 17,
color: "#888"
},
submit: {
padding: 20,
}
}, },
searchBar: { searchBar: {
padding: 10, padding: 10,
fontSize: 17, fontSize: 17,

View File

@ -1,5 +1,6 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { import {
ScrollView,
View, View,
TextInput, TextInput,
Text, Text,
@ -7,7 +8,7 @@ import {
Image, Image,
} from "react-native"; } from "react-native";
import { TabView, TabBar, SceneMap } from "react-native-tab-view"; import { TabView, TabBar, SceneMap } from "react-native-tab-view";
import { FontAwesome } from '@expo/vector-icons'; import { Ionicons, FontAwesome5 } from '@expo/vector-icons';
import AsyncStorage from "@react-native-async-storage/async-storage"; import AsyncStorage from "@react-native-async-storage/async-storage";
import * as requests from "src/requests"; import * as requests from "src/requests";
@ -112,7 +113,7 @@ const Search = ({navigation}) => {
const [ routes ] = useState([ const [ routes ] = useState([
{ {
key: "accounts", key: "accounts",
icon: "user", icon: "user-alt",
}, },
{ {
key: "hashtags", key: "hashtags",
@ -152,7 +153,7 @@ const Search = ({navigation}) => {
); );
const renderIcon = ({ route, color }) => ( const renderIcon = ({ route, color }) => (
<FontAwesome <FontAwesome5
name = { route.icon } name = { route.icon }
size = { 24 } size = { 24 }
color = { color } /> color = { color } />
@ -161,7 +162,7 @@ const Search = ({navigation}) => {
return ( return (
<> <>
{ state.loaded { state.loaded
? <> ? <ScrollView>
<View style = { styles.form.container }> <View style = { styles.form.container }>
<TextInput <TextInput
style = { styles.form.input } style = { styles.form.input }
@ -182,7 +183,7 @@ const Search = ({navigation}) => {
<TouchableOpacity <TouchableOpacity
onPress = { _handleSearch } onPress = { _handleSearch }
style = { styles.form.submit }> style = { styles.form.submit }>
<FontAwesome name="search" size={24} color="black" /> <Ionicons name="search" size={24} color="black" />
</TouchableOpacity> </TouchableOpacity>
</View> </View>
{ state.results { state.results
@ -194,7 +195,7 @@ const Search = ({navigation}) => {
initialLayout = { { width: SCREEN_WIDTH } } /> initialLayout = { { width: SCREEN_WIDTH } } />
: <></> : <></>
} }
</> </ScrollView>
: <></> : <></>
} }
</> </>

View File

@ -1,14 +1,14 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { View, Image, Dimensions, Text } from "react-native"; import { ScrollView, View, Image, Dimensions, Text } from "react-native";
import PagedGrid from "src/components/posts/paged-grid"; import PagedGrid from "src/components/posts/paged-grid";
import * as requests from "src/requests"; import * as requests from "src/requests";
import AsyncStorage from "@react-native-async-storage/async-storage"; import AsyncStorage from "@react-native-async-storage/async-storage";
const ViewHashtag = ({navigation}) => { const ViewHashtag = ({ navigation, route }) => {
const FETCH_LIMIT = 18; const FETCH_LIMIT = 18;
let [state, setState] = useState({ let [state, setState] = useState({
tag: navigation.getParam("tag", null), tag: route.params.tag,
posts: [], posts: [],
offset: 0, offset: 0,
followed: false, followed: false,
@ -66,10 +66,16 @@ const ViewHashtag = ({navigation}) => {
}); });
}; };
const latest = state.tag.history[0]; // A hashtag's history describes how actively it's being used. There's
// one element in the history array for every set interval of time.
// state.tag.history may be undefined, and its length might be 0.
let latest = null;
if (state.tag.history && state.tag.history.length > 0) {
latest = state.tag.history[0];
}
return ( return (
<> <ScrollView>
<View> <View>
<View style = { styles.headerContainer }> <View style = { styles.headerContainer }>
<View> <View>
@ -105,17 +111,19 @@ const ViewHashtag = ({navigation}) => {
</View> </View>
<> <>
{ state.loaded && state.posts.length > 0 { state.loaded && state.posts.length > 0
? <PagedGrid ? state.posts.length > 0
navigation = { navigation } ? <PagedGrid
posts = { state.posts } navigation = { navigation }
onShowMore = { _handleShowMore } /> posts = { state.posts }
: <Text style = { styles.nothing }> onShowMore = { _handleShowMore } />
Nothing to show : <Text style = { styles.nothing }>
</Text> Nothing to show
</Text>
: <></>
} }
</> </>
</View> </View>
</> </ScrollView>
); );
}; };

View File

@ -6,6 +6,7 @@ import {
Text, Text,
TouchableOpacity, TouchableOpacity,
FlatList, FlatList,
ScrollView,
} from "react-native"; } from "react-native";
import * as Linking from "expo-linking"; import * as Linking from "expo-linking";
@ -13,7 +14,12 @@ import AsyncStorage from "@react-native-async-storage/async-storage";
import { activeOrNot } from "src/interface/interactions"; import { activeOrNot } from "src/interface/interactions";
import HTML from "react-native-render-html"; import HTML from "react-native-render-html";
import { withLeadingAcct, withoutHTML, pluralize } from "src/interface/rendering"; import {
withLeadingAcct,
withoutHTML,
pluralize,
StatusBarSpace,
} from "src/interface/rendering";
import * as requests from "src/requests"; import * as requests from "src/requests";
import GridView from "src/components/posts/grid-view"; import GridView from "src/components/posts/grid-view";
@ -56,11 +62,11 @@ const HTMLLink = ({link}) => {
} }
} }
const ViewProfile = ({navigation}) => { const ViewProfile = ({ navigation, route }) => {
// As rendered when opened from somewhere other than the tab bar // As rendered when opened from somewhere other than the tab bar
const [state, setState] = useState({ const [state, setState] = useState({
loaded: false, loaded: false,
profile: navigation.getParam("profile"), profile: route.params.profile,
}); });
useEffect(() => { useEffect(() => {
@ -159,9 +165,7 @@ const ViewProfile = ({navigation}) => {
return ( return (
<> <>
{ state.loaded { state.loaded
? <> ? <ScrollView>
active = { navigation.getParam("originTab") }
navigation = { navigation }>
<RawProfile <RawProfile
navigation = { navigation } navigation = { navigation }
onFollow = { _handleFollow } onFollow = { _handleFollow }
@ -172,7 +176,7 @@ const ViewProfile = ({navigation}) => {
listedUsers = { state.listedUsers } listedUsers = { state.listedUsers }
followed = { state.followed } followed = { state.followed }
posts = { state.posts }/> posts = { state.posts }/>
</> </ScrollView>
: <></> : <></>
} }
</> </>
@ -184,57 +188,65 @@ const Profile = ({ navigation }) => {
loaded: false, loaded: false,
}); });
useEffect(() => { const init = async () => {
let profile; const [
let notifs; profilePair,
let domain; notifPair,
let accessToken; instancePair,
tokenPair
] = await AsyncStorage.multiGet([
"@user_profile",
"@user_notifications",
"@user_instance",
"@user_token",
]);
AsyncStorage const profile = JSON.parse(profilePair[1]);
.multiGet([ const notifs = JSON.parse(notifPair[1]);
const instance = instancePair[1];
const accessToken = JSON.parse(tokenPair[1]).access_token;
const latestProfile =
await requests.fetchProfile(instance, profile.id, accessToken);
const posts =
await requests.fetchAccountStatuses(instance, profile.id, accessToken);
const followers =
await requests.fetchFollowers(instance, profile.id, accessToken);
const latestProfileString = JSON.stringify(latestProfile);
// Update the profile in AsyncStorage if it's changed
if(latestProfileString != JSON.stringify(profile)) {
await AsyncStorage.setItem(
"@user_profile", "@user_profile",
"@user_notifications", latestProfileString
"@user_instance", );
"@user_token", }
])
.then(([profilePair, notifPair, domainPair, tokenPair]) => {
profile = JSON.parse(profilePair[1]);
notifs = JSON.parse(notifPair[1]);
domain = domainPair[1];
accessToken = JSON.parse(tokenPair[1]).access_token;
return Promise.all([ setState({...state,
requests.fetchProfile(domain, profile.id), profile: latestProfile,
requests.fetchAccountStatuses(domain, profile.id, accessToken), notifs: notifs,
requests.fetchFollowers(domain, profile.id, accessToken), posts: posts,
]);
})
.then(([latestProfile, posts, followers]) => {
if(JSON.stringify(latestProfile) != JSON.stringify(profile)) {
profile = latestProfile
}
setState({...state,
profile: profile,
notifs: notifs,
posts: posts,
listedUsers: followers, listedUsers: followers,
loaded: true, loaded: true,
}); });
}); };
}, []);
useEffect(() => { init(); }, []);
return ( return (
<> <>
<StatusBarSpace/>
{ state.loaded { state.loaded
? <> ? <ScrollView>
<RawProfile <RawProfile
navigation = { navigation } navigation = { navigation }
own = { true } own = { true }
profile = { state.profile } profile = { state.profile }
posts = { state.posts } posts = { state.posts }
listedUsers = { state.listedUsers } listedUsers = { state.listedUsers }
notifs = { state.notifs }/> notifs = { state.notifs }/>
</> </ScrollView>
: <></> : <></>
} }
</> </>

View File

@ -1,6 +1,7 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { import {
ScrollView,
SafeAreaView, SafeAreaView,
View, View,
TextInput, TextInput,
@ -134,7 +135,7 @@ const Settings = (props) => {
return ( return (
<> <>
{ state.loaded { state.loaded
? <> ? <ScrollView>
<View style = { styles.avatar.container }> <View style = { styles.avatar.container }>
<Image <Image
source = { { uri: state.newAvatar.uri } } source = { { uri: state.newAvatar.uri } }
@ -215,7 +216,7 @@ const Settings = (props) => {
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
</View> </View>
</> </ScrollView>
: <></> : <></>
} }
</> </>

View File

@ -40,7 +40,7 @@ const GridView = (props) => {
&& p.media_attachments.length > 0 && p.media_attachments.length > 0
); );
let rows = partition(props.posts, 3); let rows = partition(postsWithMedia, 3);
return ( return (
<View> <View>
{ {

View File

@ -80,6 +80,12 @@ export const RawPost = (props) => {
}); });
}; };
useEffect(() => {
if (props.onRendered != null) {
props.onRendered();
}
}, []);
return ( return (
<View> <View>
<View style = { styles.postHeader }> <View style = { styles.postHeader }>
@ -349,6 +355,7 @@ export const PostByData = (props) => {
<RawPost <RawPost
data = { state.data } data = { state.data }
dimensions = { state.dimensions } dimensions = { state.dimensions }
onRendered = { props.onRendered }
onFavourite = { _handleFavourite } onFavourite = { _handleFavourite }
onReblog = { _handleReblog } onReblog = { _handleReblog }
onBookmark = { _handleDelete } onBookmark = { _handleDelete }

View File

@ -104,8 +104,8 @@ export async function verifyCredentials(domain, token) {
return resp.json(); return resp.json();
} }
export async function fetchProfile(domain, id) { export async function fetchProfile(domain, id, token) {
const resp = await get(`https://${domain}/api/v1/accounts/${id}`); const resp = await get(`https://${domain}/api/v1/accounts/${id}`, token);
return resp.json(); return resp.json();
} }