Merge pull request #124 from tooot-app/main

Nightly 210511
This commit is contained in:
xmflsct 2021-05-11 21:39:48 +02:00 committed by GitHub
commit 27a9f9fdc0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 234 additions and 186 deletions

View File

@ -151,4 +151,8 @@ declare namespace Nav {
fields?: Mastodon.Source['fields']
}
}
type TabMePushStackParamList = {
'Tab-Me-Push-Root': undefined
}
}

View File

@ -86,6 +86,7 @@ export interface Props {
start: number
end: number
}>
maxLength?: number
}
const ComponentEmojis: React.FC<Props> = ({
@ -93,6 +94,7 @@ const ComponentEmojis: React.FC<Props> = ({
value,
setValue,
selectionRange,
maxLength,
children
}) => {
const { reduceMotionEnabled } = useAccessibility()
@ -125,9 +127,13 @@ const ComponentEmojis: React.FC<Props> = ({
const newTextWithSpace = ` ${emojiShortcode}${
whiteSpaceRear ? '' : ' '
}`
setValue([contentFront, newTextWithSpace, contentRear].join(''))
setValue(
[contentFront, newTextWithSpace, contentRear]
.join('')
.slice(0, maxLength)
)
} else {
setValue(`${emojiShortcode} `)
setValue(`${emojiShortcode} `.slice(0, maxLength))
}
},
[value, selectionRange.current?.start, selectionRange.current?.end]

View File

@ -107,6 +107,7 @@ const Input: React.FC<Props> = ({
value={value}
setValue={setValue}
selectionRange={selectionRange}
maxLength={options?.maxLength}
>
<View
style={[

View File

@ -115,15 +115,10 @@ const TabMe = React.memo(
<Stack.Screen
name='Tab-Me-Push'
component={TabMePush}
options={({ navigation }: any) => ({
headerTitle: t('me.stacks.push.name'),
...(Platform.OS === 'android' && {
headerCenter: () => (
<HeaderCenter content={t('me.stacks.push.name')} />
)
}),
headerLeft: () => <HeaderLeft onPress={() => navigation.pop(1)} />
})}
options={{
stackPresentation: 'modal',
headerShown: false
}}
/>
<Stack.Screen
name='Tab-Me-Settings'

View File

@ -6,10 +6,10 @@ import { useTranslation } from 'react-i18next'
import { KeyboardAvoidingView, Platform } from 'react-native'
import FlashMessage from 'react-native-flash-message'
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
import ScreenMeProfileFields from './Profile/Fields'
import ScreenMeProfileName from './Profile/Name'
import ScreenMeProfileNote from './Profile/Note'
import ScreenMeProfileRoot from './Profile/Root'
import TabMeProfileFields from './Profile/Fields'
import TabMeProfileName from './Profile/Name'
import TabMeProfileNote from './Profile/Note'
import TabMeProfileRoot from './Profile/Root'
const Stack = createNativeStackNavigator<Nav.TabMeProfileStackParamList>()
@ -30,7 +30,7 @@ const TabMeProfile: React.FC<StackScreenProps<
>
<Stack.Screen
name='Tab-Me-Profile-Root'
component={ScreenMeProfileRoot}
component={TabMeProfileRoot}
options={{
headerTitle: t('me.stacks.profile.name'),
...(Platform.OS === 'android' && {
@ -58,7 +58,7 @@ const TabMeProfile: React.FC<StackScreenProps<
}}
>
{({ route, navigation }) => (
<ScreenMeProfileName
<TabMeProfileName
messageRef={messageRef}
route={route}
navigation={navigation}
@ -77,7 +77,7 @@ const TabMeProfile: React.FC<StackScreenProps<
}}
>
{({ route, navigation }) => (
<ScreenMeProfileNote
<TabMeProfileNote
messageRef={messageRef}
route={route}
navigation={navigation}
@ -96,7 +96,7 @@ const TabMeProfile: React.FC<StackScreenProps<
}}
>
{({ route, navigation }) => (
<ScreenMeProfileFields
<TabMeProfileFields
messageRef={messageRef}
route={route}
navigation={navigation}

View File

@ -24,7 +24,7 @@ const prepareFields = (
})
}
const ScreenMeProfileFields: React.FC<StackScreenProps<
const TabMeProfileFields: React.FC<StackScreenProps<
Nav.TabMeProfileStackParamList,
'Tab-Me-Profile-Fields'
> & { messageRef: RefObject<FlashMessage> }> = ({
@ -112,7 +112,7 @@ const ScreenMeProfileFields: React.FC<StackScreenProps<
}, [mode, i18n.language, dirty, status, newFields])
return (
<ScrollView style={styles.base} keyboardShouldPersistTaps='handled'>
<ScrollView style={styles.base} keyboardShouldPersistTaps='always'>
<View style={{ marginBottom: StyleConstants.Spacing.L * 2 }}>
{Array.from(Array(4).keys()).map(index => (
<View key={index} style={styles.group}>
@ -168,4 +168,4 @@ const styles = StyleSheet.create({
}
})
export default ScreenMeProfileFields
export default TabMeProfileFields

View File

@ -11,7 +11,7 @@ import { Alert, StyleSheet } from 'react-native'
import FlashMessage from 'react-native-flash-message'
import { ScrollView } from 'react-native-gesture-handler'
const ScreenMeProfileName: React.FC<StackScreenProps<
const TabMeProfileName: React.FC<StackScreenProps<
Nav.TabMeProfileStackParamList,
'Tab-Me-Profile-Name'
> & { messageRef: RefObject<FlashMessage> }> = ({
@ -94,7 +94,7 @@ const ScreenMeProfileName: React.FC<StackScreenProps<
}, [mode, i18n.language, dirty, status, displayName])
return (
<ScrollView style={styles.base} keyboardShouldPersistTaps='handled'>
<ScrollView style={styles.base} keyboardShouldPersistTaps='always'>
<Input
value={displayName}
setValue={setDisplayName}
@ -116,4 +116,4 @@ const styles = StyleSheet.create({
}
})
export default ScreenMeProfileName
export default TabMeProfileName

View File

@ -11,7 +11,7 @@ import { Alert, StyleSheet, View } from 'react-native'
import FlashMessage from 'react-native-flash-message'
import { ScrollView } from 'react-native-gesture-handler'
const ScreenMeProfileNote: React.FC<StackScreenProps<
const TabMeProfileNote: React.FC<StackScreenProps<
Nav.TabMeProfileStackParamList,
'Tab-Me-Profile-Note'
> & { messageRef: RefObject<FlashMessage> }> = ({
@ -94,7 +94,7 @@ const ScreenMeProfileNote: React.FC<StackScreenProps<
}, [mode, i18n.language, dirty, status, newNote])
return (
<ScrollView style={styles.base} keyboardShouldPersistTaps='handled'>
<ScrollView style={styles.base} keyboardShouldPersistTaps='always'>
<View style={{ marginBottom: StyleConstants.Spacing.XL * 2 }}>
<Input
value={newNote}
@ -114,4 +114,4 @@ const styles = StyleSheet.create({
}
})
export default ScreenMeProfileNote
export default TabMeProfileNote

View File

@ -6,7 +6,7 @@ import React, { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import { ScrollView } from 'react-native-gesture-handler'
const ScreenMeProfileRoot: React.FC<StackScreenProps<
const TabMeProfileRoot: React.FC<StackScreenProps<
Nav.TabMeProfileStackParamList,
'Tab-Me-Profile-Root'
>> = ({ navigation }) => {
@ -180,4 +180,4 @@ const ScreenMeProfileRoot: React.FC<StackScreenProps<
)
}
export default ScreenMeProfileRoot
export default TabMeProfileRoot

View File

@ -1,162 +1,42 @@
import { MenuContainer, MenuRow } from '@components/Menu'
import { updateInstancePush } from '@utils/slices/instances/updatePush'
import { updateInstancePushAlert } from '@utils/slices/instances/updatePushAlert'
import { updateInstancePushDecode } from '@utils/slices/instances/updatePushDecode'
import {
clearPushLoading,
getInstanceAccount,
getInstancePush,
getInstanceUri
} from '@utils/slices/instancesSlice'
import * as WebBrowser from 'expo-web-browser'
import * as Notifications from 'expo-notifications'
import React, { useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { ScrollView } from 'react-native-gesture-handler'
import { useDispatch, useSelector } from 'react-redux'
import layoutAnimation from '@utils/styles/layoutAnimation'
import Button from '@components/Button'
import { StyleConstants } from '@utils/styles/constants'
import { AppState, Linking } from 'react-native'
import { HeaderCenter, HeaderLeft } from '@components/Header'
import { StackScreenProps } from '@react-navigation/stack'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { Platform } from 'react-native'
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
import TabMePushRoot from './Push/Root'
const Stack = createNativeStackNavigator<Nav.TabMePushStackParamList>()
const TabMePush: React.FC<StackScreenProps<
Nav.TabMeStackParamList,
'Tab-Me-Push'
>> = () => {
>> = ({ navigation }) => {
const { t } = useTranslation('screenTabs')
const instanceAccount = useSelector(
getInstanceAccount,
(prev, next) => prev?.acct === next?.acct
)
const instanceUri = useSelector(getInstanceUri)
const dispatch = useDispatch()
const instancePush = useSelector(getInstancePush)
const [pushEnabled, setPushEnabled] = useState<boolean>()
const [pushCanAskAgain, setPushCanAskAgain] = useState<boolean>()
const checkPush = async () => {
const settings = await Notifications.getPermissionsAsync()
layoutAnimation()
setPushEnabled(settings.granted)
setPushCanAskAgain(settings.canAskAgain)
}
useEffect(() => {
checkPush()
AppState.addEventListener('change', checkPush)
return () => {
AppState.removeEventListener('change', checkPush)
}
}, [])
useEffect(() => {
dispatch(clearPushLoading())
}, [])
const isLoading = instancePush?.global.loading || instancePush?.decode.loading
const alerts = useMemo(() => {
return instancePush?.alerts
? (['follow', 'favourite', 'reblog', 'mention', 'poll'] as [
'follow',
'favourite',
'reblog',
'mention',
'poll'
]).map(alert => (
<MenuRow
key={alert}
title={t(`me.push.${alert}.heading`)}
switchDisabled={
!pushEnabled || !instancePush.global.value || isLoading
}
switchValue={instancePush?.alerts[alert].value}
switchOnValueChange={() =>
dispatch(
updateInstancePushAlert({
changed: alert,
alerts: {
...instancePush?.alerts,
[alert]: {
...instancePush?.alerts[alert],
value: !instancePush?.alerts[alert].value
}
}
})
)
}
/>
))
: null
}, [pushEnabled, instancePush?.global, instancePush?.alerts, isLoading])
return (
<ScrollView>
{pushEnabled === false ? (
<MenuContainer>
<Button
type='text'
content={
pushCanAskAgain
? t('me.push.enable.direct')
: t('me.push.enable.settings')
}
style={{
marginTop: StyleConstants.Spacing.Global.PagePadding,
marginHorizontal: StyleConstants.Spacing.Global.PagePadding * 2
}}
onPress={async () => {
if (pushCanAskAgain) {
const result = await Notifications.requestPermissionsAsync()
setPushEnabled(result.granted)
setPushCanAskAgain(result.canAskAgain)
} else {
Linking.openSettings()
}
<Stack.Navigator
screenOptions={{ headerHideShadow: true, headerTopInsetEnabled: false }}
>
<Stack.Screen
name='Tab-Me-Push-Root'
component={TabMePushRoot}
options={{
headerTitle: t('me.stacks.push.name'),
...(Platform.OS === 'android' && {
headerCenter: () => (
<HeaderCenter content={t('me.stacks.push.name')} />
)
}),
headerLeft: () => (
<HeaderLeft
content='ChevronDown'
onPress={() => navigation.goBack()}
/>
)
}}
/>
</MenuContainer>
) : null}
<MenuContainer>
<MenuRow
title={t('me.push.global.heading', {
acct: `@${instanceAccount?.acct}@${instanceUri}`
})}
description={t('me.push.global.description')}
loading={instancePush?.global.loading}
switchDisabled={!pushEnabled || isLoading}
switchValue={
pushEnabled === false ? false : instancePush?.global.value
}
switchOnValueChange={() =>
dispatch(updateInstancePush(!instancePush?.global.value))
}
/>
</MenuContainer>
<MenuContainer>
<MenuRow
title={t('me.push.decode.heading')}
description={t('me.push.decode.description')}
loading={instancePush?.decode.loading}
switchDisabled={
!pushEnabled || !instancePush?.global.value || isLoading
}
switchValue={instancePush?.decode.value}
switchOnValueChange={() =>
dispatch(updateInstancePushDecode(!instancePush?.decode.value))
}
/>
<MenuRow
title={t('me.push.howitworks')}
iconBack='ExternalLink'
onPress={() =>
WebBrowser.openBrowserAsync('https://tooot.app/how-push-works')
}
/>
</MenuContainer>
<MenuContainer>{alerts}</MenuContainer>
</ScrollView>
</Stack.Navigator>
)
}

View File

@ -0,0 +1,163 @@
import { MenuContainer, MenuRow } from '@components/Menu'
import { updateInstancePush } from '@utils/slices/instances/updatePush'
import { updateInstancePushAlert } from '@utils/slices/instances/updatePushAlert'
import { updateInstancePushDecode } from '@utils/slices/instances/updatePushDecode'
import {
clearPushLoading,
getInstanceAccount,
getInstancePush,
getInstanceUri
} from '@utils/slices/instancesSlice'
import * as WebBrowser from 'expo-web-browser'
import * as Notifications from 'expo-notifications'
import React, { useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { ScrollView } from 'react-native-gesture-handler'
import { useDispatch, useSelector } from 'react-redux'
import layoutAnimation from '@utils/styles/layoutAnimation'
import Button from '@components/Button'
import { StyleConstants } from '@utils/styles/constants'
import { AppState, Linking } from 'react-native'
import { StackScreenProps } from '@react-navigation/stack'
const TabMePushRoot: React.FC<StackScreenProps<
Nav.TabMeStackParamList,
'Tab-Me-Push'
>> = () => {
const { t } = useTranslation('screenTabs')
const instanceAccount = useSelector(
getInstanceAccount,
(prev, next) => prev?.acct === next?.acct
)
const instanceUri = useSelector(getInstanceUri)
const dispatch = useDispatch()
const instancePush = useSelector(getInstancePush)
const [pushEnabled, setPushEnabled] = useState<boolean>()
const [pushCanAskAgain, setPushCanAskAgain] = useState<boolean>()
const checkPush = async () => {
const settings = await Notifications.getPermissionsAsync()
layoutAnimation()
setPushEnabled(settings.granted)
setPushCanAskAgain(settings.canAskAgain)
}
useEffect(() => {
checkPush()
AppState.addEventListener('change', checkPush)
return () => {
AppState.removeEventListener('change', checkPush)
}
}, [])
useEffect(() => {
dispatch(clearPushLoading())
}, [])
const isLoading = instancePush?.global.loading || instancePush?.decode.loading
const alerts = useMemo(() => {
return instancePush?.alerts
? (['follow', 'favourite', 'reblog', 'mention', 'poll'] as [
'follow',
'favourite',
'reblog',
'mention',
'poll'
]).map(alert => (
<MenuRow
key={alert}
title={t(`me.push.${alert}.heading`)}
switchDisabled={
!pushEnabled || !instancePush.global.value || isLoading
}
switchValue={instancePush?.alerts[alert].value}
switchOnValueChange={() =>
dispatch(
updateInstancePushAlert({
changed: alert,
alerts: {
...instancePush?.alerts,
[alert]: {
...instancePush?.alerts[alert],
value: !instancePush?.alerts[alert].value
}
}
})
)
}
/>
))
: null
}, [pushEnabled, instancePush?.global, instancePush?.alerts, isLoading])
return (
<ScrollView>
{pushEnabled === false ? (
<MenuContainer>
<Button
type='text'
content={
pushCanAskAgain
? t('me.push.enable.direct')
: t('me.push.enable.settings')
}
style={{
marginTop: StyleConstants.Spacing.Global.PagePadding,
marginHorizontal: StyleConstants.Spacing.Global.PagePadding * 2
}}
onPress={async () => {
if (pushCanAskAgain) {
const result = await Notifications.requestPermissionsAsync()
setPushEnabled(result.granted)
setPushCanAskAgain(result.canAskAgain)
} else {
Linking.openSettings()
}
}}
/>
</MenuContainer>
) : null}
<MenuContainer>
<MenuRow
title={t('me.push.global.heading', {
acct: `@${instanceAccount?.acct}@${instanceUri}`
})}
description={t('me.push.global.description')}
loading={instancePush?.global.loading}
switchDisabled={!pushEnabled || isLoading}
switchValue={
pushEnabled === false ? false : instancePush?.global.value
}
switchOnValueChange={() =>
dispatch(updateInstancePush(!instancePush?.global.value))
}
/>
</MenuContainer>
<MenuContainer>
<MenuRow
title={t('me.push.decode.heading')}
description={t('me.push.decode.description')}
loading={instancePush?.decode.loading}
switchDisabled={
!pushEnabled || !instancePush?.global.value || isLoading
}
switchValue={instancePush?.decode.value}
switchOnValueChange={() =>
dispatch(updateInstancePushDecode(!instancePush?.decode.value))
}
/>
<MenuRow
title={t('me.push.howitworks')}
iconBack='ExternalLink'
onPress={() =>
WebBrowser.openBrowserAsync('https://tooot.app/how-push-works')
}
/>
</MenuContainer>
<MenuContainer>{alerts}</MenuContainer>
</ScrollView>
)
}
export default TabMePushRoot

View File

@ -4,7 +4,7 @@ import React from 'react'
import { useTranslation } from 'react-i18next'
import { KeyboardAvoidingView, Platform } from 'react-native'
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
import ScreenMeSwitchRoot from './Switch/Root'
import TabMeSwitchRoot from './Switch/Root'
const Stack = createNativeStackNavigator()
@ -23,7 +23,7 @@ const TabMeSwitch: React.FC<StackScreenProps<
>
<Stack.Screen
name='Screen-Me-Switch-Root'
component={ScreenMeSwitchRoot}
component={TabMeSwitchRoot}
options={{
headerTitle: t('me.stacks.switch.name'),
...(Platform.OS === 'android' && {

View File

@ -11,7 +11,6 @@ import {
} from '@utils/slices/instancesSlice'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import { groupBy } from 'lodash'
import React, { useRef } from 'react'
import { useTranslation } from 'react-i18next'
import { StyleSheet, Text, View } from 'react-native'
@ -48,7 +47,7 @@ const AccountButton: React.FC<Props> = ({ instance, selected = false }) => {
)
}
const ScreenMeSwitchRoot: React.FC = () => {
const TabMeSwitchRoot: React.FC = () => {
const { t } = useTranslation('screenTabs')
const { theme } = useTheme()
const instances = useSelector(getInstances, () => true)
@ -137,4 +136,4 @@ const styles = StyleSheet.create({
}
})
export default ScreenMeSwitchRoot
export default TabMeSwitchRoot