Merge branch 'main' into candidate

This commit is contained in:
xmflsct 2022-12-19 23:27:59 +01:00
commit 327ec6d9c5
21 changed files with 157 additions and 125 deletions

View File

@ -56,7 +56,7 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
useEffect(() => {
const screenshotListener = addScreenshotListener(() =>
Alert.alert(t('screenshot.title'), t('screenshot.message'), [
{ text: t('screenshot.button'), style: 'destructive' }
{ text: t('common:buttons.confirm'), style: 'destructive' }
])
)
Platform.select({ ios: screenshotListener })

View File

@ -53,7 +53,7 @@ const ComponentHashtag: React.FC<PropsWithChildren & Props> = ({
#{hashtag.name}
</CustomText>
<View
style={{ flexDirection: 'row', alignItems: 'center' }}
style={{ flexDirection: 'row', alignItems: 'center', alignSelf: 'stretch' }}
onLayout={({
nativeEvent: {
layout: { height }

View File

@ -4,8 +4,8 @@ import { getSettingsFontsize } from '@utils/slices/settingsSlice'
import { StyleConstants } from '@utils/styles/constants'
import { adaptiveScale } from '@utils/styles/scaling'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useMemo } from 'react'
import { Platform, StyleSheet, TextStyle } from 'react-native'
import React from 'react'
import { Platform, TextStyle } from 'react-native'
import FastImage from 'react-native-fast-image'
import { useSelector } from 'react-redux'
import validUrl from 'valid-url'
@ -36,23 +36,19 @@ const ParseEmojis = React.memo(
)
const { colors, theme } = useTheme()
const styles = useMemo(() => {
return StyleSheet.create({
text: {
color: colors.primaryDefault,
fontSize: adaptedFontsize,
lineHeight: adaptedLineheight
},
image: {
width: adaptedFontsize,
height: adaptedFontsize,
...(Platform.OS === 'android' && { transform: [{ translateY: 2 }] })
}
})
}, [theme, adaptiveFontsize])
return (
<CustomText style={[styles.text, style]} fontWeight={fontBold ? 'Bold' : undefined}>
<CustomText
style={[
{
color: colors.primaryDefault,
fontSize: adaptedFontsize,
lineHeight: adaptedLineheight
},
style
]}
fontWeight={fontBold ? 'Bold' : undefined}
>
{emojis ? (
content
.split(regexEmoji)
@ -73,7 +69,14 @@ const ParseEmojis = React.memo(
return (
<CustomText key={emojiShortcode + i}>
{i === 0 ? ' ' : undefined}
<FastImage source={{ uri }} style={styles.image} />
<FastImage
source={{ uri }}
style={{
width: adaptedFontsize,
height: adaptedFontsize,
transform: [{ translateY: Platform.OS === 'ios' ? -1 : 2 }]
}}
/>
</CustomText>
)
} else {

View File

@ -135,7 +135,7 @@ const renderNode = ({
size={adaptedFontsize}
style={{
marginLeft: StyleConstants.Spacing.XS,
...(Platform.OS === 'android' && { transform: [{ translateY: 2 }] })
transform: [{ translateY: Platform.OS === 'ios' ? -1 : 2 }]
}}
/>
) : null}

View File

@ -2,6 +2,7 @@ import Icon from '@components/Icon'
import { displayMessage } from '@components/Message'
import CustomText from '@components/Text'
import { useActionSheet } from '@expo/react-native-action-sheet'
import { androidActionSheetStyles } from '@helpers/androidActionSheetStyles'
import { useNavigation } from '@react-navigation/native'
import { StackNavigationProp } from '@react-navigation/stack'
import { RootStackParamList } from '@utils/navigation/navigators'
@ -99,7 +100,8 @@ const TimelineActions: React.FC = () => {
t('shared.actions.reblogged.options.unlisted'),
t('common:buttons.cancel')
],
cancelButtonIndex: 2
cancelButtonIndex: 2,
...androidActionSheetStyles(colors)
},
(selectedIndex: number) => {
switch (selectedIndex) {

View File

@ -1,8 +1,12 @@
import { ParseHTML } from '@components/Parse'
import CustomText from '@components/Text'
import { getInstanceAccount } from '@utils/slices/instancesSlice'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useContext } from 'react'
import { useTranslation } from 'react-i18next'
import { Platform } from 'react-native'
import { Platform, StyleSheet, View } from 'react-native'
import { Path, Svg } from 'react-native-svg'
import { useSelector } from 'react-redux'
import { isRtlLang } from 'rtl-detect'
import StatusContext from './Context'
@ -16,6 +20,7 @@ const TimelineContent: React.FC<Props> = ({ notificationOwnToot = false, setSpoi
const { status, highlighted, inThread, disableDetails } = useContext(StatusContext)
if (!status || typeof status.content !== 'string' || !status.content.length) return null
const { colors } = useTheme()
const { t } = useTranslation('componentTimeline')
const instanceAccount = useSelector(getInstanceAccount, () => true)
@ -39,6 +44,11 @@ const TimelineContent: React.FC<Props> = ({ notificationOwnToot = false, setSpoi
: undefined
}
/>
{inThread ? (
<CustomText fontStyle='S' style={{ textAlign: 'center', color: colors.secondary, paddingVertical: StyleConstants.Spacing.XS }}>
{t('shared.content.expandHint')}
</CustomText>
) : null}
<ParseHTML
content={status.content}
size={highlighted ? 'L' : 'M'}

View File

@ -16,7 +16,7 @@ import {
import { getInstanceAccount } from '@utils/slices/instancesSlice'
import { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Platform } from 'react-native'
import { Alert, Platform } from 'react-native'
import { useQueryClient } from '@tanstack/react-query'
import { useSelector } from 'react-redux'
@ -186,12 +186,22 @@ const menuAccount = ({
key: 'account-block',
item: {
onSelect: () =>
timelineMutation.mutate({
type: 'updateAccountProperty',
queryKey,
id: account.id,
payload: { property: 'block', currentValue: data?.blocking }
}),
Alert.alert(t('account.block.alert.title', { username: account.username }), undefined, [
{
text: t('common:buttons.confirm'),
style: 'destructive',
onPress: () =>
timelineMutation.mutate({
type: 'updateAccountProperty',
queryKey,
id: account.id,
payload: { property: 'block', currentValue: data?.blocking }
})
},
{
text: t('common:buttons.cancel')
}
]),
disabled: Platform.OS !== 'android' ? !data || !isFetched : false,
destructive: !data?.blocking,
hidden: false
@ -204,20 +214,34 @@ const menuAccount = ({
{
key: 'account-reports',
item: {
onSelect: () => {
timelineMutation.mutate({
type: 'updateAccountProperty',
queryKey,
id: account.id,
payload: { property: 'reports' }
})
timelineMutation.mutate({
type: 'updateAccountProperty',
queryKey,
id: account.id,
payload: { property: 'block', currentValue: false }
})
},
onSelect: () =>
Alert.alert(
t('account.reports.alert.title', { username: account.username }),
undefined,
[
{
text: t('common:buttons.confirm'),
style: 'destructive',
onPress: () => {
timelineMutation.mutate({
type: 'updateAccountProperty',
queryKey,
id: account.id,
payload: { property: 'reports' }
})
timelineMutation.mutate({
type: 'updateAccountProperty',
queryKey,
id: account.id,
payload: { property: 'block', currentValue: false }
})
}
},
{
text: t('common:buttons.cancel')
}
]
),
disabled: false,
destructive: true,
hidden: false

View File

@ -49,7 +49,7 @@ const menuInstance = ({
t('instance.block.alert.message'),
[
{
text: t('instance.block.alert.buttons.confirm'),
text: t('common:buttons.confirm'),
style: 'destructive',
onPress: () => {
mutation.mutate({

View File

@ -109,7 +109,7 @@ const menuStatus = ({
onSelect: () =>
Alert.alert(t('status.deleteEdit.alert.title'), t('status.deleteEdit.alert.message'), [
{
text: t('status.deleteEdit.alert.buttons.confirm'),
text: t('common:buttons.confirm'),
style: 'destructive',
onPress: async () => {
let replyToStatus: Mastodon.Status | undefined = undefined
@ -153,7 +153,7 @@ const menuStatus = ({
onSelect: () =>
Alert.alert(t('status.delete.alert.title'), t('status.delete.alert.message'), [
{
text: t('status.delete.alert.buttons.confirm'),
text: t('common:buttons.confirm'),
style: 'destructive',
onPress: async () => {
mutation.mutate({

View File

@ -0,0 +1,5 @@
export const androidActionSheetStyles = (colors: any) => ({
containerStyle: { backgroundColor: colors.backgroundDefault },
textStyle: { color: colors.primaryDefault },
titleTextStyle: { color: colors.secondary }
})

View File

@ -7,7 +7,8 @@
"continue": "Continue",
"create": "Create",
"delete": "Delete",
"done": "Done"
"done": "Done",
"confirm": "Confirm"
},
"customEmoji": {
"accessibilityLabel": "Custom emoji {{emoji}}"

View File

@ -13,10 +13,16 @@
},
"block": {
"action_false": "Block user",
"action_true": "Unblock user"
"action_true": "Unblock user",
"alert": {
"title": "Confirm blocking user @{{username}} ?"
}
},
"reports": {
"action": "Report and block user"
"action": "Report and block user",
"alert": {
"title": "Confirm report and blocking user @{{username}} ?"
}
}
},
"at": {
@ -33,10 +39,7 @@
"action": "Block instance {{instance}}",
"alert": {
"title": "Confirm blocking instance {{instance}} ?",
"message": "Mostly you can mute or block certain user.\n\nAfter blocking instance, all its content including followers from this instance will be removed!",
"buttons": {
"confirm": "Confirm"
}
"message": "Mostly you can mute or block certain user.\n\nAfter blocking instance, all its content including followers from this instance will be removed!"
}
}
},
@ -57,20 +60,14 @@
"action": "Delete toot",
"alert": {
"title": "Confirm deleting?",
"message": "All boosts and favourites will be cleared, including all replies.",
"buttons": {
"confirm": "Confirm"
}
"message": "All boosts and favourites will be cleared, including all replies."
}
},
"deleteEdit": {
"action": "Delete toot and repost",
"alert": {
"title": "Confirm deleting and repost?",
"message": "All boosts and favourites will be cleared, including all replies.",
"buttons": {
"confirm": "Confirm"
}
"message": "All boosts and favourites will be cleared, including all replies."
}
},
"mute": {

View File

@ -1,8 +1,7 @@
{
"screenshot": {
"title": "Privacy Protection",
"message": "Please do not disclose other user's identity, such as username, avatar, etc. Thank you!",
"button": "Confirm"
"message": "Please do not disclose other user's identity, such as username, avatar, etc. Thank you!"
},
"localCorrupt": {
"message": "Login expired, please login again"

View File

@ -2,6 +2,7 @@ import { emojis } from '@components/Emojis'
import EmojisContext from '@components/Emojis/helpers/EmojisContext'
import Icon from '@components/Icon'
import { useActionSheet } from '@expo/react-native-action-sheet'
import { androidActionSheetStyles } from '@helpers/androidActionSheetStyles'
import { getInstanceConfigurationStatusMaxAttachments } from '@utils/slices/instancesSlice'
import layoutAnimation from '@utils/styles/layoutAnimation'
import { useTheme } from '@utils/styles/ThemeManager'
@ -16,7 +17,7 @@ const ComposeActions: React.FC = () => {
const { showActionSheetWithOptions } = useActionSheet()
const { composeState, composeDispatch } = useContext(ComposeContext)
const { t } = useTranslation('screenCompose')
const { colors, mode } = useTheme()
const { colors } = useTheme()
const instanceConfigurationStatusMaxAttachments = useSelector(
getInstanceConfigurationStatusMaxAttachments,
() => true
@ -89,7 +90,7 @@ const ComposeActions: React.FC = () => {
t('common:buttons.cancel')
],
cancelButtonIndex: 4,
userInterfaceStyle: mode
...androidActionSheetStyles(colors)
},
buttonIndex => {
switch (buttonIndex) {

View File

@ -3,6 +3,7 @@ import Icon from '@components/Icon'
import { MenuRow } from '@components/Menu'
import CustomText from '@components/Text'
import { useActionSheet } from '@expo/react-native-action-sheet'
import { androidActionSheetStyles } from '@helpers/androidActionSheetStyles'
import { getInstanceConfigurationPoll } from '@utils/slices/instancesSlice'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
@ -23,13 +24,9 @@ const ComposePoll: React.FC = () => {
const { t } = useTranslation('screenCompose')
const { colors, mode } = useTheme()
const instanceConfigurationPoll = useSelector(
getInstanceConfigurationPoll,
() => true
)
const instanceConfigurationPoll = useSelector(getInstanceConfigurationPoll, () => true)
const MAX_OPTIONS = instanceConfigurationPoll.max_options
const MAX_CHARS_PER_OPTION =
instanceConfigurationPoll.max_characters_per_option
const MAX_CHARS_PER_OPTION = instanceConfigurationPoll.max_characters_per_option
const MIN_EXPIRATION = instanceConfigurationPoll.min_expiration
const MAX_EXPIRATION = instanceConfigurationPoll.max_expiration
@ -127,10 +124,9 @@ const ComposePoll: React.FC = () => {
)
}
: {
accessibilityHint: t(
'content.root.footer.poll.quantity.reduce.accessibilityHint',
{ amount: total }
)
accessibilityHint: t('content.root.footer.poll.quantity.reduce.accessibilityHint', {
amount: total
})
})}
onPress={() => {
total > 2 &&
@ -179,9 +175,7 @@ const ComposePoll: React.FC = () => {
disabled={!(total < MAX_OPTIONS)}
/>
</View>
<View
style={{ paddingHorizontal: StyleConstants.Spacing.Global.PagePadding }}
>
<View style={{ paddingHorizontal: StyleConstants.Spacing.Global.PagePadding }}>
<MenuRow
title={t('content.root.footer.poll.multiple.heading')}
content={
@ -198,7 +192,7 @@ const ComposePoll: React.FC = () => {
t('common:buttons.cancel')
],
cancelButtonIndex: 2,
userInterfaceStyle: mode
...androidActionSheetStyles(colors)
},
index => {
if (index && index < 2) {
@ -226,19 +220,16 @@ const ComposePoll: React.FC = () => {
'604800'
].filter(
expiration =>
parseInt(expiration) >= MIN_EXPIRATION &&
parseInt(expiration) <= MAX_EXPIRATION
parseInt(expiration) >= MIN_EXPIRATION && parseInt(expiration) <= MAX_EXPIRATION
)
showActionSheetWithOptions(
{
options: [
...expirations.map(e =>
t(`content.root.footer.poll.expiration.options.${e}`)
),
...expirations.map(e => t(`content.root.footer.poll.expiration.options.${e}`)),
t('common:buttons.cancel')
],
cancelButtonIndex: expirations.length,
userInterfaceStyle: mode
...androidActionSheetStyles(colors)
},
index => {
if (index !== undefined && index < expirations.length) {

View File

@ -1,6 +1,7 @@
import GracefullyImage from '@components/GracefullyImage'
import { HeaderCenter, HeaderLeft, HeaderRight } from '@components/Header'
import { useActionSheet } from '@expo/react-native-action-sheet'
import { androidActionSheetStyles } from '@helpers/androidActionSheetStyles'
import { RootStackScreenProps } from '@utils/navigation/navigators'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useCallback, useState } from 'react'
@ -39,7 +40,7 @@ const ScreenImagesViewer = ({
const insets = useSafeAreaInsets()
const { mode } = useTheme()
const { mode, colors } = useTheme()
const { t } = useTranslation('screenImageViewer')
const initialIndex = imageUrls.findIndex(image => image.id === id)
@ -55,7 +56,7 @@ const ScreenImagesViewer = ({
t('common:buttons.cancel')
],
cancelButtonIndex: 2,
userInterfaceStyle: mode
...androidActionSheetStyles(colors)
},
async buttonIndex => {
switch (buttonIndex) {
@ -181,7 +182,7 @@ const ScreenImagesViewer = ({
t('common:buttons.cancel')
],
cancelButtonIndex: 2,
userInterfaceStyle: mode
...androidActionSheetStyles(colors)
},
async buttonIndex => {
switch (buttonIndex) {

View File

@ -61,7 +61,7 @@ const Root: React.FC<NativeStackScreenProps<TabLocalStackParamList, 'Tab-Local-R
/>
{page.page === 'Following' && !instanceFollowingPage.showBoosts ? (
<Icon
name='MessageCircle'
name='Repeat'
size={StyleConstants.Font.Size.M}
color={colors.red}
style={{ marginLeft: StyleConstants.Spacing.S }}
@ -70,7 +70,7 @@ const Root: React.FC<NativeStackScreenProps<TabLocalStackParamList, 'Tab-Local-R
) : null}
{page.page === 'Following' && !instanceFollowingPage.showReplies ? (
<Icon
name='Repeat'
name='MessageCircle'
size={StyleConstants.Font.Size.M}
color={colors.red}
style={{ marginLeft: StyleConstants.Spacing.S }}
@ -100,7 +100,7 @@ const Root: React.FC<NativeStackScreenProps<TabLocalStackParamList, 'Tab-Local-R
</DropdownMenu.Item>
<DropdownMenu.CheckboxItem
key='showBoosts'
value={instanceFollowingPage.showBoosts ? 'on' : 'mixed'}
value={instanceFollowingPage.showBoosts ? 'on' : 'off'}
onValueChange={() => {
setQueryKey([
'Timeline',
@ -120,7 +120,7 @@ const Root: React.FC<NativeStackScreenProps<TabLocalStackParamList, 'Tab-Local-R
</DropdownMenu.CheckboxItem>
<DropdownMenu.CheckboxItem
key='showReplies'
value={instanceFollowingPage.showReplies ? 'on' : 'mixed'}
value={instanceFollowingPage.showReplies ? 'on' : 'off'}
onValueChange={() => {
setQueryKey([
'Timeline',
@ -174,7 +174,7 @@ const Root: React.FC<NativeStackScreenProps<TabLocalStackParamList, 'Tab-Local-R
/>
)
})
}, [mode, queryKey[1], instanceFollowingPage])
}, [mode, queryKey[1], instanceFollowingPage, lists])
usePopToTop()

View File

@ -1,5 +1,6 @@
import { MenuContainer, MenuRow } from '@components/Menu'
import { useActionSheet } from '@expo/react-native-action-sheet'
import { androidActionSheetStyles } from '@helpers/androidActionSheetStyles'
import { useAppDispatch } from '@root/store'
import { TabMeProfileStackScreenProps } from '@utils/navigation/navigators'
import { useProfileMutation, useProfileQuery } from '@utils/queryHooks/profile'
@ -16,7 +17,7 @@ const TabMeProfileRoot: React.FC<
messageRef: RefObject<FlashMessage>
}
> = ({ messageRef, navigation }) => {
const { mode } = useTheme()
const { colors } = useTheme()
const { t } = useTranslation('screenTabs')
const { showActionSheetWithOptions } = useActionSheet()
@ -93,7 +94,7 @@ const TabMeProfileRoot: React.FC<
t('common:buttons.cancel')
],
cancelButtonIndex: 3,
userInterfaceStyle: mode
...androidActionSheetStyles(colors)
},
async buttonIndex => {
switch (buttonIndex) {

View File

@ -1,6 +1,7 @@
import haptics from '@components/haptics'
import { MenuContainer, MenuRow } from '@components/Menu'
import { useActionSheet } from '@expo/react-native-action-sheet'
import { androidActionSheetStyles } from '@helpers/androidActionSheetStyles'
import { useNavigation } from '@react-navigation/native'
import { LOCALES } from '@root/i18n/locales'
import { useAppDispatch } from '@root/store'
@ -15,6 +16,7 @@ import {
getSettingsStaticEmoji,
changeStaticEmoji
} from '@utils/slices/settingsSlice'
import { useTheme } from '@utils/styles/ThemeManager'
import * as Localization from 'expo-localization'
import React from 'react'
import { useTranslation } from 'react-i18next'
@ -26,6 +28,7 @@ const SettingsApp: React.FC = () => {
const navigation = useNavigation<any>()
const dispatch = useAppDispatch()
const { showActionSheetWithOptions } = useActionSheet()
const { colors } = useTheme()
const { t, i18n } = useTranslation('screenTabs')
const settingsFontsize = useSelector(getSettingsFontsize)
@ -71,7 +74,8 @@ const SettingsApp: React.FC = () => {
t('me.settings.theme.options.dark'),
t('common:buttons.cancel')
],
cancelButtonIndex: 3
cancelButtonIndex: 3,
...androidActionSheetStyles(colors)
},
buttonIndex => {
switch (buttonIndex) {
@ -105,7 +109,8 @@ const SettingsApp: React.FC = () => {
t('me.settings.darkTheme.options.darker'),
t('common:buttons.cancel')
],
cancelButtonIndex: 2
cancelButtonIndex: 2,
...androidActionSheetStyles(colors)
},
buttonIndex => {
switch (buttonIndex) {
@ -135,7 +140,8 @@ const SettingsApp: React.FC = () => {
t('me.settings.browser.options.external'),
t('common:buttons.cancel')
],
cancelButtonIndex: 2
cancelButtonIndex: 2,
...androidActionSheetStyles(colors)
},
buttonIndex => {
switch (buttonIndex) {

View File

@ -3,6 +3,7 @@ import { MenuContainer, MenuRow } from '@components/Menu'
import { displayMessage } from '@components/Message'
import CustomText from '@components/Text'
import { useActionSheet } from '@expo/react-native-action-sheet'
import { androidActionSheetStyles } from '@helpers/androidActionSheetStyles'
import { persistor } from '@root/store'
import { getInstanceActive, getInstances } from '@utils/slices/instancesSlice'
import { StyleConstants } from '@utils/styles/constants'
@ -13,7 +14,7 @@ import { DevSettings } from 'react-native'
import { useSelector } from 'react-redux'
const SettingsDev: React.FC = () => {
const { colors, mode } = useTheme()
const { colors } = useTheme()
const { showActionSheetWithOptions } = useActionSheet()
const instanceActive = useSelector(getInstanceActive)
const instances = useSelector(getInstances, () => true)
@ -58,7 +59,7 @@ const SettingsDev: React.FC = () => {
})
.concat(['Cancel']),
cancelButtonIndex: instances.length,
userInterfaceStyle: mode
...androidActionSheetStyles(colors)
},
() => {}
)

View File

@ -1,33 +1,26 @@
import apiGeneral from '@api/general'
import apiTooot from '@api/tooot'
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
import { RootState } from '@root/store'
import { isDevelopment } from '@utils/checkEnvironment'
import Constants from 'expo-constants'
import * as Notifications from 'expo-notifications'
export const retrieveExpoToken = createAsyncThunk(
'app/expoToken',
async (): Promise<string> => {
if (isDevelopment) {
return 'ExponentPushToken[DEVELOPMENT_1]'
}
const res = await Notifications.getExpoPushTokenAsync({
experienceId: '@xmflsct/tooot',
applicationId: 'com.xmflsct.app.tooot'
})
return res.data
export const retrieveExpoToken = createAsyncThunk('app/expoToken', async (): Promise<string> => {
if (isDevelopment) {
return 'ExponentPushToken[DEVELOPMENT_1]'
}
)
const res = await Notifications.getExpoPushTokenAsync({
experienceId: '@xmflsct/tooot',
applicationId: 'com.xmflsct.app.tooot'
})
return res.data
})
export const retrieveVersionLatest = createAsyncThunk(
'app/versionUpdate',
async (): Promise<string> => {
const res = await apiGeneral<{ latest: string }>({
method: 'get',
domain: 'tooot.app',
url: 'version.json'
})
const res = await apiTooot<{ latest: string }>({ method: 'get', url: 'version.json' })
return res.body.latest
}
)
@ -55,11 +48,8 @@ const appSlice = createSlice({
})
.addCase(retrieveVersionLatest.fulfilled, (state, action) => {
if (action.payload && Constants.expoConfig?.version) {
if (
parseFloat(action.payload) > parseFloat(Constants.expoConfig?.version)
) {
state.versionUpdate = true
}
state.versionUpdate =
parseFloat(action.payload) > parseFloat(Constants.expoConfig.version)
}
})
}