1
0
mirror of https://github.com/tooot-app/app synced 2025-04-26 07:58:48 +02:00

Merge pull request #224 from tooot-app/main

Release v3.4.4
This commit is contained in:
xmflsct 2022-02-12 19:22:25 +01:00 committed by GitHub
commit 50815bc1c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
116 changed files with 899 additions and 598 deletions

View File

@ -4,7 +4,7 @@
"native": "220206", "native": "220206",
"major": 3, "major": 3,
"minor": 4, "minor": 4,
"patch": 3, "patch": 4,
"expo": "44.0.0" "expo": "44.0.0"
}, },
"description": "tooot app for Mastodon", "description": "tooot app for Mastodon",

View File

@ -26,7 +26,6 @@ import { addScreenshotListener } from 'expo-screen-capture'
import React, { useCallback, useEffect, useRef, useState } from 'react' import React, { useCallback, useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { Alert, Platform, StatusBar } from 'react-native' import { Alert, Platform, StatusBar } from 'react-native'
import { useQueryClient } from 'react-query'
import { useDispatch, useSelector } from 'react-redux' import { useDispatch, useSelector } from 'react-redux'
import * as Sentry from 'sentry-expo' import * as Sentry from 'sentry-expo'
@ -40,7 +39,7 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
const { t } = useTranslation('screens') const { t } = useTranslation('screens')
const dispatch = useDispatch() const dispatch = useDispatch()
const instanceActive = useSelector(getInstanceActive) const instanceActive = useSelector(getInstanceActive)
const { mode, theme } = useTheme() const { colors, mode, theme } = useTheme()
enum barStyle { enum barStyle {
light = 'dark-content', light = 'dark-content',
dark = 'light-content' dark = 'light-content'
@ -53,7 +52,6 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
getInstances, getInstances,
(prev, next) => prev.length === next.length (prev, next) => prev.length === next.length
) )
const queryClient = useQueryClient()
pushUseConnect({ t, instances }) pushUseConnect({ t, instances })
pushUseReceive({ instances }) pushUseReceive({ instances })
pushUseRespond({ instances }) pushUseRespond({ instances })
@ -77,8 +75,9 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
message: t('localCorrupt.message'), message: t('localCorrupt.message'),
description: localCorrupt.length ? localCorrupt : undefined, description: localCorrupt.length ? localCorrupt : undefined,
type: 'error', type: 'error',
mode theme
}) })
// @ts-ignore
navigationRef.navigate('Screen-Tabs', { navigationRef.navigate('Screen-Tabs', {
screen: 'Tab-Me' screen: 'Tab-Me'
}) })
@ -164,11 +163,11 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
<> <>
<StatusBar <StatusBar
barStyle={barStyle[mode]} barStyle={barStyle[mode]}
backgroundColor={theme.backgroundDefault} backgroundColor={colors.backgroundDefault}
/> />
<NavigationContainer <NavigationContainer
ref={navigationRef} ref={navigationRef}
theme={themes[mode]} theme={themes[theme]}
onReady={navigationContainerOnReady} onReady={navigationContainerOnReady}
onStateChange={navigationContainerOnStateChange} onStateChange={navigationContainerOnStateChange}
> >

View File

@ -20,10 +20,9 @@ const ComponentAccount: React.FC<Props> = ({
onPress: customOnPress, onPress: customOnPress,
origin origin
}) => { }) => {
const { theme } = useTheme() const { colors } = useTheme()
const navigation = useNavigation< const navigation =
StackNavigationProp<TabLocalStackParamList> useNavigation<StackNavigationProp<TabLocalStackParamList>>()
>()
const onPress = useCallback(() => { const onPress = useCallback(() => {
analytics('search_account_press', { page: origin }) analytics('search_account_press', { page: origin })
@ -37,7 +36,7 @@ const ComponentAccount: React.FC<Props> = ({
onPress={customOnPress || onPress} onPress={customOnPress || onPress}
> >
<GracefullyImage <GracefullyImage
uri={{ original: account.avatar_static }} uri={{ original: account.avatar, static: account.avatar_static }}
style={styles.itemAccountAvatar} style={styles.itemAccountAvatar}
/> />
<View> <View>
@ -51,7 +50,7 @@ const ComponentAccount: React.FC<Props> = ({
</Text> </Text>
<Text <Text
numberOfLines={1} numberOfLines={1}
style={[styles.itemAccountAcct, { color: theme.secondary }]} style={[styles.itemAccountAcct, { color: colors.secondary }]}
> >
@{account.acct} @{account.acct}
</Text> </Text>

View File

@ -54,7 +54,7 @@ const Button: React.FC<Props> = ({
overlay = false, overlay = false,
onPress onPress
}) => { }) => {
const { mode, theme } = useTheme() const { colors, theme } = useTheme()
const mounted = useRef(false) const mounted = useRef(false)
useEffect(() => { useEffect(() => {
@ -68,35 +68,35 @@ const Button: React.FC<Props> = ({
const loadingSpinkit = useMemo( const loadingSpinkit = useMemo(
() => ( () => (
<View style={{ position: 'absolute' }}> <View style={{ position: 'absolute' }}>
<Flow size={StyleConstants.Font.Size[size]} color={theme.secondary} /> <Flow size={StyleConstants.Font.Size[size]} color={colors.secondary} />
</View> </View>
), ),
[mode] [theme]
) )
const mainColor = useMemo(() => { const mainColor = useMemo(() => {
if (selected) { if (selected) {
return theme.blue return colors.blue
} else if (overlay) { } else if (overlay) {
return theme.primaryOverlay return colors.primaryOverlay
} else if (disabled || loading) { } else if (disabled || loading) {
return theme.disabled return colors.disabled
} else { } else {
if (destructive) { if (destructive) {
return theme.red return colors.red
} else { } else {
return theme.primaryDefault return colors.primaryDefault
} }
} }
}, [mode, disabled, loading, selected]) }, [theme, disabled, loading, selected])
const colorBackground = useMemo(() => { const colorBackground = useMemo(() => {
if (overlay) { if (overlay) {
return theme.backgroundOverlayInvert return colors.backgroundOverlayInvert
} else { } else {
return theme.backgroundDefault return colors.backgroundDefault
} }
}, [mode]) }, [theme])
const children = useMemo(() => { const children = useMemo(() => {
switch (type) { switch (type) {
@ -130,7 +130,7 @@ const Button: React.FC<Props> = ({
</> </>
) )
} }
}, [mode, content, loading, disabled]) }, [theme, content, loading, disabled])
const [layoutHeight, setLayoutHeight] = useState<number | undefined>() const [layoutHeight, setLayoutHeight] = useState<number | undefined>()

View File

@ -7,7 +7,7 @@ import EmojisContext from './helpers/EmojisContext'
const EmojisButton = React.memo( const EmojisButton = React.memo(
() => { () => {
const { theme } = useTheme() const { colors } = useTheme()
const { emojisState, emojisDispatch } = useContext(EmojisContext) const { emojisState, emojisDispatch } = useContext(EmojisContext)
return emojisState.enabled ? ( return emojisState.enabled ? (
@ -30,8 +30,8 @@ const EmojisButton = React.memo(
size={StyleConstants.Font.Size.L} size={StyleConstants.Font.Size.L}
color={ color={
emojisState.emojis && emojisState.emojis.length emojisState.emojis && emojisState.emojis.length
? theme.primaryDefault ? colors.primaryDefault
: theme.disabled : colors.disabled
} }
/> />
} }

View File

@ -23,11 +23,11 @@ const EmojisList = React.memo(
const { t } = useTranslation() const { t } = useTranslation()
const { emojisState, emojisDispatch } = useContext(EmojisContext) const { emojisState, emojisDispatch } = useContext(EmojisContext)
const { theme } = useTheme() const { colors } = useTheme()
const listHeader = useCallback( const listHeader = useCallback(
({ section: { title } }) => ( ({ section: { title } }) => (
<Text style={[styles.group, { color: theme.secondary }]}>{title}</Text> <Text style={[styles.group, { color: colors.secondary }]}>{title}</Text>
), ),
[] []
) )

View File

@ -1,3 +1,4 @@
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
import { useTheme } from '@utils/styles/ThemeManager' import { useTheme } from '@utils/styles/ThemeManager'
import React, { useCallback, useMemo, useState } from 'react' import React, { useCallback, useMemo, useState } from 'react'
import { import {
@ -23,7 +24,7 @@ export interface Props {
accessibilityHint?: AccessibilityProps['accessibilityHint'] accessibilityHint?: AccessibilityProps['accessibilityHint']
hidden?: boolean hidden?: boolean
uri: { preview?: string; original?: string; remote?: string } uri: { preview?: string; original?: string; remote?: string; static?: string }
blurhash?: string blurhash?: string
dimension?: { width: number; height: number } dimension?: { width: number; height: number }
onPress?: () => void onPress?: () => void
@ -51,7 +52,8 @@ const GracefullyImage = React.memo(
imageStyle, imageStyle,
setImageDimensions setImageDimensions
}: Props) => { }: Props) => {
const { theme } = useTheme() const { reduceMotionEnabled } = useAccessibility()
const { colors } = useTheme()
const [originalFailed, setOriginalFailed] = useState(false) const [originalFailed, setOriginalFailed] = useState(false)
const [imageLoaded, setImageLoaded] = useState(false) const [imageLoaded, setImageLoaded] = useState(false)
@ -59,7 +61,9 @@ const GracefullyImage = React.memo(
if (originalFailed) { if (originalFailed) {
return { uri: uri.remote || undefined } return { uri: uri.remote || undefined }
} else { } else {
return { uri: uri.original } return {
uri: reduceMotionEnabled && uri.static ? uri.static : uri.original
}
} }
}, [originalFailed]) }, [originalFailed])
@ -85,7 +89,7 @@ const GracefullyImage = React.memo(
source={{ uri: uri.preview }} source={{ uri: uri.preview }}
style={[ style={[
styles.placeholder, styles.placeholder,
{ backgroundColor: theme.shimmerDefault } { backgroundColor: colors.shimmerDefault }
]} ]}
/> />
) : null, ) : null,
@ -118,7 +122,7 @@ const GracefullyImage = React.memo(
<View <View
style={[ style={[
styles.placeholder, styles.placeholder,
{ backgroundColor: theme.shimmerDefault } { backgroundColor: colors.shimmerDefault }
]} ]}
/> />
) )
@ -135,7 +139,7 @@ const GracefullyImage = React.memo(
: { accessibilityRole: 'image' })} : { accessibilityRole: 'image' })}
accessibilityLabel={accessibilityLabel} accessibilityLabel={accessibilityLabel}
accessibilityHint={accessibilityHint} accessibilityHint={accessibilityHint}
style={[style, dimension, { backgroundColor: theme.shimmerDefault }]} style={[style, dimension, { backgroundColor: colors.shimmerDefault }]}
{...(onPress {...(onPress
? hidden ? hidden
? { disabled: true } ? { disabled: true }

View File

@ -17,10 +17,9 @@ const ComponentHashtag: React.FC<Props> = ({
onPress: customOnPress, onPress: customOnPress,
origin origin
}) => { }) => {
const { theme } = useTheme() const { colors } = useTheme()
const navigation = useNavigation< const navigation =
StackNavigationProp<Nav.TabLocalStackParamList> useNavigation<StackNavigationProp<Nav.TabLocalStackParamList>>()
>()
const onPress = useCallback(() => { const onPress = useCallback(() => {
analytics('search_account_press', { page: origin }) analytics('search_account_press', { page: origin })
@ -33,7 +32,7 @@ const ComponentHashtag: React.FC<Props> = ({
style={styles.itemDefault} style={styles.itemDefault}
onPress={customOnPress || onPress} onPress={customOnPress || onPress}
> >
<Text style={[styles.itemHashtag, { color: theme.primaryDefault }]}> <Text style={[styles.itemHashtag, { color: colors.primaryDefault }]}>
#{hashtag.name} #{hashtag.name}
</Text> </Text>
</Pressable> </Pressable>

View File

@ -11,13 +11,13 @@ export interface Props {
// Used for Android mostly // Used for Android mostly
const HeaderCenter = React.memo( const HeaderCenter = React.memo(
({ content, inverted = false }: Props) => { ({ content, inverted = false }: Props) => {
const { theme } = useTheme() const { colors } = useTheme()
return ( return (
<Text <Text
style={[ style={[
styles.text, styles.text,
{ color: inverted ? theme.primaryOverlay : theme.primaryDefault } { color: inverted ? colors.primaryOverlay : colors.primaryDefault }
]} ]}
children={content} children={content}
/> />

View File

@ -20,14 +20,14 @@ const HeaderLeft: React.FC<Props> = ({
background = false, background = false,
onPress onPress
}) => { }) => {
const { theme } = useTheme() const { colors, theme } = useTheme()
const children = useMemo(() => { const children = useMemo(() => {
switch (type) { switch (type) {
case 'icon': case 'icon':
return ( return (
<Icon <Icon
color={theme.primaryDefault} color={colors.primaryDefault}
name={content || 'ChevronLeft'} name={content || 'ChevronLeft'}
size={StyleConstants.Spacing.M * 1.25} size={StyleConstants.Spacing.M * 1.25}
/> />
@ -35,7 +35,7 @@ const HeaderLeft: React.FC<Props> = ({
case 'text': case 'text':
return ( return (
<Text <Text
style={[styles.text, { color: theme.primaryDefault }]} style={[styles.text, { color: colors.primaryDefault }]}
children={content} children={content}
/> />
) )
@ -50,7 +50,7 @@ const HeaderLeft: React.FC<Props> = ({
styles.base, styles.base,
{ {
backgroundColor: background backgroundColor: background
? theme.backgroundOverlayDefault ? colors.backgroundOverlayDefault
: undefined, : undefined,
minHeight: 44, minHeight: 44,
minWidth: 44, minWidth: 44,

View File

@ -41,14 +41,14 @@ const HeaderRight: React.FC<Props> = ({
disabled, disabled,
onPress onPress
}) => { }) => {
const { theme } = useTheme() const { colors, theme } = useTheme()
const loadingSpinkit = useMemo( const loadingSpinkit = useMemo(
() => ( () => (
<View style={{ position: 'absolute' }}> <View style={{ position: 'absolute' }}>
<Flow <Flow
size={StyleConstants.Font.Size.M * 1.25} size={StyleConstants.Font.Size.M * 1.25}
color={theme.secondary} color={colors.secondary}
/> />
</View> </View>
), ),
@ -64,7 +64,7 @@ const HeaderRight: React.FC<Props> = ({
name={content} name={content}
style={{ opacity: loading ? 0 : 1 }} style={{ opacity: loading ? 0 : 1 }}
size={StyleConstants.Spacing.M * 1.25} size={StyleConstants.Spacing.M * 1.25}
color={disabled ? theme.secondary : theme.primaryDefault} color={disabled ? colors.secondary : colors.primaryDefault}
/> />
{loading && loadingSpinkit} {loading && loadingSpinkit}
</> </>
@ -76,7 +76,7 @@ const HeaderRight: React.FC<Props> = ({
style={[ style={[
styles.text, styles.text,
{ {
color: disabled ? theme.secondary : theme.primaryDefault, color: disabled ? colors.secondary : colors.primaryDefault,
opacity: loading ? 0 : 1 opacity: loading ? 0 : 1
} }
]} ]}
@ -101,7 +101,7 @@ const HeaderRight: React.FC<Props> = ({
styles.base, styles.base,
{ {
backgroundColor: background backgroundColor: background
? theme.backgroundOverlayDefault ? colors.backgroundOverlayDefault
: undefined, : undefined,
minHeight: 44, minHeight: 44,
minWidth: 44, minWidth: 44,

View File

@ -57,7 +57,7 @@ const Input: React.FC<Props> = ({
setValue, setValue,
options options
}) => { }) => {
const { mode, theme } = useTheme() const { colors, mode } = useTheme()
const animateTitle = useAnimatedStyle(() => { const animateTitle = useAnimatedStyle(() => {
if (value) { if (value) {
@ -66,7 +66,7 @@ const Input: React.FC<Props> = ({
paddingHorizontal: withTiming(StyleConstants.Spacing.XS), paddingHorizontal: withTiming(StyleConstants.Spacing.XS),
left: withTiming(StyleConstants.Spacing.S), left: withTiming(StyleConstants.Spacing.S),
top: withTiming(-(StyleConstants.Font.Size.S / 2) - 2), top: withTiming(-(StyleConstants.Font.Size.S / 2) - 2),
backgroundColor: withTiming(theme.backgroundDefault) backgroundColor: withTiming(colors.backgroundDefault)
} }
} else { } else {
return { return {
@ -74,7 +74,7 @@ const Input: React.FC<Props> = ({
paddingHorizontal: withTiming(0), paddingHorizontal: withTiming(0),
left: withTiming(StyleConstants.Spacing.S), left: withTiming(StyleConstants.Spacing.S),
top: withTiming(StyleConstants.Spacing.S + 1), top: withTiming(StyleConstants.Spacing.S + 1),
backgroundColor: withTiming(theme.backgroundDefaultTransparent) backgroundColor: withTiming(colors.backgroundDefaultTransparent)
} }
} }
}, [mode, value]) }, [mode, value])
@ -109,7 +109,7 @@ const Input: React.FC<Props> = ({
style={[ style={[
styles.base, styles.base,
{ {
borderColor: theme.border, borderColor: colors.border,
flexDirection: multiline ? 'column' : 'row', flexDirection: multiline ? 'column' : 'row',
alignItems: 'stretch' alignItems: 'stretch'
} }
@ -127,7 +127,7 @@ const Input: React.FC<Props> = ({
style={[ style={[
styles.textInput, styles.textInput,
{ {
color: theme.primaryDefault, color: colors.primaryDefault,
minHeight: minHeight:
Platform.OS === 'ios' && multiline Platform.OS === 'ios' && multiline
? StyleConstants.Font.LineHeight.M * 5 ? StyleConstants.Font.LineHeight.M * 5
@ -149,14 +149,14 @@ const Input: React.FC<Props> = ({
</EmojisContext.Consumer> </EmojisContext.Consumer>
{title ? ( {title ? (
<Animated.Text <Animated.Text
style={[styles.title, animateTitle, { color: theme.secondary }]} style={[styles.title, animateTitle, { color: colors.secondary }]}
> >
{title} {title}
</Animated.Text> </Animated.Text>
) : null} ) : null}
<View style={{ flexDirection: 'row', alignSelf: 'flex-end' }}> <View style={{ flexDirection: 'row', alignSelf: 'flex-end' }}>
{options?.maxLength && value?.length ? ( {options?.maxLength && value?.length ? (
<Text style={[styles.maxLength, { color: theme.secondary }]}> <Text style={[styles.maxLength, { color: colors.secondary }]}>
{value?.length} / {options.maxLength} {value?.length} / {options.maxLength}
</Text> </Text>
) : null} ) : null}

View File

@ -39,7 +39,7 @@ const ComponentInstance: React.FC<Props> = ({
goBack = false goBack = false
}) => { }) => {
const { t } = useTranslation('componentInstance') const { t } = useTranslation('componentInstance')
const { mode, theme } = useTheme() const { colors, mode } = useTheme()
const { screenReaderEnabled } = useAccessibility() const { screenReaderEnabled } = useAccessibility()
const instances = useSelector(getInstances, () => true) const instances = useSelector(getInstances, () => true)
@ -149,10 +149,10 @@ const ComponentInstance: React.FC<Props> = ({
style={[ style={[
styles.prefix, styles.prefix,
{ {
color: theme.primaryDefault, color: colors.primaryDefault,
borderBottomColor: instanceQuery.isError borderBottomColor: instanceQuery.isError
? theme.red ? colors.red
: theme.border : colors.border
} }
]} ]}
editable={false} editable={false}
@ -162,10 +162,10 @@ const ComponentInstance: React.FC<Props> = ({
style={[ style={[
styles.textInput, styles.textInput,
{ {
color: theme.primaryDefault, color: colors.primaryDefault,
borderBottomColor: instanceQuery.isError borderBottomColor: instanceQuery.isError
? theme.red ? colors.red
: theme.border : colors.border
} }
]} ]}
onChangeText={onChangeText} onChangeText={onChangeText}
@ -175,7 +175,7 @@ const ComponentInstance: React.FC<Props> = ({
textContentType='URL' textContentType='URL'
onSubmitEditing={onSubmitEditing} onSubmitEditing={onSubmitEditing}
placeholder={' ' + t('server.textInput.placeholder')} placeholder={' ' + t('server.textInput.placeholder')}
placeholderTextColor={theme.secondary} placeholderTextColor={colors.secondary}
returnKeyType='go' returnKeyType='go'
keyboardAppearance={mode} keyboardAppearance={mode}
{...(scrollViewRef && { {...(scrollViewRef && {
@ -234,11 +234,11 @@ const ComponentInstance: React.FC<Props> = ({
<Icon <Icon
name='Lock' name='Lock'
size={StyleConstants.Font.Size.S} size={StyleConstants.Font.Size.S}
color={theme.secondary} color={colors.secondary}
style={styles.disclaimerIcon} style={styles.disclaimerIcon}
/> />
<Text <Text
style={[styles.disclaimerText, { color: theme.secondary }]} style={[styles.disclaimerText, { color: colors.secondary }]}
accessibilityRole='link' accessibilityRole='link'
onPress={() => { onPress={() => {
if (screenReaderEnabled) { if (screenReaderEnabled) {
@ -252,7 +252,7 @@ const ComponentInstance: React.FC<Props> = ({
{t('server.disclaimer.base')} {t('server.disclaimer.base')}
<Text <Text
accessible accessible
style={{ color: theme.blue }} style={{ color: colors.blue }}
onPress={() => { onPress={() => {
analytics('view_privacy') analytics('view_privacy')
WebBrowser.openBrowserAsync( WebBrowser.openBrowserAsync(

View File

@ -13,15 +13,15 @@ export interface Props {
const InstanceInfo = React.memo( const InstanceInfo = React.memo(
({ style, header, content, potentialWidth }: Props) => { ({ style, header, content, potentialWidth }: Props) => {
const { theme } = useTheme() const { colors } = useTheme()
return ( return (
<View style={[styles.base, style]} accessible> <View style={[styles.base, style]} accessible>
<Text style={[styles.header, { color: theme.primaryDefault }]}> <Text style={[styles.header, { color: colors.primaryDefault }]}>
{header} {header}
</Text> </Text>
{content ? ( {content ? (
<Text style={[styles.content, { color: theme.primaryDefault }]}> <Text style={[styles.content, { color: colors.primaryDefault }]}>
{content} {content}
</Text> </Text>
) : ( ) : (
@ -32,7 +32,7 @@ const InstanceInfo = React.memo(
: undefined : undefined
} }
height={StyleConstants.Font.LineHeight.M} height={StyleConstants.Font.LineHeight.M}
color={theme.shimmerDefault} color={colors.shimmerDefault}
noMargin noMargin
style={{ borderRadius: 0 }} style={{ borderRadius: 0 }}
/> />

View File

@ -8,11 +8,11 @@ export interface Props {
} }
const MenuHeader: React.FC<Props> = ({ heading }) => { const MenuHeader: React.FC<Props> = ({ heading }) => {
const { theme } = useTheme() const { colors } = useTheme()
return ( return (
<View style={styles.base}> <View style={styles.base}>
<Text style={[styles.text, { color: theme.secondary }]}>{heading}</Text> <Text style={[styles.text, { color: colors.secondary }]}>{heading}</Text>
</View> </View>
) )
} }

View File

@ -43,7 +43,7 @@ const MenuRow: React.FC<Props> = ({
loading = false, loading = false,
onPress onPress
}) => { }) => {
const { theme } = useTheme() const { colors, theme } = useTheme()
const { screenReaderEnabled } = useAccessibility() const { screenReaderEnabled } = useAccessibility()
const loadingSpinkit = useMemo( const loadingSpinkit = useMemo(
@ -51,7 +51,7 @@ const MenuRow: React.FC<Props> = ({
<View style={{ position: 'absolute' }}> <View style={{ position: 'absolute' }}>
<Flow <Flow
size={StyleConstants.Font.Size.M * 1.25} size={StyleConstants.Font.Size.M * 1.25}
color={theme.secondary} color={colors.secondary}
/> />
</View> </View>
), ),
@ -83,7 +83,7 @@ const MenuRow: React.FC<Props> = ({
<Icon <Icon
name={iconFront} name={iconFront}
size={StyleConstants.Font.Size.L} size={StyleConstants.Font.Size.L}
color={theme[iconFrontColor]} color={colors[iconFrontColor]}
style={styles.iconFront} style={styles.iconFront}
/> />
)} )}
@ -92,7 +92,7 @@ const MenuRow: React.FC<Props> = ({
style={{ style={{
width: 8, width: 8,
height: 8, height: 8,
backgroundColor: theme.red, backgroundColor: colors.red,
borderRadius: 8, borderRadius: 8,
marginRight: StyleConstants.Spacing.S marginRight: StyleConstants.Spacing.S
}} }}
@ -100,7 +100,7 @@ const MenuRow: React.FC<Props> = ({
) : null} ) : null}
<View style={styles.main}> <View style={styles.main}>
<Text <Text
style={[styles.title, { color: theme.primaryDefault }]} style={[styles.title, { color: colors.primaryDefault }]}
numberOfLines={1} numberOfLines={1}
> >
{title} {title}
@ -116,7 +116,7 @@ const MenuRow: React.FC<Props> = ({
style={[ style={[
styles.content, styles.content,
{ {
color: theme.secondary, color: colors.secondary,
opacity: !iconBack && loading ? 0 : 1 opacity: !iconBack && loading ? 0 : 1
} }
]} ]}
@ -133,7 +133,7 @@ const MenuRow: React.FC<Props> = ({
value={switchValue} value={switchValue}
onValueChange={switchOnValueChange} onValueChange={switchOnValueChange}
disabled={switchDisabled} disabled={switchDisabled}
trackColor={{ true: theme.blue, false: theme.disabled }} trackColor={{ true: colors.blue, false: colors.disabled }}
style={{ opacity: loading ? 0 : 1 }} style={{ opacity: loading ? 0 : 1 }}
/> />
) : null} ) : null}
@ -141,7 +141,7 @@ const MenuRow: React.FC<Props> = ({
<Icon <Icon
name={iconBack} name={iconBack}
size={StyleConstants.Font.Size.L} size={StyleConstants.Font.Size.L}
color={theme[iconBackColor]} color={colors[iconBackColor]}
style={[styles.iconBack, { opacity: loading ? 0 : 1 }]} style={[styles.iconBack, { opacity: loading ? 0 : 1 }]}
/> />
) : null} ) : null}
@ -150,7 +150,7 @@ const MenuRow: React.FC<Props> = ({
) : null} ) : null}
</View> </View>
{description ? ( {description ? (
<Text style={[styles.description, { color: theme.secondary }]}> <Text style={[styles.description, { color: colors.secondary }]}>
{description} {description}
</Text> </Text>
) : null} ) : null}

View File

@ -1,7 +1,7 @@
import Icon from '@components/Icon' import Icon from '@components/Icon'
import { StyleConstants } from '@utils/styles/constants' import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager' import { useTheme } from '@utils/styles/ThemeManager'
import { getTheme } from '@utils/styles/themes' import { getColors, Theme } from '@utils/styles/themes'
import React, { RefObject } from 'react' import React, { RefObject } from 'react'
import { AccessibilityInfo } from 'react-native' import { AccessibilityInfo } from 'react-native'
import FlashMessage, { import FlashMessage, {
@ -17,7 +17,7 @@ const displayMessage = ({
message, message,
description, description,
onPress, onPress,
mode, theme,
type type
}: }:
| { | {
@ -27,7 +27,7 @@ const displayMessage = ({
message: string message: string
description?: string description?: string
onPress?: () => void onPress?: () => void
mode?: undefined theme?: undefined
type?: undefined type?: undefined
} }
| { | {
@ -37,7 +37,7 @@ const displayMessage = ({
message: string message: string
description?: string description?: string
onPress?: () => void onPress?: () => void
mode: 'light' | 'dark' theme: Theme
type: 'success' | 'error' | 'warning' type: 'success' | 'error' | 'warning'
}) => { }) => {
AccessibilityInfo.announceForAccessibility(message + '.' + description) AccessibilityInfo.announceForAccessibility(message + '.' + description)
@ -64,14 +64,14 @@ const displayMessage = ({
message, message,
description, description,
onPress, onPress,
...(mode && ...(theme &&
type && { type && {
renderFlashMessageIcon: () => { renderFlashMessageIcon: () => {
return ( return (
<Icon <Icon
name={iconMapping[type]} name={iconMapping[type]}
size={StyleConstants.Font.LineHeight.M} size={StyleConstants.Font.LineHeight.M}
color={getTheme(mode)[colorMapping[type]]} color={getColors(theme)[colorMapping[type]]}
style={{ marginRight: StyleConstants.Spacing.S }} style={{ marginRight: StyleConstants.Spacing.S }}
/> />
) )
@ -85,14 +85,14 @@ const displayMessage = ({
message, message,
description, description,
onPress, onPress,
...(mode && ...(theme &&
type && { type && {
renderFlashMessageIcon: () => { renderFlashMessageIcon: () => {
return ( return (
<Icon <Icon
name={iconMapping[type]} name={iconMapping[type]}
size={StyleConstants.Font.LineHeight.M} size={StyleConstants.Font.LineHeight.M}
color={getTheme(mode)[colorMapping[type]]} color={getColors(theme)[colorMapping[type]]}
style={{ marginRight: StyleConstants.Spacing.S }} style={{ marginRight: StyleConstants.Spacing.S }}
/> />
) )
@ -111,7 +111,7 @@ const removeMessage = () => {
} }
const Message = React.forwardRef<FlashMessage>((_, ref) => { const Message = React.forwardRef<FlashMessage>((_, ref) => {
const { mode, theme } = useTheme() const { colors, theme } = useTheme()
return ( return (
<FlashMessage <FlashMessage
@ -120,19 +120,19 @@ const Message = React.forwardRef<FlashMessage>((_, ref) => {
position='top' position='top'
floating floating
style={{ style={{
backgroundColor: theme.backgroundDefault, backgroundColor: colors.backgroundDefault,
shadowColor: theme.primaryDefault, shadowColor: colors.primaryDefault,
shadowOffset: { width: 0, height: 0 }, shadowOffset: { width: 0, height: 0 },
shadowOpacity: mode === 'light' ? 0.16 : 0.24, shadowOpacity: theme === 'light' ? 0.16 : 0.24,
shadowRadius: 4 shadowRadius: 4
}} }}
titleStyle={{ titleStyle={{
color: theme.primaryDefault, color: colors.primaryDefault,
...StyleConstants.FontStyle.M, ...StyleConstants.FontStyle.M,
fontWeight: StyleConstants.Font.Weight.Bold fontWeight: StyleConstants.Font.Weight.Bold
}} }}
textStyle={{ textStyle={{
color: theme.primaryDefault, color: colors.primaryDefault,
...StyleConstants.FontStyle.S ...StyleConstants.FontStyle.S
}} }}
// @ts-ignore // @ts-ignore

View File

@ -39,11 +39,11 @@ const ParseEmojis = React.memo(
adaptiveSize ? adaptiveFontsize : 0 adaptiveSize ? adaptiveFontsize : 0
) )
const { mode, theme } = useTheme() const { colors, theme } = useTheme()
const styles = useMemo(() => { const styles = useMemo(() => {
return StyleSheet.create({ return StyleSheet.create({
text: { text: {
color: theme.primaryDefault, color: colors.primaryDefault,
fontSize: adaptedFontsize, fontSize: adaptedFontsize,
lineHeight: adaptedLineheight, lineHeight: adaptedLineheight,
...(fontBold && { fontWeight: StyleConstants.Font.Weight.Bold }) ...(fontBold && { fontWeight: StyleConstants.Font.Weight.Bold })
@ -54,7 +54,7 @@ const ParseEmojis = React.memo(
transform: [{ translateY: -2 }] transform: [{ translateY: -2 }]
} }
}) })
}, [mode, adaptiveFontsize]) }, [theme, adaptiveFontsize])
return ( return (
<Text style={styles.text}> <Text style={styles.text}>

View File

@ -18,7 +18,7 @@ import { useSelector } from 'react-redux'
// Prevent going to the same hashtag multiple times // Prevent going to the same hashtag multiple times
const renderNode = ({ const renderNode = ({
routeParams, routeParams,
theme, colors,
node, node,
index, index,
adaptedFontsize, adaptedFontsize,
@ -30,7 +30,7 @@ const renderNode = ({
disableDetails disableDetails
}: { }: {
routeParams?: any routeParams?: any
theme: any colors: any
node: any node: any
index: number index: number
adaptedFontsize: number adaptedFontsize: number
@ -56,7 +56,7 @@ const renderNode = ({
accessible accessible
key={index} key={index}
style={{ style={{
color: theme.blue, color: colors.blue,
fontSize: adaptedFontsize, fontSize: adaptedFontsize,
lineHeight: adaptedLineheight lineHeight: adaptedLineheight
}} }}
@ -84,7 +84,8 @@ const renderNode = ({
<Text <Text
key={index} key={index}
style={{ style={{
color: accountIndex !== -1 ? theme.blue : theme.primaryDefault, color:
accountIndex !== -1 ? colors.blue : colors.primaryDefault,
fontSize: adaptedFontsize, fontSize: adaptedFontsize,
lineHeight: adaptedLineheight lineHeight: adaptedLineheight
}} }}
@ -114,7 +115,7 @@ const renderNode = ({
<Text <Text
key={index} key={index}
style={{ style={{
color: theme.blue, color: colors.blue,
alignItems: 'center', alignItems: 'center',
fontSize: adaptedFontsize, fontSize: adaptedFontsize,
lineHeight: adaptedLineheight lineHeight: adaptedLineheight
@ -132,7 +133,7 @@ const renderNode = ({
(showFullLink ? href : domain[1])} (showFullLink ? href : domain[1])}
{!shouldBeTag ? ( {!shouldBeTag ? (
<Icon <Icon
color={theme.blue} color={colors.blue}
name='ExternalLink' name='ExternalLink'
size={adaptedFontsize} size={adaptedFontsize}
style={{ style={{
@ -192,11 +193,10 @@ const ParseHTML = React.memo(
adaptiveSize ? adaptiveFontsize : 0 adaptiveSize ? adaptiveFontsize : 0
) )
const navigation = useNavigation< const navigation =
StackNavigationProp<Nav.TabLocalStackParamList> useNavigation<StackNavigationProp<Nav.TabLocalStackParamList>>()
>()
const route = useRoute() const route = useRoute()
const { mode, theme } = useTheme() const { colors, theme } = useTheme()
const { t, i18n } = useTranslation('componentParse') const { t, i18n } = useTranslation('componentParse')
if (!expandHint) { if (!expandHint) {
expandHint = t('HTML.defaultHint') expandHint = t('HTML.defaultHint')
@ -206,7 +206,7 @@ const ParseHTML = React.memo(
(node, index) => (node, index) =>
renderNode({ renderNode({
routeParams: route.params, routeParams: route.params,
theme, colors,
node, node,
index, index,
adaptedFontsize, adaptedFontsize,
@ -271,14 +271,14 @@ const ParseHTML = React.memo(
justifyContent: 'center', justifyContent: 'center',
marginTop: expanded ? 0 : -adaptedLineheight, marginTop: expanded ? 0 : -adaptedLineheight,
minHeight: 44, minHeight: 44,
backgroundColor: theme.backgroundDefault backgroundColor: colors.backgroundDefault
}} }}
> >
<Text <Text
style={{ style={{
textAlign: 'center', textAlign: 'center',
...StyleConstants.FontStyle.S, ...StyleConstants.FontStyle.S,
color: theme.primaryDefault color: colors.primaryDefault
}} }}
children={t(`HTML.expanded.${expanded.toString()}`, { children={t(`HTML.expanded.${expanded.toString()}`, {
hint: expandHint hint: expandHint
@ -289,7 +289,7 @@ const ParseHTML = React.memo(
</View> </View>
) )
}, },
[mode, i18n.language] [theme, i18n.language]
) )
return ( return (

View File

@ -19,7 +19,7 @@ export interface Props {
} }
const RelationshipIncoming: React.FC<Props> = ({ id }) => { const RelationshipIncoming: React.FC<Props> = ({ id }) => {
const { mode } = useTheme() const { theme } = useTheme()
const { t } = useTranslation() const { t } = useTranslation()
const queryKeyRelationship: QueryKeyRelationship = ['Relationship', { id }] const queryKeyRelationship: QueryKeyRelationship = ['Relationship', { id }]
@ -40,7 +40,7 @@ const RelationshipIncoming: React.FC<Props> = ({ id }) => {
haptics('Error') haptics('Error')
displayMessage({ displayMessage({
type: 'error', type: 'error',
mode, theme,
message: t('common:message.error.message', { message: t('common:message.error.message', {
function: t(`relationship:${type}.function`) function: t(`relationship:${type}.function`)
}), }),

View File

@ -19,7 +19,7 @@ export interface Props {
const RelationshipOutgoing = React.memo( const RelationshipOutgoing = React.memo(
({ id }: Props) => { ({ id }: Props) => {
const { mode } = useTheme() const { theme } = useTheme()
const { t } = useTranslation('componentRelationship') const { t } = useTranslation('componentRelationship')
const query = useRelationshipQuery({ id }) const query = useRelationshipQuery({ id })
@ -40,7 +40,7 @@ const RelationshipOutgoing = React.memo(
}, },
onError: (err: any, { payload: { action } }) => { onError: (err: any, { payload: { action } }) => {
displayMessage({ displayMessage({
mode, theme,
type: 'error', type: 'error',
message: t('common:message.error.message', { message: t('common:message.error.message', {
function: t(`${action}.function`) function: t(`${action}.function`)

View File

@ -10,13 +10,13 @@ export interface Props {
const ComponentSeparator = React.memo( const ComponentSeparator = React.memo(
({ extraMarginLeft = 0, extraMarginRight = 0 }: Props) => { ({ extraMarginLeft = 0, extraMarginRight = 0 }: Props) => {
const { theme } = useTheme() const { colors } = useTheme()
return ( return (
<View <View
style={{ style={{
backgroundColor: theme.backgroundDefault, backgroundColor: colors.backgroundDefault,
borderTopColor: theme.border, borderTopColor: colors.border,
borderTopWidth: StyleSheet.hairlineWidth, borderTopWidth: StyleSheet.hairlineWidth,
marginLeft: marginLeft:
StyleConstants.Spacing.Global.PagePadding + extraMarginLeft, StyleConstants.Spacing.Global.PagePadding + extraMarginLeft,

View File

@ -48,7 +48,7 @@ const Timeline: React.FC<Props> = ({
lookback, lookback,
customProps customProps
}) => { }) => {
const { theme } = useTheme() const { colors } = useTheme()
const { const {
data, data,
@ -118,8 +118,8 @@ const Timeline: React.FC<Props> = ({
refreshControl: ( refreshControl: (
<RefreshControl <RefreshControl
enabled enabled
colors={[theme.primaryDefault]} colors={[colors.primaryDefault]}
progressBackgroundColor={theme.backgroundDefault} progressBackgroundColor={colors.backgroundDefault}
refreshing={isFetching || isLoading} refreshing={isFetching || isLoading}
onRefresh={() => refetch()} onRefresh={() => refetch()}
/> />

View File

@ -32,7 +32,7 @@ const Avatars: React.FC<{ accounts: Mastodon.Account[] }> = ({ accounts }) => {
{accounts.slice(0, 4).map(account => ( {accounts.slice(0, 4).map(account => (
<GracefullyImage <GracefullyImage
key={account.id} key={account.id}
uri={{ original: account.avatar_static }} uri={{ original: account.avatar, static: account.avatar_static }}
dimension={{ dimension={{
width: StyleConstants.Avatar.M, width: StyleConstants.Avatar.M,
height: height:
@ -62,7 +62,7 @@ const TimelineConversation: React.FC<Props> = ({
getInstanceAccount, getInstanceAccount,
(prev, next) => prev?.id === next?.id (prev, next) => prev?.id === next?.id
) )
const { theme } = useTheme() const { colors } = useTheme()
const queryClient = useQueryClient() const queryClient = useQueryClient()
const fireMutation = useCallback(() => { const fireMutation = useCallback(() => {
@ -77,9 +77,8 @@ const TimelineConversation: React.FC<Props> = ({
} }
}) })
const navigation = useNavigation< const navigation =
StackNavigationProp<Nav.TabLocalStackParamList> useNavigation<StackNavigationProp<Nav.TabLocalStackParamList>>()
>()
const onPress = useCallback(() => { const onPress = useCallback(() => {
analytics('timeline_conversation_press') analytics('timeline_conversation_press')
if (conversation.last_status) { if (conversation.last_status) {
@ -95,10 +94,10 @@ const TimelineConversation: React.FC<Props> = ({
<Pressable <Pressable
style={[ style={[
styles.base, styles.base,
{ backgroundColor: theme.backgroundDefault }, { backgroundColor: colors.backgroundDefault },
conversation.unread && { conversation.unread && {
borderLeftWidth: StyleConstants.Spacing.XS, borderLeftWidth: StyleConstants.Spacing.XS,
borderLeftColor: theme.blue, borderLeftColor: colors.blue,
paddingLeft: paddingLeft:
StyleConstants.Spacing.Global.PagePadding - StyleConstants.Spacing.Global.PagePadding -
StyleConstants.Spacing.XS StyleConstants.Spacing.XS

View File

@ -42,11 +42,10 @@ const TimelineDefault: React.FC<Props> = ({
disableDetails = false, disableDetails = false,
disableOnPress = false disableOnPress = false
}) => { }) => {
const { theme } = useTheme() const { colors } = useTheme()
const instanceAccount = useSelector(getInstanceAccount, () => true) const instanceAccount = useSelector(getInstanceAccount, () => true)
const navigation = useNavigation< const navigation =
StackNavigationProp<Nav.TabLocalStackParamList> useNavigation<StackNavigationProp<Nav.TabLocalStackParamList>>()
>()
const actualStatus = item.reblog ? item.reblog : item const actualStatus = item.reblog ? item.reblog : item
@ -78,7 +77,7 @@ const TimelineDefault: React.FC<Props> = ({
style={[ style={[
styles.statusView, styles.statusView,
{ {
backgroundColor: theme.backgroundDefault, backgroundColor: colors.backgroundDefault,
paddingBottom: paddingBottom:
disableDetails && disableOnPress disableDetails && disableOnPress
? StyleConstants.Spacing.Global.PagePadding ? StyleConstants.Spacing.Global.PagePadding

View File

@ -20,14 +20,17 @@ const TimelineEmpty = React.memo(
options: { notifyOnChangeProps: ['status'] } options: { notifyOnChangeProps: ['status'] }
}) })
const { mode, theme } = useTheme() const { colors, theme } = useTheme()
const { t, i18n } = useTranslation('componentTimeline') const { t, i18n } = useTranslation('componentTimeline')
const children = useMemo(() => { const children = useMemo(() => {
switch (status) { switch (status) {
case 'loading': case 'loading':
return ( return (
<Circle size={StyleConstants.Font.Size.L} color={theme.secondary} /> <Circle
size={StyleConstants.Font.Size.L}
color={colors.secondary}
/>
) )
case 'error': case 'error':
return ( return (
@ -35,9 +38,9 @@ const TimelineEmpty = React.memo(
<Icon <Icon
name='Frown' name='Frown'
size={StyleConstants.Font.Size.L} size={StyleConstants.Font.Size.L}
color={theme.primaryDefault} color={colors.primaryDefault}
/> />
<Text style={[styles.error, { color: theme.primaryDefault }]}> <Text style={[styles.error, { color: colors.primaryDefault }]}>
{t('empty.error.message')} {t('empty.error.message')}
</Text> </Text>
<Button <Button
@ -56,18 +59,18 @@ const TimelineEmpty = React.memo(
<Icon <Icon
name='Smartphone' name='Smartphone'
size={StyleConstants.Font.Size.L} size={StyleConstants.Font.Size.L}
color={theme.primaryDefault} color={colors.primaryDefault}
/> />
<Text style={[styles.error, { color: theme.primaryDefault }]}> <Text style={[styles.error, { color: colors.primaryDefault }]}>
{t('empty.success.message')} {t('empty.success.message')}
</Text> </Text>
</> </>
) )
} }
}, [mode, i18n.language, status]) }, [theme, i18n.language, status])
return ( return (
<View <View
style={[styles.base, { backgroundColor: theme.backgroundDefault }]} style={[styles.base, { backgroundColor: colors.backgroundDefault }]}
children={children} children={children}
/> />
) )

View File

@ -24,21 +24,21 @@ const TimelineFooter = React.memo(
} }
}) })
const { theme } = useTheme() const { colors } = useTheme()
return ( return (
<View style={styles.base}> <View style={styles.base}>
{!disableInfinity && hasNextPage ? ( {!disableInfinity && hasNextPage ? (
<Circle size={StyleConstants.Font.Size.L} color={theme.secondary} /> <Circle size={StyleConstants.Font.Size.L} color={colors.secondary} />
) : ( ) : (
<Text style={[styles.text, { color: theme.secondary }]}> <Text style={[styles.text, { color: colors.secondary }]}>
<Trans <Trans
i18nKey='componentTimeline:end.message' i18nKey='componentTimeline:end.message'
components={[ components={[
<Icon <Icon
name='Coffee' name='Coffee'
size={StyleConstants.Font.Size.S} size={StyleConstants.Font.Size.S}
color={theme.secondary} color={colors.secondary}
/> />
]} ]}
/> />

View File

@ -7,12 +7,14 @@ import { StyleSheet, Text, View } from 'react-native'
const TimelineLookback = React.memo( const TimelineLookback = React.memo(
() => { () => {
const { t } = useTranslation('componentTimeline') const { t } = useTranslation('componentTimeline')
const { theme } = useTheme() const { colors } = useTheme()
return ( return (
<View style={[styles.base, { backgroundColor: theme.backgroundDefault }]}> <View
style={[styles.base, { backgroundColor: colors.backgroundDefault }]}
>
<Text <Text
style={[StyleConstants.FontStyle.S, { color: theme.primaryDefault }]} style={[StyleConstants.FontStyle.S, { color: colors.primaryDefault }]}
> >
{t('lookback.message')} {t('lookback.message')}
</Text> </Text>

View File

@ -38,14 +38,13 @@ const TimelineNotifications: React.FC<Props> = ({
return <TimelineFiltered /> return <TimelineFiltered />
} }
const { theme } = useTheme() const { colors } = useTheme()
const instanceAccount = useSelector( const instanceAccount = useSelector(
getInstanceAccount, getInstanceAccount,
(prev, next) => prev?.id === next?.id (prev, next) => prev?.id === next?.id
) )
const navigation = useNavigation< const navigation =
StackNavigationProp<Nav.TabLocalStackParamList> useNavigation<StackNavigationProp<Nav.TabLocalStackParamList>>()
>()
const actualAccount = notification.status const actualAccount = notification.status
? notification.status.account ? notification.status.account
@ -65,7 +64,7 @@ const TimelineNotifications: React.FC<Props> = ({
style={[ style={[
styles.notificationView, styles.notificationView,
{ {
backgroundColor: theme.backgroundDefault, backgroundColor: colors.backgroundDefault,
paddingBottom: notification.status paddingBottom: notification.status
? 0 ? 0
: StyleConstants.Spacing.Global.PagePadding : StyleConstants.Spacing.Global.PagePadding
@ -148,8 +147,10 @@ const TimelineNotifications: React.FC<Props> = ({
status={notification.status} status={notification.status}
highlighted={highlighted} highlighted={highlighted}
accts={uniqBy( accts={uniqBy(
([notification.status.account] as Mastodon.Account[] & (
Mastodon.Mention[]) [notification.status.account] as Mastodon.Account[] &
Mastodon.Mention[]
)
.concat(notification.status.mentions) .concat(notification.status.mentions)
.filter(d => d?.id !== instanceAccount?.id), .filter(d => d?.id !== instanceAccount?.id),
d => d?.id d => d?.id

View File

@ -101,7 +101,7 @@ const TimelineRefresh: React.FC<Props> = ({
}) })
const { t } = useTranslation('componentTimeline') const { t } = useTranslation('componentTimeline')
const { theme } = useTheme() const { colors } = useTheme()
const queryClient = useQueryClient() const queryClient = useQueryClient()
const clearFirstPage = () => { const clearFirstPage = () => {
@ -254,13 +254,16 @@ const TimelineRefresh: React.FC<Props> = ({
<View style={styles.base}> <View style={styles.base}>
{isFetching ? ( {isFetching ? (
<View style={styles.container2}> <View style={styles.container2}>
<Circle size={StyleConstants.Font.Size.L} color={theme.secondary} /> <Circle
size={StyleConstants.Font.Size.L}
color={colors.secondary}
/>
</View> </View>
) : ( ) : (
<> <>
<View style={styles.container1}> <View style={styles.container1}>
<Text <Text
style={[styles.explanation, { color: theme.primaryDefault }]} style={[styles.explanation, { color: colors.primaryDefault }]}
onLayout={onLayout} onLayout={onLayout}
children={t('refresh.fetchPreviousPage')} children={t('refresh.fetchPreviousPage')}
/> />
@ -277,14 +280,14 @@ const TimelineRefresh: React.FC<Props> = ({
<Icon <Icon
name='ArrowLeft' name='ArrowLeft'
size={StyleConstants.Font.Size.M} size={StyleConstants.Font.Size.M}
color={theme.primaryDefault} color={colors.primaryDefault}
/> />
} }
/> />
</View> </View>
<View style={styles.container2}> <View style={styles.container2}>
<Text <Text
style={[styles.explanation, { color: theme.primaryDefault }]} style={[styles.explanation, { color: colors.primaryDefault }]}
onLayout={onLayout} onLayout={onLayout}
children={t('refresh.refetch')} children={t('refresh.refetch')}
/> />

View File

@ -18,12 +18,11 @@ export interface Props {
const TimelineActioned = React.memo( const TimelineActioned = React.memo(
({ account, action, notification = false }: Props) => { ({ account, action, notification = false }: Props) => {
const { t } = useTranslation('componentTimeline') const { t } = useTranslation('componentTimeline')
const { theme } = useTheme() const { colors } = useTheme()
const navigation = useNavigation< const navigation =
StackNavigationProp<Nav.TabLocalStackParamList> useNavigation<StackNavigationProp<Nav.TabLocalStackParamList>>()
>()
const name = account.display_name || account.username const name = account.display_name || account.username
const iconColor = theme.primaryDefault const iconColor = colors.primaryDefault
const content = (content: string) => ( const content = (content: string) => (
<ParseEmojis content={content} emojis={account.emojis} size='S' /> <ParseEmojis content={content} emojis={account.emojis} size='S' />

View File

@ -33,8 +33,8 @@ const TimelineActions: React.FC<Props> = ({
}) => { }) => {
const navigation = useNavigation() const navigation = useNavigation()
const { t } = useTranslation('componentTimeline') const { t } = useTranslation('componentTimeline')
const { mode, theme } = useTheme() const { colors, theme } = useTheme()
const iconColor = theme.secondary const iconColor = colors.secondary
const queryClient = useQueryClient() const queryClient = useQueryClient()
const mutation = useTimelineMutation({ const mutation = useTimelineMutation({
@ -83,7 +83,7 @@ const TimelineActions: React.FC<Props> = ({
onError: (err: any, params, oldData) => { onError: (err: any, params, oldData) => {
const correctParam = params as MutationVarsTimelineUpdateStatusProperty const correctParam = params as MutationVarsTimelineUpdateStatusProperty
displayMessage({ displayMessage({
mode, theme,
type: 'error', type: 'error',
message: t('common:message.error.message', { message: t('common:message.error.message', {
function: t( function: t(
@ -185,7 +185,7 @@ const TimelineActions: React.FC<Props> = ({
{status.replies_count > 0 ? ( {status.replies_count > 0 ? (
<Text <Text
style={{ style={{
color: theme.secondary, color: colors.secondary,
fontSize: StyleConstants.Font.Size.M, fontSize: StyleConstants.Font.Size.M,
marginLeft: StyleConstants.Spacing.XS marginLeft: StyleConstants.Spacing.XS
}} }}
@ -198,14 +198,14 @@ const TimelineActions: React.FC<Props> = ({
[status.replies_count] [status.replies_count]
) )
const childrenReblog = useMemo(() => { const childrenReblog = useMemo(() => {
const color = (state: boolean) => (state ? theme.green : theme.secondary) const color = (state: boolean) => (state ? colors.green : colors.secondary)
return ( return (
<> <>
<Icon <Icon
name='Repeat' name='Repeat'
color={ color={
status.visibility === 'private' || status.visibility === 'direct' status.visibility === 'private' || status.visibility === 'direct'
? theme.disabled ? colors.disabled
: color(status.reblogged) : color(status.reblogged)
} }
size={StyleConstants.Font.Size.L} size={StyleConstants.Font.Size.L}
@ -225,7 +225,7 @@ const TimelineActions: React.FC<Props> = ({
) )
}, [status.reblogged, status.reblogs_count]) }, [status.reblogged, status.reblogs_count])
const childrenFavourite = useMemo(() => { const childrenFavourite = useMemo(() => {
const color = (state: boolean) => (state ? theme.red : theme.secondary) const color = (state: boolean) => (state ? colors.red : colors.secondary)
return ( return (
<> <>
<Icon <Icon
@ -249,7 +249,7 @@ const TimelineActions: React.FC<Props> = ({
) )
}, [status.favourited, status.favourites_count]) }, [status.favourited, status.favourites_count])
const childrenBookmark = useMemo(() => { const childrenBookmark = useMemo(() => {
const color = (state: boolean) => (state ? theme.yellow : theme.secondary) const color = (state: boolean) => (state ? colors.yellow : colors.secondary)
return ( return (
<Icon <Icon
name='Bookmark' name='Bookmark'

View File

@ -19,10 +19,9 @@ const TimelineActionsUsers = React.memo(
} }
const { t } = useTranslation('componentTimeline') const { t } = useTranslation('componentTimeline')
const { theme } = useTheme() const { colors } = useTheme()
const navigation = useNavigation< const navigation =
StackNavigationProp<Nav.TabLocalStackParamList> useNavigation<StackNavigationProp<Nav.TabLocalStackParamList>>()
>()
return ( return (
<View style={styles.base}> <View style={styles.base}>
@ -38,7 +37,7 @@ const TimelineActionsUsers = React.memo(
'shared.actionsUsers.reblogged_by.accessibilityHint' 'shared.actionsUsers.reblogged_by.accessibilityHint'
)} )}
accessibilityRole='button' accessibilityRole='button'
style={[styles.text, { color: theme.blue }]} style={[styles.text, { color: colors.blue }]}
onPress={() => { onPress={() => {
analytics('timeline_shared_actionsusers_press_boosted', { analytics('timeline_shared_actionsusers_press_boosted', {
count: status.reblogs_count count: status.reblogs_count
@ -68,7 +67,7 @@ const TimelineActionsUsers = React.memo(
'shared.actionsUsers.favourited_by.accessibilityHint' 'shared.actionsUsers.favourited_by.accessibilityHint'
)} )}
accessibilityRole='button' accessibilityRole='button'
style={[styles.text, { color: theme.blue }]} style={[styles.text, { color: colors.blue }]}
onPress={() => { onPress={() => {
analytics('timeline_shared_actionsusers_press_boosted', { analytics('timeline_shared_actionsusers_press_boosted', {
count: status.favourites_count count: status.favourites_count

View File

@ -23,7 +23,7 @@ const AttachmentAudio: React.FC<Props> = ({
sensitiveShown, sensitiveShown,
audio audio
}) => { }) => {
const { theme } = useTheme() const { colors } = useTheme()
const [audioPlayer, setAudioPlayer] = useState<Audio.Sound>() const [audioPlayer, setAudioPlayer] = useState<Audio.Sound>()
const [audioPlaying, setAudioPlaying] = useState(false) const [audioPlaying, setAudioPlaying] = useState(false)
@ -56,7 +56,7 @@ const AttachmentAudio: React.FC<Props> = ({
style={[ style={[
styles.base, styles.base,
{ {
backgroundColor: theme.disabled, backgroundColor: colors.disabled,
aspectRatio: attachmentAspectRatio({ total, index }) aspectRatio: attachmentAspectRatio({ total, index })
} }
]} ]}
@ -102,7 +102,7 @@ const AttachmentAudio: React.FC<Props> = ({
alignSelf: 'flex-end', alignSelf: 'flex-end',
width: '100%', width: '100%',
height: StyleConstants.Spacing.M + StyleConstants.Spacing.S * 2, height: StyleConstants.Spacing.M + StyleConstants.Spacing.S * 2,
backgroundColor: theme.backgroundOverlayInvert, backgroundColor: colors.backgroundOverlayInvert,
paddingHorizontal: StyleConstants.Spacing.Global.PagePadding, paddingHorizontal: StyleConstants.Spacing.Global.PagePadding,
borderRadius: 100, borderRadius: 100,
opacity: sensitiveShown ? 0.35 : undefined opacity: sensitiveShown ? 0.35 : undefined
@ -112,8 +112,8 @@ const AttachmentAudio: React.FC<Props> = ({
minimumValue={0} minimumValue={0}
maximumValue={audio.meta.original.duration * 1000} maximumValue={audio.meta.original.duration * 1000}
value={audioPosition} value={audioPosition}
minimumTrackTintColor={theme.secondary} minimumTrackTintColor={colors.secondary}
maximumTrackTintColor={theme.disabled} maximumTrackTintColor={colors.disabled}
// onSlidingStart={() => { // onSlidingStart={() => {
// audioPlayer?.pauseAsync() // audioPlayer?.pauseAsync()
// setAudioPlaying(false) // setAudioPlaying(false)
@ -123,7 +123,7 @@ const AttachmentAudio: React.FC<Props> = ({
// }} // }}
enabled={false} // Bug in above sliding actions enabled={false} // Bug in above sliding actions
thumbSize={StyleConstants.Spacing.M} thumbSize={StyleConstants.Spacing.M}
thumbTintColor={theme.primaryOverlay} thumbTintColor={colors.primaryOverlay}
/> />
</View> </View>
) : null} ) : null}

View File

@ -28,7 +28,17 @@ const AttachmentImage = React.memo(
uri={{ original: image.preview_url, remote: image.remote_url }} uri={{ original: image.preview_url, remote: image.remote_url }}
blurhash={image.blurhash} blurhash={image.blurhash}
onPress={onPress} onPress={onPress}
style={[{ aspectRatio: attachmentAspectRatio({ total, index }) }]} style={[
{
aspectRatio:
total > 1 ||
!image.meta?.original?.width ||
!image.meta?.original?.height ||
image.meta.original.width / image.meta.original.height > 2
? attachmentAspectRatio({ total, index })
: image.meta.original.width / image.meta.original.height
}
]}
/> />
</View> </View>
) )

View File

@ -23,7 +23,7 @@ const AttachmentUnsupported: React.FC<Props> = ({
attachment attachment
}) => { }) => {
const { t } = useTranslation('componentTimeline') const { t } = useTranslation('componentTimeline')
const { theme } = useTheme() const { colors } = useTheme()
return ( return (
<View <View
@ -49,8 +49,8 @@ const AttachmentUnsupported: React.FC<Props> = ({
styles.text, styles.text,
{ {
color: attachment.blurhash color: attachment.blurhash
? theme.backgroundDefault ? colors.backgroundDefault
: theme.primaryDefault : colors.primaryDefault
} }
]} ]}
> >

View File

@ -16,9 +16,8 @@ export interface Props {
const TimelineAvatar = React.memo( const TimelineAvatar = React.memo(
({ queryKey, account, highlighted }: Props) => { ({ queryKey, account, highlighted }: Props) => {
const { t } = useTranslation('componentTimeline') const { t } = useTranslation('componentTimeline')
const navigation = useNavigation< const navigation =
StackNavigationProp<Nav.TabLocalStackParamList> useNavigation<StackNavigationProp<Nav.TabLocalStackParamList>>()
>()
// Need to fix go back root // Need to fix go back root
const onPress = useCallback(() => { const onPress = useCallback(() => {
analytics('timeline_shared_avatar_press', { analytics('timeline_shared_avatar_press', {
@ -38,7 +37,7 @@ const TimelineAvatar = React.memo(
}) })
})} })}
onPress={onPress} onPress={onPress}
uri={{ original: account.avatar_static }} uri={{ original: account.avatar, static: account.avatar_static }}
dimension={{ dimension={{
width: StyleConstants.Avatar.M, width: StyleConstants.Avatar.M,
height: StyleConstants.Avatar.M height: StyleConstants.Avatar.M

View File

@ -13,14 +13,14 @@ export interface Props {
const TimelineCard = React.memo( const TimelineCard = React.memo(
({ card }: Props) => { ({ card }: Props) => {
const { theme } = useTheme() const { colors } = useTheme()
const navigation = useNavigation() const navigation = useNavigation()
return ( return (
<Pressable <Pressable
accessible accessible
accessibilityRole='link' accessibilityRole='link'
style={[styles.card, { borderColor: theme.border }]} style={[styles.card, { borderColor: colors.border }]}
onPress={async () => { onPress={async () => {
analytics('timeline_shared_card_press') analytics('timeline_shared_card_press')
await openLink(card.url, navigation) await openLink(card.url, navigation)
@ -38,7 +38,7 @@ const TimelineCard = React.memo(
<View style={styles.right}> <View style={styles.right}>
<Text <Text
numberOfLines={2} numberOfLines={2}
style={[styles.rightTitle, { color: theme.primaryDefault }]} style={[styles.rightTitle, { color: colors.primaryDefault }]}
testID='title' testID='title'
> >
{card.title} {card.title}
@ -46,7 +46,10 @@ const TimelineCard = React.memo(
{card.description ? ( {card.description ? (
<Text <Text
numberOfLines={1} numberOfLines={1}
style={[styles.rightDescription, { color: theme.primaryDefault }]} style={[
styles.rightDescription,
{ color: colors.primaryDefault }
]}
testID='description' testID='description'
> >
{card.description} {card.description}
@ -54,7 +57,7 @@ const TimelineCard = React.memo(
) : null} ) : null}
<Text <Text
numberOfLines={1} numberOfLines={1}
style={[styles.rightLink, { color: theme.secondary }]} style={[styles.rightLink, { color: colors.secondary }]}
> >
{card.url} {card.url}
</Text> </Text>

View File

@ -10,15 +10,15 @@ import { Text, View } from 'react-native'
const TimelineFiltered = React.memo( const TimelineFiltered = React.memo(
() => { () => {
const { theme } = useTheme() const { colors } = useTheme()
const { t } = useTranslation('componentTimeline') const { t } = useTranslation('componentTimeline')
return ( return (
<View style={{ backgroundColor: theme.backgroundDefault }}> <View style={{ backgroundColor: colors.backgroundDefault }}>
<Text <Text
style={{ style={{
...StyleConstants.FontStyle.S, ...StyleConstants.FontStyle.S,
color: theme.secondary, color: colors.secondary,
textAlign: 'center', textAlign: 'center',
paddingVertical: StyleConstants.Spacing.S, paddingVertical: StyleConstants.Spacing.S,
paddingLeft: StyleConstants.Avatar.M + StyleConstants.Spacing.S paddingLeft: StyleConstants.Avatar.M + StyleConstants.Spacing.S

View File

@ -13,7 +13,7 @@ export interface Props {
const TimelineFullConversation = React.memo( const TimelineFullConversation = React.memo(
({ queryKey, status }: Props) => { ({ queryKey, status }: Props) => {
const { t } = useTranslation('componentTimeline') const { t } = useTranslation('componentTimeline')
const { theme } = useTheme() const { colors } = useTheme()
return queryKey && return queryKey &&
queryKey[1].page !== 'Toot' && queryKey[1].page !== 'Toot' &&
@ -25,7 +25,7 @@ const TimelineFullConversation = React.memo(
<Text <Text
style={{ style={{
...StyleConstants.FontStyle.S, ...StyleConstants.FontStyle.S,
color: theme.blue, color: colors.blue,
marginTop: StyleConstants.Spacing.S marginTop: StyleConstants.Spacing.S
}} }}
> >

View File

@ -18,12 +18,12 @@ import HeaderSharedMuted from './HeaderShared/Muted'
const Names = React.memo( const Names = React.memo(
({ accounts }: { accounts: Mastodon.Account[] }) => { ({ accounts }: { accounts: Mastodon.Account[] }) => {
const { t } = useTranslation('componentTimeline') const { t } = useTranslation('componentTimeline')
const { theme } = useTheme() const { colors } = useTheme()
return ( return (
<Text <Text
numberOfLines={1} numberOfLines={1}
style={[styles.namesLeading, { color: theme.secondary }]} style={[styles.namesLeading, { color: colors.secondary }]}
> >
<Text>{t('shared.header.conversation.withAccounts')}</Text> <Text>{t('shared.header.conversation.withAccounts')}</Text>
{accounts.map((account, index) => ( {accounts.map((account, index) => (
@ -49,7 +49,7 @@ export interface Props {
const HeaderConversation = React.memo( const HeaderConversation = React.memo(
({ queryKey, conversation }: Props) => { ({ queryKey, conversation }: Props) => {
const { mode } = useTheme() const { colors, theme } = useTheme()
const { t } = useTranslation('componentTimeline') const { t } = useTranslation('componentTimeline')
const queryClient = useQueryClient() const queryClient = useQueryClient()
@ -57,7 +57,7 @@ const HeaderConversation = React.memo(
onMutate: true, onMutate: true,
onError: (err: any, _, oldData) => { onError: (err: any, _, oldData) => {
displayMessage({ displayMessage({
mode, theme,
type: 'error', type: 'error',
message: t('common:message.error.message', { message: t('common:message.error.message', {
function: t(`shared.header.conversation.delete.function`) function: t(`shared.header.conversation.delete.function`)
@ -74,8 +74,6 @@ const HeaderConversation = React.memo(
} }
}) })
const { theme } = useTheme()
const actionOnPress = useCallback(() => { const actionOnPress = useCallback(() => {
analytics('timeline_conversation_delete_press') analytics('timeline_conversation_delete_press')
mutation.mutate({ mutation.mutate({
@ -90,7 +88,7 @@ const HeaderConversation = React.memo(
() => ( () => (
<Icon <Icon
name='Trash' name='Trash'
color={theme.secondary} color={colors.secondary}
size={StyleConstants.Font.Size.L} size={StyleConstants.Font.Size.L}
/> />
), ),

View File

@ -22,7 +22,7 @@ const TimelineHeaderDefault = React.memo(
({ queryKey, rootQueryKey, status }: Props) => { ({ queryKey, rootQueryKey, status }: Props) => {
const { t } = useTranslation('componentTimeline') const { t } = useTranslation('componentTimeline')
const navigation = useNavigation() const navigation = useNavigation()
const { theme } = useTheme() const { colors } = useTheme()
return ( return (
<View style={styles.base}> <View style={styles.base}>
@ -52,7 +52,7 @@ const TimelineHeaderDefault = React.memo(
children={ children={
<Icon <Icon
name='MoreHorizontal' name='MoreHorizontal'
color={theme.secondary} color={colors.secondary}
size={StyleConstants.Font.Size.L} size={StyleConstants.Font.Size.L}
/> />
} }

View File

@ -23,7 +23,7 @@ export interface Props {
const TimelineHeaderNotification = React.memo( const TimelineHeaderNotification = React.memo(
({ queryKey, notification }: Props) => { ({ queryKey, notification }: Props) => {
const navigation = useNavigation() const navigation = useNavigation()
const { theme } = useTheme() const { colors } = useTheme()
const actions = useMemo(() => { const actions = useMemo(() => {
switch (notification.type) { switch (notification.type) {
@ -52,7 +52,7 @@ const TimelineHeaderNotification = React.memo(
children={ children={
<Icon <Icon
name='MoreHorizontal' name='MoreHorizontal'
color={theme.secondary} color={colors.secondary}
size={StyleConstants.Font.Size.L} size={StyleConstants.Font.Size.L}
/> />
} }

View File

@ -13,7 +13,7 @@ export interface Props {
const HeaderSharedAccount = React.memo( const HeaderSharedAccount = React.memo(
({ account, withoutName = false }: Props) => { ({ account, withoutName = false }: Props) => {
const { t } = useTranslation('componentTimeline') const { t } = useTranslation('componentTimeline')
const { theme } = useTheme() const { colors } = useTheme()
return ( return (
<View style={styles.base}> <View style={styles.base}>
@ -36,7 +36,7 @@ const HeaderSharedAccount = React.memo(
accessibilityHint={t( accessibilityHint={t(
'shared.header.shared.account.account.accessibilityHint' 'shared.header.shared.account.account.accessibilityHint'
)} )}
style={[styles.acct, { color: theme.secondary }]} style={[styles.acct, { color: colors.secondary }]}
numberOfLines={1} numberOfLines={1}
> >
@{account.acct} @{account.acct}

View File

@ -12,7 +12,7 @@ export interface Props {
const HeaderSharedApplication = React.memo( const HeaderSharedApplication = React.memo(
({ application }: Props) => { ({ application }: Props) => {
const { theme } = useTheme() const { colors } = useTheme()
const { t } = useTranslation('componentTimeline') const { t } = useTranslation('componentTimeline')
return application && application.name !== 'Web' ? ( return application && application.name !== 'Web' ? (
@ -24,7 +24,7 @@ const HeaderSharedApplication = React.memo(
}) })
application.website && (await openLink(application.website)) application.website && (await openLink(application.website))
}} }}
style={[styles.application, { color: theme.secondary }]} style={[styles.application, { color: colors.secondary }]}
numberOfLines={1} numberOfLines={1}
> >
{t('shared.header.shared.application', { {t('shared.header.shared.application', {

View File

@ -10,10 +10,10 @@ export interface Props {
const HeaderSharedCreated = React.memo( const HeaderSharedCreated = React.memo(
({ created_at }: Props) => { ({ created_at }: Props) => {
const { theme } = useTheme() const { colors } = useTheme()
return ( return (
<Text style={[styles.created_at, { color: theme.secondary }]}> <Text style={[styles.created_at, { color: colors.secondary }]}>
<RelativeTime date={created_at} /> <RelativeTime date={created_at} />
</Text> </Text>
) )

View File

@ -12,14 +12,14 @@ export interface Props {
const HeaderSharedMuted = React.memo( const HeaderSharedMuted = React.memo(
({ muted }: Props) => { ({ muted }: Props) => {
const { t } = useTranslation('componentTimeline') const { t } = useTranslation('componentTimeline')
const { theme } = useTheme() const { colors } = useTheme()
return muted ? ( return muted ? (
<Icon <Icon
accessibilityLabel={t('shared.header.shared.muted.accessibilityLabel')} accessibilityLabel={t('shared.header.shared.muted.accessibilityLabel')}
name='VolumeX' name='VolumeX'
size={StyleConstants.Font.Size.S} size={StyleConstants.Font.Size.S}
color={theme.secondary} color={colors.secondary}
style={styles.visibility} style={styles.visibility}
/> />
) : null ) : null

View File

@ -12,7 +12,7 @@ export interface Props {
const HeaderSharedVisibility = React.memo( const HeaderSharedVisibility = React.memo(
({ visibility }: Props) => { ({ visibility }: Props) => {
const { t } = useTranslation('componentTimeline') const { t } = useTranslation('componentTimeline')
const { theme } = useTheme() const { colors } = useTheme()
switch (visibility) { switch (visibility) {
case 'private': case 'private':
@ -23,7 +23,7 @@ const HeaderSharedVisibility = React.memo(
)} )}
name='Lock' name='Lock'
size={StyleConstants.Font.Size.S} size={StyleConstants.Font.Size.S}
color={theme.secondary} color={colors.secondary}
style={styles.visibility} style={styles.visibility}
/> />
) )
@ -35,7 +35,7 @@ const HeaderSharedVisibility = React.memo(
)} )}
name='Mail' name='Mail'
size={StyleConstants.Font.Size.S} size={StyleConstants.Font.Size.S}
color={theme.secondary} color={colors.secondary}
style={styles.visibility} style={styles.visibility}
/> />
) )

View File

@ -36,7 +36,7 @@ const TimelinePoll: React.FC<Props> = ({
reblog, reblog,
sameAccount sameAccount
}) => { }) => {
const { mode, theme } = useTheme() const { colors, theme } = useTheme()
const { t, i18n } = useTranslation('componentTimeline') const { t, i18n } = useTranslation('componentTimeline')
const [allOptions, setAllOptions] = useState( const [allOptions, setAllOptions] = useState(
@ -53,7 +53,7 @@ const TimelinePoll: React.FC<Props> = ({
haptics('Success') haptics('Success')
switch (theParams.payload.property) { switch (theParams.payload.property) {
case 'poll': case 'poll':
theParams.payload.data = (body as unknown) as Mastodon.Poll theParams.payload.data = body as unknown as Mastodon.Poll
updateStatusProperty(theParams) updateStatusProperty(theParams)
break break
} }
@ -61,7 +61,7 @@ const TimelinePoll: React.FC<Props> = ({
onError: (err: any, params) => { onError: (err: any, params) => {
const theParams = params as MutationVarsTimelineUpdateStatusProperty const theParams = params as MutationVarsTimelineUpdateStatusProperty
displayMessage({ displayMessage({
mode, theme,
type: 'error', type: 'error',
message: t('common:message.error.message', { message: t('common:message.error.message', {
// @ts-ignore // @ts-ignore
@ -136,7 +136,7 @@ const TimelinePoll: React.FC<Props> = ({
} }
} }
}, [ }, [
mode, theme,
i18n.language, i18n.language,
poll.expired, poll.expired,
poll.voted, poll.voted,
@ -147,14 +147,14 @@ const TimelinePoll: React.FC<Props> = ({
const pollExpiration = useMemo(() => { const pollExpiration = useMemo(() => {
if (poll.expired) { if (poll.expired) {
return ( return (
<Text style={[styles.expiration, { color: theme.secondary }]}> <Text style={[styles.expiration, { color: colors.secondary }]}>
{t('shared.poll.meta.expiration.expired')} {t('shared.poll.meta.expiration.expired')}
</Text> </Text>
) )
} else { } else {
if (poll.expires_at) { if (poll.expires_at) {
return ( return (
<Text style={[styles.expiration, { color: theme.secondary }]}> <Text style={[styles.expiration, { color: colors.secondary }]}>
<Trans <Trans
i18nKey='componentTimeline:shared.poll.meta.expiration.until' i18nKey='componentTimeline:shared.poll.meta.expiration.until'
components={[<RelativeTime date={poll.expires_at} />]} components={[<RelativeTime date={poll.expires_at} />]}
@ -163,7 +163,7 @@ const TimelinePoll: React.FC<Props> = ({
) )
} }
} }
}, [mode, i18n.language, poll.expired, poll.expires_at]) }, [theme, i18n.language, poll.expired, poll.expires_at])
const isSelected = useCallback( const isSelected = useCallback(
(index: number): string => (index: number): string =>
@ -174,8 +174,10 @@ const TimelinePoll: React.FC<Props> = ({
) )
const pollBodyDisallow = useMemo(() => { const pollBodyDisallow = useMemo(() => {
const maxValue = maxBy(poll.options, option => option.votes_count) const maxValue = maxBy(
?.votes_count poll.options,
option => option.votes_count
)?.votes_count
return poll.options.map((option, index) => ( return poll.options.map((option, index) => (
<View key={index} style={styles.optionContainer}> <View key={index} style={styles.optionContainer}>
<View style={styles.optionContent}> <View style={styles.optionContent}>
@ -188,14 +190,14 @@ const TimelinePoll: React.FC<Props> = ({
} }
size={StyleConstants.Font.Size.M} size={StyleConstants.Font.Size.M}
color={ color={
poll.own_votes?.includes(index) ? theme.blue : theme.disabled poll.own_votes?.includes(index) ? colors.blue : colors.disabled
} }
/> />
<Text style={styles.optionText}> <Text style={styles.optionText}>
<ParseEmojis content={option.title} emojis={poll.emojis} /> <ParseEmojis content={option.title} emojis={poll.emojis} />
</Text> </Text>
<Text <Text
style={[styles.optionPercentage, { color: theme.primaryDefault }]} style={[styles.optionPercentage, { color: colors.primaryDefault }]}
> >
{poll.votes_count {poll.votes_count
? Math.round( ? Math.round(
@ -217,13 +219,13 @@ const TimelinePoll: React.FC<Props> = ({
100 100
)}%`, )}%`,
backgroundColor: backgroundColor:
option.votes_count === maxValue ? theme.blue : theme.disabled option.votes_count === maxValue ? colors.blue : colors.disabled
} }
]} ]}
/> />
</View> </View>
)) ))
}, [mode, poll.options]) }, [theme, poll.options])
const pollBodyAllow = useMemo(() => { const pollBodyAllow = useMemo(() => {
return poll.options.map((option, index) => ( return poll.options.map((option, index) => (
<Pressable <Pressable
@ -256,7 +258,7 @@ const TimelinePoll: React.FC<Props> = ({
style={styles.optionSelection} style={styles.optionSelection}
name={isSelected(index)} name={isSelected(index)}
size={StyleConstants.Font.Size.M} size={StyleConstants.Font.Size.M}
color={theme.primaryDefault} color={colors.primaryDefault}
/> />
<Text style={styles.optionText}> <Text style={styles.optionText}>
<ParseEmojis content={option.title} emojis={poll.emojis} /> <ParseEmojis content={option.title} emojis={poll.emojis} />
@ -264,19 +266,19 @@ const TimelinePoll: React.FC<Props> = ({
</View> </View>
</Pressable> </Pressable>
)) ))
}, [mode, allOptions]) }, [theme, allOptions])
const pollVoteCounts = useMemo(() => { const pollVoteCounts = useMemo(() => {
if (poll.voters_count !== null) { if (poll.voters_count !== null) {
return ( return (
<Text style={[styles.votes, { color: theme.secondary }]}> <Text style={[styles.votes, { color: colors.secondary }]}>
{t('shared.poll.meta.count.voters', { count: poll.voters_count })} {t('shared.poll.meta.count.voters', { count: poll.voters_count })}
{' • '} {' • '}
</Text> </Text>
) )
} else if (poll.votes_count !== null) { } else if (poll.votes_count !== null) {
return ( return (
<Text style={[styles.votes, { color: theme.secondary }]}> <Text style={[styles.votes, { color: colors.secondary }]}>
{t('shared.poll.meta.count.votes', { count: poll.votes_count })} {t('shared.poll.meta.count.votes', { count: poll.votes_count })}
{' • '} {' • '}
</Text> </Text>

View File

@ -26,7 +26,7 @@ const TimelineTranslate = React.memo(
} }
const { t } = useTranslation('componentTimeline') const { t } = useTranslation('componentTimeline')
const { theme } = useTheme() const { colors } = useTheme()
const tootLanguage = status.language.slice(0, 2) const tootLanguage = status.language.slice(0, 2)
@ -82,10 +82,10 @@ const TimelineTranslate = React.memo(
...StyleConstants.FontStyle.M, ...StyleConstants.FontStyle.M,
color: color:
isLoading || isSuccess isLoading || isSuccess
? theme.secondary ? colors.secondary
: isError : isError
? theme.red ? colors.red
: theme.blue : colors.blue
}} }}
> >
{isError {isError
@ -109,7 +109,7 @@ const TimelineTranslate = React.memo(
{isLoading ? ( {isLoading ? (
<Circle <Circle
size={StyleConstants.Font.Size.M} size={StyleConstants.Font.Size.M}
color={theme.disabled} color={colors.disabled}
style={{ marginLeft: StyleConstants.Spacing.S }} style={{ marginLeft: StyleConstants.Spacing.S }}
/> />
) : null} ) : null}

View File

@ -232,6 +232,14 @@
"cancel": "$t(common:buttons.cancel)" "cancel": "$t(common:buttons.cancel)"
} }
}, },
"darkTheme": {
"heading": "Dark theme",
"options": {
"lighter": "Lighter",
"darker": "Darker",
"cancel": "$t(common:buttons.cancel)"
}
},
"browser": { "browser": {
"heading": "Opening Link", "heading": "Opening Link",
"options": { "options": {

View File

@ -5,7 +5,7 @@
"cancel": "$t(common:buttons.cancel)" "cancel": "$t(common:buttons.cancel)"
}, },
"notificationsFilter": { "notificationsFilter": {
"heading": "Chỉ hiện thông báo", "heading": "Những kiểu thông báo cho phép",
"content": { "content": {
"follow": "$t(screenTabs:me.push.follow.heading)", "follow": "$t(screenTabs:me.push.follow.heading)",
"favourite": "$t(screenTabs:me.push.favourite.heading)", "favourite": "$t(screenTabs:me.push.favourite.heading)",

View File

@ -13,10 +13,10 @@
}, },
"right": { "right": {
"button": { "button": {
"default": "Tút", "default": "Đăng",
"conversation": "Tin nhắn", "conversation": "Tin nhắn",
"reply": "Trả lời", "reply": "Trả lời",
"edit": "Tút" "edit": "Sửa"
}, },
"alert": { "alert": {
"default": { "default": {

View File

@ -150,11 +150,11 @@
"settings": "Bật trong cài đặt" "settings": "Bật trong cài đặt"
}, },
"global": { "global": {
"heading": "Bật khi {{acct}}", "heading": "Bật cho {{acct}}",
"description": "Thông báo được truyền qua máy chủ tooot" "description": "Thông báo được truyền qua máy chủ tooot"
}, },
"decode": { "decode": {
"heading": "Chi tiết thông báo", "heading": "Hiện chi tiết thông báo",
"description": "Theo mặc định, thông báo truyền qua máy chủ tooot sẽ được mã hóa, nhưng bạn cũng có thể chọn không mã hóa. Máy chủ của chúng tôi luôn công khai mã nguồn và không lưu lại bất cứ gì." "description": "Theo mặc định, thông báo truyền qua máy chủ tooot sẽ được mã hóa, nhưng bạn cũng có thể chọn không mã hóa. Máy chủ của chúng tôi luôn công khai mã nguồn và không lưu lại bất cứ gì."
}, },
"default": { "default": {
@ -240,6 +240,9 @@
"cancel": "$t(common:buttons.cancel)" "cancel": "$t(common:buttons.cancel)"
} }
}, },
"feedback": {
"heading": "Yêu cầu tính năng"
},
"support": { "support": {
"heading": "Ủng hộ tooot" "heading": "Ủng hộ tooot"
}, },
@ -310,7 +313,7 @@
}, },
"users": { "users": {
"accounts": { "accounts": {
"following": "{{count}} Theo dõi", "following": "{{count}} theo dõi",
"followers": "{{count}} người theo dõi" "followers": "{{count}} người theo dõi"
}, },
"statuses": { "statuses": {

View File

@ -68,7 +68,7 @@ const ScreenActions = React.memo(
break break
} }
const { theme } = useTheme() const { colors } = useTheme()
const insets = useSafeAreaInsets() const insets = useSafeAreaInsets()
const DEFAULT_VALUE = 350 const DEFAULT_VALUE = 350
@ -189,7 +189,7 @@ const ScreenActions = React.memo(
<Animated.View <Animated.View
style={[ style={[
styles.overlay, styles.overlay,
{ backgroundColor: theme.backgroundOverlayInvert } { backgroundColor: colors.backgroundOverlayInvert }
]} ]}
> >
<PanGestureHandler onGestureEvent={onGestureEvent}> <PanGestureHandler onGestureEvent={onGestureEvent}>
@ -198,7 +198,7 @@ const ScreenActions = React.memo(
styles.container, styles.container,
styleTop, styleTop,
{ {
backgroundColor: theme.backgroundDefault, backgroundColor: colors.backgroundDefault,
paddingBottom: insets.bottom || StyleConstants.Spacing.L paddingBottom: insets.bottom || StyleConstants.Spacing.L
} }
]} ]}
@ -206,7 +206,7 @@ const ScreenActions = React.memo(
<View <View
style={[ style={[
styles.handle, styles.handle,
{ backgroundColor: theme.primaryOverlay } { backgroundColor: colors.primaryOverlay }
]} ]}
/> />
{actions} {actions}

View File

@ -24,7 +24,7 @@ const ActionsAccount: React.FC<Props> = ({
account, account,
dismiss dismiss
}) => { }) => {
const { mode } = useTheme() const { theme } = useTheme()
const { t } = useTranslation('componentTimeline') const { t } = useTranslation('componentTimeline')
const queryClient = useQueryClient() const queryClient = useQueryClient()
@ -32,7 +32,7 @@ const ActionsAccount: React.FC<Props> = ({
onSuccess: (_, params) => { onSuccess: (_, params) => {
const theParams = params as MutationVarsTimelineUpdateAccountProperty const theParams = params as MutationVarsTimelineUpdateAccountProperty
displayMessage({ displayMessage({
mode, theme,
type: 'success', type: 'success',
message: t('common:message.success.message', { message: t('common:message.success.message', {
function: t( function: t(
@ -47,7 +47,7 @@ const ActionsAccount: React.FC<Props> = ({
onError: (err: any, params) => { onError: (err: any, params) => {
const theParams = params as MutationVarsTimelineUpdateAccountProperty const theParams = params as MutationVarsTimelineUpdateAccountProperty
displayMessage({ displayMessage({
mode, theme,
type: 'error', type: 'error',
message: t('common:message.error.message', { message: t('common:message.error.message', {
function: t( function: t(

View File

@ -26,13 +26,13 @@ const ActionsDomain: React.FC<Props> = ({
domain, domain,
dismiss dismiss
}) => { }) => {
const { mode } = useTheme() const { theme } = useTheme()
const { t } = useTranslation('componentTimeline') const { t } = useTranslation('componentTimeline')
const queryClient = useQueryClient() const queryClient = useQueryClient()
const mutation = useTimelineMutation({ const mutation = useTimelineMutation({
onSettled: () => { onSettled: () => {
displayMessage({ displayMessage({
mode, theme,
type: 'success', type: 'success',
message: t('common:message.success.message', { message: t('common:message.success.message', {
function: t(`shared.header.actions.domain.block.function`) function: t(`shared.header.actions.domain.block.function`)

View File

@ -30,7 +30,7 @@ const ActionsStatus: React.FC<Props> = ({
status, status,
dismiss dismiss
}) => { }) => {
const { mode } = useTheme() const { theme } = useTheme()
const { t } = useTranslation('componentTimeline') const { t } = useTranslation('componentTimeline')
const queryClient = useQueryClient() const queryClient = useQueryClient()
@ -42,7 +42,7 @@ const ActionsStatus: React.FC<Props> = ({
? (params as MutationVarsTimelineUpdateStatusProperty).payload.property ? (params as MutationVarsTimelineUpdateStatusProperty).payload.property
: 'delete' : 'delete'
displayMessage({ displayMessage({
mode, theme,
type: 'error', type: 'error',
message: t('common:message.error.message', { message: t('common:message.error.message', {
function: t(`shared.header.actions.status.${theFunction}.function`) function: t(`shared.header.actions.status.${theFunction}.function`)

View File

@ -36,7 +36,7 @@ const ScreenAnnouncements: React.FC<
navigation navigation
}) => { }) => {
const { reduceMotionEnabled } = useAccessibility() const { reduceMotionEnabled } = useAccessibility()
const { mode, theme } = useTheme() const { colors, mode } = useTheme()
const [index, setIndex] = useState(0) const [index, setIndex] = useState(0)
const { t } = useTranslation('screenAnnouncements') const { t } = useTranslation('screenAnnouncements')
@ -73,12 +73,12 @@ const ScreenAnnouncements: React.FC<
style={[ style={[
styles.announcement, styles.announcement,
{ {
borderColor: theme.primaryDefault, borderColor: colors.primaryDefault,
backgroundColor: theme.backgroundDefault backgroundColor: colors.backgroundDefault
} }
]} ]}
> >
<Text style={[styles.published, { color: theme.secondary }]}> <Text style={[styles.published, { color: colors.secondary }]}>
<Trans <Trans
i18nKey='screenAnnouncements:content.published' i18nKey='screenAnnouncements:content.published'
components={[<RelativeTime date={item.published_at} />]} components={[<RelativeTime date={item.published_at} />]}
@ -103,11 +103,11 @@ const ScreenAnnouncements: React.FC<
styles.reaction, styles.reaction,
{ {
borderColor: reaction.me borderColor: reaction.me
? theme.disabled ? colors.disabled
: theme.primaryDefault, : colors.primaryDefault,
backgroundColor: reaction.me backgroundColor: reaction.me
? theme.disabled ? colors.disabled
: theme.backgroundDefault : colors.backgroundDefault
} }
]} ]}
onPress={() => { onPress={() => {
@ -138,7 +138,7 @@ const ScreenAnnouncements: React.FC<
<Text <Text
style={[ style={[
styles.reactionCount, styles.reactionCount,
{ color: theme.primaryDefault } { color: colors.primaryDefault }
]} ]}
> >
{reaction.count} {reaction.count}
@ -147,13 +147,13 @@ const ScreenAnnouncements: React.FC<
</Pressable> </Pressable>
))} ))}
{/* <Pressable {/* <Pressable
style={[styles.reaction, { borderColor: theme.primaryDefault }]} style={[styles.reaction, { borderColor: colors.primaryDefault }]}
onPress={() => invisibleTextInputRef.current?.focus()} onPress={() => invisibleTextInputRef.current?.focus()}
> >
<Icon <Icon
name='Plus' name='Plus'
size={StyleConstants.Font.Size.M} size={StyleConstants.Font.Size.M}
color={theme.primaryDefault} color={colors.primaryDefault}
/> />
</Pressable> */} </Pressable> */}
</View> </View>
@ -177,7 +177,7 @@ const ScreenAnnouncements: React.FC<
</View> </View>
</View> </View>
), ),
[theme] [mode]
) )
const onMomentumScrollEnd = useCallback( const onMomentumScrollEnd = useCallback(
@ -201,7 +201,7 @@ const ScreenAnnouncements: React.FC<
alignItems: 'center' alignItems: 'center'
}} }}
> >
<Circle size={StyleConstants.Font.Size.L} color={theme.secondary} /> <Circle size={StyleConstants.Font.Size.L} color={colors.secondary} />
</View> </View>
) )
}, []) }, [])
@ -211,7 +211,7 @@ const ScreenAnnouncements: React.FC<
blurType={mode} blurType={mode}
blurAmount={20} blurAmount={20}
style={styles.base} style={styles.base}
reducedTransparencyFallbackColor={theme.backgroundDefault} reducedTransparencyFallbackColor={colors.backgroundDefault}
> >
<SafeAreaView style={styles.base}> <SafeAreaView style={styles.base}>
<FlatList <FlatList
@ -232,9 +232,9 @@ const ScreenAnnouncements: React.FC<
style={[ style={[
styles.indicator, styles.indicator,
{ {
borderColor: theme.primaryDefault, borderColor: colors.primaryDefault,
backgroundColor: backgroundColor:
i === index ? theme.primaryDefault : undefined, i === index ? colors.primaryDefault : undefined,
marginLeft: marginLeft:
i === query.data.length ? 0 : StyleConstants.Spacing.S i === query.data.length ? 0 : StyleConstants.Spacing.S
} }
@ -248,7 +248,7 @@ const ScreenAnnouncements: React.FC<
</BlurView> </BlurView>
) : ( ) : (
<SafeAreaView <SafeAreaView
style={[styles.base, { backgroundColor: theme.backgroundDefault }]} style={[styles.base, { backgroundColor: colors.backgroundDefault }]}
> >
<FlatList <FlatList
horizontal horizontal
@ -268,9 +268,9 @@ const ScreenAnnouncements: React.FC<
style={[ style={[
styles.indicator, styles.indicator,
{ {
borderColor: theme.primaryDefault, borderColor: colors.primaryDefault,
backgroundColor: backgroundColor:
i === index ? theme.primaryDefault : undefined, i === index ? colors.primaryDefault : undefined,
marginLeft: marginLeft:
i === query.data.length ? 0 : StyleConstants.Spacing.S i === query.data.length ? 0 : StyleConstants.Spacing.S
} }

View File

@ -50,7 +50,7 @@ const ScreenCompose: React.FC<RootStackScreenProps<'Screen-Compose'>> = ({
navigation navigation
}) => { }) => {
const { t } = useTranslation('screenCompose') const { t } = useTranslation('screenCompose')
const { theme } = useTheme() const { colors } = useTheme()
const queryClient = useQueryClient() const queryClient = useQueryClient()
const [hasKeyboard, setHasKeyboard] = useState(false) const [hasKeyboard, setHasKeyboard] = useState(false)
@ -373,7 +373,7 @@ const ScreenCompose: React.FC<RootStackScreenProps<'Screen-Compose'>> = ({
component={ComposeRoot} component={ComposeRoot}
options={{ options={{
title: headerContent, title: headerContent,
titleStyle: { headerTitleStyle: {
fontWeight: fontWeight:
totalTextCount > maxTootChars totalTextCount > maxTootChars
? StyleConstants.Font.Weight.Bold ? StyleConstants.Font.Weight.Bold
@ -381,7 +381,7 @@ const ScreenCompose: React.FC<RootStackScreenProps<'Screen-Compose'>> = ({
fontSize: StyleConstants.Font.Size.M fontSize: StyleConstants.Font.Size.M
}, },
headerTintColor: headerTintColor:
totalTextCount > maxTootChars ? theme.red : theme.secondary, totalTextCount > maxTootChars ? colors.red : colors.secondary,
headerLeft, headerLeft,
headerRight headerRight
}} }}

View File

@ -37,7 +37,7 @@ const ComposeDraftsListRoot: React.FC<Props> = ({ timestamp }) => {
const { t } = useTranslation('screenCompose') const { t } = useTranslation('screenCompose')
const navigation = useNavigation() const navigation = useNavigation()
const dispatch = useDispatch() const dispatch = useDispatch()
const { mode, theme } = useTheme() const { colors, theme } = useTheme()
const instanceDrafts = useSelector(getInstanceDrafts)?.filter( const instanceDrafts = useSelector(getInstanceDrafts)?.filter(
draft => draft.timestamp !== timestamp draft => draft.timestamp !== timestamp
) )
@ -56,7 +56,7 @@ const ComposeDraftsListRoot: React.FC<Props> = ({ timestamp }) => {
return ( return (
<Pressable <Pressable
accessibilityHint={t('content.draftsList.content.accessibilityHint')} accessibilityHint={t('content.draftsList.content.accessibilityHint')}
style={[styles.draft, { backgroundColor: theme.backgroundDefault }]} style={[styles.draft, { backgroundColor: colors.backgroundDefault }]}
onPress={async () => { onPress={async () => {
setCheckingAttachments(true) setCheckingAttachments(true)
let tempDraft = item let tempDraft = item
@ -104,7 +104,7 @@ const ComposeDraftsListRoot: React.FC<Props> = ({ timestamp }) => {
<HeaderSharedCreated created_at={item.timestamp} /> <HeaderSharedCreated created_at={item.timestamp} />
<Text <Text
numberOfLines={2} numberOfLines={2}
style={[styles.text, { color: theme.primaryDefault }]} style={[styles.text, { color: colors.primaryDefault }]}
> >
{item.text || {item.text ||
item.spoiler || item.spoiler ||
@ -132,12 +132,12 @@ const ComposeDraftsListRoot: React.FC<Props> = ({ timestamp }) => {
</Pressable> </Pressable>
) )
}, },
[mode] [theme]
) )
const renderHiddenItem = useCallback( const renderHiddenItem = useCallback(
({ item }) => ( ({ item }) => (
<View <View
style={[styles.hiddenBase, { backgroundColor: theme.red }]} style={[styles.hiddenBase, { backgroundColor: colors.red }]}
children={ children={
<Pressable <Pressable
style={styles.action} style={styles.action}
@ -146,14 +146,14 @@ const ComposeDraftsListRoot: React.FC<Props> = ({ timestamp }) => {
<Icon <Icon
name='Trash' name='Trash'
size={StyleConstants.Font.Size.L} size={StyleConstants.Font.Size.L}
color={theme.primaryOverlay} color={colors.primaryOverlay}
/> />
} }
/> />
} }
/> />
), ),
[mode] [theme]
) )
return ( return (
@ -184,14 +184,14 @@ const ComposeDraftsListRoot: React.FC<Props> = ({ timestamp }) => {
<View <View
style={[ style={[
styles.modal, styles.modal,
{ backgroundColor: theme.backgroundOverlayInvert } { backgroundColor: colors.backgroundOverlayInvert }
]} ]}
children={ children={
<Text <Text
children='检查附件在服务器的状态…' children='检查附件在服务器的状态…'
style={{ style={{
...StyleConstants.FontStyle.M, ...StyleConstants.FontStyle.M,
color: theme.primaryOverlay color: colors.primaryOverlay
}} }}
/> />
} }

View File

@ -22,7 +22,7 @@ export interface Props {
const ComposeEditAttachmentImage: React.FC<Props> = ({ index }) => { const ComposeEditAttachmentImage: React.FC<Props> = ({ index }) => {
const { t } = useTranslation('screenCompose') const { t } = useTranslation('screenCompose')
const { theme } = useTheme() const { colors } = useTheme()
const { screenReaderEnabled } = useAccessibility() const { screenReaderEnabled } = useAccessibility()
const { composeState, composeDispatch } = useContext(ComposeContext) const { composeState, composeDispatch } = useContext(ComposeContext)
@ -146,16 +146,21 @@ const ComposeEditAttachmentImage: React.FC<Props> = ({ index }) => {
<G> <G>
<Path <Path
d='M1000,0 L1000,1000 L0,1000 L0,0 L1000,0 Z M500,475 C486.192881,475 475,486.192881 475,500 C475,513.807119 486.192881,525 500,525 C513.807119,525 525,513.807119 525,500 C525,486.192881 513.807119,475 500,475 Z' d='M1000,0 L1000,1000 L0,1000 L0,0 L1000,0 Z M500,475 C486.192881,475 475,486.192881 475,500 C475,513.807119 486.192881,525 500,525 C513.807119,525 525,513.807119 525,500 C525,486.192881 513.807119,475 500,475 Z'
fill={theme.backgroundOverlayInvert} fill={colors.backgroundOverlayInvert}
/> />
<Circle <Circle
stroke={theme.primaryOverlay} stroke={colors.primaryOverlay}
stroke-width='2' stroke-width='2'
cx='500' cx='500'
cy='500' cy='500'
r='24' r='24'
/> />
<Circle fill={theme.primaryOverlay} cx='500' cy='500' r='2' /> <Circle
fill={colors.primaryOverlay}
cx='500'
cy='500'
r='2'
/>
</G> </G>
</G> </G>
</Svg> </Svg>
@ -163,7 +168,7 @@ const ComposeEditAttachmentImage: React.FC<Props> = ({ index }) => {
</PanGestureHandler> </PanGestureHandler>
</View> </View>
{screenReaderEnabled ? null : ( {screenReaderEnabled ? null : (
<Text style={[styles.imageFocusText, { color: theme.primaryDefault }]}> <Text style={[styles.imageFocusText, { color: colors.primaryDefault }]}>
{t('content.editAttachment.content.imageFocus')} {t('content.editAttachment.content.imageFocus')}
</Text> </Text>
)} )}

View File

@ -13,7 +13,7 @@ export interface Props {
const ComposeEditAttachmentRoot: React.FC<Props> = ({ index }) => { const ComposeEditAttachmentRoot: React.FC<Props> = ({ index }) => {
const { t } = useTranslation('screenCompose') const { t } = useTranslation('screenCompose')
const { mode, theme } = useTheme() const { colors, mode } = useTheme()
const { composeState, composeDispatch } = useContext(ComposeContext) const { composeState, composeDispatch } = useContext(ComposeContext)
const theAttachment = composeState.attachments.uploads[index].remote! const theAttachment = composeState.attachments.uploads[index].remote!
@ -61,13 +61,15 @@ const ComposeEditAttachmentRoot: React.FC<Props> = ({ index }) => {
<ScrollView ref={scrollViewRef}> <ScrollView ref={scrollViewRef}>
{mediaDisplay} {mediaDisplay}
<View style={styles.altTextContainer}> <View style={styles.altTextContainer}>
<Text style={[styles.altTextInputHeading, { color: theme.primaryDefault }]}> <Text
style={[styles.altTextInputHeading, { color: colors.primaryDefault }]}
>
{t('content.editAttachment.content.altText.heading')} {t('content.editAttachment.content.altText.heading')}
</Text> </Text>
<TextInput <TextInput
style={[ style={[
styles.altTextInput, styles.altTextInput,
{ borderColor: theme.border, color: theme.primaryDefault } { borderColor: colors.border, color: colors.primaryDefault }
]} ]}
onFocus={() => scrollViewRef.current?.scrollToEnd()} onFocus={() => scrollViewRef.current?.scrollToEnd()}
autoCapitalize='none' autoCapitalize='none'
@ -76,12 +78,12 @@ const ComposeEditAttachmentRoot: React.FC<Props> = ({ index }) => {
multiline multiline
onChangeText={onChangeText} onChangeText={onChangeText}
placeholder={t('content.editAttachment.content.altText.placeholder')} placeholder={t('content.editAttachment.content.altText.placeholder')}
placeholderTextColor={theme.secondary} placeholderTextColor={colors.secondary}
scrollEnabled scrollEnabled
value={theAttachment.description} value={theAttachment.description}
keyboardAppearance={mode} keyboardAppearance={mode}
/> />
<Text style={[styles.altTextLength, { color: theme.secondary }]}> <Text style={[styles.altTextLength, { color: colors.secondary }]}>
{theAttachment.description?.length || 0} / 1500 {theAttachment.description?.length || 0} / 1500
</Text> </Text>
</View> </View>

View File

@ -6,7 +6,7 @@ import ComposeContext from './utils/createContext'
const ComposePosting = React.memo( const ComposePosting = React.memo(
() => { () => {
const { composeState } = useContext(ComposeContext) const { composeState } = useContext(ComposeContext)
const { theme } = useTheme() const { colors } = useTheme()
return ( return (
<Modal <Modal
@ -14,7 +14,9 @@ const ComposePosting = React.memo(
animationType='fade' animationType='fade'
visible={composeState.posting} visible={composeState.posting}
children={ children={
<View style={{ flex: 1, backgroundColor: theme.backgroundOverlayInvert }} /> <View
style={{ flex: 1, backgroundColor: colors.backgroundOverlayInvert }}
/>
} }
/> />
) )

View File

@ -61,7 +61,7 @@ export let instanceConfigurationStatusCharsURL = 23
const ComposeRoot = React.memo( const ComposeRoot = React.memo(
() => { () => {
const { reduceMotionEnabled } = useAccessibility() const { reduceMotionEnabled } = useAccessibility()
const { theme } = useTheme() const { colors } = useTheme()
instanceConfigurationStatusCharsURL = useSelector( instanceConfigurationStatusCharsURL = useSelector(
getInstanceConfigurationStatusCharsURL, getInstanceConfigurationStatusCharsURL,
@ -122,7 +122,7 @@ const ComposeRoot = React.memo(
<View key='listEmpty' style={styles.loading}> <View key='listEmpty' style={styles.loading}>
<Circle <Circle
size={StyleConstants.Font.Size.M * 1.25} size={StyleConstants.Font.Size.M * 1.25}
color={theme.secondary} color={colors.secondary}
/> />
</View> </View>
) )

View File

@ -16,19 +16,19 @@ const ComposeActions: React.FC = () => {
const { showActionSheetWithOptions } = useActionSheet() const { showActionSheetWithOptions } = useActionSheet()
const { composeState, composeDispatch } = useContext(ComposeContext) const { composeState, composeDispatch } = useContext(ComposeContext)
const { t } = useTranslation('screenCompose') const { t } = useTranslation('screenCompose')
const { theme } = useTheme() const { colors, mode } = useTheme()
const instanceConfigurationStatusMaxAttachments = useSelector( const instanceConfigurationStatusMaxAttachments = useSelector(
getInstanceConfigurationStatusMaxAttachments, getInstanceConfigurationStatusMaxAttachments,
() => true () => true
) )
const attachmentColor = useMemo(() => { const attachmentColor = useMemo(() => {
if (composeState.poll.active) return theme.disabled if (composeState.poll.active) return colors.disabled
if (composeState.attachments.uploads.length) { if (composeState.attachments.uploads.length) {
return theme.primaryDefault return colors.primaryDefault
} else { } else {
return theme.secondary return colors.secondary
} }
}, [composeState.poll.active, composeState.attachments.uploads]) }, [composeState.poll.active, composeState.attachments.uploads])
const attachmentOnPress = useCallback(async () => { const attachmentOnPress = useCallback(async () => {
@ -49,12 +49,12 @@ const ComposeActions: React.FC = () => {
}, [composeState.poll.active, composeState.attachments.uploads]) }, [composeState.poll.active, composeState.attachments.uploads])
const pollColor = useMemo(() => { const pollColor = useMemo(() => {
if (composeState.attachments.uploads.length) return theme.disabled if (composeState.attachments.uploads.length) return colors.disabled
if (composeState.poll.active) { if (composeState.poll.active) {
return theme.primaryDefault return colors.primaryDefault
} else { } else {
return theme.secondary return colors.secondary
} }
}, [composeState.poll.active, composeState.attachments.uploads]) }, [composeState.poll.active, composeState.attachments.uploads])
const pollOnPress = useCallback(() => { const pollOnPress = useCallback(() => {
@ -97,7 +97,8 @@ const ComposeActions: React.FC = () => {
t('content.root.actions.visibility.options.direct'), t('content.root.actions.visibility.options.direct'),
t('content.root.actions.visibility.options.cancel') t('content.root.actions.visibility.options.cancel')
], ],
cancelButtonIndex: 4 cancelButtonIndex: 4,
userInterfaceStyle: mode
}, },
buttonIndex => { buttonIndex => {
switch (buttonIndex) { switch (buttonIndex) {
@ -150,12 +151,12 @@ const ComposeActions: React.FC = () => {
}, [composeState.spoiler.active, composeState.textInputFocus]) }, [composeState.spoiler.active, composeState.textInputFocus])
const emojiColor = useMemo(() => { const emojiColor = useMemo(() => {
if (!composeState.emoji.emojis) return theme.disabled if (!composeState.emoji.emojis) return colors.disabled
if (composeState.emoji.active) { if (composeState.emoji.active) {
return theme.primaryDefault return colors.primaryDefault
} else { } else {
return theme.secondary return colors.secondary
} }
}, [composeState.emoji.active, composeState.emoji.emojis]) }, [composeState.emoji.active, composeState.emoji.emojis])
const emojiOnPress = useCallback(() => { const emojiOnPress = useCallback(() => {
@ -177,8 +178,8 @@ const ComposeActions: React.FC = () => {
style={[ style={[
styles.additions, styles.additions,
{ {
backgroundColor: theme.backgroundDefault, backgroundColor: colors.backgroundDefault,
borderTopColor: theme.border borderTopColor: colors.border
} }
]} ]}
> >
@ -223,7 +224,7 @@ const ComposeActions: React.FC = () => {
name={visibilityIcon} name={visibilityIcon}
size={24} size={24}
color={ color={
composeState.visibilityLock ? theme.disabled : theme.secondary composeState.visibilityLock ? colors.disabled : colors.secondary
} }
/> />
} }
@ -242,8 +243,8 @@ const ComposeActions: React.FC = () => {
size={24} size={24}
color={ color={
composeState.spoiler.active composeState.spoiler.active
? theme.primaryDefault ? colors.primaryDefault
: theme.secondary : colors.secondary
} }
/> />
} }

View File

@ -39,7 +39,7 @@ const ComposeAttachments: React.FC<Props> = ({ accessibleRefAttachments }) => {
const { showActionSheetWithOptions } = useActionSheet() const { showActionSheetWithOptions } = useActionSheet()
const { composeState, composeDispatch } = useContext(ComposeContext) const { composeState, composeDispatch } = useContext(ComposeContext)
const { t } = useTranslation('screenCompose') const { t } = useTranslation('screenCompose')
const { theme } = useTheme() const { colors, mode } = useTheme()
const navigation = useNavigation<any>() const navigation = useNavigation<any>()
const flatListRef = useRef<FlatList>(null) const flatListRef = useRef<FlatList>(null)
@ -135,8 +135,8 @@ const ComposeAttachments: React.FC<Props> = ({ accessibleRefAttachments }) => {
style={[ style={[
styles.duration, styles.duration,
{ {
color: theme.backgroundDefault, color: colors.backgroundDefault,
backgroundColor: theme.backgroundOverlayInvert backgroundColor: colors.backgroundOverlayInvert
} }
]} ]}
> >
@ -147,12 +147,12 @@ const ComposeAttachments: React.FC<Props> = ({ accessibleRefAttachments }) => {
<View <View
style={[ style={[
styles.uploading, styles.uploading,
{ backgroundColor: theme.backgroundOverlayInvert } { backgroundColor: colors.backgroundOverlayInvert }
]} ]}
> >
<Circle <Circle
size={StyleConstants.Font.Size.L} size={StyleConstants.Font.Size.L}
color={theme.primaryOverlay} color={colors.primaryOverlay}
/> />
</View> </View>
) : ( ) : (
@ -213,7 +213,7 @@ const ComposeAttachments: React.FC<Props> = ({ accessibleRefAttachments }) => {
styles.container, styles.container,
{ {
width: DEFAULT_HEIGHT, width: DEFAULT_HEIGHT,
backgroundColor: theme.backgroundOverlayInvert backgroundColor: colors.backgroundOverlayInvert
} }
]} ]}
onPress={async () => { onPress={async () => {
@ -255,9 +255,9 @@ const ComposeAttachments: React.FC<Props> = ({ accessibleRefAttachments }) => {
<Icon <Icon
name={composeState.attachments.sensitive ? 'CheckCircle' : 'Circle'} name={composeState.attachments.sensitive ? 'CheckCircle' : 'Circle'}
size={StyleConstants.Font.Size.L} size={StyleConstants.Font.Size.L}
color={theme.primaryDefault} color={colors.primaryDefault}
/> />
<Text style={[styles.sensitiveText, { color: theme.primaryDefault }]}> <Text style={[styles.sensitiveText, { color: colors.primaryDefault }]}>
{t('content.root.footer.attachments.sensitive')} {t('content.root.footer.attachments.sensitive')}
</Text> </Text>
</Pressable> </Pressable>

View File

@ -25,7 +25,7 @@ export interface Props {
const ComposeEmojis: React.FC<Props> = ({ accessibleRefEmojis }) => { const ComposeEmojis: React.FC<Props> = ({ accessibleRefEmojis }) => {
const { composeState, composeDispatch } = useContext(ComposeContext) const { composeState, composeDispatch } = useContext(ComposeContext)
const { reduceMotionEnabled } = useAccessibility() const { reduceMotionEnabled } = useAccessibility()
const { theme } = useTheme() const { colors } = useTheme()
const { t } = useTranslation() const { t } = useTranslation()
useEffect(() => { useEffect(() => {
@ -37,7 +37,7 @@ const ComposeEmojis: React.FC<Props> = ({ accessibleRefEmojis }) => {
const listHeader = useCallback( const listHeader = useCallback(
({ section: { title } }) => ( ({ section: { title } }) => (
<Text style={[styles.group, { color: theme.secondary }]}>{title}</Text> <Text style={[styles.group, { color: colors.secondary }]}>{title}</Text>
), ),
[] []
) )

View File

@ -21,7 +21,7 @@ const ComposePoll: React.FC = () => {
composeDispatch composeDispatch
} = useContext(ComposeContext) } = useContext(ComposeContext)
const { t } = useTranslation('screenCompose') const { t } = useTranslation('screenCompose')
const { mode, theme } = useTheme() const { colors, mode } = useTheme()
const instanceConfigurationPoll = useSelector( const instanceConfigurationPoll = useSelector(
getInstanceConfigurationPoll, getInstanceConfigurationPoll,
@ -39,7 +39,7 @@ const ComposePoll: React.FC = () => {
}, []) }, [])
return ( return (
<View style={[styles.base, { borderColor: theme.border }]}> <View style={[styles.base, { borderColor: colors.border }]}>
<View style={styles.options}> <View style={styles.options}>
{[...Array(total)].map((e, i) => { {[...Array(total)].map((e, i) => {
const restOptions = Object.keys(options).filter( const restOptions = Object.keys(options).filter(
@ -57,7 +57,7 @@ const ComposePoll: React.FC = () => {
<Icon <Icon
name={multiple ? 'Square' : 'Circle'} name={multiple ? 'Square' : 'Circle'}
size={StyleConstants.Font.Size.L} size={StyleConstants.Font.Size.L}
color={theme.secondary} color={colors.secondary}
/> />
<TextInput <TextInput
accessibilityLabel={t( accessibilityLabel={t(
@ -69,8 +69,8 @@ const ComposePoll: React.FC = () => {
style={[ style={[
styles.textInput, styles.textInput,
{ {
borderColor: theme.border, borderColor: colors.border,
color: hasConflict ? theme.red : theme.primaryDefault color: hasConflict ? colors.red : colors.primaryDefault
} }
]} ]}
placeholder={ placeholder={
@ -78,7 +78,7 @@ const ComposePoll: React.FC = () => {
? t('content.root.footer.poll.option.placeholder.multiple') ? t('content.root.footer.poll.option.placeholder.multiple')
: t('content.root.footer.poll.option.placeholder.single') : t('content.root.footer.poll.option.placeholder.single')
} }
placeholderTextColor={theme.disabled} placeholderTextColor={colors.disabled}
maxLength={MAX_CHARS_PER_OPTION} maxLength={MAX_CHARS_PER_OPTION}
// @ts-ignore // @ts-ignore
value={options[i]} value={options[i]}
@ -168,7 +168,8 @@ const ComposePoll: React.FC = () => {
t('content.root.footer.poll.multiple.options.multiple'), t('content.root.footer.poll.multiple.options.multiple'),
t('content.root.footer.poll.multiple.options.cancel') t('content.root.footer.poll.multiple.options.cancel')
], ],
cancelButtonIndex: 2 cancelButtonIndex: 2,
userInterfaceStyle: mode
}, },
index => { index => {
if (index && index < 2) { if (index && index < 2) {
@ -211,7 +212,8 @@ const ComposePoll: React.FC = () => {
), ),
t('content.root.footer.poll.expiration.options.cancel') t('content.root.footer.poll.expiration.options.cancel')
], ],
cancelButtonIndex: expirations.length cancelButtonIndex: expirations.length,
userInterfaceStyle: mode
}, },
index => { index => {
if (index && index < expirations.length) { if (index && index < expirations.length) {

View File

@ -8,10 +8,10 @@ const ComposeReply: React.FC = () => {
const { const {
composeState: { replyToStatus } composeState: { replyToStatus }
} = useContext(ComposeContext) } = useContext(ComposeContext)
const { theme } = useTheme() const { colors } = useTheme()
return ( return (
<View style={[styles.base, { borderTopColor: theme.border }]}> <View style={[styles.base, { borderTopColor: colors.border }]}>
<TimelineDefault item={replyToStatus!} disableDetails disableOnPress /> <TimelineDefault item={replyToStatus!} disableDetails disableOnPress />
</View> </View>
) )

View File

@ -12,7 +12,7 @@ import { useSelector } from 'react-redux'
const ComposePostingAs = React.memo( const ComposePostingAs = React.memo(
() => { () => {
const { t } = useTranslation('screenCompose') const { t } = useTranslation('screenCompose')
const { theme } = useTheme() const { colors } = useTheme()
const instanceAccount = useSelector( const instanceAccount = useSelector(
getInstanceAccount, getInstanceAccount,
@ -21,7 +21,7 @@ const ComposePostingAs = React.memo(
const instanceUri = useSelector(getInstanceUri) const instanceUri = useSelector(getInstanceUri)
return ( return (
<Text style={[styles.text, { color: theme.secondary }]}> <Text style={[styles.text, { color: colors.secondary }]}>
{t('content.root.header.postingAs', { {t('content.root.header.postingAs', {
acct: instanceAccount?.acct, acct: instanceAccount?.acct,
domain: instanceUri domain: instanceUri

View File

@ -9,7 +9,7 @@ import ComposeContext from '../../utils/createContext'
const ComposeSpoilerInput: React.FC = () => { const ComposeSpoilerInput: React.FC = () => {
const { composeState, composeDispatch } = useContext(ComposeContext) const { composeState, composeDispatch } = useContext(ComposeContext)
const { t } = useTranslation('screenCompose') const { t } = useTranslation('screenCompose')
const { mode, theme } = useTheme() const { colors, mode } = useTheme()
return ( return (
<TextInput <TextInput
@ -17,8 +17,8 @@ const ComposeSpoilerInput: React.FC = () => {
style={[ style={[
styles.spoilerInput, styles.spoilerInput,
{ {
color: theme.primaryDefault, color: colors.primaryDefault,
borderBottomColor: theme.border borderBottomColor: colors.border
} }
]} ]}
autoCapitalize='none' autoCapitalize='none'
@ -27,7 +27,7 @@ const ComposeSpoilerInput: React.FC = () => {
enablesReturnKeyAutomatically enablesReturnKeyAutomatically
multiline multiline
placeholder={t('content.root.header.spoilerInput.placeholder')} placeholder={t('content.root.header.spoilerInput.placeholder')}
placeholderTextColor={theme.secondary} placeholderTextColor={colors.secondary}
onChangeText={content => onChangeText={content =>
formatText({ formatText({
textInput: 'spoiler', textInput: 'spoiler',

View File

@ -9,7 +9,7 @@ import ComposeContext from '../../utils/createContext'
const ComposeTextInput: React.FC = () => { const ComposeTextInput: React.FC = () => {
const { composeState, composeDispatch } = useContext(ComposeContext) const { composeState, composeDispatch } = useContext(ComposeContext)
const { t } = useTranslation('screenCompose') const { t } = useTranslation('screenCompose')
const { mode, theme } = useTheme() const { colors, mode } = useTheme()
return ( return (
<TextInput <TextInput
@ -17,15 +17,15 @@ const ComposeTextInput: React.FC = () => {
style={[ style={[
styles.textInput, styles.textInput,
{ {
color: theme.primaryDefault, color: colors.primaryDefault,
borderBottomColor: theme.border borderBottomColor: colors.border
} }
]} ]}
autoFocus autoFocus
enablesReturnKeyAutomatically enablesReturnKeyAutomatically
multiline multiline
placeholder={t('content.root.header.textInput.placeholder')} placeholder={t('content.root.header.textInput.placeholder')}
placeholderTextColor={theme.secondary} placeholderTextColor={colors.secondary}
onChangeText={content => onChangeText={content =>
formatText({ formatText({
textInput: 'text', textInput: 'text',

View File

@ -16,9 +16,9 @@ export interface Params {
} }
const TagText = ({ text }: { text: string }) => { const TagText = ({ text }: { text: string }) => {
const { theme } = useTheme() const { colors } = useTheme()
return <Text style={{ color: theme.blue }}>{text}</Text> return <Text style={{ color: colors.blue }}>{text}</Text>
} }
const debouncedSuggestions = debounce( const debouncedSuggestions = debounce(

View File

@ -2,6 +2,7 @@ import haptics from '@components/haptics'
import { displayMessage } from '@components/Message' import { displayMessage } from '@components/Message'
import CameraRoll from '@react-native-community/cameraroll' import CameraRoll from '@react-native-community/cameraroll'
import { RootStackParamList } from '@utils/navigation/navigators' import { RootStackParamList } from '@utils/navigation/navigators'
import { Theme } from '@utils/styles/themes'
import * as FileSystem from 'expo-file-system' import * as FileSystem from 'expo-file-system'
import i18next from 'i18next' import i18next from 'i18next'
import { RefObject } from 'react' import { RefObject } from 'react'
@ -10,17 +11,17 @@ import FlashMessage from 'react-native-flash-message'
type CommonProps = { type CommonProps = {
messageRef: RefObject<FlashMessage> messageRef: RefObject<FlashMessage>
mode: 'light' | 'dark' theme: Theme
image: RootStackParamList['Screen-ImagesViewer']['imageUrls'][0] image: RootStackParamList['Screen-ImagesViewer']['imageUrls'][0]
} }
const saveIos = async ({ messageRef, mode, image }: CommonProps) => { const saveIos = async ({ messageRef, theme, image }: CommonProps) => {
CameraRoll.save(image.url) CameraRoll.save(image.url)
.then(() => { .then(() => {
haptics('Success') haptics('Success')
displayMessage({ displayMessage({
ref: messageRef, ref: messageRef,
mode, theme,
type: 'success', type: 'success',
message: i18next.t('screenImageViewer:content.save.succeed') message: i18next.t('screenImageViewer:content.save.succeed')
}) })
@ -32,7 +33,7 @@ const saveIos = async ({ messageRef, mode, image }: CommonProps) => {
haptics('Success') haptics('Success')
displayMessage({ displayMessage({
ref: messageRef, ref: messageRef,
mode, theme,
type: 'success', type: 'success',
message: i18next.t('screenImageViewer:content.save.succeed') message: i18next.t('screenImageViewer:content.save.succeed')
}) })
@ -41,7 +42,7 @@ const saveIos = async ({ messageRef, mode, image }: CommonProps) => {
haptics('Error') haptics('Error')
displayMessage({ displayMessage({
ref: messageRef, ref: messageRef,
mode, theme,
type: 'error', type: 'error',
message: i18next.t('screenImageViewer:content.save.failed') message: i18next.t('screenImageViewer:content.save.failed')
}) })
@ -50,7 +51,7 @@ const saveIos = async ({ messageRef, mode, image }: CommonProps) => {
haptics('Error') haptics('Error')
displayMessage({ displayMessage({
ref: messageRef, ref: messageRef,
mode, theme,
type: 'error', type: 'error',
message: i18next.t('screenImageViewer:content.save.failed') message: i18next.t('screenImageViewer:content.save.failed')
}) })
@ -58,7 +59,7 @@ const saveIos = async ({ messageRef, mode, image }: CommonProps) => {
}) })
} }
const saveAndroid = async ({ messageRef, mode, image }: CommonProps) => { const saveAndroid = async ({ messageRef, theme, image }: CommonProps) => {
const fileUri: string = `${FileSystem.documentDirectory}${image.id}.jpg` const fileUri: string = `${FileSystem.documentDirectory}${image.id}.jpg`
const downloadedFile: FileSystem.FileSystemDownloadResult = const downloadedFile: FileSystem.FileSystemDownloadResult =
await FileSystem.downloadAsync(image.url, fileUri) await FileSystem.downloadAsync(image.url, fileUri)
@ -67,7 +68,7 @@ const saveAndroid = async ({ messageRef, mode, image }: CommonProps) => {
haptics('Error') haptics('Error')
displayMessage({ displayMessage({
ref: messageRef, ref: messageRef,
mode, theme,
type: 'error', type: 'error',
message: i18next.t('screenImageViewer:content.save.failed') message: i18next.t('screenImageViewer:content.save.failed')
}) })
@ -83,7 +84,7 @@ const saveAndroid = async ({ messageRef, mode, image }: CommonProps) => {
haptics('Error') haptics('Error')
displayMessage({ displayMessage({
ref: messageRef, ref: messageRef,
mode, theme,
type: 'error', type: 'error',
message: i18next.t('screenImageViewer:content.save.failed') message: i18next.t('screenImageViewer:content.save.failed')
}) })
@ -96,7 +97,7 @@ const saveAndroid = async ({ messageRef, mode, image }: CommonProps) => {
haptics('Success') haptics('Success')
displayMessage({ displayMessage({
ref: messageRef, ref: messageRef,
mode, theme,
type: 'success', type: 'success',
message: i18next.t('screenImageViewer:content.save.succeed') message: i18next.t('screenImageViewer:content.save.succeed')
}) })
@ -105,7 +106,7 @@ const saveAndroid = async ({ messageRef, mode, image }: CommonProps) => {
haptics('Error') haptics('Error')
displayMessage({ displayMessage({
ref: messageRef, ref: messageRef,
mode, theme,
type: 'error', type: 'error',
message: i18next.t('screenImageViewer:content.save.failed') message: i18next.t('screenImageViewer:content.save.failed')
}) })

View File

@ -35,7 +35,7 @@ const HeaderComponent = React.memo(
imageUrls: RootStackParamList['Screen-ImagesViewer']['imageUrls'] imageUrls: RootStackParamList['Screen-ImagesViewer']['imageUrls']
}) => { }) => {
const insets = useSafeAreaInsets() const insets = useSafeAreaInsets()
const { mode } = useTheme() const { mode, theme } = useTheme()
const { t } = useTranslation('screenImageViewer') const { t } = useTranslation('screenImageViewer')
const { showActionSheetWithOptions } = useActionSheet() const { showActionSheetWithOptions } = useActionSheet()
@ -48,13 +48,14 @@ const HeaderComponent = React.memo(
t('content.options.share'), t('content.options.share'),
t('content.options.cancel') t('content.options.cancel')
], ],
cancelButtonIndex: 2 cancelButtonIndex: 2,
userInterfaceStyle: mode
}, },
async buttonIndex => { async buttonIndex => {
switch (buttonIndex) { switch (buttonIndex) {
case 0: case 0:
analytics('imageviewer_more_save_press') analytics('imageviewer_more_save_press')
saveImage({ messageRef, mode, image: imageUrls[currentIndex] }) saveImage({ messageRef, theme, image: imageUrls[currentIndex] })
break break
case 1: case 1:
analytics('imageviewer_more_share_press') analytics('imageviewer_more_share_press')
@ -117,7 +118,7 @@ const ScreenImagesViewer = ({
return null return null
} }
const { mode } = useTheme() const { theme } = useTheme()
const initialIndex = imageUrls.findIndex(image => image.id === id) const initialIndex = imageUrls.findIndex(image => image.id === id)
const [currentIndex, setCurrentIndex] = useState(initialIndex) const [currentIndex, setCurrentIndex] = useState(initialIndex)
@ -132,7 +133,7 @@ const ScreenImagesViewer = ({
imageIndex={initialIndex} imageIndex={initialIndex}
onImageIndexChange={index => setCurrentIndex(index)} onImageIndexChange={index => setCurrentIndex(index)}
onRequestClose={() => navigation.goBack()} onRequestClose={() => navigation.goBack()}
onLongPress={image => saveImage({ messageRef, mode, image })} onLongPress={image => saveImage({ messageRef, theme, image })}
HeaderComponent={() => ( HeaderComponent={() => (
<HeaderComponent <HeaderComponent
messageRef={messageRef} messageRef={messageRef}

View File

@ -31,7 +31,7 @@ const Tab = createBottomTabNavigator<ScreenTabsStackParamList>()
const ScreenTabs = React.memo( const ScreenTabs = React.memo(
({ navigation }: RootStackScreenProps<'Screen-Tabs'>) => { ({ navigation }: RootStackScreenProps<'Screen-Tabs'>) => {
const { theme } = useTheme() const { colors } = useTheme()
const instanceActive = useSelector(getInstanceActive) const instanceActive = useSelector(getInstanceActive)
const instanceAccount = useSelector( const instanceAccount = useSelector(
@ -42,8 +42,8 @@ const ScreenTabs = React.memo(
const screenOptions = useCallback( const screenOptions = useCallback(
({ route }): BottomTabNavigationOptions => ({ ({ route }): BottomTabNavigationOptions => ({
headerShown: false, headerShown: false,
tabBarActiveTintColor: theme.primaryDefault, tabBarActiveTintColor: colors.primaryDefault,
tabBarInactiveTintColor: theme.secondary, tabBarInactiveTintColor: colors.secondary,
tabBarShowLabel: false, tabBarShowLabel: false,
...(Platform.OS === 'android' && { tabBarHideOnKeyboard: true }), ...(Platform.OS === 'android' && { tabBarHideOnKeyboard: true }),
tabBarStyle: { display: instanceActive !== -1 ? 'flex' : 'none' }, tabBarStyle: { display: instanceActive !== -1 ? 'flex' : 'none' },
@ -78,7 +78,7 @@ const ScreenTabs = React.memo(
borderRadius: size, borderRadius: size,
overflow: 'hidden', overflow: 'hidden',
borderWidth: focused ? 2 : 0, borderWidth: focused ? 2 : 0,
borderColor: focused ? theme.secondary : color borderColor: focused ? colors.secondary : color
}} }}
/> />
) )

View File

@ -23,16 +23,18 @@ const prepareFields = (
}) })
} }
const TabMeProfileFields: React.FC<TabMeProfileStackScreenProps< const TabMeProfileFields: React.FC<
'Tab-Me-Profile-Fields' TabMeProfileStackScreenProps<'Tab-Me-Profile-Fields'> & {
> & { messageRef: RefObject<FlashMessage> }> = ({ messageRef: RefObject<FlashMessage>
}
> = ({
messageRef, messageRef,
route: { route: {
params: { fields } params: { fields }
}, },
navigation navigation
}) => { }) => {
const { mode, theme } = useTheme() const { colors, theme } = useTheme()
const { t, i18n } = useTranslation('screenTabs') const { t, i18n } = useTranslation('screenTabs')
const { mutateAsync, status } = useProfileMutation() const { mutateAsync, status } = useProfileMutation()
@ -77,7 +79,7 @@ const TabMeProfileFields: React.FC<TabMeProfileStackScreenProps<
content='Save' content='Save'
onPress={async () => { onPress={async () => {
mutateAsync({ mutateAsync({
mode, theme,
messageRef, messageRef,
message: { message: {
text: 'me.profile.root.note.title', text: 'me.profile.root.note.title',
@ -95,14 +97,14 @@ const TabMeProfileFields: React.FC<TabMeProfileStackScreenProps<
/> />
) )
}) })
}, [mode, i18n.language, dirty, status, newFields]) }, [theme, i18n.language, dirty, status, newFields])
return ( return (
<ScrollView style={styles.base} keyboardShouldPersistTaps='always'> <ScrollView style={styles.base} keyboardShouldPersistTaps='always'>
<View style={{ marginBottom: StyleConstants.Spacing.L * 2 }}> <View style={{ marginBottom: StyleConstants.Spacing.L * 2 }}>
{Array.from(Array(4).keys()).map(index => ( {Array.from(Array(4).keys()).map(index => (
<View key={index} style={styles.group}> <View key={index} style={styles.group}>
<Text style={[styles.headline, { color: theme.primaryDefault }]}> <Text style={[styles.headline, { color: colors.primaryDefault }]}>
{t('me.profile.fields.group', { index: index + 1 })} {t('me.profile.fields.group', { index: index + 1 })}
</Text> </Text>
<Input <Input

View File

@ -21,7 +21,7 @@ const TabMeProfileName: React.FC<
}, },
navigation navigation
}) => { }) => {
const { mode } = useTheme() const { theme } = useTheme()
const { t, i18n } = useTranslation('screenTabs') const { t, i18n } = useTranslation('screenTabs')
const { mutateAsync, status } = useProfileMutation() const { mutateAsync, status } = useProfileMutation()
@ -66,7 +66,7 @@ const TabMeProfileName: React.FC<
content='Save' content='Save'
onPress={async () => { onPress={async () => {
mutateAsync({ mutateAsync({
mode, theme,
messageRef, messageRef,
message: { message: {
text: 'me.profile.root.name.title', text: 'me.profile.root.name.title',
@ -82,7 +82,7 @@ const TabMeProfileName: React.FC<
/> />
) )
}) })
}, [mode, i18n.language, dirty, status, displayName]) }, [theme, i18n.language, dirty, status, displayName])
return ( return (
<ScrollView style={styles.base} keyboardShouldPersistTaps='always'> <ScrollView style={styles.base} keyboardShouldPersistTaps='always'>

View File

@ -10,16 +10,18 @@ import { Alert, StyleSheet, View } from 'react-native'
import FlashMessage from 'react-native-flash-message' import FlashMessage from 'react-native-flash-message'
import { ScrollView } from 'react-native-gesture-handler' import { ScrollView } from 'react-native-gesture-handler'
const TabMeProfileNote: React.FC<TabMeProfileStackScreenProps< const TabMeProfileNote: React.FC<
'Tab-Me-Profile-Note' TabMeProfileStackScreenProps<'Tab-Me-Profile-Note'> & {
> & { messageRef: RefObject<FlashMessage> }> = ({ messageRef: RefObject<FlashMessage>
}
> = ({
messageRef, messageRef,
route: { route: {
params: { note } params: { note }
}, },
navigation navigation
}) => { }) => {
const { mode } = useTheme() const { theme } = useTheme()
const { t, i18n } = useTranslation('screenTabs') const { t, i18n } = useTranslation('screenTabs')
const { mutateAsync, status } = useProfileMutation() const { mutateAsync, status } = useProfileMutation()
@ -64,7 +66,7 @@ const TabMeProfileNote: React.FC<TabMeProfileStackScreenProps<
content='Save' content='Save'
onPress={async () => { onPress={async () => {
mutateAsync({ mutateAsync({
mode, theme,
messageRef, messageRef,
message: { message: {
text: 'me.profile.root.note.title', text: 'me.profile.root.note.title',
@ -80,7 +82,7 @@ const TabMeProfileNote: React.FC<TabMeProfileStackScreenProps<
/> />
) )
}) })
}, [mode, i18n.language, dirty, status, newNote]) }, [theme, i18n.language, dirty, status, newNote])
return ( return (
<ScrollView style={styles.base} keyboardShouldPersistTaps='always'> <ScrollView style={styles.base} keyboardShouldPersistTaps='always'>

View File

@ -12,10 +12,12 @@ import { ScrollView } from 'react-native-gesture-handler'
import { useDispatch } from 'react-redux' import { useDispatch } from 'react-redux'
import ProfileAvatarHeader from './Root/AvatarHeader' import ProfileAvatarHeader from './Root/AvatarHeader'
const TabMeProfileRoot: React.FC<TabMeProfileStackScreenProps< const TabMeProfileRoot: React.FC<
'Tab-Me-Profile-Root' TabMeProfileStackScreenProps<'Tab-Me-Profile-Root'> & {
> & { messageRef: RefObject<FlashMessage> }> = ({ messageRef, navigation }) => { messageRef: RefObject<FlashMessage>
const { mode } = useTheme() }
> = ({ messageRef, navigation }) => {
const { mode, theme } = useTheme()
const { t } = useTranslation('screenTabs') const { t } = useTranslation('screenTabs')
const { showActionSheetWithOptions } = useActionSheet() const { showActionSheetWithOptions } = useActionSheet()
@ -34,7 +36,8 @@ const TabMeProfileRoot: React.FC<TabMeProfileStackScreenProps<
t('me.profile.root.visibility.options.private'), t('me.profile.root.visibility.options.private'),
t('me.profile.root.visibility.options.cancel') t('me.profile.root.visibility.options.cancel')
], ],
cancelButtonIndex: 3 cancelButtonIndex: 3,
userInterfaceStyle: mode
}, },
async buttonIndex => { async buttonIndex => {
switch (buttonIndex) { switch (buttonIndex) {
@ -54,7 +57,7 @@ const TabMeProfileRoot: React.FC<TabMeProfileStackScreenProps<
new: indexVisibilityMapping[buttonIndex] new: indexVisibilityMapping[buttonIndex]
}) })
mutateAsync({ mutateAsync({
mode, theme,
messageRef, messageRef,
message: { message: {
text: 'me.profile.root.visibility.title', text: 'me.profile.root.visibility.title',
@ -69,7 +72,7 @@ const TabMeProfileRoot: React.FC<TabMeProfileStackScreenProps<
} }
} }
) )
}, [data?.source.privacy]) }, [theme, data?.source.privacy])
const onPressSensitive = useCallback(() => { const onPressSensitive = useCallback(() => {
analytics('me_profile_sensitive', { analytics('me_profile_sensitive', {
@ -77,7 +80,7 @@ const TabMeProfileRoot: React.FC<TabMeProfileStackScreenProps<
new: data?.source.sensitive === undefined ? true : !data.source.sensitive new: data?.source.sensitive === undefined ? true : !data.source.sensitive
}) })
mutateAsync({ mutateAsync({
mode, theme,
messageRef, messageRef,
message: { message: {
text: 'me.profile.root.sensitive.title', text: 'me.profile.root.sensitive.title',
@ -95,7 +98,7 @@ const TabMeProfileRoot: React.FC<TabMeProfileStackScreenProps<
new: data?.locked === undefined ? true : !data.locked new: data?.locked === undefined ? true : !data.locked
}) })
mutateAsync({ mutateAsync({
mode, theme,
messageRef, messageRef,
message: { message: {
text: 'me.profile.root.lock.title', text: 'me.profile.root.lock.title',
@ -105,7 +108,7 @@ const TabMeProfileRoot: React.FC<TabMeProfileStackScreenProps<
type: 'locked', type: 'locked',
data: data?.locked === undefined ? true : !data.locked data: data?.locked === undefined ? true : !data.locked
}) })
}, [data?.locked]) }, [theme, data?.locked])
const onPressBot = useCallback(() => { const onPressBot = useCallback(() => {
analytics('me_profile_bot', { analytics('me_profile_bot', {
@ -113,7 +116,7 @@ const TabMeProfileRoot: React.FC<TabMeProfileStackScreenProps<
new: data?.bot === undefined ? true : !data.bot new: data?.bot === undefined ? true : !data.bot
}) })
mutateAsync({ mutateAsync({
mode, theme,
messageRef, messageRef,
message: { message: {
text: 'me.profile.root.bot.title', text: 'me.profile.root.bot.title',
@ -123,7 +126,7 @@ const TabMeProfileRoot: React.FC<TabMeProfileStackScreenProps<
type: 'bot', type: 'bot',
data: data?.bot === undefined ? true : !data.bot data: data?.bot === undefined ? true : !data.bot
}) })
}, [data?.bot]) }, [theme, data?.bot])
return ( return (
<ScrollView> <ScrollView>

View File

@ -14,7 +14,7 @@ export interface Props {
} }
const ProfileAvatarHeader: React.FC<Props> = ({ type, messageRef }) => { const ProfileAvatarHeader: React.FC<Props> = ({ type, messageRef }) => {
const { mode } = useTheme() const { theme } = useTheme()
const { t } = useTranslation('screenTabs') const { t } = useTranslation('screenTabs')
const { showActionSheetWithOptions } = useActionSheet() const { showActionSheetWithOptions } = useActionSheet()
@ -35,7 +35,7 @@ const ProfileAvatarHeader: React.FC<Props> = ({ type, messageRef }) => {
resize: { width: 400, height: 400 } resize: { width: 400, height: 400 }
}) })
mutation.mutate({ mutation.mutate({
mode, theme,
messageRef, messageRef,
message: { message: {
text: `me.profile.root.${type}.title`, text: `me.profile.root.${type}.title`,

View File

@ -23,7 +23,7 @@ import { AppState, Linking, ScrollView, Text, View } from 'react-native'
import { useDispatch, useSelector } from 'react-redux' import { useDispatch, useSelector } from 'react-redux'
const TabMePush: React.FC = () => { const TabMePush: React.FC = () => {
const { theme } = useTheme() const { colors } = useTheme()
const { t } = useTranslation('screenTabs') const { t } = useTranslation('screenTabs')
const instanceAccount = useSelector( const instanceAccount = useSelector(
getInstanceAccount, getInstanceAccount,
@ -202,12 +202,12 @@ const TabMePush: React.FC = () => {
<Icon <Icon
name='Frown' name='Frown'
size={StyleConstants.Font.Size.L} size={StyleConstants.Font.Size.L}
color={theme.primaryDefault} color={colors.primaryDefault}
/> />
<Text <Text
style={{ style={{
...StyleConstants.FontStyle.M, ...StyleConstants.FontStyle.M,
color: theme.primaryDefault color: colors.primaryDefault
}} }}
> >
{t('me.push.notAvailable')} {t('me.push.notAvailable')}

View File

@ -13,7 +13,7 @@ import { useDispatch, useSelector } from 'react-redux'
const SettingsAnalytics: React.FC = () => { const SettingsAnalytics: React.FC = () => {
const dispatch = useDispatch() const dispatch = useDispatch()
const { theme } = useTheme() const { colors } = useTheme()
const { t } = useTranslation('screenTabs') const { t } = useTranslation('screenTabs')
const settingsAnalytics = useSelector(getSettingsAnalytics) const settingsAnalytics = useSelector(getSettingsAnalytics)
@ -28,7 +28,7 @@ const SettingsAnalytics: React.FC = () => {
dispatch(changeAnalytics(!settingsAnalytics)) dispatch(changeAnalytics(!settingsAnalytics))
} }
/> />
<Text style={[styles.version, { color: theme.secondary }]}> <Text style={[styles.version, { color: colors.secondary }]}>
{t('me.settings.version', { version: Constants.manifest?.version })} {t('me.settings.version', { version: Constants.manifest?.version })}
</Text> </Text>
</MenuContainer> </MenuContainer>

View File

@ -12,7 +12,9 @@ import {
changeTheme, changeTheme,
getSettingsTheme, getSettingsTheme,
getSettingsBrowser, getSettingsBrowser,
getSettingsFontsize getSettingsFontsize,
getSettingsDarkTheme,
changeDarkTheme
} from '@utils/slices/settingsSlice' } from '@utils/slices/settingsSlice'
import { useTheme } from '@utils/styles/ThemeManager' import { useTheme } from '@utils/styles/ThemeManager'
import * as Notifications from 'expo-notifications' import * as Notifications from 'expo-notifications'
@ -26,12 +28,13 @@ const SettingsApp: React.FC = () => {
const navigation = useNavigation<any>() const navigation = useNavigation<any>()
const dispatch = useDispatch() const dispatch = useDispatch()
const { showActionSheetWithOptions } = useActionSheet() const { showActionSheetWithOptions } = useActionSheet()
const { setTheme } = useTheme() const { mode } = useTheme()
const { t, i18n } = useTranslation('screenTabs') const { t, i18n } = useTranslation('screenTabs')
const instances = useSelector(getInstances, () => true) const instances = useSelector(getInstances, () => true)
const settingsFontsize = useSelector(getSettingsFontsize) const settingsFontsize = useSelector(getSettingsFontsize)
const settingsTheme = useSelector(getSettingsTheme) const settingsTheme = useSelector(getSettingsTheme)
const settingsDarkTheme = useSelector(getSettingsDarkTheme)
const settingsBrowser = useSelector(getSettingsBrowser) const settingsBrowser = useSelector(getSettingsBrowser)
return ( return (
@ -61,7 +64,8 @@ const SettingsApp: React.FC = () => {
{ {
title: t('me.settings.language.heading'), title: t('me.settings.language.heading'),
options, options,
cancelButtonIndex: options.length - 1 cancelButtonIndex: options.length - 1,
userInterfaceStyle: mode
}, },
buttonIndex => { buttonIndex => {
if (buttonIndex === undefined) return if (buttonIndex === undefined) return
@ -171,7 +175,6 @@ const SettingsApp: React.FC = () => {
}) })
haptics('Success') haptics('Success')
dispatch(changeTheme('light')) dispatch(changeTheme('light'))
setTheme('light')
break break
case 2: case 2:
analytics('settings_appearance_press', { analytics('settings_appearance_press', {
@ -180,7 +183,44 @@ const SettingsApp: React.FC = () => {
}) })
haptics('Success') haptics('Success')
dispatch(changeTheme('dark')) dispatch(changeTheme('dark'))
setTheme('dark') break
}
}
)
}
/>
<MenuRow
title={t('me.settings.darkTheme.heading')}
content={t(`me.settings.darkTheme.options.${settingsDarkTheme}`)}
iconBack='ChevronRight'
onPress={() =>
showActionSheetWithOptions(
{
title: t('me.settings.darkTheme.heading'),
options: [
t('me.settings.darkTheme.options.lighter'),
t('me.settings.darkTheme.options.darker'),
t('me.settings.darkTheme.options.cancel')
],
cancelButtonIndex: 2
},
buttonIndex => {
switch (buttonIndex) {
case 0:
analytics('settings_darktheme_press', {
current: settingsDarkTheme,
new: 'lighter'
})
haptics('Success')
dispatch(changeDarkTheme('lighter'))
break
case 1:
analytics('settings_darktheme_press', {
current: settingsDarkTheme,
new: 'darker'
})
haptics('Success')
dispatch(changeDarkTheme('darker'))
break break
} }
} }

View File

@ -11,7 +11,7 @@ import { DevSettings, Text } from 'react-native'
import { useSelector } from 'react-redux' import { useSelector } from 'react-redux'
const SettingsDev: React.FC = () => { const SettingsDev: React.FC = () => {
const { theme } = useTheme() const { colors, mode } = useTheme()
const { showActionSheetWithOptions } = useActionSheet() const { showActionSheetWithOptions } = useActionSheet()
const instanceActive = useSelector(getInstanceActive) const instanceActive = useSelector(getInstanceActive)
const instances = useSelector(getInstances, () => true) const instances = useSelector(getInstances, () => true)
@ -23,7 +23,7 @@ const SettingsDev: React.FC = () => {
style={{ style={{
paddingHorizontal: StyleConstants.Spacing.Global.PagePadding, paddingHorizontal: StyleConstants.Spacing.Global.PagePadding,
...StyleConstants.FontStyle.S, ...StyleConstants.FontStyle.S,
color: theme.primaryDefault color: colors.primaryDefault
}} }}
> >
{instances[instanceActive]?.token} {instances[instanceActive]?.token}
@ -45,7 +45,8 @@ const SettingsDev: React.FC = () => {
return instance.url + ': ' + instance.account.id return instance.url + ': ' + instance.account.id
}) })
.concat(['Cancel']), .concat(['Cancel']),
cancelButtonIndex: instances.length cancelButtonIndex: instances.length,
userInterfaceStyle: mode
}, },
() => {} () => {}
) )

View File

@ -16,7 +16,7 @@ import { isDevelopment, isRelease } from '@utils/checkEnvironment'
const SettingsTooot: React.FC = () => { const SettingsTooot: React.FC = () => {
const instanceActive = useSelector(getInstanceActive) const instanceActive = useSelector(getInstanceActive)
const navigation = useNavigation<any>() const navigation = useNavigation<any>()
const { theme } = useTheme() const { colors } = useTheme()
const { t } = useTranslation('screenTabs') const { t } = useTranslation('screenTabs')
return ( return (
@ -27,7 +27,7 @@ const SettingsTooot: React.FC = () => {
<Icon <Icon
name='MessageSquare' name='MessageSquare'
size={StyleConstants.Font.Size.M} size={StyleConstants.Font.Size.M}
color={theme.secondary} color={colors.secondary}
/> />
} }
iconBack='ChevronRight' iconBack='ChevronRight'
@ -42,7 +42,7 @@ const SettingsTooot: React.FC = () => {
<Icon <Icon
name='Heart' name='Heart'
size={StyleConstants.Font.Size.M} size={StyleConstants.Font.Size.M}
color={theme.red} color={colors.red}
/> />
} }
iconBack='ChevronRight' iconBack='ChevronRight'
@ -76,7 +76,7 @@ const SettingsTooot: React.FC = () => {
<Icon <Icon
name='Mail' name='Mail'
size={StyleConstants.Font.Size.M} size={StyleConstants.Font.Size.M}
color={theme.secondary} color={colors.secondary}
/> />
} }
iconBack='ChevronRight' iconBack='ChevronRight'

View File

@ -35,7 +35,7 @@ export const mapFontsizeToName = (size: SettingsState['fontsize']) => {
const TabMeSettingsFontsize: React.FC< const TabMeSettingsFontsize: React.FC<
TabMeStackScreenProps<'Tab-Me-Settings-Fontsize'> TabMeStackScreenProps<'Tab-Me-Settings-Fontsize'>
> = () => { > = () => {
const { mode, theme } = useTheme() const { colors, theme } = useTheme()
const { t } = useTranslation('screenTabs') const { t } = useTranslation('screenTabs')
const initialSize = useSelector(getSettingsFontsize) const initialSize = useSelector(getSettingsFontsize)
const dispatch = useDispatch() const dispatch = useDispatch()
@ -90,9 +90,11 @@ const TabMeSettingsFontsize: React.FC<
? StyleConstants.Font.Weight.Bold ? StyleConstants.Font.Weight.Bold
: undefined, : undefined,
color: color:
initialSize === size ? theme.primaryDefault : theme.secondary, initialSize === size
? colors.primaryDefault
: colors.secondary,
borderWidth: StyleSheet.hairlineWidth, borderWidth: StyleSheet.hairlineWidth,
borderColor: theme.border borderColor: colors.border
} }
]} ]}
> >
@ -101,11 +103,11 @@ const TabMeSettingsFontsize: React.FC<
))} ))}
</> </>
) )
}, [mode, initialSize]) }, [theme, initialSize])
return ( return (
<ScrollView scrollEnabled={false}> <ScrollView scrollEnabled={false}>
<Text style={[styles.header, { color: theme.primaryDefault }]}> <Text style={[styles.header, { color: colors.primaryDefault }]}>
{t('me.fontSize.showcase')} {t('me.fontSize.showcase')}
</Text> </Text>
<View> <View>
@ -124,7 +126,7 @@ const TabMeSettingsFontsize: React.FC<
extraMarginRight={-StyleConstants.Spacing.Global.PagePadding} extraMarginRight={-StyleConstants.Spacing.Global.PagePadding}
/> />
</View> </View>
<Text style={[styles.header, { color: theme.primaryDefault }]}> <Text style={[styles.header, { color: colors.primaryDefault }]}>
{t('me.fontSize.availableSizes')} {t('me.fontSize.availableSizes')}
</Text> </Text>
<View style={styles.sizesDemo}>{sizesDemo}</View> <View style={styles.sizesDemo}>{sizesDemo}</View>

View File

@ -51,7 +51,7 @@ const AccountButton: React.FC<Props> = ({ instance, selected = false }) => {
const TabMeSwitch: React.FC = () => { const TabMeSwitch: React.FC = () => {
const { t } = useTranslation('screenTabs') const { t } = useTranslation('screenTabs')
const { theme } = useTheme() const { colors } = useTheme()
const instances = useSelector(getInstances, () => true) const instances = useSelector(getInstances, () => true)
const instanceActive = useSelector(getInstanceActive, () => true) const instanceActive = useSelector(getInstanceActive, () => true)
@ -68,9 +68,9 @@ const TabMeSwitch: React.FC = () => {
keyboardShouldPersistTaps='always' keyboardShouldPersistTaps='always'
> >
<View <View
style={[styles.firstSection, { borderBottomColor: theme.border }]} style={[styles.firstSection, { borderBottomColor: colors.border }]}
> >
<Text style={[styles.header, { color: theme.primaryDefault }]}> <Text style={[styles.header, { color: colors.primaryDefault }]}>
{t('me.switch.existing')} {t('me.switch.existing')}
</Text> </Text>
<View style={styles.accountButtons}> <View style={styles.accountButtons}>
@ -101,7 +101,7 @@ const TabMeSwitch: React.FC = () => {
</View> </View>
<View style={styles.secondSection}> <View style={styles.secondSection}>
<Text style={[styles.header, { color: theme.primaryDefault }]}> <Text style={[styles.header, { color: colors.primaryDefault }]}>
{t('me.switch.new')} {t('me.switch.new')}
</Text> </Text>
<ComponentInstance <ComponentInstance

View File

@ -18,16 +18,16 @@ import AccountHeader from './Account/Header'
import AccountInformation from './Account/Information' import AccountInformation from './Account/Information'
import AccountNav from './Account/Nav' import AccountNav from './Account/Nav'
const TabSharedAccount: React.FC<TabSharedStackScreenProps< const TabSharedAccount: React.FC<
'Tab-Shared-Account' TabSharedStackScreenProps<'Tab-Shared-Account'>
>> = ({ > = ({
route: { route: {
params: { account } params: { account }
}, },
navigation navigation
}) => { }) => {
const { t, i18n } = useTranslation('screenTabs') const { t, i18n } = useTranslation('screenTabs')
const { mode, theme } = useTheme() const { colors, mode } = useTheme()
const { data } = useAccountQuery({ id: account.id }) const { data } = useAccountQuery({ id: account.id })
@ -83,7 +83,7 @@ const TabSharedAccount: React.FC<TabSharedStackScreenProps<
const ListHeaderComponent = useMemo(() => { const ListHeaderComponent = useMemo(() => {
return ( return (
<> <>
<View style={[styles.header, { borderBottomColor: theme.border }]}> <View style={[styles.header, { borderBottomColor: colors.border }]}>
<AccountHeader account={data} /> <AccountHeader account={data} />
<AccountInformation account={data} /> <AccountInformation account={data} />
{fetchedTimeline.current ? ( {fetchedTimeline.current ? (

View File

@ -24,10 +24,9 @@ export interface Props {
const AccountAttachments = React.memo( const AccountAttachments = React.memo(
({ account }: Props) => { ({ account }: Props) => {
const navigation = useNavigation< const navigation =
StackNavigationProp<TabLocalStackParamList> useNavigation<StackNavigationProp<TabLocalStackParamList>>()
>() const { colors } = useTheme()
const { theme } = useTheme()
const DISPLAY_AMOUNT = 6 const DISPLAY_AMOUNT = 6
@ -71,7 +70,7 @@ const AccountAttachments = React.memo(
<View <View
style={{ style={{
marginHorizontal: StyleConstants.Spacing.Global.PagePadding, marginHorizontal: StyleConstants.Spacing.Global.PagePadding,
backgroundColor: theme.backgroundOverlayInvert, backgroundColor: colors.backgroundOverlayInvert,
width: width, width: width,
height: width, height: width,
justifyContent: 'center', justifyContent: 'center',
@ -80,7 +79,7 @@ const AccountAttachments = React.memo(
children={ children={
<Icon <Icon
name='MoreHorizontal' name='MoreHorizontal'
color={theme.primaryOverlay} color={colors.primaryOverlay}
size={StyleConstants.Font.Size.L * 1.5} size={StyleConstants.Font.Size.L * 1.5}
/> />
} }
@ -117,7 +116,7 @@ const AccountAttachments = React.memo(
), ),
paddingVertical: StyleConstants.Spacing.Global.PagePadding, paddingVertical: StyleConstants.Spacing.Global.PagePadding,
borderTopWidth: 1, borderTopWidth: 1,
borderTopColor: theme.border borderTopColor: colors.border
} }
} else { } else {
return {} return {}

View File

@ -13,7 +13,7 @@ export interface Props {
const AccountHeader = React.memo( const AccountHeader = React.memo(
({ account, edit }: Props) => { ({ account, edit }: Props) => {
const { reduceMotionEnabled } = useAccessibility() const { reduceMotionEnabled } = useAccessibility()
const { theme } = useTheme() const { colors } = useTheme()
const topInset = useSafeAreaInsets().top const topInset = useSafeAreaInsets().top
return ( return (
@ -24,7 +24,7 @@ const AccountHeader = React.memo(
}} }}
style={{ style={{
height: Dimensions.get('screen').width / 3 + topInset, height: Dimensions.get('screen').width / 3 + topInset,
backgroundColor: theme.disabled backgroundColor: colors.disabled
}} }}
/> />
{edit ? ( {edit ? (

View File

@ -19,16 +19,16 @@ export interface Props {
const AccountInformation = React.memo( const AccountInformation = React.memo(
({ account }: Props) => { ({ account }: Props) => {
const { mode, theme } = useTheme() const { colors, theme } = useTheme()
const { name } = useRoute() const { name } = useRoute()
const myInfo = name !== 'Tab-Shared-Account' const myInfo = name !== 'Tab-Shared-Account'
const animation = useCallback( const animation = useCallback(
props => ( props => (
<Fade {...props} style={{ backgroundColor: theme.shimmerHighlight }} /> <Fade {...props} style={{ backgroundColor: colors.shimmerHighlight }} />
), ),
[mode] [theme]
) )
return ( return (

View File

@ -15,8 +15,11 @@ export interface Props {
localInstance: boolean localInstance: boolean
} }
const AccountInformationAccount: React.FC<Props> = ({ account, localInstance }) => { const AccountInformationAccount: React.FC<Props> = ({
const { theme } = useTheme() account,
localInstance
}) => {
const { colors } = useTheme()
const instanceAccount = useSelector( const instanceAccount = useSelector(
getInstanceAccount, getInstanceAccount,
(prev, next) => prev?.acct === next?.acct (prev, next) => prev?.acct === next?.acct
@ -38,7 +41,7 @@ const AccountInformationAccount: React.FC<Props> = ({ account, localInstance })
<Text <Text
style={[ style={[
styles.moved, styles.moved,
{ color: theme.secondary, ...StyleConstants.FontStyle.M } { color: colors.secondary, ...StyleConstants.FontStyle.M }
]} ]}
selectable selectable
> >
@ -57,7 +60,7 @@ const AccountInformationAccount: React.FC<Props> = ({ account, localInstance })
style={[ style={[
movedStyle.base, movedStyle.base,
{ {
color: theme.secondary, color: colors.secondary,
...StyleConstants.FontStyle.M ...StyleConstants.FontStyle.M
} }
]} ]}
@ -71,7 +74,7 @@ const AccountInformationAccount: React.FC<Props> = ({ account, localInstance })
<Icon <Icon
name='Lock' name='Lock'
style={styles.type} style={styles.type}
color={theme.secondary} color={colors.secondary}
size={StyleConstants.Font.Size.M} size={StyleConstants.Font.Size.M}
/> />
) : null} ) : null}
@ -79,7 +82,7 @@ const AccountInformationAccount: React.FC<Props> = ({ account, localInstance })
<Icon <Icon
name='HardDrive' name='HardDrive'
style={styles.type} style={styles.type}
color={theme.secondary} color={colors.secondary}
size={StyleConstants.Font.Size.M} size={StyleConstants.Font.Size.M}
/> />
) : null} ) : null}
@ -90,7 +93,7 @@ const AccountInformationAccount: React.FC<Props> = ({ account, localInstance })
<PlaceholderLine <PlaceholderLine
width={StyleConstants.Font.Size.M * 3} width={StyleConstants.Font.Size.M * 3}
height={StyleConstants.Font.LineHeight.M} height={StyleConstants.Font.LineHeight.M}
color={theme.shimmerDefault} color={colors.shimmerDefault}
noMargin noMargin
style={styles.base} style={styles.base}
/> />

View File

@ -3,7 +3,6 @@ import Button from '@components/Button'
import GracefullyImage from '@components/GracefullyImage' import GracefullyImage from '@components/GracefullyImage'
import { useNavigation } from '@react-navigation/native' import { useNavigation } from '@react-navigation/native'
import { StackNavigationProp } from '@react-navigation/stack' import { StackNavigationProp } from '@react-navigation/stack'
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
import { TabLocalStackParamList } from '@utils/navigation/navigators' import { TabLocalStackParamList } from '@utils/navigation/navigators'
import { StyleConstants } from '@utils/styles/constants' import { StyleConstants } from '@utils/styles/constants'
import React from 'react' import React from 'react'
@ -20,11 +19,8 @@ const AccountInformationAvatar: React.FC<Props> = ({
myInfo, myInfo,
edit edit
}) => { }) => {
const navigation = useNavigation< const navigation =
StackNavigationProp<TabLocalStackParamList> useNavigation<StackNavigationProp<TabLocalStackParamList>>()
>()
const { reduceMotionEnabled } = useAccessibility()
return ( return (
<Pressable <Pressable
disabled={!myInfo} disabled={!myInfo}
@ -37,11 +33,7 @@ const AccountInformationAvatar: React.FC<Props> = ({
<GracefullyImage <GracefullyImage
key={account?.avatar} key={account?.avatar}
style={styles.image} style={styles.image}
uri={{ uri={{ original: account?.avatar, static: account?.avatar_static }}
original: reduceMotionEnabled
? account?.avatar_static
: account?.avatar
}}
/> />
{edit ? ( {edit ? (
<View <View

View File

@ -18,7 +18,7 @@ const AccountInformationCreated = React.memo(
} }
const { i18n } = useTranslation() const { i18n } = useTranslation()
const { theme } = useTheme() const { colors } = useTheme()
const { t } = useTranslation('screenTabs') const { t } = useTranslation('screenTabs')
if (account) { if (account) {
@ -29,12 +29,12 @@ const AccountInformationCreated = React.memo(
<Icon <Icon
name='Calendar' name='Calendar'
size={StyleConstants.Font.Size.S} size={StyleConstants.Font.Size.S}
color={theme.secondary} color={colors.secondary}
style={styles.icon} style={styles.icon}
/> />
<Text <Text
style={{ style={{
color: theme.secondary, color: colors.secondary,
...StyleConstants.FontStyle.S ...StyleConstants.FontStyle.S
}} }}
> >
@ -56,7 +56,7 @@ const AccountInformationCreated = React.memo(
<PlaceholderLine <PlaceholderLine
width={StyleConstants.Font.Size.S * 4} width={StyleConstants.Font.Size.S * 4}
height={StyleConstants.Font.LineHeight.S} height={StyleConstants.Font.LineHeight.S}
color={theme.shimmerDefault} color={colors.shimmerDefault}
noMargin noMargin
style={styles.base} style={styles.base}
/> />

View File

@ -16,17 +16,17 @@ const AccountInformationFields = React.memo(
return null return null
} }
const { theme } = useTheme() const { colors } = useTheme()
return ( return (
<View style={[styles.fields, { borderTopColor: theme.border }]}> <View style={[styles.fields, { borderTopColor: colors.border }]}>
{account.fields.map((field, index) => ( {account.fields.map((field, index) => (
<View <View
key={index} key={index}
style={[styles.field, { borderBottomColor: theme.border }]} style={[styles.field, { borderBottomColor: colors.border }]}
> >
<View <View
style={[styles.fieldLeft, { borderRightColor: theme.border }]} style={[styles.fieldLeft, { borderRightColor: colors.border }]}
> >
<ParseHTML <ParseHTML
content={field.name} content={field.name}
@ -40,7 +40,7 @@ const AccountInformationFields = React.memo(
<Icon <Icon
name='CheckCircle' name='CheckCircle'
size={StyleConstants.Font.Size.M} size={StyleConstants.Font.Size.M}
color={theme.primaryDefault} color={colors.primaryDefault}
style={styles.fieldCheck} style={styles.fieldCheck}
/> />
) : null} ) : null}

View File

@ -12,7 +12,7 @@ export interface Props {
} }
const AccountInformationName: React.FC<Props> = ({ account, edit }) => { const AccountInformationName: React.FC<Props> = ({ account, edit }) => {
const { theme } = useTheme() const { colors } = useTheme()
const movedContent = useMemo(() => { const movedContent = useMemo(() => {
if (account?.moved) { if (account?.moved) {
@ -57,7 +57,7 @@ const AccountInformationName: React.FC<Props> = ({ account, edit }) => {
<PlaceholderLine <PlaceholderLine
width={StyleConstants.Font.Size.L * 2} width={StyleConstants.Font.Size.L * 2}
height={StyleConstants.Font.LineHeight.L} height={StyleConstants.Font.LineHeight.L}
color={theme.shimmerDefault} color={colors.shimmerDefault}
noMargin noMargin
style={{ borderRadius: 0 }} style={{ borderRadius: 0 }}
/> />

View File

@ -15,17 +15,16 @@ export interface Props {
} }
const AccountInformationStats: React.FC<Props> = ({ account, myInfo }) => { const AccountInformationStats: React.FC<Props> = ({ account, myInfo }) => {
const navigation = useNavigation< const navigation =
StackNavigationProp<TabLocalStackParamList> useNavigation<StackNavigationProp<TabLocalStackParamList>>()
>() const { colors } = useTheme()
const { theme } = useTheme()
const { t } = useTranslation('screenTabs') const { t } = useTranslation('screenTabs')
return ( return (
<View style={[styles.stats, { flexDirection: 'row' }]}> <View style={[styles.stats, { flexDirection: 'row' }]}>
{account ? ( {account ? (
<Text <Text
style={[styles.stat, { color: theme.primaryDefault }]} style={[styles.stat, { color: colors.primaryDefault }]}
children={t('shared.account.summary.statuses_count', { children={t('shared.account.summary.statuses_count', {
count: account.statuses_count || 0 count: account.statuses_count || 0
})} })}
@ -40,7 +39,7 @@ const AccountInformationStats: React.FC<Props> = ({ account, myInfo }) => {
<PlaceholderLine <PlaceholderLine
width={StyleConstants.Font.Size.S * 1.25} width={StyleConstants.Font.Size.S * 1.25}
height={StyleConstants.Font.LineHeight.S} height={StyleConstants.Font.LineHeight.S}
color={theme.shimmerDefault} color={colors.shimmerDefault}
noMargin noMargin
style={{ borderRadius: 0 }} style={{ borderRadius: 0 }}
/> />
@ -49,7 +48,7 @@ const AccountInformationStats: React.FC<Props> = ({ account, myInfo }) => {
<Text <Text
style={[ style={[
styles.stat, styles.stat,
{ color: theme.primaryDefault, textAlign: 'right' } { color: colors.primaryDefault, textAlign: 'right' }
]} ]}
children={t('shared.account.summary.following_count', { children={t('shared.account.summary.following_count', {
count: account.following_count count: account.following_count
@ -70,7 +69,7 @@ const AccountInformationStats: React.FC<Props> = ({ account, myInfo }) => {
<PlaceholderLine <PlaceholderLine
width={StyleConstants.Font.Size.S * 1.25} width={StyleConstants.Font.Size.S * 1.25}
height={StyleConstants.Font.LineHeight.S} height={StyleConstants.Font.LineHeight.S}
color={theme.shimmerDefault} color={colors.shimmerDefault}
noMargin noMargin
style={{ borderRadius: 0 }} style={{ borderRadius: 0 }}
/> />
@ -79,7 +78,7 @@ const AccountInformationStats: React.FC<Props> = ({ account, myInfo }) => {
<Text <Text
style={[ style={[
styles.stat, styles.stat,
{ color: theme.primaryDefault, textAlign: 'center' } { color: colors.primaryDefault, textAlign: 'center' }
]} ]}
children={t('shared.account.summary.followers_count', { children={t('shared.account.summary.followers_count', {
count: account.followers_count count: account.followers_count
@ -100,7 +99,7 @@ const AccountInformationStats: React.FC<Props> = ({ account, myInfo }) => {
<PlaceholderLine <PlaceholderLine
width={StyleConstants.Font.Size.S * 1.25} width={StyleConstants.Font.Size.S * 1.25}
height={StyleConstants.Font.LineHeight.S} height={StyleConstants.Font.LineHeight.S}
color={theme.shimmerDefault} color={colors.shimmerDefault}
noMargin noMargin
style={{ borderRadius: 0 }} style={{ borderRadius: 0 }}
/> />

View File

@ -17,7 +17,7 @@ export interface Props {
const AccountNav = React.memo( const AccountNav = React.memo(
({ scrollY, account }: Props) => { ({ scrollY, account }: Props) => {
const { theme } = useTheme() const { colors } = useTheme()
const headerHeight = useSafeAreaInsets().top + 44 const headerHeight = useSafeAreaInsets().top + 44
const nameY = const nameY =
@ -48,7 +48,7 @@ const AccountNav = React.memo(
style={[ style={[
styles.base, styles.base,
styleOpacity, styleOpacity,
{ backgroundColor: theme.backgroundDefault, height: headerHeight } { backgroundColor: colors.backgroundDefault, height: headerHeight }
]} ]}
> >
<View <View

Some files were not shown because too many files have changed in this diff Show More