mirror of https://github.com/tooot-app/app
Add static emoji option
This commit is contained in:
parent
9c3e8f58b0
commit
dde33ad1ad
|
@ -166,7 +166,7 @@ const styles = StyleSheet.create({
|
|||
core: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
paddingVertical: StyleConstants.Spacing.S
|
||||
paddingTop: StyleConstants.Spacing.S
|
||||
},
|
||||
front: {
|
||||
flex: 2,
|
||||
|
|
|
@ -130,7 +130,9 @@ const Timeline: React.FC<Props> = ({
|
|||
}
|
||||
ListEmptyComponent={<TimelineEmpty queryKey={queryKey} />}
|
||||
ItemSeparatorComponent={ItemSeparatorComponent}
|
||||
maintainVisibleContentPosition={{ minIndexForVisible: 0 }}
|
||||
{...(isFetchingPreviousPage && {
|
||||
maintainVisibleContentPosition: { minIndexForVisible: 0 }
|
||||
})}
|
||||
refreshing={isFetchingPreviousPage}
|
||||
onRefresh={() => {
|
||||
if (!disableRefresh && !isFetchingPreviousPage) {
|
||||
|
|
|
@ -251,6 +251,10 @@
|
|||
"cancel": "$t(common:buttons.cancel)"
|
||||
}
|
||||
},
|
||||
"staticEmoji": {
|
||||
"heading": "Use static emoji",
|
||||
"description": "If you encounter frequent app crash when viewing emoji list, you can try to use static emoji instead."
|
||||
},
|
||||
"feedback": {
|
||||
"heading": "Feature Requests"
|
||||
},
|
||||
|
|
|
@ -3,6 +3,7 @@ import CustomText from '@components/Text'
|
|||
import { useAppDispatch } from '@root/store'
|
||||
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
|
||||
import { countInstanceEmoji } from '@utils/slices/instancesSlice'
|
||||
import { getSettingsStaticEmoji } from '@utils/slices/settingsSlice'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React, { RefObject, useCallback, useContext, useEffect } from 'react'
|
||||
|
@ -10,11 +11,13 @@ import { useTranslation } from 'react-i18next'
|
|||
import {
|
||||
AccessibilityInfo,
|
||||
findNodeHandle,
|
||||
Image,
|
||||
Pressable,
|
||||
SectionList,
|
||||
View
|
||||
} from 'react-native'
|
||||
import FastImage from 'react-native-fast-image'
|
||||
import { useSelector } from 'react-redux'
|
||||
import validUrl from 'valid-url'
|
||||
import updateText from '../../updateText'
|
||||
import ComposeContext from '../../utils/createContext'
|
||||
|
@ -30,6 +33,8 @@ const ComposeEmojis: React.FC<Props> = ({ accessibleRefEmojis }) => {
|
|||
const { t } = useTranslation()
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
const staticEmoji = useSelector(getSettingsStaticEmoji)
|
||||
|
||||
useEffect(() => {
|
||||
const tagEmojis = findNodeHandle(accessibleRefEmojis.current)
|
||||
if (composeState.emoji.active) {
|
||||
|
@ -82,24 +87,45 @@ const ComposeEmojis: React.FC<Props> = ({ accessibleRefEmojis }) => {
|
|||
dispatch(countInstanceEmoji(emoji))
|
||||
}}
|
||||
>
|
||||
<FastImage
|
||||
accessibilityLabel={t(
|
||||
'common:customEmoji.accessibilityLabel',
|
||||
{
|
||||
emoji: emoji.shortcode
|
||||
}
|
||||
)}
|
||||
accessibilityHint={t(
|
||||
'screenCompose:content.root.footer.emojis.accessibilityHint'
|
||||
)}
|
||||
source={{ uri }}
|
||||
style={{
|
||||
width: 32,
|
||||
height: 32,
|
||||
padding: StyleConstants.Spacing.S,
|
||||
margin: StyleConstants.Spacing.S
|
||||
}}
|
||||
/>
|
||||
{staticEmoji ? (
|
||||
<Image
|
||||
accessibilityLabel={t(
|
||||
'common:customEmoji.accessibilityLabel',
|
||||
{
|
||||
emoji: emoji.shortcode
|
||||
}
|
||||
)}
|
||||
accessibilityHint={t(
|
||||
'screenCompose:content.root.footer.emojis.accessibilityHint'
|
||||
)}
|
||||
source={{ uri }}
|
||||
style={{
|
||||
width: 32,
|
||||
height: 32,
|
||||
padding: StyleConstants.Spacing.S,
|
||||
margin: StyleConstants.Spacing.S
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<FastImage
|
||||
accessibilityLabel={t(
|
||||
'common:customEmoji.accessibilityLabel',
|
||||
{
|
||||
emoji: emoji.shortcode
|
||||
}
|
||||
)}
|
||||
accessibilityHint={t(
|
||||
'screenCompose:content.root.footer.emojis.accessibilityHint'
|
||||
)}
|
||||
source={{ uri }}
|
||||
style={{
|
||||
width: 32,
|
||||
height: 32,
|
||||
padding: StyleConstants.Spacing.S,
|
||||
margin: StyleConstants.Spacing.S
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Pressable>
|
||||
)
|
||||
} else {
|
||||
|
|
|
@ -22,35 +22,39 @@ const SettingsAnalytics: React.FC = () => {
|
|||
const instanceVersion = useSelector(getInstanceVersion, () => true)
|
||||
|
||||
return (
|
||||
<MenuContainer>
|
||||
<MenuRow
|
||||
title={t('me.settings.analytics.heading')}
|
||||
description={t('me.settings.analytics.description')}
|
||||
switchValue={settingsAnalytics}
|
||||
switchOnValueChange={() =>
|
||||
dispatch(changeAnalytics(!settingsAnalytics))
|
||||
}
|
||||
/>
|
||||
<CustomText
|
||||
fontStyle='S'
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
marginTop: StyleConstants.Spacing.S,
|
||||
color: colors.secondary
|
||||
}}
|
||||
>
|
||||
{t('me.settings.version', { version: Constants.manifest?.version })}
|
||||
</CustomText>
|
||||
<CustomText
|
||||
fontStyle='S'
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
color: colors.secondary
|
||||
}}
|
||||
>
|
||||
{t('me.settings.instanceVersion', { version: instanceVersion })}
|
||||
</CustomText>
|
||||
</MenuContainer>
|
||||
<>
|
||||
<MenuContainer>
|
||||
<MenuRow
|
||||
title={t('me.settings.analytics.heading')}
|
||||
description={t('me.settings.analytics.description')}
|
||||
switchValue={settingsAnalytics}
|
||||
switchOnValueChange={() =>
|
||||
dispatch(changeAnalytics(!settingsAnalytics))
|
||||
}
|
||||
/>
|
||||
</MenuContainer>
|
||||
<MenuContainer>
|
||||
<CustomText
|
||||
fontStyle='S'
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
marginTop: StyleConstants.Spacing.S,
|
||||
color: colors.secondary
|
||||
}}
|
||||
>
|
||||
{t('me.settings.version', { version: Constants.manifest?.version })}
|
||||
</CustomText>
|
||||
<CustomText
|
||||
fontStyle='S'
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
color: colors.secondary
|
||||
}}
|
||||
>
|
||||
{t('me.settings.instanceVersion', { version: instanceVersion })}
|
||||
</CustomText>
|
||||
</MenuContainer>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,9 @@ import {
|
|||
getSettingsBrowser,
|
||||
getSettingsFontsize,
|
||||
getSettingsDarkTheme,
|
||||
changeDarkTheme
|
||||
changeDarkTheme,
|
||||
getSettingsStaticEmoji,
|
||||
changeStaticEmoji
|
||||
} from '@utils/slices/settingsSlice'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import * as Notifications from 'expo-notifications'
|
||||
|
@ -37,6 +39,7 @@ const SettingsApp: React.FC = () => {
|
|||
const settingsTheme = useSelector(getSettingsTheme)
|
||||
const settingsDarkTheme = useSelector(getSettingsDarkTheme)
|
||||
const settingsBrowser = useSelector(getSettingsBrowser)
|
||||
const settingsStaticEmoji = useSelector(getSettingsStaticEmoji)
|
||||
|
||||
return (
|
||||
<MenuContainer>
|
||||
|
@ -266,6 +269,18 @@ const SettingsApp: React.FC = () => {
|
|||
)
|
||||
}
|
||||
/>
|
||||
<MenuRow
|
||||
title={t('me.settings.staticEmoji.heading')}
|
||||
description={t('me.settings.staticEmoji.description')}
|
||||
switchValue={settingsStaticEmoji}
|
||||
switchOnValueChange={() => {
|
||||
analytics('settings_staticemoji_press', {
|
||||
current: settingsStaticEmoji.toString(),
|
||||
new: !settingsStaticEmoji.toString()
|
||||
})
|
||||
dispatch(changeStaticEmoji(!settingsStaticEmoji))
|
||||
}}
|
||||
/>
|
||||
</MenuContainer>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { SettingsV0 } from './v0'
|
||||
import { SettingsV1 } from './v1'
|
||||
import { SettingsV2 } from './v2'
|
||||
|
||||
const settingsMigration = {
|
||||
1: (state: SettingsV0): SettingsV1 => {
|
||||
|
@ -7,6 +8,13 @@ const settingsMigration = {
|
|||
...state,
|
||||
darkTheme: 'lighter'
|
||||
}
|
||||
},
|
||||
2: (state: SettingsV1): SettingsV2 => {
|
||||
return {
|
||||
...state,
|
||||
darkTheme: 'lighter',
|
||||
staticEmoji: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
export type SettingsV2 = {
|
||||
fontsize: -1 | 0 | 1 | 2 | 3
|
||||
language: string
|
||||
theme: 'light' | 'dark' | 'auto'
|
||||
darkTheme: 'lighter' | 'darker'
|
||||
browser: 'internal' | 'external'
|
||||
staticEmoji: boolean
|
||||
analytics: boolean
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit'
|
||||
import { LOCALES } from '@root/i18n/locales'
|
||||
import { RootState } from '@root/store'
|
||||
import { SettingsV2 } from '@utils/migrations/settings/v2'
|
||||
import * as Analytics from 'expo-firebase-analytics'
|
||||
import * as Localization from 'expo-localization'
|
||||
import { pickBy } from 'lodash'
|
||||
|
@ -13,14 +14,7 @@ export const changeAnalytics = createAsyncThunk(
|
|||
}
|
||||
)
|
||||
|
||||
export type SettingsState = {
|
||||
fontsize: -1 | 0 | 1 | 2 | 3
|
||||
language: string
|
||||
theme: 'light' | 'dark' | 'auto'
|
||||
darkTheme: 'lighter' | 'darker'
|
||||
browser: 'internal' | 'external'
|
||||
analytics: boolean
|
||||
}
|
||||
export type SettingsState = SettingsV2
|
||||
|
||||
export const settingsInitialState = {
|
||||
fontsize: 0,
|
||||
|
@ -37,6 +31,7 @@ export const settingsInitialState = {
|
|||
theme: 'auto',
|
||||
darkTheme: 'lighter',
|
||||
browser: 'internal',
|
||||
staticEmoji: false,
|
||||
analytics: true
|
||||
}
|
||||
|
||||
|
@ -73,6 +68,12 @@ const settingsSlice = createSlice({
|
|||
action: PayloadAction<NonNullable<SettingsState['browser']>>
|
||||
) => {
|
||||
state.browser = action.payload
|
||||
},
|
||||
changeStaticEmoji: (
|
||||
state,
|
||||
action: PayloadAction<NonNullable<SettingsState['staticEmoji']>>
|
||||
) => {
|
||||
state.staticEmoji = action.payload
|
||||
}
|
||||
},
|
||||
extraReducers: builder => {
|
||||
|
@ -89,6 +90,8 @@ export const getSettingsTheme = (state: RootState) => state.settings.theme
|
|||
export const getSettingsDarkTheme = (state: RootState) =>
|
||||
state.settings.darkTheme
|
||||
export const getSettingsBrowser = (state: RootState) => state.settings.browser
|
||||
export const getSettingsStaticEmoji = (state: RootState) =>
|
||||
state.settings.staticEmoji
|
||||
export const getSettingsAnalytics = (state: RootState) =>
|
||||
state.settings.analytics
|
||||
|
||||
|
@ -97,6 +100,7 @@ export const {
|
|||
changeLanguage,
|
||||
changeTheme,
|
||||
changeDarkTheme,
|
||||
changeBrowser
|
||||
changeBrowser,
|
||||
changeStaticEmoji
|
||||
} = settingsSlice.actions
|
||||
export default settingsSlice.reducer
|
||||
|
|
Loading…
Reference in New Issue