1
0
mirror of https://github.com/tooot-app/app synced 2025-06-05 22:19:13 +02:00

Added store review

This commit is contained in:
Zhiyuan Zheng
2021-01-18 00:23:40 +01:00
parent f977fdfa8b
commit 5c4f7ce8c7
20 changed files with 302 additions and 108 deletions

View File

@ -122,7 +122,7 @@ const Button: React.FC<Props> = ({
style={{ opacity: loading ? 0 : 1 }}
size={StyleConstants.Font.Size[size] * (size === 'L' ? 1.25 : 1)}
/>
{loading && loadingSpinkit}
{loading ? loadingSpinkit : null}
</>
)
case 'text':
@ -141,7 +141,7 @@ const Button: React.FC<Props> = ({
children={content}
testID='text'
/>
{loading && loadingSpinkit}
{loading ? loadingSpinkit : null}
</>
)
}

View File

@ -14,24 +14,55 @@ import { Image as ImageCache } from 'react-native-expo-image-cache'
import { useTheme } from '@utils/styles/ThemeManager'
type CancelPromise = ((reason?: Error) => void) | undefined
type ImageSize = { width: number; height: number }
interface ImageSizeOperation {
start: () => Promise<ImageSize>
start: () => Promise<string>
cancel: CancelPromise
}
const getImageSize = (uri: string): ImageSizeOperation => {
const getImageSize = ({
preview,
original,
remote
}: {
preview?: string
original: string
remote?: string
}): ImageSizeOperation => {
let cancel: CancelPromise
const start = (): Promise<ImageSize> =>
new Promise<{ width: number; height: number }>((resolve, reject) => {
const start = (): Promise<string> =>
new Promise<string>((resolve, reject) => {
cancel = reject
Image.getSize(
uri,
(width, height) => {
preview || '',
() => {
cancel = undefined
resolve({ width, height })
resolve(preview!)
},
error => {
reject(error)
() => {
cancel = reject
Image.getSize(
original,
() => {
cancel = undefined
resolve(original)
},
() => {
cancel = reject
if (!remote) {
reject()
} else {
Image.getSize(
remote,
() => {
cancel = undefined
resolve(remote)
},
error => {
reject(error)
}
)
}
}
)
}
)
})
@ -61,51 +92,22 @@ const GracefullyImage: React.FC<Props> = ({
const { mode, theme } = useTheme()
const [imageVisible, setImageVisible] = useState<string>()
const [imageLoadingFailed, setImageLoadingFailed] = useState(false)
useEffect(() => {
let mounted = true
let cancel: CancelPromise
const sideEffect = async (): Promise<void> => {
try {
if (uri.preview) {
const tryPreview = getImageSize(uri.preview)
cancel = tryPreview.cancel
const res = await tryPreview.start()
if (res) {
setImageVisible(uri.preview)
return
}
const prefetchImage = getImageSize(uri as { original: string })
cancel = prefetchImage.cancel
const res = await prefetchImage.start()
if (mounted) {
setImageVisible(res)
}
return
} catch (error) {
if (__DEV__) console.warn('Image preview', error)
}
try {
const tryOriginal = getImageSize(uri.original!)
cancel = tryOriginal.cancel
const res = await tryOriginal.start()
if (res) {
setImageVisible(uri.original!)
return
}
} catch (error) {
if (__DEV__) console.warn('Image original', error)
}
try {
if (uri.remote) {
const tryRemote = getImageSize(uri.remote)
cancel = tryRemote.cancel
const res = await tryRemote.start()
if (res) {
setImageVisible(uri.remote)
return
}
}
} catch (error) {
if (__DEV__) console.warn('Image remote', error)
}
setImageLoadingFailed(true)
}
if (uri.original) {
@ -113,6 +115,7 @@ const GracefullyImage: React.FC<Props> = ({
}
return () => {
mounted = false
if (cancel) {
cancel()
}

View File

@ -13,7 +13,7 @@ export interface Props {
title: string
description?: string
content?: string
content?: string | React.ReactNode
switchValue?: boolean
switchDisabled?: boolean
@ -90,26 +90,28 @@ const MenuRow: React.FC<Props> = ({
</View>
</View>
{(content && content.length) ||
switchValue !== undefined ||
iconBack ? (
{content || switchValue !== undefined || iconBack ? (
<View style={styles.back}>
{content && content.length ? (
<>
<Text
style={[
styles.content,
{
color: theme.secondary,
opacity: !iconBack && loading ? 0 : 1
}
]}
numberOfLines={1}
>
{content}
</Text>
{loading && !iconBack && loadingSpinkit}
</>
{content ? (
typeof content === 'string' ? (
<>
<Text
style={[
styles.content,
{
color: theme.secondary,
opacity: !iconBack && loading ? 0 : 1
}
]}
numberOfLines={1}
>
{content}
</Text>
{loading && !iconBack && loadingSpinkit}
</>
) : (
content
)
) : null}
{switchValue !== undefined ? (
<Switch

View File

@ -16,10 +16,11 @@ import {
StyleSheet
} from 'react-native'
import { FlatList } from 'react-native-gesture-handler'
import { useDispatch } from 'react-redux'
import { useDispatch, useSelector } from 'react-redux'
import { QueryKeyTimeline, useTimelineQuery } from '@utils/queryHooks/timeline'
import { findIndex } from 'lodash'
import { InfiniteData, useQueryClient } from 'react-query'
import { getPublicRemoteNotice } from '@utils/slices/contextsSlice'
export interface Props {
page: App.Pages
@ -212,6 +213,8 @@ const Timeline: React.FC<Props> = ({
)
}, [])
const publicRemoteNotice = useSelector(getPublicRemoteNotice).hidden
useScrollToTop(flRef)
return (
@ -231,7 +234,8 @@ const Timeline: React.FC<Props> = ({
{...(!disableRefresh && { refreshControl })}
ItemSeparatorComponent={ItemSeparatorComponent}
{...(queryKey &&
queryKey[1].page === 'RemotePublic' && { ListHeaderComponent })}
queryKey[1].page === 'RemotePublic' &&
!publicRemoteNotice && { ListHeaderComponent })}
{...(toot && isSuccess && { onScrollToIndexFailed })}
maintainVisibleContentPosition={{
minIndexForVisible: 0,

View File

@ -2,11 +2,14 @@ import { useNavigation } from '@react-navigation/native'
import Icon from '@root/components/Icon'
import { StyleConstants } from '@root/utils/styles/constants'
import { useTheme } from '@root/utils/styles/ThemeManager'
import { updatePublicRemoteNotice } from '@utils/slices/contextsSlice'
import React from 'react'
import { StyleSheet, Text, View } from 'react-native'
import { useDispatch } from 'react-redux'
const TimelineHeader = React.memo(
() => {
const dispatch = useDispatch()
const navigation = useNavigation()
const { theme } = useTheme()
@ -17,6 +20,7 @@ const TimelineHeader = React.memo(
<Text
style={{ color: theme.blue }}
onPress={() => {
dispatch(updatePublicRemoteNotice(1))
navigation.navigate('Screen-Me', {
screen: 'Screen-Me-Root',
params: { navigateAway: 'Screen-Me-Settings-UpdateRemote' }

View File

@ -57,9 +57,10 @@ const TimelineAttachment: React.FC<Props> = ({ status }) => {
return (
<AttachmentImage
key={index}
total={status.media_attachments.length}
index={index}
sensitiveShown={sensitiveShown}
image={attachment}
imageIndex={index}
navigateToImagesViewer={navigateToImagesViewer}
/>
)
@ -67,6 +68,8 @@ const TimelineAttachment: React.FC<Props> = ({ status }) => {
return (
<AttachmentVideo
key={index}
total={status.media_attachments.length}
index={index}
sensitiveShown={sensitiveShown}
video={attachment}
/>
@ -75,6 +78,8 @@ const TimelineAttachment: React.FC<Props> = ({ status }) => {
return (
<AttachmentVideo
key={index}
total={status.media_attachments.length}
index={index}
sensitiveShown={sensitiveShown}
video={attachment}
/>
@ -83,6 +88,8 @@ const TimelineAttachment: React.FC<Props> = ({ status }) => {
return (
<AttachmentAudio
key={index}
total={status.media_attachments.length}
index={index}
sensitiveShown={sensitiveShown}
audio={attachment}
/>
@ -91,6 +98,8 @@ const TimelineAttachment: React.FC<Props> = ({ status }) => {
return (
<AttachmentUnsupported
key={index}
total={status.media_attachments.length}
index={index}
sensitiveShown={sensitiveShown}
attachment={attachment}
/>

View File

@ -1,4 +1,5 @@
import Button from '@components/Button'
import GracefullyImage from '@components/GracefullyImage'
import { Slider } from '@sharcoux/slider'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
@ -7,14 +8,21 @@ import { Surface } from 'gl-react-expo'
import { Blurhash } from 'gl-react-blurhash'
import React, { useCallback, useState } from 'react'
import { StyleSheet, View } from 'react-native'
import GracefullyImage from '@components/GracefullyImage'
import attachmentAspectRatio from './aspectRatio'
export interface Props {
total: number
index: number
sensitiveShown: boolean
audio: Mastodon.AttachmentAudio
}
const AttachmentAudio: React.FC<Props> = ({ sensitiveShown, audio }) => {
const AttachmentAudio: React.FC<Props> = ({
total,
index,
sensitiveShown,
audio
}) => {
const { theme } = useTheme()
const [audioPlayer, setAudioPlayer] = useState<Audio.Sound>()
@ -39,9 +47,17 @@ const AttachmentAudio: React.FC<Props> = ({ sensitiveShown, audio }) => {
audioPlayer!.pauseAsync()
setAudioPlaying(false)
}, [audioPlayer])
console.log(audio)
return (
<View style={[styles.base, { backgroundColor: theme.disabled }]}>
<View
style={[
styles.base,
{
backgroundColor: theme.disabled,
aspectRatio: attachmentAspectRatio({ total, index })
}
]}
>
<View style={styles.overlay}>
{sensitiveShown ? (
audio.blurhash && (
@ -116,7 +132,6 @@ const styles = StyleSheet.create({
base: {
flex: 1,
flexBasis: '50%',
aspectRatio: 16 / 9,
padding: StyleConstants.Spacing.XS / 2,
flexDirection: 'row'
},

View File

@ -1,22 +1,25 @@
import GracefullyImage from '@components/GracefullyImage'
import { StyleConstants } from '@utils/styles/constants'
import React, { useCallback } from 'react'
import { StyleSheet } from 'react-native'
import { StyleConstants } from '@utils/styles/constants'
import GracefullyImage from '@components/GracefullyImage'
import attachmentAspectRatio from './aspectRatio'
export interface Props {
total: number
index: number
sensitiveShown: boolean
image: Mastodon.AttachmentImage
imageIndex: number
navigateToImagesViewer: (imageIndex: number) => void
}
const AttachmentImage: React.FC<Props> = ({
total,
index,
sensitiveShown,
image,
imageIndex,
navigateToImagesViewer
}) => {
const onPress = useCallback(() => navigateToImagesViewer(imageIndex), [])
const onPress = useCallback(() => navigateToImagesViewer(index), [])
return (
<GracefullyImage
@ -28,7 +31,10 @@ const AttachmentImage: React.FC<Props> = ({
}}
blurhash={image.blurhash}
onPress={onPress}
style={styles.base}
style={[
styles.base,
{ aspectRatio: attachmentAspectRatio({ total, index }) }
]}
/>
)
}
@ -37,7 +43,6 @@ const styles = StyleSheet.create({
base: {
flex: 1,
flexBasis: '50%',
aspectRatio: 16 / 9,
padding: StyleConstants.Spacing.XS / 2
}
})

View File

@ -7,13 +7,18 @@ import { Surface } from 'gl-react-expo'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { StyleSheet, Text, View } from 'react-native'
import attachmentAspectRatio from './aspectRatio'
export interface Props {
total: number
index: number
sensitiveShown: boolean
attachment: Mastodon.AttachmentUnknown
}
const AttachmentUnsupported: React.FC<Props> = ({
total,
index,
sensitiveShown,
attachment
}) => {
@ -21,7 +26,12 @@ const AttachmentUnsupported: React.FC<Props> = ({
const { theme } = useTheme()
return (
<View style={styles.base}>
<View
style={[
styles.base,
{ aspectRatio: attachmentAspectRatio({ total, index }) }
]}
>
{attachment.blurhash ? (
<Surface
style={{
@ -62,7 +72,6 @@ const styles = StyleSheet.create({
base: {
flex: 1,
flexBasis: '50%',
aspectRatio: 16 / 9,
padding: StyleConstants.Spacing.XS / 2,
justifyContent: 'center',
alignItems: 'center'

View File

@ -1,17 +1,25 @@
import React, { useCallback, useRef, useState } from 'react'
import { Pressable, StyleSheet, View } from 'react-native'
import { Video } from 'expo-av'
import Button from '@components/Button'
import { StyleConstants } from '@utils/styles/constants'
import { Video } from 'expo-av'
import { Surface } from 'gl-react-expo'
import { Blurhash } from 'gl-react-blurhash'
import { StyleConstants } from '@root/utils/styles/constants'
import React, { useCallback, useRef, useState } from 'react'
import { Pressable, StyleSheet, View } from 'react-native'
import attachmentAspectRatio from './aspectRatio'
export interface Props {
total: number
index: number
sensitiveShown: boolean
video: Mastodon.AttachmentVideo | Mastodon.AttachmentGifv
}
const AttachmentVideo: React.FC<Props> = ({ sensitiveShown, video }) => {
const AttachmentVideo: React.FC<Props> = ({
total,
index,
sensitiveShown,
video
}) => {
const videoPlayer = useRef<Video>(null)
const [videoLoading, setVideoLoading] = useState(false)
const [videoLoaded, setVideoLoaded] = useState(false)
@ -23,7 +31,6 @@ const AttachmentVideo: React.FC<Props> = ({ sensitiveShown, video }) => {
}
await videoPlayer.current?.setPositionAsync(videoPosition)
await videoPlayer.current?.presentFullscreenPlayer()
console.log('playing!!!')
videoPlayer.current?.playAsync()
setVideoLoading(false)
videoPlayer.current?.setOnPlaybackStatusUpdate(props => {
@ -39,7 +46,12 @@ const AttachmentVideo: React.FC<Props> = ({ sensitiveShown, video }) => {
}, [videoLoaded, videoPosition])
return (
<View style={styles.base}>
<View
style={[
styles.base,
{ aspectRatio: attachmentAspectRatio({ total, index }) }
]}
>
<Video
ref={videoPlayer}
style={{
@ -90,7 +102,6 @@ const styles = StyleSheet.create({
base: {
flex: 1,
flexBasis: '50%',
aspectRatio: 16 / 9,
padding: StyleConstants.Spacing.XS / 2
},
overlay: {

View File

@ -0,0 +1,25 @@
const attachmentAspectRatio = ({
total,
index
}: {
total: number
index?: number
}) => {
switch (total) {
case 1:
case 4:
return 16 / 9
case 2:
return 8 / 9
case 3:
if (index === 2) {
return 32 / 9
} else {
return 16 / 9
}
default:
return 16 / 9
}
}
export default attachmentAspectRatio