Rewrap pages in ScrollViews
This commit is contained in:
parent
52e8f8f59b
commit
985cbe6ca1
|
@ -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>
|
}/>
|
||||||
|
<TouchableOpacity
|
||||||
|
style = { styles.form.submit }>
|
||||||
|
<Ionicons name="search" size={24} color="black" />
|
||||||
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
|
||||||
</TouchableWithoutFeedback>
|
|
||||||
<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: {
|
||||||
|
container: {
|
||||||
|
flexDirection: "row",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
backgroundColor: "white",
|
backgroundColor: "white",
|
||||||
padding: 20
|
padding: 20,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
input: {
|
||||||
|
flexGrow: 1,
|
||||||
|
padding: 10,
|
||||||
|
fontSize: 17,
|
||||||
|
color: "#888"
|
||||||
|
},
|
||||||
|
|
||||||
|
submit: {
|
||||||
|
padding: 20,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
searchBar: {
|
searchBar: {
|
||||||
padding: 10,
|
padding: 10,
|
||||||
fontSize: 17,
|
fontSize: 17,
|
||||||
|
|
|
@ -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>
|
||||||
: <></>
|
: <></>
|
||||||
}
|
}
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -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,6 +111,7 @@ const ViewHashtag = ({navigation}) => {
|
||||||
</View>
|
</View>
|
||||||
<>
|
<>
|
||||||
{ state.loaded && state.posts.length > 0
|
{ state.loaded && state.posts.length > 0
|
||||||
|
? state.posts.length > 0
|
||||||
? <PagedGrid
|
? <PagedGrid
|
||||||
navigation = { navigation }
|
navigation = { navigation }
|
||||||
posts = { state.posts }
|
posts = { state.posts }
|
||||||
|
@ -112,10 +119,11 @@ const ViewHashtag = ({navigation}) => {
|
||||||
: <Text style = { styles.nothing }>
|
: <Text style = { styles.nothing }>
|
||||||
Nothing to show
|
Nothing to show
|
||||||
</Text>
|
</Text>
|
||||||
|
: <></>
|
||||||
}
|
}
|
||||||
</>
|
</>
|
||||||
</View>
|
</View>
|
||||||
</>
|
</ScrollView>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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,49 +188,57 @@ const Profile = ({ navigation }) => {
|
||||||
loaded: false,
|
loaded: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
const init = async () => {
|
||||||
let profile;
|
const [
|
||||||
let notifs;
|
profilePair,
|
||||||
let domain;
|
notifPair,
|
||||||
let accessToken;
|
instancePair,
|
||||||
|
tokenPair
|
||||||
AsyncStorage
|
] = await AsyncStorage.multiGet([
|
||||||
.multiGet([
|
|
||||||
"@user_profile",
|
"@user_profile",
|
||||||
"@user_notifications",
|
"@user_notifications",
|
||||||
"@user_instance",
|
"@user_instance",
|
||||||
"@user_token",
|
"@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([
|
|
||||||
requests.fetchProfile(domain, profile.id),
|
|
||||||
requests.fetchAccountStatuses(domain, profile.id, accessToken),
|
|
||||||
requests.fetchFollowers(domain, profile.id, accessToken),
|
|
||||||
]);
|
]);
|
||||||
})
|
|
||||||
.then(([latestProfile, posts, followers]) => {
|
const profile = JSON.parse(profilePair[1]);
|
||||||
if(JSON.stringify(latestProfile) != JSON.stringify(profile)) {
|
const notifs = JSON.parse(notifPair[1]);
|
||||||
profile = latestProfile
|
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",
|
||||||
|
latestProfileString
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
setState({...state,
|
setState({...state,
|
||||||
profile: profile,
|
profile: latestProfile,
|
||||||
notifs: notifs,
|
notifs: notifs,
|
||||||
posts: posts,
|
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 }
|
||||||
|
@ -234,7 +246,7 @@ const Profile = ({ navigation }) => {
|
||||||
posts = { state.posts }
|
posts = { state.posts }
|
||||||
listedUsers = { state.listedUsers }
|
listedUsers = { state.listedUsers }
|
||||||
notifs = { state.notifs }/>
|
notifs = { state.notifs }/>
|
||||||
</>
|
</ScrollView>
|
||||||
: <></>
|
: <></>
|
||||||
}
|
}
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -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>
|
||||||
: <></>
|
: <></>
|
||||||
}
|
}
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -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>
|
||||||
{
|
{
|
||||||
|
|
|
@ -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 }
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue