mirror of
https://github.com/tooot-app/app
synced 2025-01-30 18:24:50 +01:00
Updates
This commit is contained in:
parent
13efb56324
commit
796b0544c4
@ -86,6 +86,7 @@ GEM
|
|||||||
xcpretty (~> 0.3.0)
|
xcpretty (~> 0.3.0)
|
||||||
xcpretty-travis-formatter (>= 0.0.3)
|
xcpretty-travis-formatter (>= 0.0.3)
|
||||||
fastlane-plugin-json (1.0.0)
|
fastlane-plugin-json (1.0.0)
|
||||||
|
fastlane-plugin-sentry (1.8.0)
|
||||||
fastlane-plugin-versioning_android (0.1.0)
|
fastlane-plugin-versioning_android (0.1.0)
|
||||||
fastlane-plugin-yarn (1.2)
|
fastlane-plugin-yarn (1.2)
|
||||||
gh_inspector (1.1.3)
|
gh_inspector (1.1.3)
|
||||||
@ -200,6 +201,7 @@ PLATFORMS
|
|||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
fastlane
|
fastlane
|
||||||
fastlane-plugin-json
|
fastlane-plugin-json
|
||||||
|
fastlane-plugin-sentry
|
||||||
fastlane-plugin-versioning_android
|
fastlane-plugin-versioning_android
|
||||||
fastlane-plugin-yarn
|
fastlane-plugin-yarn
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ fastlane_version "2.173.0"
|
|||||||
skip_docs
|
skip_docs
|
||||||
|
|
||||||
ensure_env_vars(
|
ensure_env_vars(
|
||||||
env_vars: ["TOOOT_ENVIRONMENT"]
|
env_vars: ["TOOOT_ENVIRONMENT", "SENTRY_ORGANIZATION", "SENTRY_PROJECT", "SENTRY_AUTH_TOKEN"]
|
||||||
)
|
)
|
||||||
|
|
||||||
VERSIONS = read_json( json_path: "./package.json" )[:versions]
|
VERSIONS = read_json( json_path: "./package.json" )[:versions]
|
||||||
@ -15,7 +15,7 @@ case ENVIRONMENT
|
|||||||
when "development"
|
when "development"
|
||||||
GITHUB_RELEASE= ""
|
GITHUB_RELEASE= ""
|
||||||
when "staging"
|
when "staging"
|
||||||
GITHUB_RELEASE = "v#{VERSION}-rc#{VERSIONS[:patch]}"
|
GITHUB_RELEASE = "v#{VERSION}-#{VERSIONS[:patch]}"
|
||||||
when "production"
|
when "production"
|
||||||
GITHUB_RELEASE = "v#{VERSION}"
|
GITHUB_RELEASE = "v#{VERSION}"
|
||||||
end
|
end
|
||||||
@ -37,6 +37,15 @@ private_lane :update_expo_ios do
|
|||||||
set_info_plist_value( path: EXPO_PLIST, key: "EXUpdatesReleaseChannel", value: RELEASE_CHANNEL )
|
set_info_plist_value( path: EXPO_PLIST, key: "EXUpdatesReleaseChannel", value: RELEASE_CHANNEL )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
desc 'IOS: Upload dSYM'
|
||||||
|
lane :upload_symbols_ios do
|
||||||
|
download_dsyms
|
||||||
|
sentry_upload_dsym(
|
||||||
|
org_slug: ENV["SENTRY_ORGANIZATION"],
|
||||||
|
project_slug: ENV["SENTRY_PROJECT"]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
desc "ANDROID: Prepare play store"
|
desc "ANDROID: Prepare play store"
|
||||||
private_lane :prepare_playstore_android do
|
private_lane :prepare_playstore_android do
|
||||||
android_set_version_name( version_name: VERSION, gradle_file: "./android/app/build.gradle" )
|
android_set_version_name( version_name: VERSION, gradle_file: "./android/app/build.gradle" )
|
||||||
@ -77,13 +86,14 @@ private_lane :build_ios do
|
|||||||
when "staging"
|
when "staging"
|
||||||
prepare_appstore_ios
|
prepare_appstore_ios
|
||||||
match( type: "appstore", readonly: true )
|
match( type: "appstore", readonly: true )
|
||||||
build_ios_app( export_method: "app-store" )
|
build_ios_app( export_method: "app-store", include_symbols: true, include_bitcode: true )
|
||||||
upload_to_testflight(
|
upload_to_testflight(
|
||||||
demo_account_required: true,
|
demo_account_required: true,
|
||||||
distribute_external: true,
|
distribute_external: true,
|
||||||
groups: "内测用户",
|
groups: "内测用户",
|
||||||
changelog: "Ready for testing"
|
changelog: "Ready for testing"
|
||||||
)
|
)
|
||||||
|
upload_symbols_ios
|
||||||
when "production"
|
when "production"
|
||||||
prepare_appstore_ios
|
prepare_appstore_ios
|
||||||
match( type: "appstore", readonly: true )
|
match( type: "appstore", readonly: true )
|
||||||
|
@ -5,3 +5,4 @@
|
|||||||
gem 'fastlane-plugin-yarn'
|
gem 'fastlane-plugin-yarn'
|
||||||
gem 'fastlane-plugin-json'
|
gem 'fastlane-plugin-json'
|
||||||
gem 'fastlane-plugin-versioning_android'
|
gem 'fastlane-plugin-versioning_android'
|
||||||
|
gem 'fastlane-plugin-sentry'
|
||||||
|
@ -64,7 +64,7 @@
|
|||||||
"react-native-tab-view-viewpager-adapter": "^1.1.0",
|
"react-native-tab-view-viewpager-adapter": "^1.1.0",
|
||||||
"react-native-toast-message": "^1.4.3",
|
"react-native-toast-message": "^1.4.3",
|
||||||
"react-native-unimodules": "~0.12.0",
|
"react-native-unimodules": "~0.12.0",
|
||||||
"react-query": "^3.8.2",
|
"react-query": "^3.9.7",
|
||||||
"react-redux": "^7.2.2",
|
"react-redux": "^7.2.2",
|
||||||
"react-timeago": "^5.2.0",
|
"react-timeago": "^5.2.0",
|
||||||
"reconnecting-websocket": "^4.4.0",
|
"reconnecting-websocket": "^4.4.0",
|
||||||
|
@ -162,12 +162,12 @@ const ComponentInstance: React.FC<Props> = ({
|
|||||||
type='text'
|
type='text'
|
||||||
content={t('server.button.local')}
|
content={t('server.button.local')}
|
||||||
onPress={processUpdate}
|
onPress={processUpdate}
|
||||||
disabled={!instanceQuery.data?.uri || !agreed}
|
disabled={!instanceQuery.data?.uri}
|
||||||
loading={instanceQuery.isFetching || appsQuery.isFetching}
|
loading={instanceQuery.isFetching || appsQuery.isFetching}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<EULA agreed={agreed} setAgreed={setAgreed} />
|
{/* <EULA agreed={agreed} setAgreed={setAgreed} /> */}
|
||||||
|
|
||||||
<View>
|
<View>
|
||||||
<Placeholder
|
<Placeholder
|
||||||
|
@ -82,19 +82,26 @@ const Timeline: React.FC<Props> = ({
|
|||||||
...queryKeyParams,
|
...queryKeyParams,
|
||||||
options: {
|
options: {
|
||||||
getPreviousPageParam: firstPage =>
|
getPreviousPageParam: firstPage =>
|
||||||
firstPage.links?.prev && {
|
firstPage?.links?.prev && {
|
||||||
min_id: firstPage.links.prev,
|
min_id: firstPage.links.prev,
|
||||||
// https://github.com/facebook/react-native/issues/25239#issuecomment-731100372
|
// https://github.com/facebook/react-native/issues/25239#issuecomment-731100372
|
||||||
limit: '6'
|
limit: '5'
|
||||||
},
|
},
|
||||||
|
|
||||||
getNextPageParam: lastPage =>
|
getNextPageParam: lastPage =>
|
||||||
lastPage.links?.next && { max_id: lastPage.links.next }
|
lastPage?.links?.next && { max_id: lastPage.links.next }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const flattenData = data?.pages ? data.pages.flatMap(d => [...d.body]) : []
|
const flattenData = data?.pages ? data.pages.flatMap(d => [...d.body]) : []
|
||||||
|
|
||||||
|
// Auto go back when toot page is empty
|
||||||
|
const navigation = useNavigation()
|
||||||
|
useEffect(() => {
|
||||||
|
if (toot && isSuccess && flattenData.length === 0) {
|
||||||
|
navigation.goBack()
|
||||||
|
}
|
||||||
|
}, [isSuccess, flattenData.length])
|
||||||
// Toot page auto scroll to selected toot
|
// Toot page auto scroll to selected toot
|
||||||
const flRef = useRef<FlatList<any>>(null)
|
const flRef = useRef<FlatList<any>>(null)
|
||||||
const scrolled = useRef(false)
|
const scrolled = useRef(false)
|
||||||
@ -119,13 +126,6 @@ const Timeline: React.FC<Props> = ({
|
|||||||
350
|
350
|
||||||
)
|
)
|
||||||
}, [])
|
}, [])
|
||||||
// Auto go back when toot page is empty
|
|
||||||
const navigation = useNavigation()
|
|
||||||
useEffect(() => {
|
|
||||||
if (toot && isSuccess && flattenData.length === 0) {
|
|
||||||
navigation.goBack()
|
|
||||||
}
|
|
||||||
}, [isSuccess, flattenData.length])
|
|
||||||
|
|
||||||
const keyExtractor = useCallback(({ id }) => id, [])
|
const keyExtractor = useCallback(({ id }) => id, [])
|
||||||
const renderItem = useCallback(
|
const renderItem = useCallback(
|
||||||
@ -233,26 +233,57 @@ const Timeline: React.FC<Props> = ({
|
|||||||
scrollY.value = nativeEvent.contentOffset.y
|
scrollY.value = nativeEvent.contentOffset.y
|
||||||
}, [])
|
}, [])
|
||||||
const onResponderRelease = useCallback(() => {
|
const onResponderRelease = useCallback(() => {
|
||||||
if (
|
if (!disableRefresh) {
|
||||||
scrollY.value <= -StyleConstants.Spacing.XL &&
|
const separation01 = -(
|
||||||
isFetchingLatest === 0 &&
|
(StyleConstants.Spacing.M * 2.5) / 2 +
|
||||||
!disableRefresh
|
StyleConstants.Font.Size.S / 2
|
||||||
) {
|
)
|
||||||
haptics('Light')
|
const separation02 = -(
|
||||||
setIsFetchingLatest(1)
|
StyleConstants.Spacing.M * 2.5 * 1.5 +
|
||||||
flRef.current?.scrollToOffset({
|
StyleConstants.Font.Size.S / 2
|
||||||
animated: true,
|
)
|
||||||
offset: 1
|
if (
|
||||||
})
|
scrollY.value <= separation02 &&
|
||||||
|
!isFetching &&
|
||||||
|
isFetchingLatest === 0
|
||||||
|
) {
|
||||||
|
haptics('Light')
|
||||||
|
queryClient.setQueryData<InfiniteData<any> | undefined>(
|
||||||
|
queryKey,
|
||||||
|
data => {
|
||||||
|
if (data?.pages[0].body.length === 0) {
|
||||||
|
return {
|
||||||
|
pages: data.pages.slice(1),
|
||||||
|
pageParams: data.pageParams.slice(1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
refetch()
|
||||||
|
} else if (
|
||||||
|
scrollY.value <= separation01 &&
|
||||||
|
!isFetching &&
|
||||||
|
isFetchingLatest === 0
|
||||||
|
) {
|
||||||
|
haptics('Light')
|
||||||
|
setIsFetchingLatest(1)
|
||||||
|
flRef.current?.scrollToOffset({
|
||||||
|
animated: true,
|
||||||
|
offset: 1
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [scrollY.value, isFetchingLatest, disableRefresh])
|
}, [scrollY.value, isFetching, isFetchingLatest, disableRefresh])
|
||||||
const headerPadding = useAnimatedStyle(() => {
|
const headerPadding = useAnimatedStyle(() => {
|
||||||
if (isFetchingLatest !== 0) {
|
return {
|
||||||
return { paddingTop: withTiming(StyleConstants.Spacing.XL) }
|
paddingTop:
|
||||||
} else {
|
isFetchingLatest !== 0 || (isFetching && !isLoading)
|
||||||
return { paddingTop: withTiming(0) }
|
? withTiming(StyleConstants.Spacing.M * 2.5)
|
||||||
|
: withTiming(0)
|
||||||
}
|
}
|
||||||
}, [isFetchingLatest])
|
}, [isFetchingLatest, isFetching, isLoading])
|
||||||
const ListHeaderComponent = useMemo(
|
const ListHeaderComponent = useMemo(
|
||||||
() => <Animated.View style={headerPadding} />,
|
() => <Animated.View style={headerPadding} />,
|
||||||
[]
|
[]
|
||||||
@ -267,7 +298,7 @@ const Timeline: React.FC<Props> = ({
|
|||||||
colors={[theme.primary]}
|
colors={[theme.primary]}
|
||||||
progressBackgroundColor={theme.background}
|
progressBackgroundColor={theme.background}
|
||||||
refreshing={isFetching || isLoading}
|
refreshing={isFetching || isLoading}
|
||||||
// onRefresh={() => refetch()}
|
onRefresh={() => refetch()}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@ -276,8 +307,14 @@ const Timeline: React.FC<Props> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TimelineRefresh isLoading={isLoading} disable={disableRefresh} />
|
<TimelineRefresh
|
||||||
|
scrollY={scrollY}
|
||||||
|
isLoading={isLoading}
|
||||||
|
isFetching={isFetching}
|
||||||
|
disable={disableRefresh}
|
||||||
|
/>
|
||||||
<FlatList
|
<FlatList
|
||||||
|
scrollEventThrottle={16}
|
||||||
onScroll={onScroll}
|
onScroll={onScroll}
|
||||||
onResponderRelease={onResponderRelease}
|
onResponderRelease={onResponderRelease}
|
||||||
ref={flRef}
|
ref={flRef}
|
||||||
|
@ -13,6 +13,7 @@ import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
|||||||
import { getLocalAccount } from '@utils/slices/instancesSlice'
|
import { getLocalAccount } from '@utils/slices/instancesSlice'
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
|
import { uniqBy } from 'lodash'
|
||||||
import React, { useCallback } from 'react'
|
import React, { useCallback } from 'react'
|
||||||
import { Pressable, StyleSheet, View } from 'react-native'
|
import { Pressable, StyleSheet, View } from 'react-native'
|
||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux'
|
||||||
@ -75,7 +76,6 @@ const TimelineDefault: React.FC<Props> = ({
|
|||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
disabled={queryKey && queryKey[1].toot !== undefined}
|
|
||||||
>
|
>
|
||||||
{item.reblog ? (
|
{item.reblog ? (
|
||||||
<TimelineActioned action='reblog' account={item.account} />
|
<TimelineActioned action='reblog' account={item.account} />
|
||||||
@ -143,11 +143,13 @@ const TimelineDefault: React.FC<Props> = ({
|
|||||||
queryKey={queryKey}
|
queryKey={queryKey}
|
||||||
rootQueryKey={rootQueryKey}
|
rootQueryKey={rootQueryKey}
|
||||||
status={actualStatus}
|
status={actualStatus}
|
||||||
accts={([actualStatus.account] as Mastodon.Account[] &
|
accts={uniqBy(
|
||||||
Mastodon.Mention[])
|
([actualStatus.account] as Mastodon.Account[] &
|
||||||
.concat(actualStatus.mentions)
|
Mastodon.Mention[])
|
||||||
.filter(d => d.id !== localAccount?.id)
|
.concat(actualStatus.mentions)
|
||||||
.map(d => d.acct)}
|
.filter(d => d.id !== localAccount?.id),
|
||||||
|
d => d.id
|
||||||
|
).map(d => d.acct)}
|
||||||
reblog={item.reblog ? true : false}
|
reblog={item.reblog ? true : false}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
@ -13,6 +13,7 @@ import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
|||||||
import { getLocalAccount } from '@utils/slices/instancesSlice'
|
import { getLocalAccount } from '@utils/slices/instancesSlice'
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
|
import { uniqBy } from 'lodash'
|
||||||
import React, { useCallback } from 'react'
|
import React, { useCallback } from 'react'
|
||||||
import { Pressable, StyleSheet, View } from 'react-native'
|
import { Pressable, StyleSheet, View } from 'react-native'
|
||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux'
|
||||||
@ -126,11 +127,13 @@ const TimelineNotifications: React.FC<Props> = ({
|
|||||||
<TimelineActions
|
<TimelineActions
|
||||||
queryKey={queryKey}
|
queryKey={queryKey}
|
||||||
status={notification.status}
|
status={notification.status}
|
||||||
accts={([notification.status.account] as Mastodon.Account[] &
|
accts={uniqBy(
|
||||||
Mastodon.Mention[])
|
([notification.status.account] as Mastodon.Account[] &
|
||||||
.concat(notification.status.mentions)
|
Mastodon.Mention[])
|
||||||
.filter(d => d.id !== localAccount?.id)
|
.concat(notification.status.mentions)
|
||||||
.map(d => d.acct)}
|
.filter(d => d.id !== localAccount?.id),
|
||||||
|
d => d.id
|
||||||
|
).map(d => d.acct)}
|
||||||
reblog={false}
|
reblog={false}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
@ -1,25 +1,164 @@
|
|||||||
|
import haptics from '@components/haptics'
|
||||||
|
import Icon from '@components/Icon'
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import React from 'react'
|
import React, { useCallback, useState } from 'react'
|
||||||
import { StyleSheet, View } from 'react-native'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { StyleSheet, Text, View } from 'react-native'
|
||||||
import { Circle } from 'react-native-animated-spinkit'
|
import { Circle } from 'react-native-animated-spinkit'
|
||||||
|
import Animated, {
|
||||||
|
Extrapolate,
|
||||||
|
interpolate,
|
||||||
|
runOnJS,
|
||||||
|
useAnimatedReaction,
|
||||||
|
useAnimatedStyle,
|
||||||
|
useSharedValue,
|
||||||
|
withTiming
|
||||||
|
} from 'react-native-reanimated'
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
|
scrollY: Animated.SharedValue<number>
|
||||||
isLoading: boolean
|
isLoading: boolean
|
||||||
|
isFetching: boolean
|
||||||
disable?: boolean
|
disable?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const TimelineRefresh: React.FC<Props> = ({ isLoading, disable = false }) => {
|
const CONTAINER_HEIGHT = StyleConstants.Spacing.M * 2.5
|
||||||
const { theme } = useTheme()
|
|
||||||
return !isLoading && !disable ? (
|
const TimelineRefresh = React.memo(
|
||||||
<View
|
({ scrollY, isLoading, isFetching, disable = false }: Props) => {
|
||||||
style={styles.base}
|
if (disable || isLoading) {
|
||||||
children={
|
return null
|
||||||
<Circle size={StyleConstants.Font.Size.L} color={theme.secondary} />
|
}
|
||||||
}
|
|
||||||
/>
|
const { t } = useTranslation('componentTimeline')
|
||||||
) : null
|
const { theme } = useTheme()
|
||||||
}
|
|
||||||
|
const separation01 = -(
|
||||||
|
CONTAINER_HEIGHT / 2 +
|
||||||
|
StyleConstants.Font.Size.S / 2
|
||||||
|
)
|
||||||
|
const separation02 = -(
|
||||||
|
CONTAINER_HEIGHT * 1.5 +
|
||||||
|
StyleConstants.Font.Size.S / 2
|
||||||
|
)
|
||||||
|
const [textRight, setTextRight] = useState(0)
|
||||||
|
const arrowY = useAnimatedStyle(() => ({
|
||||||
|
transform: [
|
||||||
|
{
|
||||||
|
translateY: interpolate(
|
||||||
|
scrollY.value,
|
||||||
|
[0, separation01],
|
||||||
|
[
|
||||||
|
-CONTAINER_HEIGHT / 2 - StyleConstants.Font.Size.M / 2,
|
||||||
|
CONTAINER_HEIGHT / 2 - StyleConstants.Font.Size.S / 2
|
||||||
|
],
|
||||||
|
Extrapolate.CLAMP
|
||||||
|
)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}))
|
||||||
|
const arrowTop = useAnimatedStyle(() => ({
|
||||||
|
marginTop:
|
||||||
|
scrollY.value < separation02
|
||||||
|
? withTiming(CONTAINER_HEIGHT)
|
||||||
|
: withTiming(0)
|
||||||
|
}))
|
||||||
|
|
||||||
|
const arrowStage = useSharedValue(0)
|
||||||
|
const onLayout = useCallback(
|
||||||
|
({ nativeEvent }) => {
|
||||||
|
if (nativeEvent.layout.x + nativeEvent.layout.width > textRight) {
|
||||||
|
setTextRight(nativeEvent.layout.x + nativeEvent.layout.width)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[textRight]
|
||||||
|
)
|
||||||
|
useAnimatedReaction(
|
||||||
|
() => {
|
||||||
|
if (isFetching) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
switch (arrowStage.value) {
|
||||||
|
case 0:
|
||||||
|
if (scrollY.value < separation01) {
|
||||||
|
arrowStage.value = 1
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
case 1:
|
||||||
|
if (scrollY.value < separation02) {
|
||||||
|
arrowStage.value = 2
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (scrollY.value > separation01) {
|
||||||
|
arrowStage.value = 0
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
case 2:
|
||||||
|
if (scrollY.value > separation02) {
|
||||||
|
arrowStage.value = 1
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data => {
|
||||||
|
if (data) {
|
||||||
|
runOnJS(haptics)('Light')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[isFetching]
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.base}>
|
||||||
|
{isFetching ? (
|
||||||
|
<View style={styles.container2}>
|
||||||
|
<Circle size={StyleConstants.Font.Size.L} color={theme.secondary} />
|
||||||
|
</View>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<View style={styles.container1}>
|
||||||
|
<Text
|
||||||
|
style={[styles.explanation, { color: theme.primary }]}
|
||||||
|
onLayout={onLayout}
|
||||||
|
children={t('refresh.fetchPreviousPage')}
|
||||||
|
/>
|
||||||
|
<Animated.View
|
||||||
|
style={[
|
||||||
|
{
|
||||||
|
position: 'absolute',
|
||||||
|
left: textRight + StyleConstants.Spacing.S
|
||||||
|
},
|
||||||
|
arrowY,
|
||||||
|
arrowTop
|
||||||
|
]}
|
||||||
|
children={
|
||||||
|
<Icon
|
||||||
|
name='ArrowLeft'
|
||||||
|
size={StyleConstants.Font.Size.M}
|
||||||
|
color={theme.primary}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<View style={styles.container2}>
|
||||||
|
<Text
|
||||||
|
style={[styles.explanation, { color: theme.primary }]}
|
||||||
|
onLayout={onLayout}
|
||||||
|
children={t('refresh.refetch')}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
(prev, next) =>
|
||||||
|
prev.isLoading === next.isLoading && prev.isFetching === next.isFetching
|
||||||
|
)
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
base: {
|
base: {
|
||||||
@ -27,9 +166,18 @@ const styles = StyleSheet.create({
|
|||||||
top: 0,
|
top: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
height: StyleConstants.Spacing.XL,
|
height: CONTAINER_HEIGHT * 2,
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center'
|
alignItems: 'center'
|
||||||
|
},
|
||||||
|
container1: {
|
||||||
|
flex: 1,
|
||||||
|
flexDirection: 'row',
|
||||||
|
height: CONTAINER_HEIGHT
|
||||||
|
},
|
||||||
|
container2: { height: CONTAINER_HEIGHT, justifyContent: 'center' },
|
||||||
|
explanation: {
|
||||||
|
fontSize: StyleConstants.Font.Size.S,
|
||||||
|
lineHeight: CONTAINER_HEIGHT
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -11,10 +11,9 @@ export default {
|
|||||||
end: {
|
end: {
|
||||||
message: 'The end, what about a cup of <0 />'
|
message: 'The end, what about a cup of <0 />'
|
||||||
},
|
},
|
||||||
header: {
|
refresh: {
|
||||||
explanation:
|
fetchPreviousPage: 'Refresh upwards',
|
||||||
'External instance might not be known to logged in instance, thus actions are not allowed but only for reading. You can switch to any instance in the settings.',
|
refetch: 'Refresh all'
|
||||||
button: 'Go to settings'
|
|
||||||
},
|
},
|
||||||
shared: {
|
shared: {
|
||||||
actioned: {
|
actioned: {
|
||||||
|
@ -11,10 +11,9 @@ export default {
|
|||||||
end: {
|
end: {
|
||||||
message: '居然刷到底了,喝杯 <0 /> 吧'
|
message: '居然刷到底了,喝杯 <0 /> 吧'
|
||||||
},
|
},
|
||||||
header: {
|
refresh: {
|
||||||
explanation:
|
fetchPreviousPage: '向上刷新',
|
||||||
'围观的社区可能不属于已经登录的社区的已知连结,因此只可围观嘟文,不能进行操作。设置里可以切换想要围观的社区。',
|
refetch: '完全刷新'
|
||||||
button: '前往设置'
|
|
||||||
},
|
},
|
||||||
shared: {
|
shared: {
|
||||||
actioned: {
|
actioned: {
|
||||||
|
@ -8736,10 +8736,10 @@ react-navigation@*, react-navigation@^4.4.3:
|
|||||||
"@react-navigation/core" "^3.7.9"
|
"@react-navigation/core" "^3.7.9"
|
||||||
"@react-navigation/native" "^3.8.3"
|
"@react-navigation/native" "^3.8.3"
|
||||||
|
|
||||||
react-query@^3.8.2:
|
react-query@^3.9.7:
|
||||||
version "3.8.2"
|
version "3.9.7"
|
||||||
resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.8.2.tgz#e2dac76b5d9b3465d854f4ca040a35ba4bcae1ae"
|
resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.9.7.tgz#324c697f418827c129c8c126d233c6052bb1e35e"
|
||||||
integrity sha512-Ha8+WZLIHOUkKhqE4+2RZZB03WvEWmNhN4WIIw3zWVCtR7blo2n2TXtu+d3YhaY1o6dt+sHT+J+zNV8IzR583w==
|
integrity sha512-vpQgRFOljd7Lr1wL8hOwxWzb7awLIjaeqaq6DJ1fzA8N9mK1fAkK+UVrt8WaXJGBfz7JEnfCiXuENQspk0N7Sw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "^7.5.5"
|
"@babel/runtime" "^7.5.5"
|
||||||
match-sorter "^6.0.2"
|
match-sorter "^6.0.2"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user