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

Added instance configuration support

This commit is contained in:
Zhiyuan Zheng
2021-11-15 22:34:43 +01:00
parent 98dd7b2b46
commit 7ac789c18c
16 changed files with 302 additions and 101 deletions

View File

@ -9,7 +9,7 @@ import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
import { updateStoreReview } from '@utils/slices/contextsSlice'
import {
getInstanceAccount,
getInstanceMaxTootChar,
getInstanceConfigurationStatusMaxChars,
removeInstanceDraft,
updateInstanceDraft
} from '@utils/slices/instancesSlice'
@ -103,7 +103,10 @@ const ScreenCompose: React.FC<RootStackScreenProps<'Screen-Compose'>> = ({
initialReducerState
)
const maxTootChars = useSelector(getInstanceMaxTootChar, () => true)
const maxTootChars = useSelector(
getInstanceConfigurationStatusMaxChars,
() => true
)
const totalTextCount =
(composeState.spoiler.active ? composeState.spoiler.count : 0) +
composeState.text.count

View File

@ -29,6 +29,8 @@ import ComposeDrafts from './Root/Drafts'
import FastImage from 'react-native-fast-image'
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
import { ComposeState } from './utils/types'
import { useSelector } from 'react-redux'
import { getInstanceConfigurationStatusCharsURL } from '@utils/slices/instancesSlice'
const prefetchEmojis = (
sortedEmojis: NonNullable<ComposeState['emoji']['emojis']>,
@ -54,11 +56,18 @@ const prefetchEmojis = (
} catch {}
}
export let instanceConfigurationStatusCharsURL = 23
const ComposeRoot = React.memo(
() => {
const { reduceMotionEnabled } = useAccessibility()
const { theme } = useTheme()
instanceConfigurationStatusCharsURL = useSelector(
getInstanceConfigurationStatusCharsURL,
() => true
)
const accessibleRefDrafts = useRef(null)
const accessibleRefAttachments = useRef(null)
const accessibleRefEmojis = useRef(null)

View File

@ -1,12 +1,14 @@
import analytics from '@components/analytics'
import Icon from '@components/Icon'
import { useActionSheet } from '@expo/react-native-action-sheet'
import { getInstanceConfigurationStatusMaxAttachments } from '@utils/slices/instancesSlice'
import { StyleConstants } from '@utils/styles/constants'
import layoutAnimation from '@utils/styles/layoutAnimation'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useCallback, useContext, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { Pressable, StyleSheet, View } from 'react-native'
import { useSelector } from 'react-redux'
import ComposeContext from '../utils/createContext'
import addAttachment from './Footer/addAttachment'
@ -15,6 +17,10 @@ const ComposeActions: React.FC = () => {
const { composeState, composeDispatch } = useContext(ComposeContext)
const { t } = useTranslation('screenCompose')
const { theme } = useTheme()
const instanceConfigurationStatusMaxAttachments = useSelector(
getInstanceConfigurationStatusMaxAttachments,
() => true
)
const attachmentColor = useMemo(() => {
if (composeState.poll.active) return theme.disabled
@ -28,7 +34,10 @@ const ComposeActions: React.FC = () => {
const attachmentOnPress = useCallback(async () => {
if (composeState.poll.active) return
if (composeState.attachments.uploads.length < 4) {
if (
composeState.attachments.uploads.length <
instanceConfigurationStatusMaxAttachments
) {
analytics('compose_actions_attachment_press', {
count: composeState.attachments.uploads.length
})

View File

@ -3,11 +3,13 @@ import Button from '@components/Button'
import Icon from '@components/Icon'
import { MenuRow } from '@components/Menu'
import { useActionSheet } from '@expo/react-native-action-sheet'
import { getInstanceConfigurationPoll } from '@utils/slices/instancesSlice'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useContext, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { StyleSheet, TextInput, View } from 'react-native'
import { StyleSheet, Text, TextInput, View } from 'react-native'
import { useSelector } from 'react-redux'
import ComposeContext from '../../utils/createContext'
const ComposePoll: React.FC = () => {
@ -21,6 +23,16 @@ const ComposePoll: React.FC = () => {
const { t } = useTranslation('screenCompose')
const { mode, theme } = useTheme()
const instanceConfigurationPoll = useSelector(
getInstanceConfigurationPoll,
() => true
)
const MAX_OPTIONS = instanceConfigurationPoll.max_options
const MAX_CHARS_PER_OPTION =
instanceConfigurationPoll.max_characters_per_option
const MIN_EXPIRATION = instanceConfigurationPoll.min_expiration
const MAX_EXPIRATION = instanceConfigurationPoll.max_expiration
const [firstRender, setFirstRender] = useState(true)
useEffect(() => {
setFirstRender(false)
@ -67,7 +79,7 @@ const ComposePoll: React.FC = () => {
: t('content.root.footer.poll.option.placeholder.single')
}
placeholderTextColor={theme.disabled}
maxLength={50}
maxLength={MAX_CHARS_PER_OPTION}
// @ts-ignore
value={options[i]}
onChangeText={e =>
@ -82,37 +94,38 @@ const ComposePoll: React.FC = () => {
})}
</View>
<View style={styles.controlAmount}>
<View style={styles.firstButton}>
<Button
{...(total > 2
? {
accessibilityLabel: t(
'content.root.footer.poll.quantity.reduce.accessibilityLabel',
{ amount: total - 1 }
)
}
: {
accessibilityHint: t(
'content.root.footer.poll.quantity.reduce.accessibilityHint',
{ amount: total }
)
})}
onPress={() => {
analytics('compose_poll_reduce_press')
total > 2 &&
composeDispatch({
type: 'poll',
payload: { total: total - 1 }
})
}}
type='icon'
content='Minus'
round
disabled={!(total > 2)}
/>
</View>
<Button
{...(total < 4
{...(total > 2
? {
accessibilityLabel: t(
'content.root.footer.poll.quantity.reduce.accessibilityLabel',
{ amount: total - 1 }
)
}
: {
accessibilityHint: t(
'content.root.footer.poll.quantity.reduce.accessibilityHint',
{ amount: total }
)
})}
onPress={() => {
analytics('compose_poll_reduce_press')
total > 2 &&
composeDispatch({
type: 'poll',
payload: { total: total - 1 }
})
}}
type='icon'
content='Minus'
round
disabled={!(total > 2)}
/>
<Text style={styles.controlCount}>
{total} / {MAX_OPTIONS}
</Text>
<Button
{...(total < MAX_OPTIONS
? {
accessibilityLabel: t(
'content.root.footer.poll.quantity.increase.accessibilityLabel',
@ -127,7 +140,7 @@ const ComposePoll: React.FC = () => {
})}
onPress={() => {
analytics('compose_poll_increase_press')
total < 4 &&
total < MAX_OPTIONS &&
composeDispatch({
type: 'poll',
payload: { total: total + 1 }
@ -136,7 +149,7 @@ const ComposePoll: React.FC = () => {
type='icon'
content='Plus'
round
disabled={!(total < 4)}
disabled={!(total < MAX_OPTIONS)}
/>
</View>
<View style={styles.controlOptions}>
@ -158,7 +171,7 @@ const ComposePoll: React.FC = () => {
cancelButtonIndex: 2
},
index => {
if (index < 2) {
if (index && index < 2) {
analytics('compose_poll_expiration_press', {
current: multiple,
new: index === 1
@ -177,6 +190,7 @@ const ComposePoll: React.FC = () => {
title={t('content.root.footer.poll.expiration.heading')}
content={t(`content.root.footer.poll.expiration.options.${expire}`)}
onPress={() => {
// @ts-ignore
const expirations: [
'300',
'1800',
@ -185,7 +199,19 @@ const ComposePoll: React.FC = () => {
'86400',
'259200',
'604800'
] = ['300', '1800', '3600', '21600', '86400', '259200', '604800']
] = [
'300',
'1800',
'3600',
'21600',
'86400',
'259200',
'604800'
].filter(
expiration =>
parseInt(expiration) >= MIN_EXPIRATION &&
parseInt(expiration) <= MAX_EXPIRATION
)
showActionSheetWithOptions(
{
options: [
@ -197,7 +223,7 @@ const ComposePoll: React.FC = () => {
cancelButtonIndex: 7
},
index => {
if (index < 7) {
if (index && expirations.length < 7) {
analytics('compose_poll_expiration_press', {
current: expire,
new: expirations[index]
@ -246,14 +272,15 @@ const styles = StyleSheet.create({
controlAmount: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'flex-end',
marginRight: StyleConstants.Spacing.M
},
controlOptions: {
paddingHorizontal: StyleConstants.Spacing.Global.PagePadding
},
firstButton: {
marginRight: StyleConstants.Spacing.S
controlCount: {
marginHorizontal: StyleConstants.Spacing.S
}
})

View File

@ -13,7 +13,7 @@ export interface Props {
composeDispatch: Dispatch<ComposeAction>
showActionSheetWithOptions: (
options: ActionSheetOptions,
callback: (i: number) => void
callback: (i?: number | undefined) => void | Promise<void>
) => void
}

View File

@ -5,6 +5,7 @@ import { FetchOptions } from 'react-query/types/core/query'
import Autolinker from '@root/modules/autolinker'
import { useTheme } from '@utils/styles/ThemeManager'
import { ComposeAction, ComposeState } from './utils/types'
import { instanceConfigurationStatusCharsURL } from './Root'
export interface Params {
textInput: ComposeState['textInputFocus']['current']
@ -92,7 +93,7 @@ const formatText = ({
children.push(<TagText key={index} text={main} />)
switch (tag.type) {
case 'url':
contentLength = contentLength + 23
contentLength = contentLength + instanceConfigurationStatusCharsURL
break
case 'accounts':
const theMatch = main.match(/@/g)