Allow custom exit

This commit is contained in:
xmflsct 2022-09-23 00:21:41 +02:00
parent 8ef2b89a09
commit 7d9056b562
12 changed files with 38 additions and 71 deletions

View File

@ -1,20 +1,12 @@
import EmojisButton from '@components/Emojis/Button'
import EmojisList from '@components/Emojis/List'
import { PasteInputRef } from '@mattermost/react-native-paste-input'
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
import { useEmojisQuery } from '@utils/queryHooks/emojis'
import { getInstanceFrequentEmojis } from '@utils/slices/instancesSlice'
import { chunk, forEach, groupBy, sortBy } from 'lodash'
import React, {
createRef,
PropsWithChildren,
RefObject,
useEffect,
useReducer,
useState
} from 'react'
import React, { createRef, PropsWithChildren, useEffect, useReducer, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Keyboard, KeyboardAvoidingView, TextInput, View } from 'react-native'
import { Keyboard, KeyboardAvoidingView, View } from 'react-native'
import FastImage from 'react-native-fast-image'
import { Edge, SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context'
import { useSelector } from 'react-redux'
@ -49,7 +41,6 @@ const prefetchEmojis = (
export type Props = {
inputProps: EmojisState['inputProps']
focusRef?: RefObject<TextInput | PasteInputRef>
customButton?: boolean
customEdges?: Edge[]
customBehavior?: 'height' | 'padding' | 'position'
@ -60,7 +51,6 @@ export const emojis: Emojis = createRef()
const ComponentEmojis: React.FC<Props & PropsWithChildren> = ({
children,
inputProps,
focusRef,
customButton = false,
customEdges = ['bottom'],
customBehavior
@ -79,14 +69,14 @@ const ComponentEmojis: React.FC<Props & PropsWithChildren> = ({
if (data && data.length) {
let sortedEmojis: NonNullable<Emojis['current']> = []
forEach(groupBy(sortBy(data, ['category', 'shortcode']), 'category'), (value, key) =>
sortedEmojis.push({ title: key, data: chunk(value, 4) })
sortedEmojis.push({ title: key, data: chunk(value, 5) })
)
if (frequentEmojis.length) {
sortedEmojis.unshift({
title: t('componentEmojis:frequentUsed'),
data: chunk(
frequentEmojis.map(e => e.emoji),
4
5
),
type: 'frequent'
})
@ -115,11 +105,6 @@ const ComponentEmojis: React.FC<Props & PropsWithChildren> = ({
hideSubscription.remove()
}
}, [inputProps])
useEffect(() => {
if (focusRef) {
setTimeout(() => focusRef.current?.focus(), 500)
}
}, [])
return (
<KeyboardAvoidingView style={{ flex: 1 }} behavior={customBehavior}>
@ -129,7 +114,7 @@ const ComponentEmojis: React.FC<Props & PropsWithChildren> = ({
{children}
<View
style={[
keyboardShown ? { position: 'absolute', bottom: 0, width: '100%' } : null,
{ position: 'absolute', bottom: 0, width: '100%' },
{
marginBottom: keyboardShown && emojisState.targetIndex === -1 ? insets.bottom : 0
}

View File

@ -27,7 +27,7 @@ const EmojisList = () => {
const { reduceMotionEnabled } = useAccessibility()
const { t } = useTranslation()
const { emojisState } = useContext(EmojisContext)
const { emojisState, emojisDispatch } = useContext(EmojisContext)
const { colors, mode } = useTheme()
const addEmoji = (shortcode: string) => {
@ -165,6 +165,17 @@ const EmojisList = () => {
autoCorrect={false}
spellCheck={false}
/>
<Pressable
style={{ paddingLeft: StyleConstants.Spacing.M }}
onPress={() => {
if (emojisState.targetIndex !== -1) {
emojisState.inputProps[emojisState.targetIndex].ref?.current?.focus()
}
emojisDispatch({ type: 'target', payload: -1 })
}}
>
<Icon name='ChevronDown' size={StyleConstants.Font.Size.L} color={colors.secondary} />
</Pressable>
</View>
<SectionList
accessible

View File

@ -5,9 +5,8 @@ type inputProps = {
value: [string, (value: string) => void]
selection: [{ start: number; end?: number }, (selection: { start: number; end?: number }) => void]
isFocused: MutableRefObject<boolean>
ref?: RefObject<TextInput> // For controlling focus
ref: RefObject<TextInput> // For controlling focus
maxLength?: number
addFunc?: (add: string) => void // For none default state update
}
export type Emojis = MutableRefObject<

View File

@ -365,7 +365,8 @@ const ScreenCompose: React.FC<RootStackScreenProps<'Screen-Compose'>> = ({
selection => composeDispatch({ type: 'text', payload: { selection } })
],
isFocused: composeState.textInputFocus.isFocused.text,
maxLength: maxTootChars - (composeState.spoiler.active ? composeState.spoiler.count : 0)
maxLength: maxTootChars - (composeState.spoiler.active ? composeState.spoiler.count : 0),
ref: composeState.textInputFocus.refs.text
},
{
value: [
@ -377,7 +378,8 @@ const ScreenCompose: React.FC<RootStackScreenProps<'Screen-Compose'>> = ({
selection => composeDispatch({ type: 'spoiler', payload: { selection } })
],
isFocused: composeState.textInputFocus.isFocused.spoiler,
maxLength: maxTootChars - composeState.text.count
maxLength: maxTootChars - composeState.text.count,
ref: composeState.textInputFocus.refs.spoiler
}
]

View File

@ -1,7 +1,7 @@
import { HeaderLeft } from '@components/Header'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import { ScreenComposeStackScreenProps } from '@utils/navigation/navigators'
import React, { useCallback } from 'react'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { KeyboardAvoidingView, Platform } from 'react-native'
import { SafeAreaView } from 'react-native-safe-area-context'

View File

@ -1,9 +1,7 @@
import ComponentSeparator from '@components/Separator'
import { useEmojisQuery } from '@utils/queryHooks/emojis'
import { useSearchQuery } from '@utils/queryHooks/search'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import { chunk, forEach, groupBy, sortBy } from 'lodash'
import React, { useContext, useEffect, useMemo, useRef } from 'react'
import { AccessibilityInfo, findNodeHandle, FlatList, View } from 'react-native'
import { Circle } from 'react-native-animated-spinkit'
@ -14,19 +12,13 @@ import ComposeRootHeader from './Root/Header'
import ComposeRootSuggestion from './Root/Suggestion'
import ComposeContext from './utils/createContext'
import ComposeDrafts from './Root/Drafts'
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
import { useSelector } from 'react-redux'
import {
getInstanceConfigurationStatusCharsURL,
getInstanceFrequentEmojis
} from '@utils/slices/instancesSlice'
import { useTranslation } from 'react-i18next'
import { getInstanceConfigurationStatusCharsURL } from '@utils/slices/instancesSlice'
export let instanceConfigurationStatusCharsURL = 23
const ComposeRoot = React.memo(
() => {
const { reduceMotionEnabled } = useAccessibility()
const { colors } = useTheme()
instanceConfigurationStatusCharsURL = useSelector(
@ -42,7 +34,7 @@ const ComposeRoot = React.memo(
tagDrafts && AccessibilityInfo.setAccessibilityFocus(tagDrafts)
}, [accessibleRefDrafts.current])
const { composeState, composeDispatch } = useContext(ComposeContext)
const { composeState } = useContext(ComposeContext)
const mapSchemaToType = () => {
if (composeState.tag) {
@ -71,30 +63,6 @@ const ComposeRoot = React.memo(
}
}, [composeState.tag])
const { t } = useTranslation()
const { data: emojisData } = useEmojisQuery({})
const frequentEmojis = useSelector(getInstanceFrequentEmojis, () => true)
useEffect(() => {
if (emojisData && emojisData.length) {
const sortedEmojis: {
title: string
data: Pick<Mastodon.Emoji, 'shortcode' | 'url' | 'static_url'>[][]
}[] = []
forEach(groupBy(sortBy(emojisData, ['category', 'shortcode']), 'category'), (value, key) =>
sortedEmojis.push({ title: key, data: chunk(value, 5) })
)
if (frequentEmojis.length) {
sortedEmojis.unshift({
title: t('componentEmojis:frequentUsed'),
data: chunk(
frequentEmojis.map(e => e.emoji),
5
)
})
}
}
}, [emojisData, reduceMotionEnabled])
const listEmpty = useMemo(() => {
if (isFetching) {
return (

View File

@ -21,6 +21,7 @@ const ComposeSpoilerInput: React.FC = () => {
return (
<TextInput
ref={composeState.textInputFocus.refs.spoiler}
keyboardAppearance={mode}
style={{
...StyleConstants.FontStyle.M,

View File

@ -39,7 +39,7 @@ const composeInitialState: Omit<ComposeState, 'timestamp'> = {
replyToStatus: undefined,
textInputFocus: {
current: 'text',
refs: { text: createRef() },
refs: { text: createRef(), spoiler: createRef() },
isFocused: { text: createRef(), spoiler: createRef() }
}
}

View File

@ -1,3 +1,4 @@
import { RefObject } from 'react';
import { Asset } from 'react-native-image-picker'
export type ExtendedAttachment = {
@ -39,10 +40,6 @@ export type ComposeState = {
index: number
lastIndex: number
raw: string
// type: 'url' | 'accounts' | 'hashtags'
// text: string
// offset: number
// length: number
}
poll: {
active: boolean
@ -62,7 +59,7 @@ export type ComposeState = {
replyToStatus?: Mastodon.Status
textInputFocus: {
current: 'text' | 'spoiler'
refs: { text: RefObject<TextInput> }
refs: { text: RefObject<TextInput>, spoiler: RefObject<TextInput> }
isFocused: { text: MutableRefObject<boolean>, spoiler: MutableRefObject<boolean> }
}
}

View File

@ -9,7 +9,7 @@ import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { Dispatch, RefObject, SetStateAction, useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Alert, ScrollView } from 'react-native'
import { Alert, ScrollView, TextInput } from 'react-native'
import FlashMessage from 'react-native-flash-message'
const Field: React.FC<{
@ -21,19 +21,23 @@ const Field: React.FC<{
const { colors } = useTheme()
const { t } = useTranslation('screenTabs')
const nameRef = useRef<TextInput>(null)
const valueRef = useRef<TextInput>(null)
const [name, setName] = useState(field?.name || '')
const [value, setValue] = useState(field?.value || '')
allProps[index * 2] = {
value: [name, setName],
selection: useState({ start: name.length }),
isFocused: useRef<boolean>(false),
maxLength: 255
maxLength: 255,
ref: nameRef
}
allProps[index * 2 + 1] = {
value: [value, setValue],
selection: useState({ start: value.length }),
isFocused: useRef<boolean>(false),
maxLength: 255
maxLength: 255,
ref: valueRef
}
useEffect(() => {

View File

@ -93,7 +93,7 @@ const TabMeProfileName: React.FC<
}, [theme, i18n.language, dirty, status, value])
return (
<ComponentEmojis inputProps={[displayNameProps]} focusRef={displayNameProps.ref}>
<ComponentEmojis inputProps={[displayNameProps]}>
<ScrollView style={{ paddingHorizontal: StyleConstants.Spacing.Global.PagePadding }}>
<ComponentInput
{...displayNameProps}

View File

@ -93,7 +93,7 @@ const TabMeProfileNote: React.FC<
}, [theme, i18n.language, dirty, status, notes])
return (
<ComponentEmojis inputProps={[notesProps]} focusRef={notesProps.ref}>
<ComponentEmojis inputProps={[notesProps]}>
<ScrollView style={{ paddingHorizontal: StyleConstants.Spacing.Global.PagePadding }}>
<ComponentInput {...notesProps} multiline />
</ScrollView>