Implemented new dark theme

This commit is contained in:
Zhiyuan Zheng 2022-02-12 14:51:01 +01:00
parent 50141b2963
commit 6f0c318d06
108 changed files with 863 additions and 571 deletions

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 })
@ -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

@ -51,7 +51,7 @@ const GracefullyImage = React.memo(
imageStyle, imageStyle,
setImageDimensions setImageDimensions
}: Props) => { }: Props) => {
const { theme } = useTheme() const { colors } = useTheme()
const [originalFailed, setOriginalFailed] = useState(false) const [originalFailed, setOriginalFailed] = useState(false)
const [imageLoaded, setImageLoaded] = useState(false) const [imageLoaded, setImageLoaded] = useState(false)
@ -85,7 +85,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 +118,7 @@ const GracefullyImage = React.memo(
<View <View
style={[ style={[
styles.placeholder, styles.placeholder,
{ backgroundColor: theme.shimmerDefault } { backgroundColor: colors.shimmerDefault }
]} ]}
/> />
) )
@ -135,7 +135,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

@ -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

@ -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

@ -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

@ -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

@ -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

View File

@ -20,7 +20,7 @@ const TabSharedRoot = ({
}: { }: {
Stack: ReturnType<typeof createNativeStackNavigator> Stack: ReturnType<typeof createNativeStackNavigator>
}) => { }) => {
const { mode, theme } = useTheme() const { colors, mode } = useTheme()
const { t } = useTranslation('screenTabs') const { t } = useTranslation('screenTabs')
return ( return (
@ -72,7 +72,7 @@ const TabSharedRoot = ({
<Text <Text
style={{ style={{
...StyleConstants.FontStyle.M, ...StyleConstants.FontStyle.M,
color: theme.primaryDefault, color: colors.primaryDefault,
fontWeight: StyleConstants.Font.Weight.Bold fontWeight: StyleConstants.Font.Weight.Bold
}} }}
/> />
@ -124,7 +124,7 @@ const TabSharedRoot = ({
style={[ style={[
styles.textInput, styles.textInput,
{ {
color: theme.primaryDefault color: colors.primaryDefault
} }
]} ]}
defaultValue={t('shared.search.header.prefix')} defaultValue={t('shared.search.header.prefix')}
@ -136,7 +136,7 @@ const TabSharedRoot = ({
styles.textInput, styles.textInput,
{ {
flex: 1, flex: 1,
color: theme.primaryDefault, color: colors.primaryDefault,
paddingLeft: StyleConstants.Spacing.XS paddingLeft: StyleConstants.Spacing.XS
} }
]} ]}
@ -150,7 +150,7 @@ const TabSharedRoot = ({
navigation.setParams({ text }) navigation.setParams({ text })
} }
placeholder={t('shared.search.header.placeholder')} placeholder={t('shared.search.header.placeholder')}
placeholderTextColor={theme.secondary} placeholderTextColor={colors.secondary}
returnKeyType='go' returnKeyType='go'
/> />
</View> </View>

View File

@ -26,7 +26,7 @@ const TabSharedSearch: React.FC<
} }
}) => { }) => {
const { t } = useTranslation('screenTabs') const { t } = useTranslation('screenTabs')
const { theme } = useTheme() const { colors } = useTheme()
const mapKeyToTranslations = { const mapKeyToTranslations = {
accounts: t('shared.search.sections.accounts'), accounts: t('shared.search.sections.accounts'),
@ -72,7 +72,7 @@ const TabSharedSearch: React.FC<
<View style={styles.loading}> <View 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>
) : ( ) : (
@ -81,7 +81,7 @@ const TabSharedSearch: React.FC<
style={[ style={[
styles.emptyDefault, styles.emptyDefault,
styles.emptyFontSize, styles.emptyFontSize,
{ color: theme.primaryDefault } { color: colors.primaryDefault }
]} ]}
> >
<Trans <Trans
@ -90,35 +90,37 @@ const TabSharedSearch: React.FC<
/> />
</Text> </Text>
<Text <Text
style={[styles.emptyAdvanced, { color: theme.primaryDefault }]} style={[styles.emptyAdvanced, { color: colors.primaryDefault }]}
> >
{t('shared.search.empty.advanced.header')} {t('shared.search.empty.advanced.header')}
</Text> </Text>
<Text <Text
style={[styles.emptyAdvanced, { color: theme.primaryDefault }]} style={[styles.emptyAdvanced, { color: colors.primaryDefault }]}
> >
<Text style={{ color: theme.secondary }}>@username@domain</Text> <Text style={{ color: colors.secondary }}>
@username@domain
</Text>
{' '} {' '}
{t('shared.search.empty.advanced.example.account')} {t('shared.search.empty.advanced.example.account')}
</Text> </Text>
<Text <Text
style={[styles.emptyAdvanced, { color: theme.primaryDefault }]} style={[styles.emptyAdvanced, { color: colors.primaryDefault }]}
> >
<Text style={{ color: theme.secondary }}>#example</Text> <Text style={{ color: colors.secondary }}>#example</Text>
{' '} {' '}
{t('shared.search.empty.advanced.example.hashtag')} {t('shared.search.empty.advanced.example.hashtag')}
</Text> </Text>
<Text <Text
style={[styles.emptyAdvanced, { color: theme.primaryDefault }]} style={[styles.emptyAdvanced, { color: colors.primaryDefault }]}
> >
<Text style={{ color: theme.secondary }}>URL</Text> <Text style={{ color: colors.secondary }}>URL</Text>
{' '} {' '}
{t('shared.search.empty.advanced.example.statusLink')} {t('shared.search.empty.advanced.example.statusLink')}
</Text> </Text>
<Text <Text
style={[styles.emptyAdvanced, { color: theme.primaryDefault }]} style={[styles.emptyAdvanced, { color: colors.primaryDefault }]}
> >
<Text style={{ color: theme.secondary }}>URL</Text> <Text style={{ color: colors.secondary }}>URL</Text>
{' '} {' '}
{t('shared.search.empty.advanced.example.accountLink')} {t('shared.search.empty.advanced.example.accountLink')}
</Text> </Text>
@ -133,11 +135,11 @@ const TabSharedSearch: React.FC<
<View <View
style={[ style={[
styles.sectionHeader, styles.sectionHeader,
{ backgroundColor: theme.backgroundDefault } { backgroundColor: colors.backgroundDefault }
]} ]}
> >
<Text <Text
style={[styles.sectionHeaderText, { color: theme.primaryDefault }]} style={[styles.sectionHeaderText, { color: colors.primaryDefault }]}
> >
{translation} {translation}
</Text> </Text>
@ -151,10 +153,10 @@ const TabSharedSearch: React.FC<
<View <View
style={[ style={[
styles.sectionFooter, styles.sectionFooter,
{ backgroundColor: theme.backgroundDefault } { backgroundColor: colors.backgroundDefault }
]} ]}
> >
<Text style={[styles.sectionFooterText, { color: theme.secondary }]}> <Text style={[styles.sectionFooterText, { color: colors.secondary }]}>
<Trans <Trans
i18nKey='screenTabs:shared.search.notFound' i18nKey='screenTabs:shared.search.notFound'
values={{ searchTerm: text, type: translation }} values={{ searchTerm: text, type: translation }}

View File

@ -3,6 +3,7 @@ import AsyncStorage from '@react-native-async-storage/async-storage'
import { AnyAction, configureStore, Reducer } from '@reduxjs/toolkit' import { AnyAction, configureStore, Reducer } from '@reduxjs/toolkit'
import contextsMigration from '@utils/migrations/contexts/migration' import contextsMigration from '@utils/migrations/contexts/migration'
import instancesMigration from '@utils/migrations/instances/migration' import instancesMigration from '@utils/migrations/instances/migration'
import settingsMigration from '@utils/migrations/settings/migration'
import contextsSlice, { ContextsState } from '@utils/slices/contextsSlice' import contextsSlice, { ContextsState } from '@utils/slices/contextsSlice'
import instancesSlice, { InstancesState } from '@utils/slices/instancesSlice' import instancesSlice, { InstancesState } from '@utils/slices/instancesSlice'
import settingsSlice, { SettingsState } from '@utils/slices/settingsSlice' import settingsSlice, { SettingsState } from '@utils/slices/settingsSlice'
@ -17,7 +18,7 @@ const contextsPersistConfig = {
key: 'contexts', key: 'contexts',
prefix, prefix,
storage: AsyncStorage, storage: AsyncStorage,
version: 1, version: 2,
// @ts-ignore // @ts-ignore
migrate: createMigrate(contextsMigration) migrate: createMigrate(contextsMigration)
} }
@ -34,7 +35,10 @@ const instancesPersistConfig = {
const settingsPersistConfig = { const settingsPersistConfig = {
key: 'settings', key: 'settings',
prefix, prefix,
storage: AsyncStorage storage: AsyncStorage,
version: 1,
// @ts-ignore
migrate: createMigrate(settingsMigration)
} }
const store = configureStore({ const store = configureStore({

View File

@ -1,21 +1,20 @@
import { ContextsV0 } from './v0' import { ContextsV0 } from './v0'
import { ContextsV1 } from './v1' import { ContextsV1 } from './v1'
import { ContextsV2 } from './v2'
const contextsMigration = { const contextsMigration = {
1: (state: ContextsV0) => { 1: (state: ContextsV0): ContextsV1 => {
return (state = { return {
...state, ...state,
// @ts-ignore
mePage: { mePage: {
lists: { shown: false }, lists: { shown: false },
announcements: { shown: false, unread: 0 } announcements: { shown: false, unread: 0 }
} }
}) }
}, },
2: (state: ContextsV1) => { 2: (state: ContextsV1): ContextsV2 => {
// @ts-ignore const { mePage, ...rest } = state
delete state.mePage return rest
return state
} }
} }

View File

@ -0,0 +1,13 @@
export type ContextsV2 = {
storeReview: {
context: Readonly<number>
current: number
shown: boolean
}
publicRemoteNotice: {
context: Readonly<number>
current: number
hidden: boolean
}
previousTab: 'Tab-Local' | 'Tab-Public' | 'Tab-Notifications' | 'Tab-Me'
}

View File

@ -2,15 +2,15 @@ import { InstanceV3 } from './v3'
import { InstanceV4 } from './v4' import { InstanceV4 } from './v4'
import { InstanceV5 } from './v5' import { InstanceV5 } from './v5'
import { InstanceV6 } from './v6' import { InstanceV6 } from './v6'
import { InstanceV7 } from './v7'
const instancesMigration = { const instancesMigration = {
4: (state: InstanceV3) => { 4: (state: InstanceV3): InstanceV4 => {
return { return {
instances: state.local.instances.map((instance, index) => { instances: state.local.instances.map((instance, index) => {
// @ts-ignore const { notification, ...rest } = instance
delete instance.notification
return { return {
...instance, ...rest,
active: state.local.activeIndex === index, active: state.local.activeIndex === index,
push: { push: {
global: { loading: false, value: false }, global: { loading: false, value: false },
@ -28,35 +28,42 @@ const instancesMigration = {
}) })
} }
}, },
5: (state: InstanceV4) => { 5: (state: InstanceV4): InstanceV5 => {
// @ts-ignore // @ts-ignore
if (state.instances.length && !state.instances[0].notifications_filter) { if (state.instances.length && !state.instances[0].notifications_filter) {
return { return {
// @ts-ignore
instances: state.instances.map(instance => { instances: state.instances.map(instance => {
// @ts-ignore return {
instance.notifications_filter = { ...instance,
follow: true, notifications_filter: {
favourite: true, follow: true,
reblog: true, favourite: true,
mention: true, reblog: true,
poll: true, mention: true,
follow_request: true poll: true,
follow_request: true
}
} }
return instance
}) })
} }
} else { } else {
// @ts-ignore
return state return state
} }
}, },
6: (state: InstanceV5) => { 6: (state: InstanceV5): InstanceV6 => {
return { return {
// @ts-ignore
instances: state.instances.map(instance => { instances: state.instances.map(instance => {
return { ...instance, configuration: undefined } return {
...instance,
configuration: undefined
}
}) })
} }
}, },
7: (state: InstanceV6) => { 7: (state: InstanceV6): InstanceV7 => {
return { return {
instances: state.instances.map(instance => { instances: state.instances.map(instance => {
return { return {

View File

@ -0,0 +1,77 @@
import { ComposeStateDraft } from '@screens/Compose/utils/types'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
type Instance = {
active: boolean
appData: {
clientId: string
clientSecret: string
}
url: string
token: string
uri: Mastodon.Instance['uri']
urls: Mastodon.Instance['urls']
account: {
id: Mastodon.Account['id']
acct: Mastodon.Account['acct']
avatarStatic: Mastodon.Account['avatar_static']
preferences: Mastodon.Preferences
}
max_toot_chars?: number // To be deprecated in v4
configuration?: Mastodon.Instance['configuration']
filters: Mastodon.Filter[]
notifications_filter: {
follow: boolean
favourite: boolean
reblog: boolean
mention: boolean
poll: boolean
follow_request: boolean
}
push: {
global: { loading: boolean; value: boolean }
decode: { loading: boolean; value: boolean }
alerts: {
follow: {
loading: boolean
value: Mastodon.PushSubscription['alerts']['follow']
}
favourite: {
loading: boolean
value: Mastodon.PushSubscription['alerts']['favourite']
}
reblog: {
loading: boolean
value: Mastodon.PushSubscription['alerts']['reblog']
}
mention: {
loading: boolean
value: Mastodon.PushSubscription['alerts']['mention']
}
poll: {
loading: boolean
value: Mastodon.PushSubscription['alerts']['poll']
}
}
keys: {
auth?: string
public?: string // legacy
private?: string // legacy
}
}
timelinesLookback?: {
[key: string]: {
queryKey: QueryKeyTimeline
ids: Mastodon.Status['id'][]
}
}
mePage: {
lists: { shown: boolean }
announcements: { shown: boolean; unread: number }
}
drafts: ComposeStateDraft[]
}
export type InstanceV7 = {
instances: Instance[]
}

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