mirror of
https://github.com/tooot-app/app
synced 2025-06-05 22:19:13 +02:00
Test release
Added screenshot package
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
import client from '@api/client'
|
||||
import { HeaderLeft } from '@components/Header'
|
||||
import { HeaderCenter, HeaderLeft } from '@components/Header'
|
||||
import { toast, toastConfig } from '@components/toast'
|
||||
import {
|
||||
NavigationContainer,
|
||||
@ -17,9 +17,10 @@ import {
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import { themes } from '@utils/styles/themes'
|
||||
import * as Analytics from 'expo-firebase-analytics'
|
||||
import { addScreenshotListener } from 'expo-screen-capture'
|
||||
import React, { createRef, useCallback, useEffect, useRef } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Platform, StatusBar } from 'react-native'
|
||||
import { Alert, Platform, StatusBar } from 'react-native'
|
||||
import Toast from 'react-native-toast-message'
|
||||
import { createSharedElementStackNavigator } from 'react-navigation-shared-element'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
@ -33,6 +34,7 @@ export interface Props {
|
||||
export const navigationRef = createRef<NavigationContainerRef>()
|
||||
|
||||
const Index: React.FC<Props> = ({ localCorrupt }) => {
|
||||
const { t } = useTranslation('common')
|
||||
const dispatch = useDispatch()
|
||||
const localActiveIndex = useSelector(getLocalActiveIndex)
|
||||
const { mode, theme } = useTheme()
|
||||
@ -56,8 +58,18 @@ const Index: React.FC<Props> = ({ localCorrupt }) => {
|
||||
// }
|
||||
// }, [isConnected, firstRender])
|
||||
|
||||
// Prevent screenshot alert
|
||||
useEffect(() => {
|
||||
const screenshotListener = addScreenshotListener(() =>
|
||||
Alert.alert(t('screenshot.title'), t('screenshot.message'), [
|
||||
{ text: t('screenshot.button'), style: 'destructive' }
|
||||
])
|
||||
)
|
||||
Platform.OS === 'ios' && screenshotListener
|
||||
return () => screenshotListener.remove()
|
||||
}, [])
|
||||
|
||||
// On launch display login credentials corrupt information
|
||||
const { t } = useTranslation('common')
|
||||
useEffect(() => {
|
||||
const showLocalCorrect = localCorrupt
|
||||
? toast({
|
||||
@ -153,7 +165,12 @@ const Index: React.FC<Props> = ({ localCorrupt }) => {
|
||||
component={ScreenAnnouncements}
|
||||
options={{
|
||||
gestureEnabled: false,
|
||||
title: t('sharedAnnouncements:heading'),
|
||||
headerTitle: t('sharedAnnouncements:heading'),
|
||||
...(Platform.OS === 'android' && {
|
||||
headerCenter: () => (
|
||||
<HeaderCenter content={t('sharedAnnouncements:heading')} />
|
||||
)
|
||||
}),
|
||||
headerTransparent: true,
|
||||
headerLeft: () => (
|
||||
<HeaderLeft
|
||||
|
@ -3,7 +3,6 @@ import { StyleConstants } from '@utils/styles/constants'
|
||||
import layoutAnimation from '@utils/styles/layoutAnimation'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React, { useEffect, useMemo, useRef } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
Pressable,
|
||||
StyleProp,
|
||||
@ -49,8 +48,7 @@ const Button: React.FC<Props> = ({
|
||||
overlay = false,
|
||||
onPress
|
||||
}) => {
|
||||
const { i18n } = useTranslation()
|
||||
const { theme } = useTheme()
|
||||
const { mode, theme } = useTheme()
|
||||
|
||||
const mounted = useRef(false)
|
||||
useEffect(() => {
|
||||
@ -67,7 +65,7 @@ const Button: React.FC<Props> = ({
|
||||
<Chase size={StyleConstants.Font.Size[size]} color={theme.secondary} />
|
||||
</View>
|
||||
),
|
||||
[theme]
|
||||
[mode]
|
||||
)
|
||||
|
||||
const colorContent = useMemo(() => {
|
||||
@ -88,7 +86,7 @@ const Button: React.FC<Props> = ({
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [theme, disabled])
|
||||
}, [mode, disabled])
|
||||
const colorBorder = useMemo(() => {
|
||||
if (active) {
|
||||
return theme.blue
|
||||
@ -103,14 +101,14 @@ const Button: React.FC<Props> = ({
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [theme, loading, disabled])
|
||||
}, [mode, loading, disabled])
|
||||
const colorBackground = useMemo(() => {
|
||||
if (overlay) {
|
||||
return theme.backgroundOverlay
|
||||
} else {
|
||||
return theme.background
|
||||
}
|
||||
}, [theme])
|
||||
}, [mode])
|
||||
|
||||
const children = useMemo(() => {
|
||||
switch (type) {
|
||||
@ -147,7 +145,7 @@ const Button: React.FC<Props> = ({
|
||||
</>
|
||||
)
|
||||
}
|
||||
}, [i18n.language, theme, content, loading, disabled, active])
|
||||
}, [mode, content, loading, disabled, active])
|
||||
|
||||
enum spacingMapping {
|
||||
XS = 'S',
|
||||
|
@ -28,10 +28,7 @@ const ComponentHashtag: React.FC<Props> = ({
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Pressable
|
||||
style={[styles.itemDefault, { borderBottomColor: theme.border }]}
|
||||
onPress={customOnPress || onPress}
|
||||
>
|
||||
<Pressable style={styles.itemDefault} onPress={customOnPress || onPress}>
|
||||
<Text style={[styles.itemHashtag, { color: theme.primary }]}>
|
||||
#{hashtag.name}
|
||||
</Text>
|
||||
@ -41,8 +38,7 @@ const ComponentHashtag: React.FC<Props> = ({
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
itemDefault: {
|
||||
padding: StyleConstants.Spacing.S * 1.5,
|
||||
borderBottomWidth: StyleSheet.hairlineWidth
|
||||
padding: StyleConstants.Spacing.S * 1.5
|
||||
},
|
||||
itemHashtag: {
|
||||
...StyleConstants.FontStyle.M
|
||||
|
@ -33,7 +33,7 @@ const ComponentInstance: React.FC<Props> = ({
|
||||
disableHeaderImage,
|
||||
goBack = false
|
||||
}) => {
|
||||
const { t } = useTranslation('componentInstance')
|
||||
const { t, i18n } = useTranslation('componentInstance')
|
||||
const { theme } = useTheme()
|
||||
const navigation = useNavigation()
|
||||
|
||||
@ -136,7 +136,7 @@ const ComponentInstance: React.FC<Props> = ({
|
||||
case 'remote':
|
||||
return t('server.button.remote')
|
||||
}
|
||||
}, [])
|
||||
}, [i18n.language])
|
||||
|
||||
const requestAuth = useMemo(() => {
|
||||
if (
|
||||
|
@ -164,7 +164,13 @@ const Timeline: React.FC<Props> = ({
|
||||
<RefreshControl
|
||||
{...(Platform.OS === 'android' && { enabled: true })}
|
||||
refreshing={
|
||||
isSwipeDown.current && isFetching && !isFetchingNextPage && !isLoading
|
||||
Platform.OS === 'android'
|
||||
? (isSwipeDown.current && isFetching && !isFetchingNextPage) ||
|
||||
isLoading
|
||||
: isSwipeDown.current &&
|
||||
isFetching &&
|
||||
!isFetchingNextPage &&
|
||||
!isLoading
|
||||
}
|
||||
onRefresh={() => {
|
||||
isSwipeDown.current = true
|
||||
|
@ -1,4 +1,9 @@
|
||||
export default {
|
||||
screenshot: {
|
||||
title: 'Privacy Protection',
|
||||
message: 'Please do not disclose other user\'s identity, such as username, avatar, etc. Thank you!',
|
||||
button: 'Confirm'
|
||||
},
|
||||
index: {
|
||||
localCorrupt: 'Login expired, please login again'
|
||||
},
|
||||
|
@ -1,3 +1,3 @@
|
||||
export default {
|
||||
heading: 'Direct messages'
|
||||
heading: 'Discussions'
|
||||
}
|
||||
|
@ -1,4 +1,9 @@
|
||||
export default {
|
||||
screenshot: {
|
||||
title: '隐私保护',
|
||||
message: '请确保不要泄露其它用户的敏感信息,例如用户名、头像等,谢谢!',
|
||||
button: '好的'
|
||||
},
|
||||
index: {
|
||||
localCorrupt: '登录已过期,请重新登录'
|
||||
},
|
||||
|
@ -231,6 +231,7 @@ const ScreenCompose: React.FC<ScreenComposeProp> = ({
|
||||
<KeyboardAvoidingView
|
||||
style={styles.base}
|
||||
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
||||
keyboardVerticalOffset={Platform.OS === 'android' ? 23 : 0}
|
||||
>
|
||||
<SafeAreaView
|
||||
style={styles.base}
|
||||
|
@ -5,7 +5,7 @@ import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import { forEach, groupBy, sortBy } from 'lodash'
|
||||
import React, { useCallback, useContext, useEffect, useMemo } from 'react'
|
||||
import { FlatList, Image, StyleSheet, View } from 'react-native'
|
||||
import { FlatList, StyleSheet, View } from 'react-native'
|
||||
import { Chase } from 'react-native-animated-spinkit'
|
||||
import ComposeActions from './Root/Actions'
|
||||
import ComposePosting from './Posting'
|
||||
@ -70,7 +70,7 @@ const ComposeRoot: React.FC = () => {
|
||||
const listItem = useCallback(
|
||||
({ item, index }) => (
|
||||
<ComposeRootSuggestion
|
||||
key={(item.id || item.name) + index}
|
||||
key={index}
|
||||
item={item}
|
||||
composeState={composeState}
|
||||
composeDispatch={composeDispatch}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import analytics from '@components/analytics'
|
||||
import { HeaderRight } from '@components/Header'
|
||||
import { HeaderCenter, HeaderRight } from '@components/Header'
|
||||
import { useActionSheet } from '@expo/react-native-action-sheet'
|
||||
import { StackScreenProps } from '@react-navigation/stack'
|
||||
import CameraRoll from '@react-native-community/cameraroll'
|
||||
@ -8,13 +8,7 @@ import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import { findIndex } from 'lodash'
|
||||
import React, { useCallback, useLayoutEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
PermissionsAndroid,
|
||||
Platform,
|
||||
Share,
|
||||
StyleSheet,
|
||||
Text
|
||||
} from 'react-native'
|
||||
import { PermissionsAndroid, Platform, Share, StyleSheet } from 'react-native'
|
||||
import FastImage from 'react-native-fast-image'
|
||||
import ImageViewer from 'react-native-image-zoom-viewer'
|
||||
import { SharedElement } from 'react-navigation-shared-element'
|
||||
@ -107,11 +101,9 @@ const ScreenImagesViewer = React.memo(
|
||||
() =>
|
||||
navigation.setOptions({
|
||||
headerTitle: () => (
|
||||
<Text
|
||||
style={[styles.headerCenter, { color: theme.primaryOverlay }]}
|
||||
>
|
||||
{currentIndex + 1} / {imageUrls.length}
|
||||
</Text>
|
||||
<HeaderCenter
|
||||
content={`${currentIndex + 1} / ${imageUrls.length}`}
|
||||
/>
|
||||
),
|
||||
headerRight: () => (
|
||||
<HeaderRight
|
||||
|
@ -9,8 +9,8 @@ import ScreenMeSwitchRoot from './Switch/Root'
|
||||
const Stack = createNativeStackNavigator()
|
||||
|
||||
const ScreenMeSwitch: React.FC<StackScreenProps<
|
||||
Nav.MeStackParamList,
|
||||
'Screen-Me-Switch'
|
||||
Nav.TabMeStackParamList,
|
||||
'Tab-Me-Switch'
|
||||
>> = ({ navigation }) => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
|
@ -45,8 +45,8 @@ const AccountButton: React.FC<Props> = ({ instance, disabled = false }) => {
|
||||
onPress={() => {
|
||||
haptics('Light')
|
||||
analytics('switch_existing_press')
|
||||
dispatch(localUpdateActiveIndex(instance))
|
||||
queryClient.clear()
|
||||
dispatch(localUpdateActiveIndex(instance))
|
||||
navigation.goBack()
|
||||
}}
|
||||
/>
|
||||
|
@ -2,8 +2,6 @@ import Timeline from '@components/Timelines/Timeline'
|
||||
import React from 'react'
|
||||
import { SharedHashtagProp } from './sharedScreens'
|
||||
|
||||
// Show remote hashtag? Only when private, show local version?
|
||||
|
||||
const TabSharedHashtag: React.FC<SharedHashtagProp> = ({
|
||||
route: {
|
||||
params: { hashtag }
|
||||
|
@ -136,7 +136,14 @@ const sharedScreens = (
|
||||
name='Tab-Shared-Hashtag'
|
||||
component={TabSharedHashtag}
|
||||
options={({ route, navigation }: SharedHashtagProp) => ({
|
||||
title: `#${decodeURIComponent(route.params.hashtag)}`,
|
||||
headerTitle: `#${decodeURIComponent(route.params.hashtag)}`,
|
||||
...(Platform.OS === 'android' && {
|
||||
headerCenter: () => (
|
||||
<HeaderCenter
|
||||
content={`#${decodeURIComponent(route.params.hashtag)}`}
|
||||
/>
|
||||
)
|
||||
}),
|
||||
headerLeft: () => <HeaderLeft onPress={() => navigation.goBack()} />
|
||||
})}
|
||||
/>,
|
||||
|
9
src/startup/preventScreenshot.ts
Normal file
9
src/startup/preventScreenshot.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { preventScreenCaptureAsync } from 'expo-screen-capture'
|
||||
import log from './log'
|
||||
|
||||
const preventScreenshot = () => {
|
||||
log('log', 'Screenshot', 'preventing')
|
||||
preventScreenCaptureAsync()
|
||||
}
|
||||
|
||||
export default preventScreenshot
|
Reference in New Issue
Block a user