From 95f500ae724863d173d5e37ebdd577f8bbcbc73b Mon Sep 17 00:00:00 2001 From: Zhiyuan Zheng Date: Thu, 14 Jan 2021 00:43:35 +0100 Subject: [PATCH] More adaption to Android --- App.tsx | 6 -- package.json | 4 +- src/Index.tsx | 22 ++++-- src/components/Header.tsx | 3 +- src/components/Header/Center.tsx | 31 ++++++++ src/components/Parse/HTML.tsx | 72 ++++++++----------- src/components/RelativeTime.tsx | 26 +++++++ src/components/Timelines.tsx | 64 ++++++++++------- src/components/Timelines/Timeline.tsx | 12 +++- .../Timeline/Shared/HeaderShared/Created.tsx | 4 +- .../Timelines/Timeline/Shared/Poll.tsx | 12 +--- src/components/haptics.ts | 8 +++ src/components/toast.tsx | 31 ++++---- src/i18n/en/components/relativeTime.ts | 20 ++++++ src/i18n/zh/components/relativeTime.ts | 21 ++++++ src/screens/Me.tsx | 46 +++++++++++- src/screens/Me/Switch.tsx | 11 ++- src/screens/Me/Switch/Root.tsx | 13 +++- src/screens/Me/UpdateRemote.tsx | 7 +- src/screens/Notifications.tsx | 8 +++ src/screens/Shared/Announcements.tsx | 10 +-- src/screens/Shared/Compose.tsx | 8 ++- src/screens/Shared/Compose/EditAttachment.tsx | 7 +- .../Shared/Compose/EditAttachment/Image.tsx | 32 ++++----- src/screens/Shared/Compose/addAttachment.ts | 28 ++++++-- src/screens/Shared/Search.tsx | 8 ++- src/screens/Shared/sharedScreens.tsx | 9 ++- yarn.lock | 22 +++--- 28 files changed, 376 insertions(+), 169 deletions(-) create mode 100644 src/components/Header/Center.tsx create mode 100644 src/components/RelativeTime.tsx create mode 100644 src/i18n/en/components/relativeTime.ts create mode 100644 src/i18n/zh/components/relativeTime.ts diff --git a/App.tsx b/App.tsx index a206104d..b5fc1ad1 100644 --- a/App.tsx +++ b/App.tsx @@ -15,10 +15,6 @@ import { QueryClient, QueryClientProvider } from 'react-query' import { Provider } from 'react-redux' import { PersistGate } from 'redux-persist/integration/react' import { LogBox, Platform } from 'react-native' -import Moment from 'react-moment' - -import moment from 'moment' -import 'moment/min/locales' if (Platform.OS === 'android') { LogBox.ignoreLogs(['Setting a timer for a long period of time']) @@ -28,8 +24,6 @@ dev() sentry() audio() onlineStatus() -Moment.globalMoment = moment -Moment.startPooledTimer(1000) log('log', 'react-query', 'initializing') const queryClient = new QueryClient() diff --git a/package.json b/package.json index 965720d0..5b5f0764 100644 --- a/package.json +++ b/package.json @@ -44,12 +44,10 @@ "gl-react-expo": "^4.0.1", "i18next": "^19.8.4", "lodash": "^4.17.20", - "moment": "^2.29.1", "pretty-bytes": "^5.5.0", "react": "16.13.1", "react-dom": "16.13.1", "react-i18next": "^11.8.5", - "react-moment": "^1.1.1", "react-native": "https://github.com/expo/react-native/archive/sdk-40.0.0.tar.gz", "react-native-animated-spinkit": "^1.4.2", "react-native-expo-image-cache": "^4.1.0", @@ -67,6 +65,7 @@ "react-navigation": "^4.4.3", "react-query": "^3.5.6", "react-redux": "^7.2.2", + "react-timeago": "^5.2.0", "redux-persist": "^6.0.0", "redux-persist-expo-securestore": "^2.0.0", "sentry-expo": "^3.0.4", @@ -93,6 +92,7 @@ "@types/react-navigation": "^3.4.0", "@types/react-redux": "^7.1.12", "@types/react-test-renderer": "^17.0.0", + "@types/react-timeago": "^4.1.2", "@welldone-software/why-did-you-render": "^6.0.4", "babel-plugin-module-resolver": "^4.1.0", "chalk": "^4.1.0", diff --git a/src/Index.tsx b/src/Index.tsx index 35a76da9..8caebc67 100644 --- a/src/Index.tsx +++ b/src/Index.tsx @@ -7,6 +7,7 @@ import { createBottomTabNavigator } from '@react-navigation/bottom-tabs' import { + getFocusedRouteNameFromRoute, NavigationContainer, NavigationContainerRef } from '@react-navigation/native' @@ -31,7 +32,7 @@ import React, { useMemo, useRef } from 'react' -import { StatusBar } from 'react-native' +import { Platform, StatusBar } from 'react-native' import Toast from 'react-native-toast-message' import { useDispatch, useSelector } from 'react-redux' @@ -172,6 +173,7 @@ const Index: React.FC = ({ localCorrupt }) => { }) => { let name: any let updateColor: string = color + console.log() switch (route.name) { case 'Screen-Local': name = 'Home' @@ -195,7 +197,16 @@ const Index: React.FC = ({ localCorrupt }) => { break } return - } + }, + ...(Platform.OS === 'android' && { + tabBarVisible: + getFocusedRouteNameFromRoute(route) !== 'Screen-Shared-Compose' && + getFocusedRouteNameFromRoute(route) !== + 'Screen-Shared-Announcements' && + getFocusedRouteNameFromRoute(route) !== + 'Screen-Shared-ImagesViewer' && + getFocusedRouteNameFromRoute(route) !== 'Screen-Me-Switch' + }) }), [] ) @@ -204,7 +215,8 @@ const Index: React.FC = ({ localCorrupt }) => { activeTintColor: theme.primary, inactiveTintColor: localActiveIndex !== null ? theme.secondary : theme.disabled, - showLabel: false + showLabel: false, + ...(Platform.OS === 'android' && { keyboardHidesTabBar: true }) }), [theme, localActiveIndex] ) @@ -292,7 +304,9 @@ const Index: React.FC = ({ localCorrupt }) => { - {/* */} + {Platform.OS === 'ios' ? ( + + ) : null} ) diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 3e3fc582..9deabac1 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -1,4 +1,5 @@ import HeaderLeft from '@components/Header/Left' +import HeaderCenter from '@components/Header/Center' import HeaderRight from '@components/Header/Right' -export { HeaderLeft, HeaderRight } +export { HeaderLeft, HeaderCenter, HeaderRight } diff --git a/src/components/Header/Center.tsx b/src/components/Header/Center.tsx new file mode 100644 index 00000000..ddf893da --- /dev/null +++ b/src/components/Header/Center.tsx @@ -0,0 +1,31 @@ +import { StyleConstants } from '@utils/styles/constants' +import { useTheme } from '@utils/styles/ThemeManager' +import React from 'react' +import { StyleSheet, Text } from 'react-native' + +export interface Props { + content: string +} + +// Used for Android mostly +const HeaderCenter = React.memo( + ({ content }: Props) => { + const { theme } = useTheme() + + return ( + + ) + }, + () => true +) + +const styles = StyleSheet.create({ + text: { + ...StyleConstants.FontStyle.M + } +}) + +export default HeaderCenter diff --git a/src/components/Parse/HTML.tsx b/src/components/Parse/HTML.tsx index d2bfc527..1fa3aad5 100644 --- a/src/components/Parse/HTML.tsx +++ b/src/components/Parse/HTML.tsx @@ -45,9 +45,12 @@ const renderNode = ({ ? routeParams.hashtag !== tag[1] && routeParams.hashtag !== tag[2] : true return ( - { !disableDetails && differentTag && @@ -56,16 +59,9 @@ const renderNode = ({ }) }} > - - {node.children[0].data} - {node.children[1]?.children[0].data} - - + {node.children[0].data} + {node.children[1]?.children[0].data} + ) } else if (classes.includes('mention') && mentions) { const accountIndex = mentions.findIndex( @@ -75,9 +71,12 @@ const renderNode = ({ ? routeParams.account.id !== mentions[accountIndex].id : true return ( - { accountIndex !== -1 && !disableDetails && @@ -87,16 +86,9 @@ const renderNode = ({ }) }} > - - {node.children[0].data} - {node.children[1]?.children[0].data} - - + {node.children[0].data} + {node.children[1]?.children[0].data} + ) } } else { @@ -107,9 +99,12 @@ const renderNode = ({ const shouldBeTag = tags && tags.filter(tag => `#${tag.name}` === content).length > 0 return ( - !disableDetails && !shouldBeTag ? await openLink(href) @@ -118,22 +113,15 @@ const renderNode = ({ }) } > - - {!shouldBeTag ? ( - - ) : null} - {content || (showFullLink ? href : domain[1])} - - + {!shouldBeTag ? ( + + ) : null} + {content || (showFullLink ? href : domain[1])} + ) } break diff --git a/src/components/RelativeTime.tsx b/src/components/RelativeTime.tsx new file mode 100644 index 00000000..d7d4f7eb --- /dev/null +++ b/src/components/RelativeTime.tsx @@ -0,0 +1,26 @@ +import React from 'react' +import { useTranslation } from 'react-i18next' +import { Text } from 'react-native' +import TimeAgo from 'react-timeago' +// @ts-ignore +import buildFormatter from 'react-timeago/lib/formatters/buildFormatter' + +import zh from '@root/i18n/zh/components/relativeTime' +import en from '@root/i18n/en/components/relativeTime' + +export interface Props { + date: string +} + +const RelativeTime: React.FC = ({ date }) => { + const { i18n } = useTranslation() + const mapLanguageToTranslation: { [key: string]: Object } = { + 'zh-CN': zh, + 'en-US': en + } + const formatter = buildFormatter(mapLanguageToTranslation[i18n.language]) + + return +} + +export default RelativeTime diff --git a/src/components/Timelines.tsx b/src/components/Timelines.tsx index a948696e..89e157d5 100644 --- a/src/components/Timelines.tsx +++ b/src/components/Timelines.tsx @@ -1,12 +1,12 @@ -import { HeaderRight } from '@components/Header' +import { HeaderCenter, HeaderRight } from '@components/Header' import Timeline from '@components/Timelines/Timeline' import SegmentedControl from '@react-native-community/segmented-control' import { useNavigation } from '@react-navigation/native' import sharedScreens from '@screens/Shared/sharedScreens' import { getLocalActiveIndex, getRemoteUrl } from '@utils/slices/instancesSlice' import { useTheme } from '@utils/styles/ThemeManager' -import React, { useCallback, useState } from 'react' -import { Dimensions, StyleSheet, View } from 'react-native' +import React, { useCallback, useMemo, useState } from 'react' +import { Dimensions, Platform, StyleSheet, View } from 'react-native' import { createNativeStackNavigator } from 'react-native-screens/native-stack' import { TabView } from 'react-native-tab-view' import { useSelector } from 'react-redux' @@ -68,6 +68,40 @@ const Timelines: React.FC = ({ name, content }) => { [segment, localActiveIndex] ) + const screenOptions = useMemo(() => { + if (localActiveIndex === null) { + if (name === 'Public') { + return { + headerTitle: publicDomain, + ...(Platform.OS === 'android' && { + headerCenter: () => + }) + } + } + } else { + return { + headerCenter: () => ( + + + setSegment(nativeEvent.selectedSegmentIndex) + } + /> + + ), + headerRight: () => ( + + ) + } + } + }, [localActiveIndex, mode, segment]) + return ( = ({ name, content }) => { // @ts-ignore name={`Screen-${name}-Root`} component={screenComponent} - options={{ - headerTitle: name === 'Public' ? publicDomain : '', - ...(localActiveIndex !== null && { - headerCenter: () => ( - - - setSegment(nativeEvent.selectedSegmentIndex) - } - /> - - ), - headerRight: () => ( - - ) - }) - }} + options={screenOptions} /> {sharedScreens(Stack)} diff --git a/src/components/Timelines/Timeline.tsx b/src/components/Timelines/Timeline.tsx index abfcb629..a022d112 100644 --- a/src/components/Timelines/Timeline.tsx +++ b/src/components/Timelines/Timeline.tsx @@ -9,13 +9,14 @@ import { useScrollToTop } from '@react-navigation/native' import { localUpdateNotification } from '@utils/slices/instancesSlice' import { StyleConstants } from '@utils/styles/constants' import React, { useCallback, useEffect, useMemo, useRef } from 'react' -import { RefreshControl, StyleSheet } from 'react-native' +import { Platform, RefreshControl, StyleSheet } from 'react-native' import { FlatList } from 'react-native-gesture-handler' import { useDispatch } from 'react-redux' import { QueryKeyTimeline, useTimelineQuery } from '@utils/queryHooks/timeline' import { findIndex } from 'lodash' import CustomRefreshControl from '@components/CustomRefreshControl' import { InfiniteData, useQueryClient } from 'react-query' +import { useTheme } from '@utils/styles/ThemeManager' export interface Props { page: App.Pages @@ -36,6 +37,8 @@ const Timeline: React.FC = ({ disableRefresh = false, disableInfinity = false }) => { + const { theme } = useTheme() + const queryKeyParams = { page, ...(hashtag && { hashtag }), @@ -163,8 +166,13 @@ const Timeline: React.FC = ({ const refreshControl = useMemo( () => ( { if (refreshCount.current < 2) { diff --git a/src/components/Timelines/Timeline/Shared/HeaderShared/Created.tsx b/src/components/Timelines/Timeline/Shared/HeaderShared/Created.tsx index b576a3a1..a562597c 100644 --- a/src/components/Timelines/Timeline/Shared/HeaderShared/Created.tsx +++ b/src/components/Timelines/Timeline/Shared/HeaderShared/Created.tsx @@ -1,8 +1,8 @@ +import RelativeTime from '@components/RelativeTime' import { StyleConstants } from '@utils/styles/constants' import { useTheme } from '@utils/styles/ThemeManager' import React from 'react' import { useTranslation } from 'react-i18next' -import Moment from 'react-moment' import { StyleSheet, Text } from 'react-native' export interface Props { @@ -15,7 +15,7 @@ const HeaderSharedCreated: React.FC = ({ created_at }) => { return ( - + ) } diff --git a/src/components/Timelines/Timeline/Shared/Poll.tsx b/src/components/Timelines/Timeline/Shared/Poll.tsx index b31e7952..e56a1031 100644 --- a/src/components/Timelines/Timeline/Shared/Poll.tsx +++ b/src/components/Timelines/Timeline/Shared/Poll.tsx @@ -1,7 +1,7 @@ import Button from '@components/Button' import haptics from '@components/haptics' import Icon from '@components/Icon' -import relativeTime from '@components/relativeTime' +import RelativeTime from '@components/RelativeTime' import { ParseEmojis } from '@root/components/Parse' import { toast } from '@root/components/toast' import { @@ -13,7 +13,6 @@ import { useTheme } from '@utils/styles/ThemeManager' import { maxBy } from 'lodash' import React, { useCallback, useMemo, useState } from 'react' import { Trans, useTranslation } from 'react-i18next' -import Moment from 'react-moment' import { Pressable, StyleSheet, Text, View } from 'react-native' import { useQueryClient } from 'react-query' @@ -127,14 +126,7 @@ const TimelinePoll: React.FC = ({ - ]} + components={[]} /> ) diff --git a/src/components/haptics.ts b/src/components/haptics.ts index 299f2717..b45fd141 100644 --- a/src/components/haptics.ts +++ b/src/components/haptics.ts @@ -1,9 +1,17 @@ import * as Haptics from 'expo-haptics' +import { Platform } from 'react-native' import * as Sentry from 'sentry-expo' const haptics = ( type: 'Success' | 'Warning' | 'Error' | 'Light' | 'Medium' | 'Heavy' ) => { + if (Platform.OS === 'android') { + Haptics.impactAsync(Haptics.ImpactFeedbackStyle['Light']).catch(error => + Sentry.Native.captureException(error) + ) + return + } + switch (type) { case 'Success': case 'Warning': diff --git a/src/components/toast.tsx b/src/components/toast.tsx index a1381e81..e62c9762 100644 --- a/src/components/toast.tsx +++ b/src/components/toast.tsx @@ -2,7 +2,7 @@ import Icon from '@components/Icon' import { StyleConstants } from '@utils/styles/constants' import { useTheme } from '@utils/styles/ThemeManager' import React from 'react' -import { StyleSheet, Text, View } from 'react-native' +import { Platform, StyleSheet, Text, ToastAndroid, View } from 'react-native' import { SafeAreaView } from 'react-native-safe-area-context' import Toast from 'react-native-toast-message' import * as Sentry from 'sentry-expo' @@ -33,18 +33,23 @@ const toast = ({ onShow, onHide }: Params) => { - Toast.show({ - type, - position, - text1: message, - text2: description, - visibilityTime: 1500, - autoHide, - topOffset: 0, - bottomOffset: 0, - onShow: onShow, - onHide: onHide - }) + switch (Platform.OS) { + case 'ios': + return Toast.show({ + type, + position, + text1: message, + text2: description, + visibilityTime: 1500, + autoHide, + topOffset: 0, + bottomOffset: 0, + onShow: onShow, + onHide: onHide + }) + case 'android': + return ToastAndroid.show(message, ToastAndroid.SHORT) + } } const ToastBase = ({ config }: { config: Config }) => { diff --git a/src/i18n/en/components/relativeTime.ts b/src/i18n/en/components/relativeTime.ts new file mode 100644 index 00000000..fa7ffc85 --- /dev/null +++ b/src/i18n/en/components/relativeTime.ts @@ -0,0 +1,20 @@ +const strings = { + prefixAgo: null, + prefixFromNow: null, + suffixAgo: 'ago', + suffixFromNow: 'from now', + seconds: '%d seconds', + minute: 'about a minute', + minutes: '%d minutes', + hour: 'about an hour', + hours: 'about %d hours', + day: 'a day', + days: '%d days', + month: 'about a month', + months: '%d months', + year: 'about a year', + years: '%d years', + wordSeparator: ' ' +} + +export default strings diff --git a/src/i18n/zh/components/relativeTime.ts b/src/i18n/zh/components/relativeTime.ts new file mode 100644 index 00000000..72c3b58e --- /dev/null +++ b/src/i18n/zh/components/relativeTime.ts @@ -0,0 +1,21 @@ +const strings = { + prefixAgo: null, + prefixFromNow: null, + suffixAgo: '之前', + suffixFromNow: '之后', + seconds: '%d秒', + minute: '大约1分钟', + minutes: '%d分钟', + hour: '大约1小时', + hours: '大约%d小时', + day: '1天', + days: '%d天', + month: '大约1个月', + months: '%d月', + year: '大约1年', + years: '%d年', + + wordSeparator: '' +} + +export default strings diff --git a/src/screens/Me.tsx b/src/screens/Me.tsx index 6dd68a24..4a85cb1f 100644 --- a/src/screens/Me.tsx +++ b/src/screens/Me.tsx @@ -1,4 +1,4 @@ -import { HeaderLeft } from '@components/Header' +import { HeaderCenter, HeaderLeft } from '@components/Header' import ScreenMeBookmarks from '@screens/Me/Bookmarks' import ScreenMeConversations from '@screens/Me/Cconversations' import ScreenMeFavourites from '@screens/Me/Favourites' @@ -11,6 +11,7 @@ import UpdateRemote from '@screens/Me/UpdateRemote' import sharedScreens from '@screens/Shared/sharedScreens' import React from 'react' import { useTranslation } from 'react-i18next' +import { Platform } from 'react-native' import { createNativeStackNavigator } from 'react-native-screens/native-stack' const Stack = createNativeStackNavigator() @@ -19,7 +20,9 @@ const ScreenMe: React.FC = () => { const { t } = useTranslation() return ( - + { component={ScreenMeBookmarks} options={({ navigation }: any) => ({ headerTitle: t('meBookmarks:heading'), + ...(Platform.OS === 'android' && { + headerCenter: () => ( + + ) + }), headerLeft: () => navigation.pop(1)} /> })} /> @@ -42,6 +50,11 @@ const ScreenMe: React.FC = () => { component={ScreenMeConversations} options={({ navigation }: any) => ({ headerTitle: t('meConversations:heading'), + ...(Platform.OS === 'android' && { + headerCenter: () => ( + + ) + }), headerLeft: () => navigation.pop(1)} /> })} /> @@ -50,6 +63,11 @@ const ScreenMe: React.FC = () => { component={ScreenMeFavourites} options={({ navigation }: any) => ({ headerTitle: t('meFavourites:heading'), + ...(Platform.OS === 'android' && { + headerCenter: () => ( + + ) + }), headerLeft: () => navigation.pop(1)} /> })} /> @@ -58,6 +76,9 @@ const ScreenMe: React.FC = () => { component={ScreenMeLists} options={({ navigation }: any) => ({ headerTitle: t('meLists:heading'), + ...(Platform.OS === 'android' && { + headerCenter: () => + }), headerLeft: () => navigation.pop(1)} /> })} /> @@ -66,6 +87,11 @@ const ScreenMe: React.FC = () => { component={ScreenMeListsList} options={({ route, navigation }: any) => ({ headerTitle: t('meListsList:heading', { list: route.params.title }), + ...(Platform.OS === 'android' && { + headerCenter: () => ( + + ) + }), headerLeft: () => navigation.pop(1)} /> })} /> @@ -74,6 +100,11 @@ const ScreenMe: React.FC = () => { component={ScreenMeSettings} options={({ navigation }: any) => ({ headerTitle: t('meSettings:heading'), + ...(Platform.OS === 'android' && { + headerCenter: () => ( + + ) + }), headerLeft: () => navigation.pop(1)} /> })} /> @@ -82,6 +113,11 @@ const ScreenMe: React.FC = () => { component={UpdateRemote} options={({ navigation }: any) => ({ headerTitle: t('meSettingsUpdateRemote:heading'), + ...(Platform.OS === 'android' && { + headerCenter: () => ( + + ) + }), headerLeft: () => navigation.pop(1)} /> })} /> @@ -90,7 +126,13 @@ const ScreenMe: React.FC = () => { component={ScreenMeSwitch} options={({ navigation }: any) => ({ stackPresentation: 'fullScreenModal', + headerShown: false, headerTitle: t('meSettings:heading'), + ...(Platform.OS === 'android' && { + headerCenter: () => ( + + ) + }), headerLeft: () => navigation.pop(1)} /> })} /> diff --git a/src/screens/Me/Switch.tsx b/src/screens/Me/Switch.tsx index 391c10db..476f61bb 100644 --- a/src/screens/Me/Switch.tsx +++ b/src/screens/Me/Switch.tsx @@ -1,6 +1,6 @@ -import { HeaderLeft, HeaderRight } from '@components/Header' +import { HeaderCenter, HeaderLeft } from '@components/Header' import React from 'react' -import { StyleSheet } from 'react-native' +import { Platform, StyleSheet } from 'react-native' import { createNativeStackNavigator } from 'react-native-screens/native-stack' import ScreenMeSwitchRoot from './Switch/Root' @@ -8,12 +8,17 @@ const Stack = createNativeStackNavigator() const ScreenMeSwitch: React.FC = ({ navigation }) => { return ( - + + }), headerLeft: () => ( navigation.goBack()} /> ) diff --git a/src/screens/Me/Switch/Root.tsx b/src/screens/Me/Switch/Root.tsx index e9c32b37..aa968eaf 100644 --- a/src/screens/Me/Switch/Root.tsx +++ b/src/screens/Me/Switch/Root.tsx @@ -12,7 +12,13 @@ import { import { StyleConstants } from '@utils/styles/constants' import { useTheme } from '@utils/styles/ThemeManager' import React from 'react' -import { KeyboardAvoidingView, StyleSheet, Text, View } from 'react-native' +import { + KeyboardAvoidingView, + Platform, + StyleSheet, + Text, + View +} from 'react-native' import { ScrollView } from 'react-native-gesture-handler' import { useQueryClient } from 'react-query' import { useDispatch, useSelector } from 'react-redux' @@ -59,7 +65,10 @@ const ScreenMeSwitchRoot = () => { const localActiveIndex = useSelector(getLocalActiveIndex) return ( - + diff --git a/src/screens/Me/UpdateRemote.tsx b/src/screens/Me/UpdateRemote.tsx index 76816259..89f4cf1e 100644 --- a/src/screens/Me/UpdateRemote.tsx +++ b/src/screens/Me/UpdateRemote.tsx @@ -1,11 +1,14 @@ import ComponentInstance from '@components/Instance' import React from 'react' -import { KeyboardAvoidingView } from 'react-native' +import { KeyboardAvoidingView, Platform } from 'react-native' import { ScrollView } from 'react-native-gesture-handler' const UpdateRemote: React.FC = () => { return ( - + diff --git a/src/screens/Notifications.tsx b/src/screens/Notifications.tsx index 7353245f..d2b6bf57 100644 --- a/src/screens/Notifications.tsx +++ b/src/screens/Notifications.tsx @@ -1,8 +1,10 @@ +import { HeaderCenter } from '@components/Header' import Timeline from '@components/Timelines/Timeline' import sharedScreens from '@screens/Shared/sharedScreens' import { getLocalActiveIndex } from '@utils/slices/instancesSlice' import React from 'react' import { useTranslation } from 'react-i18next' +import { Platform } from 'react-native' import { createNativeStackNavigator } from 'react-native-screens/native-stack' import { useSelector } from 'react-redux' @@ -15,7 +17,13 @@ const ScreenNotifications: React.FC = () => { return ( null, headerTitle: t('notifications:heading'), + ...(Platform.OS === 'android' && { + headerCenter: () => ( + + ) + }), headerHideShadow: true, headerTopInsetEnabled: false }} diff --git a/src/screens/Shared/Announcements.tsx b/src/screens/Shared/Announcements.tsx index 1970e599..8c9d04e7 100644 --- a/src/screens/Shared/Announcements.tsx +++ b/src/screens/Shared/Announcements.tsx @@ -1,6 +1,7 @@ import Button from '@components/Button' import haptics from '@components/haptics' import { ParseHTML } from '@components/Parse' +import RelativeTime from '@components/RelativeTime' import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs' import { useAnnouncementMutation, @@ -10,7 +11,6 @@ import { StyleConstants } from '@utils/styles/constants' import { useTheme } from '@utils/styles/ThemeManager' import React, { useCallback, useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' -import Moment from 'react-moment' import { Dimensions, Image, @@ -80,13 +80,7 @@ const ScreenSharedAnnouncements: React.FC = ({ ]} > - 发布于{' '} - + 发布于 = ({ ) return ( - + = ({ diff --git a/src/screens/Shared/Compose/EditAttachment.tsx b/src/screens/Shared/Compose/EditAttachment.tsx index d5143530..b76583dd 100644 --- a/src/screens/Shared/Compose/EditAttachment.tsx +++ b/src/screens/Shared/Compose/EditAttachment.tsx @@ -8,7 +8,7 @@ import React, { useRef, useState } from 'react' -import { Alert, KeyboardAvoidingView } from 'react-native' +import { Alert, KeyboardAvoidingView, Platform } from 'react-native' import { SafeAreaView } from 'react-native-safe-area-context' import { createNativeStackNavigator } from 'react-native-screens/native-stack' import ComposeEditAttachmentRoot from './EditAttachment/Root' @@ -144,7 +144,10 @@ const ComposeEditAttachment: React.FC = ({ ) return ( - + = ({ index, focus }) => { styleTransform, { position: 'absolute', - top: -1000 + imageDimensionis.height / 2, - left: -1000 + imageDimensionis.width / 2 + top: -500 + imageDimensionis.height / 2, + left: -500 + imageDimensionis.width / 2 } ]} > - - - + + + - - - - + + diff --git a/src/screens/Shared/Compose/addAttachment.ts b/src/screens/Shared/Compose/addAttachment.ts index 1fc63efc..98d7f5a3 100644 --- a/src/screens/Shared/Compose/addAttachment.ts +++ b/src/screens/Shared/Compose/addAttachment.ts @@ -10,27 +10,40 @@ import { ActionSheetOptions } from '@expo/react-native-action-sheet' export interface Props { composeDispatch: Dispatch - showActionSheetWithOptions: (options: ActionSheetOptions, callback: (i: number) => void) => void + showActionSheetWithOptions: ( + options: ActionSheetOptions, + callback: (i: number) => void + ) => void } -const addAttachment = async ({ composeDispatch, showActionSheetWithOptions }: Props): Promise => { +const addAttachment = async ({ + composeDispatch, + showActionSheetWithOptions +}: Props): Promise => { const uploadAttachment = async (result: ImageInfo) => { const hash = await Crypto.digestStringAsync( Crypto.CryptoDigestAlgorithm.SHA256, result.uri + Math.random() ) + + let attachmentType: string + // https://github.com/expo/expo/issues/11214 + const attachmentUri = result.uri.replace('file:/data', 'file:///data') + switch (result.type) { case 'image': + attachmentType = `image/${attachmentUri.split('.')[1]}` composeDispatch({ type: 'attachment/upload/start', payload: { - local: { ...result, local_thumbnail: result.uri, hash }, + local: { ...result, local_thumbnail: attachmentUri, hash }, uploading: true } }) break case 'video': - VideoThumbnails.getThumbnailAsync(result.uri) + attachmentType = `video/${attachmentUri.split('.')[1]}` + VideoThumbnails.getThumbnailAsync(attachmentUri) .then(({ uri }) => composeDispatch({ type: 'attachment/upload/start', @@ -51,6 +64,7 @@ const addAttachment = async ({ composeDispatch, showActionSheetWithOptions }: Pr ) break default: + attachmentType = 'unknown' composeDispatch({ type: 'attachment/upload/start', payload: { @@ -64,9 +78,9 @@ const addAttachment = async ({ composeDispatch, showActionSheetWithOptions }: Pr const formData = new FormData() formData.append('file', { // @ts-ignore - uri: result.uri, - name: result.uri.split('/').pop(), - type: 'image/jpeg/jpg' + uri: attachmentUri, + name: attachmentType, + type: attachmentType }) return client({ diff --git a/src/screens/Shared/Search.tsx b/src/screens/Shared/Search.tsx index 5b0ccd57..3599e7d6 100644 --- a/src/screens/Shared/Search.tsx +++ b/src/screens/Shared/Search.tsx @@ -8,6 +8,7 @@ import { useTheme } from '@utils/styles/ThemeManager' import React, { useCallback, useEffect, useMemo, useState } from 'react' import { KeyboardAvoidingView, + Platform, Pressable, SectionList, StyleSheet, @@ -163,14 +164,17 @@ const ScreenSharedSearch: React.FC = ({ searchTerm }) => { ) case 'statuses': - return + return default: return null } }, []) return ( - + , , ,