feat: introduce high contrast mode for ios

fixes #194
This commit is contained in:
Lei Nelissen
2024-02-12 00:01:09 +01:00
parent f95c79b254
commit 82b4223939
28 changed files with 187 additions and 109 deletions

View File

@@ -958,6 +958,10 @@ PODS:
- React-Mapbuffer (0.73.4): - React-Mapbuffer (0.73.4):
- glog - glog
- React-debug - React-debug
- react-native-accessibility-settings (0.1.2):
- glog
- RCT-Folly (= 2022.05.16.00)
- React-Core
- react-native-blur (4.4.0): - react-native-blur (4.4.0):
- glog - glog
- RCT-Folly (= 2022.05.16.00) - RCT-Folly (= 2022.05.16.00)
@@ -1246,6 +1250,7 @@ DEPENDENCIES:
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector-modern`) - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector-modern`)
- React-logger (from `../node_modules/react-native/ReactCommon/logger`) - React-logger (from `../node_modules/react-native/ReactCommon/logger`)
- React-Mapbuffer (from `../node_modules/react-native/ReactCommon`) - React-Mapbuffer (from `../node_modules/react-native/ReactCommon`)
- react-native-accessibility-settings (from `../node_modules/react-native-accessibility-settings`)
- "react-native-blur (from `../node_modules/@react-native-community/blur`)" - "react-native-blur (from `../node_modules/@react-native-community/blur`)"
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)" - "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`) - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
@@ -1364,6 +1369,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/logger" :path: "../node_modules/react-native/ReactCommon/logger"
React-Mapbuffer: React-Mapbuffer:
:path: "../node_modules/react-native/ReactCommon" :path: "../node_modules/react-native/ReactCommon"
react-native-accessibility-settings:
:path: "../node_modules/react-native-accessibility-settings"
react-native-blur: react-native-blur:
:path: "../node_modules/@react-native-community/blur" :path: "../node_modules/@react-native-community/blur"
react-native-netinfo: react-native-netinfo:
@@ -1481,6 +1488,7 @@ SPEC CHECKSUMS:
React-jsinspector: 9ac353eccf6ab54d1e0a33862ba91221d1e88460 React-jsinspector: 9ac353eccf6ab54d1e0a33862ba91221d1e88460
React-logger: 0a57b68dd2aec7ff738195f081f0520724b35dab React-logger: 0a57b68dd2aec7ff738195f081f0520724b35dab
React-Mapbuffer: 63913773ed7f96b814a2521e13e6d010282096ad React-Mapbuffer: 63913773ed7f96b814a2521e13e6d010282096ad
react-native-accessibility-settings: 9e1c5c6e8268015f8447faa7d34a5834fbaf4d8c
react-native-blur: 27113acc008facbc8accae5fb3a78b8424f64cfd react-native-blur: 27113acc008facbc8accae5fb3a78b8424f64cfd
react-native-netinfo: 8a7fd3f7130ef4ad2fb4276d5c9f8d3f28d2df3d react-native-netinfo: 8a7fd3f7130ef4ad2fb4276d5c9f8d3f28d2df3d
react-native-safe-area-context: b97eb6f9e3b7f437806c2ce5983f479f8eb5de4b react-native-safe-area-context: b97eb6f9e3b7f437806c2ce5983f479f8eb5de4b

13
package-lock.json generated
View File

@@ -28,6 +28,7 @@
"react": "^18.2.0", "react": "^18.2.0",
"react-airplay": "^1.2.0", "react-airplay": "^1.2.0",
"react-native": "^0.73.4", "react-native": "^0.73.4",
"react-native-accessibility-settings": "^0.1.2",
"react-native-collapsible": "^1.6.1", "react-native-collapsible": "^1.6.1",
"react-native-dotenv": "^3.4.9", "react-native-dotenv": "^3.4.9",
"react-native-fast-image": "^8.6.3", "react-native-fast-image": "^8.6.3",
@@ -9452,6 +9453,18 @@
"react": "18.2.0" "react": "18.2.0"
} }
}, },
"node_modules/react-native-accessibility-settings": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/react-native-accessibility-settings/-/react-native-accessibility-settings-0.1.2.tgz",
"integrity": "sha512-TYk5zZ0Un10eXQgJHn+GL5g/uVD1k8lFJPQZRnOxJcuqh6afA9mluVCF+OzvYJerwsJC2tDVzOXyrGM0/QrXsA==",
"engines": {
"node": ">= 16.0.0"
},
"peerDependencies": {
"react": "*",
"react-native": "*"
}
},
"node_modules/react-native-collapsible": { "node_modules/react-native-collapsible": {
"version": "1.6.1", "version": "1.6.1",
"resolved": "https://registry.npmjs.org/react-native-collapsible/-/react-native-collapsible-1.6.1.tgz", "resolved": "https://registry.npmjs.org/react-native-collapsible/-/react-native-collapsible-1.6.1.tgz",

View File

@@ -31,6 +31,7 @@
"react": "^18.2.0", "react": "^18.2.0",
"react-airplay": "^1.2.0", "react-airplay": "^1.2.0",
"react-native": "^0.73.4", "react-native": "^0.73.4",
"react-native-accessibility-settings": "^0.1.2",
"react-native-collapsible": "^1.6.1", "react-native-collapsible": "^1.6.1",
"react-native-dotenv": "^3.4.9", "react-native-dotenv": "^3.4.9",
"react-native-fast-image": "^8.6.3", "react-native-fast-image": "^8.6.3",

View File

@@ -1,4 +1,3 @@
export const ALBUM_CACHE_AMOUNT_OF_DAYS = 7; export const ALBUM_CACHE_AMOUNT_OF_DAYS = 7;
export const PLAYLIST_CACHE_AMOUNT_OF_DAYS = 7; export const PLAYLIST_CACHE_AMOUNT_OF_DAYS = 7;
export const ALPHABET_LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ '; export const ALPHABET_LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ ';
export const THEME_COLOR = '#FF3C00';

View File

@@ -1,6 +1,6 @@
import React, { useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
import styled from 'styled-components/native'; import styled from 'styled-components/native';
import { ALPHABET_LETTERS, THEME_COLOR } from '@/CONSTANTS'; import { ALPHABET_LETTERS } from '@/CONSTANTS';
import { View, LayoutChangeEvent } from 'react-native'; import { View, LayoutChangeEvent } from 'react-native';
import { import {
PanGestureHandler, PanGestureHandler,
@@ -8,6 +8,7 @@ import {
TapGestureHandler, TapGestureHandler,
TapGestureHandlerGestureEvent TapGestureHandlerGestureEvent
} from 'react-native-gesture-handler'; } from 'react-native-gesture-handler';
import useDefaultStyles from './Colors';
// interface LetterContainerProps { // interface LetterContainerProps {
// onPress: (letter: string) => void; // onPress: (letter: string) => void;
@@ -29,7 +30,6 @@ const Letter = styled.Text`
text-align: center; text-align: center;
padding: 1px 0; padding: 1px 0;
font-size: 12px; font-size: 12px;
color: ${THEME_COLOR};
`; `;
interface Props { interface Props {
@@ -41,6 +41,7 @@ interface Props {
* screen with all letters of the Alphabet. * screen with all letters of the Alphabet.
*/ */
const AlphabetScroller: React.FC<Props> = ({ onSelect }) => { const AlphabetScroller: React.FC<Props> = ({ onSelect }) => {
const styles = useDefaultStyles();
const [ height, setHeight ] = useState(0); const [ height, setHeight ] = useState(0);
const [ index, setIndex ] = useState<number>(); const [ index, setIndex ] = useState<number>();
@@ -69,7 +70,9 @@ const AlphabetScroller: React.FC<Props> = ({ onSelect }) => {
key={l} key={l}
onLayout={i === 0 ? handleLayout : undefined} onLayout={i === 0 ? handleLayout : undefined}
> >
<Letter>{l}</Letter> <Letter style={styles.themeColor}>
{l}
</Letter>
</View> </View>
))} ))}
</View> </View>

View File

@@ -3,7 +3,6 @@ import { SvgProps } from 'react-native-svg';
import { import {
PressableProps, ViewProps, View, PressableProps, ViewProps, View,
} from 'react-native'; } from 'react-native';
import { THEME_COLOR } from '@/CONSTANTS';
import styled, { css } from 'styled-components/native'; import styled, { css } from 'styled-components/native';
import useDefaultStyles from './Colors'; import useDefaultStyles from './Colors';
@@ -35,7 +34,6 @@ const BaseButton = styled.Pressable<{ size: ButtonSize }>`
`; `;
const ButtonText = styled.Text<{ active?: boolean, size: ButtonSize }>` const ButtonText = styled.Text<{ active?: boolean, size: ButtonSize }>`
color: ${THEME_COLOR};
font-weight: 500; font-weight: 500;
font-size: 14px; font-size: 14px;
flex-shrink: 1; flex-shrink: 1;
@@ -72,16 +70,17 @@ const Button = React.forwardRef<View, ButtonProps>(function Button(props, ref) {
<Icon <Icon
width={14} width={14}
height={14} height={14}
fill={THEME_COLOR} fill={defaultStyles.themeColor.color}
style={{ style={[
marginRight: title ? 8 : 0, { marginRight: title ? 8 : 0 }
}} ]}
/> />
} }
{title ? ( {title ? (
<ButtonText <ButtonText
active={isPressed} active={isPressed}
size={size} size={size}
style={defaultStyles.themeColor}
numberOfLines={1} numberOfLines={1}
> >
{title} {title}

View File

@@ -1,10 +1,10 @@
import { BlurView, BlurViewProps } from '@react-native-community/blur'; import { BlurView, BlurViewProps } from '@react-native-community/blur';
import { THEME_COLOR } from '@/CONSTANTS';
import React, { PropsWithChildren } from 'react'; import React, { PropsWithChildren } from 'react';
import { useContext } from 'react'; import { useContext } from 'react';
import { ColorSchemeName, Platform, StyleSheet, View, useColorScheme } from 'react-native'; import { ColorSchemeName, Platform, StyleSheet, View, useColorScheme } from 'react-native';
import { useTypedSelector } from '@/store'; import { useTypedSelector } from '@/store';
import { ColorScheme } from '@/store/settings/types'; import { ColorScheme } from '@/store/settings/types';
import { useAccessibilitySetting } from 'react-native-accessibility-settings';
const majorPlatformVersion = typeof Platform.Version === 'string' ? parseInt(Platform.Version, 10) : Platform.Version; const majorPlatformVersion = typeof Platform.Version === 'string' ? parseInt(Platform.Version, 10) : Platform.Version;
@@ -12,7 +12,7 @@ const majorPlatformVersion = typeof Platform.Version === 'string' ? parseInt(Pla
* Function for generating both the dark and light stylesheets, so that they * Function for generating both the dark and light stylesheets, so that they
* don't have to be generate on every individual component render * don't have to be generate on every individual component render
*/ */
function generateStyles(scheme: ColorSchemeName) { function generateStyles(scheme: ColorSchemeName, highContrast: boolean) {
return StyleSheet.create({ return StyleSheet.create({
text: { text: {
color: scheme === 'dark' ? '#fff' : '#000', color: scheme === 'dark' ? '#fff' : '#000',
@@ -20,12 +20,15 @@ function generateStyles(scheme: ColorSchemeName) {
fontFamily: 'Inter', fontFamily: 'Inter',
}, },
textHalfOpacity: { textHalfOpacity: {
color: scheme === 'dark' ? '#ffffff88' : '#00000088', color: highContrast
? (scheme === 'dark' ? '#ffffffbb' : '#000000bb')
: (scheme === 'dark' ? '#ffffff88' : '#00000088'),
fontSize: 14, fontSize: 14,
// fontFamily: 'Inter',
}, },
textQuarterOpacity: { textQuarterOpacity: {
color: scheme === 'dark' ? '#ffffff44' : '#00000044', color: highContrast
? (scheme === 'dark' ? '#ffffff88' : '#00000088')
: (scheme === 'dark' ? '#ffffff44' : '#00000044'),
fontSize: 14, fontSize: 14,
}, },
view: { view: {
@@ -35,7 +38,9 @@ function generateStyles(scheme: ColorSchemeName) {
borderColor: scheme === 'dark' ? '#262626' : '#ddd', borderColor: scheme === 'dark' ? '#262626' : '#ddd',
}, },
activeBackground: { activeBackground: {
backgroundColor: `${THEME_COLOR}${scheme === 'dark' ? '26' : '16'}`, backgroundColor: highContrast
? `#8b513c${scheme === 'dark' ? '26' : '10'}`
: `#FF3C00${scheme === 'dark' ? '26' : '16'}`,
}, },
imageBackground: { imageBackground: {
backgroundColor: scheme === 'dark' ? '#191919' : '#eee', backgroundColor: scheme === 'dark' ? '#191919' : '#eee',
@@ -49,7 +54,9 @@ function generateStyles(scheme: ColorSchemeName) {
backgroundColor: scheme === 'dark' ? '#000' : '#fff', backgroundColor: scheme === 'dark' ? '#000' : '#fff',
}, },
button: { button: {
backgroundColor: scheme === 'dark' ? '#ffffff09' : '#00000009', backgroundColor: highContrast
? (scheme === 'dark' ? '#ffffff0f' : '#0000000f')
: (scheme === 'dark' ? '#ffffff09' : '#00000009'),
}, },
input: { input: {
backgroundColor: scheme === 'dark' ? '#191919' : '#f3f3f3', backgroundColor: scheme === 'dark' ? '#191919' : '#f3f3f3',
@@ -67,13 +74,35 @@ function generateStyles(scheme: ColorSchemeName) {
filter: { filter: {
backgroundColor: scheme === 'dark' ? '#191919' : '#f3f3f3', backgroundColor: scheme === 'dark' ? '#191919' : '#f3f3f3',
}, },
themeColor: {
color: highContrast
? scheme === 'dark' ? '#FF7A1C' : '#c93400'
: '#FF3C00',
},
themeColorHalfOpacity: {
color: highContrast
? scheme === 'dark' ? '#FF7A1Cbb' : '#c93400bb'
: '#FF3C0088',
},
themeColorQuarterOpacity: {
color: highContrast
? scheme === 'dark' ? '#FF7A1C88' : '#c9340088'
: '#FF3C0044',
},
themeBackground: {
backgroundColor: highContrast
? scheme === 'dark' ? '#FF7A1C' : '#c93400'
: '#FF3C00',
}
}); });
} }
// Prerender both stylesheets // Prerender both stylesheets
export const themes: Record<'dark' | 'light', ReturnType<typeof generateStyles>> = { export const themes: Record<'dark' | 'light' | 'dark-highcontrast' | 'light-highcontrast', ReturnType<typeof generateStyles>> = {
'dark': generateStyles('dark'), 'dark': generateStyles('dark', false),
'light': generateStyles('light'), 'light': generateStyles('light', false),
'dark-highcontrast': generateStyles('dark', true),
'light-highcontrast': generateStyles('light', true),
}; };
// Create context for supplying the theming information // Create context for supplying the theming information
@@ -84,9 +113,12 @@ export const ColorSchemeContext = React.createContext(themes.dark);
*/ */
export function ColorSchemeProvider({ children }: PropsWithChildren<{}>) { export function ColorSchemeProvider({ children }: PropsWithChildren<{}>) {
const systemScheme = useColorScheme(); const systemScheme = useColorScheme();
const highContrast = useAccessibilitySetting('darkerSystemColors');
const userScheme = useTypedSelector((state) => state.settings.colorScheme); const userScheme = useTypedSelector((state) => state.settings.colorScheme);
const scheme = userScheme === ColorScheme.System ? systemScheme : userScheme; const scheme = userScheme === ColorScheme.System ? systemScheme : userScheme;
const theme = themes[scheme || 'light']; const theme = highContrast
? themes[`${scheme || 'light'}-highcontrast`]
: themes[scheme || 'light'];
return ( return (
<ColorSchemeContext.Provider value={theme}> <ColorSchemeContext.Provider value={theme}>

View File

@@ -6,13 +6,14 @@ import CloudExclamationMarkIcon from '@/assets/icons/cloud-exclamation-mark.svg'
import InternalDriveIcon from '@/assets/icons/internal-drive.svg'; import InternalDriveIcon from '@/assets/icons/internal-drive.svg';
import useDefaultStyles from './Colors'; import useDefaultStyles from './Colors';
import Svg, { Circle, CircleProps } from 'react-native-svg'; import Svg, { Circle, CircleProps } from 'react-native-svg';
import { Animated, Easing } from 'react-native'; import { Animated, Easing, ViewProps } from 'react-native';
import styled from 'styled-components/native'; import styled from 'styled-components/native';
interface DownloadIconProps { interface DownloadIconProps {
trackId: string; trackId: string;
size?: number; size?: number;
fill?: string; fill?: string;
style?: ViewProps['style'];
} }
const DownloadContainer = styled.View` const DownloadContainer = styled.View`
@@ -26,7 +27,7 @@ const IconOverlay = styled.View`
transform: scale(0.5); transform: scale(0.5);
`; `;
function DownloadIcon({ trackId, size = 16, fill }: DownloadIconProps) { function DownloadIcon({ trackId, size = 16, fill, style }: DownloadIconProps) {
// determine styles // determine styles
const defaultStyles = useDefaultStyles(); const defaultStyles = useDefaultStyles();
const iconFill = fill || defaultStyles.textQuarterOpacity.color; const iconFill = fill || defaultStyles.textQuarterOpacity.color;
@@ -66,19 +67,19 @@ function DownloadIcon({ trackId, size = 16, fill }: DownloadIconProps) {
if (!entity && !isQueued) { if (!entity && !isQueued) {
return ( return (
<CloudIcon width={size} height={size} fill={iconFill} /> <CloudIcon width={size} height={size} fill={iconFill} style={style} />
); );
} }
if (entity?.isComplete) { if (entity?.isComplete) {
return ( return (
<InternalDriveIcon width={size} height={size} fill={iconFill} /> <InternalDriveIcon width={size} height={size} fill={iconFill} style={style} />
); );
} }
if (entity?.isFailed) { if (entity?.isFailed) {
return ( return (
<CloudExclamationMarkIcon width={size} height={size} fill={iconFill} /> <CloudExclamationMarkIcon width={size} height={size} fill={iconFill} style={style} />
); );
} }
@@ -100,7 +101,7 @@ function DownloadIcon({ trackId, size = 16, fill }: DownloadIconProps) {
/> />
</Svg> </Svg>
<IconOverlay> <IconOverlay>
<CloudDownArrow width={size} height={size} fill={iconFill} /> <CloudDownArrow width={size} height={size} fill={iconFill} style={style} />
</IconOverlay> </IconOverlay>
</DownloadContainer> </DownloadContainer>
); );

View File

@@ -2,7 +2,6 @@ import React, { useCallback, useState } from 'react';
import { TouchableOpacityProps } from 'react-native'; import { TouchableOpacityProps } from 'react-native';
import ChevronRight from '@/assets/icons/chevron-right.svg'; import ChevronRight from '@/assets/icons/chevron-right.svg';
import styled from 'styled-components/native'; import styled from 'styled-components/native';
import { THEME_COLOR } from '@/CONSTANTS';
import useDefaultStyles from './Colors'; import useDefaultStyles from './Colors';
const BUTTON_SIZE = 14; const BUTTON_SIZE = 14;
@@ -17,7 +16,6 @@ const Container = styled.Pressable<{ active?: boolean }>`
`; `;
const Label = styled.Text<{ active?: boolean }>` const Label = styled.Text<{ active?: boolean }>`
color: ${THEME_COLOR};
font-size: 16px; font-size: 16px;
`; `;
@@ -37,8 +35,14 @@ const ListButton: React.FC<TouchableOpacityProps> = ({ children, ...props }) =>
isPressed ? defaultStyles.activeBackground : undefined isPressed ? defaultStyles.activeBackground : undefined
]} ]}
> >
<Label>{children}</Label> <Label style={defaultStyles.themeColor}>
<ChevronRight width={BUTTON_SIZE} height={BUTTON_SIZE} fill={THEME_COLOR} /> {children}
</Label>
<ChevronRight
width={BUTTON_SIZE}
height={BUTTON_SIZE}
fill={defaultStyles.themeColor.color}
/>
</Container> </Container>
); );
}; };

View File

@@ -1,4 +1,3 @@
import { THEME_COLOR } from '@/CONSTANTS';
import styled from 'styled-components/native'; import styled from 'styled-components/native';
import Animated from 'react-native-reanimated'; import Animated from 'react-native-reanimated';
@@ -51,7 +50,6 @@ const ProgressTrack = styled(Animated.View)<ProgressTrackProps>`
left: 0; left: 0;
right: 0; right: 0;
height: ${(props) => props.stroke ? props.stroke + 'px' : '100%'}; height: ${(props) => props.stroke ? props.stroke + 'px' : '100%'};
background-color: ${THEME_COLOR};
opacity: ${(props) => props.opacity || 1}; opacity: ${(props) => props.opacity || 1};
border-radius: 99px; border-radius: 99px;
`; `;

View File

@@ -15,7 +15,6 @@ import FastImage from 'react-native-fast-image';
import { useGetImage } from '@/utility/JellyfinApi'; import { useGetImage } from '@/utility/JellyfinApi';
import { ShadowWrapper } from '@/components/Shadow'; import { ShadowWrapper } from '@/components/Shadow';
import { SafeFlatList } from '@/components/SafeNavigatorView'; import { SafeFlatList } from '@/components/SafeNavigatorView';
import { THEME_COLOR } from '@/CONSTANTS';
import { t } from '@/localisation'; import { t } from '@/localisation';
const DownloadedTrack = styled.View` const DownloadedTrack = styled.View`
@@ -165,7 +164,9 @@ function Downloads() {
</DownloadedTrack> </DownloadedTrack>
{entities[item]?.error && ( {entities[item]?.error && (
<ErrorWrapper> <ErrorWrapper>
<Text style={{ color: THEME_COLOR }}>{entities[item]?.error}</Text> <Text style={defaultStyles.themeColor}>
{entities[item]?.error}
</Text>
</ErrorWrapper> </ErrorWrapper>
)} )}
</> </>

View File

@@ -2,7 +2,6 @@ import React from 'react';
import { StyleSheet } from 'react-native'; import { StyleSheet } from 'react-native';
import { createStackNavigator } from '@react-navigation/stack'; import { createStackNavigator } from '@react-navigation/stack';
import { GestureHandlerRootView } from 'react-native-gesture-handler'; import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { THEME_COLOR } from '@/CONSTANTS';
import { t } from '@/localisation'; import { t } from '@/localisation';
import useDefaultStyles, { ColoredBlurView } from '@/components/Colors'; import useDefaultStyles, { ColoredBlurView } from '@/components/Colors';
import { StackParams } from '@/screens/types'; import { StackParams } from '@/screens/types';
@@ -24,7 +23,7 @@ function MusicStack() {
return ( return (
<GestureHandlerRootView style={{ flex: 1 }}> <GestureHandlerRootView style={{ flex: 1 }}>
<Stack.Navigator initialRouteName="RecentAlbums" screenOptions={{ <Stack.Navigator initialRouteName="RecentAlbums" screenOptions={{
headerTintColor: THEME_COLOR, headerTintColor: defaultStyles.themeColor.color,
headerTitleStyle: defaultStyles.stackHeader, headerTitleStyle: defaultStyles.stackHeader,
cardStyle: defaultStyles.view, cardStyle: defaultStyles.view,
headerTransparent: true, headerTransparent: true,

View File

@@ -14,7 +14,6 @@ import { Text } from '@/components/Typography';
import useDefaultStyles, { ColoredBlurView } from '@/components/Colors'; import useDefaultStyles, { ColoredBlurView } from '@/components/Colors';
import { useNavigation } from '@react-navigation/native'; import { useNavigation } from '@react-navigation/native';
import { calculateProgressTranslation } from '@/components/Progresstrack'; import { calculateProgressTranslation } from '@/components/Progresstrack';
import { THEME_COLOR } from '@/CONSTANTS';
import { NavigationProp } from '@/screens/types'; import { NavigationProp } from '@/screens/types';
import { ShadowWrapper } from '@/components/Shadow'; import { ShadowWrapper } from '@/components/Shadow';
import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs'; import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs';
@@ -48,7 +47,6 @@ const ProgressTrack = styled(Animated.View)<{ stroke?: number; opacity?: number}
left: 0; left: 0;
right: 0; right: 0;
height: ${(props) => props.stroke ? props.stroke + 'px' : '100%'}; height: ${(props) => props.stroke ? props.stroke + 'px' : '100%'};
background-color: ${THEME_COLOR};
opacity: ${(props) => props.opacity || 1}; opacity: ${(props) => props.opacity || 1};
border-radius: 99px; border-radius: 99px;
`; `;
@@ -191,12 +189,18 @@ function NowPlaying({ offset = 0 }: { offset?: number }) {
<SelectActionButton /> <SelectActionButton />
</ActionButton> </ActionButton>
<ProgressTrack <ProgressTrack
style={{ transform: [{ translateX: bufferAnimation.current }]}} style={[
{ transform: [{ translateX: bufferAnimation.current }]},
defaultStyles.themeBackground,
]}
opacity={0.15} opacity={0.15}
stroke={4} stroke={4}
/> />
<ProgressTrack <ProgressTrack
style={{ transform: [{ translateX: progressAnimation.current }]}} style={[
{ transform: [{ translateX: progressAnimation.current }]},
defaultStyles.themeBackground,
]}
stroke={4} stroke={4}
/> />
</InnerContainer> </InnerContainer>

View File

@@ -5,7 +5,7 @@ import { useNavigation } from '@react-navigation/native';
import { differenceInDays } from 'date-fns'; import { differenceInDays } from 'date-fns';
import { useAppDispatch, useTypedSelector } from '@/store'; import { useAppDispatch, useTypedSelector } from '@/store';
import { fetchAllAlbums } from '@/store/music/actions'; import { fetchAllAlbums } from '@/store/music/actions';
import { ALBUM_CACHE_AMOUNT_OF_DAYS, THEME_COLOR } from '@/CONSTANTS'; import { ALBUM_CACHE_AMOUNT_OF_DAYS } from '@/CONSTANTS';
import AlbumImage from './components/AlbumImage'; import AlbumImage from './components/AlbumImage';
import { SectionArtistItem, SectionedArtist, selectArtists } from '@/store/music/selectors'; import { SectionArtistItem, SectionedArtist, selectArtists } from '@/store/music/selectors';
import AlphabetScroller from '@/components/AlphabetScroller'; import AlphabetScroller from '@/components/AlphabetScroller';
@@ -92,7 +92,7 @@ const GeneratedArtistItem = React.memo(function GeneratedArtistItem(props: Gener
numberOfLines={1} numberOfLines={1}
style={[ style={[
defaultStyles.text, defaultStyles.text,
pressed && { color: THEME_COLOR }, pressed && defaultStyles.themeColor,
{ flexShrink: 1 } { flexShrink: 1 }
]} ]}
@@ -201,7 +201,7 @@ const Artists: React.FC = () => {
onRefresh={retrieveData} onRefresh={retrieveData}
getItemLayout={(_, i) => { getItemLayout={(_, i) => {
if (!(i in itemLayouts)) { if (!(i in itemLayouts)) {
console.log('COuLD NOT FIND LAYOUT ITEM', i, _); // console.log('COuLD NOT FIND LAYOUT ITEM', i, _);
} }
return itemLayouts[i] ?? { length: 0, offset: 0, index: i }; return itemLayouts[i] ?? { length: 0, offset: 0, index: i };
}} }}

View File

@@ -4,7 +4,6 @@ import { useGetImage } from '@/utility/JellyfinApi';
import styled, { css } from 'styled-components/native'; import styled, { css } from 'styled-components/native';
import { useNavigation } from '@react-navigation/native'; import { useNavigation } from '@react-navigation/native';
import { useAppDispatch, useTypedSelector } from '@/store'; import { useAppDispatch, useTypedSelector } from '@/store';
import { THEME_COLOR } from '@/CONSTANTS';
import TouchableHandler from '@/components/TouchableHandler'; import TouchableHandler from '@/components/TouchableHandler';
import useCurrentTrack from '@/utility/useCurrentTrack'; import useCurrentTrack from '@/utility/useCurrentTrack';
import TrackPlayer from 'react-native-track-player'; import TrackPlayer from 'react-native-track-player';
@@ -32,7 +31,6 @@ const styles = StyleSheet.create({
marginRight: 12 marginRight: 12
}, },
activeText: { activeText: {
color: THEME_COLOR,
fontWeight: '500', fontWeight: '500',
}, },
}); });
@@ -153,13 +151,17 @@ const TrackListView: React.FC<TrackListViewProps> = ({
> >
<TrackContainer <TrackContainer
isPlaying={currentTrack?.backendId === trackId || false} isPlaying={currentTrack?.backendId === trackId || false}
style={[defaultStyles.border, currentTrack?.backendId === trackId || false ? defaultStyles.activeBackground : null ]} style={[
defaultStyles.border,
currentTrack?.backendId === trackId ? defaultStyles.activeBackground : null
]}
> >
<Text <Text
style={[ style={[
styles.index, styles.index,
{ opacity: 0.25 }, defaultStyles.textQuarterOpacity,
currentTrack?.backendId === trackId && styles.activeText currentTrack?.backendId === trackId && styles.activeText,
currentTrack?.backendId === trackId && defaultStyles.themeColorQuarterOpacity,
]} ]}
numberOfLines={1} numberOfLines={1}
> >
@@ -169,23 +171,29 @@ const TrackListView: React.FC<TrackListViewProps> = ({
</Text> </Text>
<View style={{ flexShrink: 1 }}> <View style={{ flexShrink: 1 }}>
<Text <Text
style={{ style={[
...currentTrack?.backendId === trackId && styles.activeText, currentTrack?.backendId === trackId && styles.activeText,
flexShrink: 1, currentTrack?.backendId === trackId && defaultStyles.themeColor,
marginRight: 4, {
}} flexShrink: 1,
marginRight: 4,
}
]}
numberOfLines={1} numberOfLines={1}
> >
{tracks[trackId]?.Name} {tracks[trackId]?.Name}
</Text> </Text>
{itemDisplayStyle === 'playlist' && ( {itemDisplayStyle === 'playlist' && (
<Text <Text
style={{ style={[
...currentTrack?.backendId === trackId && styles.activeText, currentTrack?.backendId === trackId && styles.activeText,
flexShrink: 1, currentTrack?.backendId === trackId && defaultStyles.themeColor,
marginRight: 4, {
opacity:currentTrack?.backendId === trackId ? 0.5 : 0.25, flexShrink: 1,
}} marginRight: 4,
opacity: currentTrack?.backendId === trackId ? 0.5 : 0.25,
}
]}
numberOfLines={1} numberOfLines={1}
> >
{tracks[trackId]?.Artists.join(', ')} {tracks[trackId]?.Artists.join(', ')}
@@ -195,19 +203,26 @@ const TrackListView: React.FC<TrackListViewProps> = ({
<View style={{ marginLeft: 'auto', flexDirection: 'row' }}> <View style={{ marginLeft: 'auto', flexDirection: 'row' }}>
<Text <Text
style={[ style={[
{ marginRight: 12, opacity: 0.25 }, { marginRight: 12 },
currentTrack?.backendId === trackId && styles.activeText defaultStyles.textQuarterOpacity,
currentTrack?.backendId === trackId && styles.activeText,
currentTrack?.backendId === trackId && defaultStyles.themeColorQuarterOpacity,
]} ]}
numberOfLines={1} numberOfLines={1}
> >
{ticksToDuration(tracks[trackId]?.RunTimeTicks || 0)} {ticksToDuration(tracks[trackId]?.RunTimeTicks || 0)}
</Text> </Text>
<DownloadIcon trackId={trackId} fill={currentTrack?.backendId === trackId ? `${THEME_COLOR}44` : undefined} /> <DownloadIcon
trackId={trackId}
fill={currentTrack?.backendId === trackId ? defaultStyles.themeColorQuarterOpacity.color : undefined}
/>
</View> </View>
</TrackContainer> </TrackContainer>
</TouchableHandler> </TouchableHandler>
)} )}
<Text style={{ paddingTop: 24, paddingBottom: 12, textAlign: 'center', opacity: 0.5 }}>{t('total-duration')}{': '}{ticksToDuration(totalDuration)}</Text> <Text style={{ paddingTop: 24, paddingBottom: 12, textAlign: 'center', opacity: 0.5 }}>
{t('total-duration')}{': '}{ticksToDuration(totalDuration)}
</Text>
<WrappableButtonRow style={{ marginTop: 24 }}> <WrappableButtonRow style={{ marginTop: 24 }}>
<WrappableButton <WrappableButton
icon={CloudDownArrow} icon={CloudDownArrow}

View File

@@ -1,6 +1,5 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { createStackNavigator } from '@react-navigation/stack'; import { createStackNavigator } from '@react-navigation/stack';
import { THEME_COLOR } from '@/CONSTANTS';
import { t } from '@/localisation'; import { t } from '@/localisation';
import useDefaultStyles, { ColoredBlurView } from '@/components/Colors'; import useDefaultStyles, { ColoredBlurView } from '@/components/Colors';
import { StackParams } from '@/screens/types'; import { StackParams } from '@/screens/types';
@@ -20,7 +19,7 @@ function SearchStack() {
<GestureHandlerRootView style={{ flex: 1 }}> <GestureHandlerRootView style={{ flex: 1 }}>
<Stack.Navigator initialRouteName="Search" <Stack.Navigator initialRouteName="Search"
screenOptions={{ screenOptions={{
headerTintColor: THEME_COLOR, headerTintColor: defaultStyles.themeColor.color,
headerTitleStyle: defaultStyles.stackHeader, headerTitleStyle: defaultStyles.stackHeader,
cardStyle: defaultStyles.view, cardStyle: defaultStyles.view,
headerTransparent: true, headerTransparent: true,

View File

@@ -1,6 +1,5 @@
import useDefaultStyles from '@/components/Colors'; import useDefaultStyles from '@/components/Colors';
import { Text } from '@/components/Typography'; import { Text } from '@/components/Typography';
import { THEME_COLOR } from '@/CONSTANTS';
import React from 'react'; import React from 'react';
import { SvgProps } from 'react-native-svg'; import { SvgProps } from 'react-native-svg';
import styled, { css } from 'styled-components/native'; import styled, { css } from 'styled-components/native';
@@ -21,7 +20,6 @@ const Label = styled(Text)<{ active?: boolean }>`
${(props) => props.active && css` ${(props) => props.active && css`
opacity: 1; opacity: 1;
font-weight: 500; font-weight: 500;
color: ${THEME_COLOR};
`} `}
`; `;
@@ -46,8 +44,10 @@ function SelectableFilter({
active={active} active={active}
onPress={onPress} onPress={onPress}
> >
<Icon width={14} height={14} fill={active ? THEME_COLOR : defaultStyles.textHalfOpacity.color} /> <Icon width={14} height={14} fill={active ? defaultStyles.themeColor.color : defaultStyles.textHalfOpacity.color} />
<Label active={active}>{text}</Label> <Label active={active} style={active && defaultStyles.themeColor}>
{text}
</Label>
</Container> </Container>
); );
} }

View File

@@ -3,7 +3,6 @@ import styled from 'styled-components/native';
import CheckmarkIcon from '@/assets/icons/checkmark.svg'; import CheckmarkIcon from '@/assets/icons/checkmark.svg';
import { Text } from '@/components/Typography'; import { Text } from '@/components/Typography';
import useDefaultStyles from '@/components/Colors'; import useDefaultStyles from '@/components/Colors';
import { THEME_COLOR } from '@/CONSTANTS';
import { Gap } from '@/components/Utility'; import { Gap } from '@/components/Utility';
import { View } from 'react-native'; import { View } from 'react-native';
@@ -52,9 +51,9 @@ export function RadioItem<T>({
} }
]} ]}
> >
{checked ? <CheckmarkIcon fill={THEME_COLOR} height={14} width={14} /> : <Gap size={14} />} {checked ? <CheckmarkIcon fill={defaultStyles.themeColor.color} height={14} width={14} /> : <Gap size={14} />}
<Gap size={8} /> <Gap size={8} />
<Text style={checked && { color: THEME_COLOR }}>{label}</Text> <Text style={checked && defaultStyles.themeColor}>{label}</Text>
</RadioItemContainer> </RadioItemContainer>
</View> </View>
); );

View File

@@ -3,7 +3,6 @@ import { StyleSheet } from 'react-native';
import { t } from '@/localisation'; import { t } from '@/localisation';
import { createStackNavigator } from '@react-navigation/stack'; import { createStackNavigator } from '@react-navigation/stack';
import { useNavigation } from '@react-navigation/native'; import { useNavigation } from '@react-navigation/native';
import { THEME_COLOR } from '@/CONSTANTS';
import ListButton from '@/components/ListButton'; import ListButton from '@/components/ListButton';
import useDefaultStyles, { ColoredBlurView } from '@/components/Colors'; import useDefaultStyles, { ColoredBlurView } from '@/components/Colors';
@@ -45,7 +44,7 @@ export default function Settings() {
return ( return (
<Stack.Navigator initialRouteName="SettingList" screenOptions={{ <Stack.Navigator initialRouteName="SettingList" screenOptions={{
headerTintColor: THEME_COLOR, headerTintColor: defaultStyles.themeColor.color,
headerTitleStyle: defaultStyles.stackHeader, headerTitleStyle: defaultStyles.stackHeader,
headerTransparent: true, headerTransparent: true,
headerBackground: () => <ColoredBlurView style={StyleSheet.absoluteFill} />, headerBackground: () => <ColoredBlurView style={StyleSheet.absoluteFill} />,

View File

@@ -6,7 +6,6 @@ import styled, { css } from 'styled-components/native';
import { isSentryEnabled, setSentryStatus } from '@/utility/Sentry'; import { isSentryEnabled, setSentryStatus } from '@/utility/Sentry';
import Accordion from 'react-native-collapsible/Accordion'; import Accordion from 'react-native-collapsible/Accordion';
import ChevronIcon from '@/assets/icons/chevron-right.svg'; import ChevronIcon from '@/assets/icons/chevron-right.svg';
import { THEME_COLOR } from '@/CONSTANTS';
import useDefaultStyles, { DefaultStylesProvider } from '@/components/Colors'; import useDefaultStyles, { DefaultStylesProvider } from '@/components/Colors';
import { t } from '@/localisation'; import { t } from '@/localisation';
import { SafeScrollView } from '@/components/SafeNavigatorView'; import { SafeScrollView } from '@/components/SafeNavigatorView';
@@ -29,10 +28,6 @@ const HeaderContainer = styled.View<{ isActive?: boolean }>`
padding: 16px 24px; padding: 16px 24px;
border-radius: 8px; border-radius: 8px;
overflow: hidden; overflow: hidden;
${props => props.isActive && css`
background-color: ${THEME_COLOR};
`}
`; `;
const HeaderText = styled(Text)` const HeaderText = styled(Text)`

View File

@@ -3,7 +3,6 @@ import { createBottomTabNavigator, BottomTabNavigationProp } from '@react-naviga
import { StackNavigationProp } from '@react-navigation/stack'; import { StackNavigationProp } from '@react-navigation/stack';
import { createNativeStackNavigator } from '@react-navigation/native-stack'; import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { CompositeNavigationProp } from '@react-navigation/native'; import { CompositeNavigationProp } from '@react-navigation/native';
import { THEME_COLOR } from '@/CONSTANTS';
import SearchStack from './Search'; import SearchStack from './Search';
import Music from './Music'; import Music from './Music';
@@ -23,7 +22,7 @@ import ErrorReportingAlert from '@/utility/ErrorReportingAlert';
import ErrorReportingPopup from './modals/ErrorReportingPopup'; import ErrorReportingPopup from './modals/ErrorReportingPopup';
import Player from './modals/Player'; import Player from './modals/Player';
import { StyleSheet } from 'react-native'; import { StyleSheet } from 'react-native';
import { ColoredBlurView } from '@/components/Colors'; import useDefaultStyles, { ColoredBlurView } from '@/components/Colors';
import { StackParams } from './types'; import { StackParams } from './types';
const Stack = createNativeStackNavigator<StackParams>(); const Stack = createNativeStackNavigator<StackParams>();
@@ -35,6 +34,7 @@ type Screens = {
} }
function Screens() { function Screens() {
const styles = useDefaultStyles();
const isOnboardingComplete = useTypedSelector(state => state.settings.isOnboardingComplete); const isOnboardingComplete = useTypedSelector(state => state.settings.isOnboardingComplete);
// GUARD: If onboarding has not been completed, we instead render the // GUARD: If onboarding has not been completed, we instead render the
@@ -62,7 +62,7 @@ function Screens() {
return null; return null;
} }
}, },
tabBarActiveTintColor: THEME_COLOR, tabBarActiveTintColor: styles.themeColor.color,
tabBarInactiveTintColor: 'gray', tabBarInactiveTintColor: 'gray',
headerShown: false, headerShown: false,
tabBarShowLabel: false, tabBarShowLabel: false,

View File

@@ -1,5 +1,4 @@
import { Text } from '@/components/Typography'; import { Text } from '@/components/Typography';
import { THEME_COLOR } from '@/CONSTANTS';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import { showRoutePicker, useAirplayRoutes } from 'react-airplay'; import { showRoutePicker, useAirplayRoutes } from 'react-airplay';
import { TouchableOpacity } from 'react-native'; import { TouchableOpacity } from 'react-native';
@@ -27,7 +26,6 @@ const Label = styled(Text)<{ active?: boolean }>`
font-size: 13px; font-size: 13px;
${(props) => props.active && css` ${(props) => props.active && css`
color: ${THEME_COLOR};
opacity: 1; opacity: 1;
`} `}
`; `;
@@ -43,9 +41,13 @@ function Casting() {
<AirplayAudioIcon <AirplayAudioIcon
width={20} width={20}
height={20} height={20}
fill={routes.length > 0 ? THEME_COLOR : defaultStyles.textHalfOpacity.color} fill={routes.length > 0 ? defaultStyles.themeColor.color : defaultStyles.textHalfOpacity.color}
/> />
<Label active={routes.length > 0} numberOfLines={1}> <Label
active={routes.length > 0}
numberOfLines={1}
style={routes.length > 0 && defaultStyles.themeColor}
>
{routes.length > 0 {routes.length > 0
? `${t('playing-on')} ${routes.map((route) => route.portName).join(', ')}` ? `${t('playing-on')} ${routes.map((route) => route.portName).join(', ')}`
: t('local-playback') : t('local-playback')

View File

@@ -1,6 +1,5 @@
import React from 'react'; import React from 'react';
import { useNetInfo } from '@react-native-community/netinfo'; import { useNetInfo } from '@react-native-community/netinfo';
import { THEME_COLOR } from '@/CONSTANTS';
import styled from 'styled-components/native'; import styled from 'styled-components/native';
import CloudSlash from '@/assets/icons/cloud-slash.svg'; import CloudSlash from '@/assets/icons/cloud-slash.svg';
import { Text } from 'react-native'; import { Text } from 'react-native';
@@ -23,8 +22,8 @@ function ConnectionNotice() {
if (!isInternetReachable) { if (!isInternetReachable) {
return ( return (
<Well style={defaultStyles.activeBackground}> <Well style={defaultStyles.activeBackground}>
<CloudSlash width={24} height={24} fill={THEME_COLOR} /> <CloudSlash width={24} height={24} fill={defaultStyles.themeColor.color} />
<Text style={{ color: THEME_COLOR, marginLeft: 12 }}> <Text style={[ defaultStyles.themeColor, { marginLeft: 12 }]}>
{t('you-are-offline-message')} {t('you-are-offline-message')}
</Text> </Text>
</Well> </Well>

View File

@@ -8,7 +8,6 @@ import ProgressTrack, {
ProgressTrackContainer ProgressTrackContainer
} from '@/components/Progresstrack'; } from '@/components/Progresstrack';
import { Gesture, GestureDetector, gestureHandlerRootHOC } from 'react-native-gesture-handler'; import { Gesture, GestureDetector, gestureHandlerRootHOC } from 'react-native-gesture-handler';
import { THEME_COLOR } from '@/CONSTANTS';
import Reanimated, { import Reanimated, {
useSharedValue, useSharedValue,
useAnimatedStyle, useAnimatedStyle,
@@ -19,6 +18,7 @@ import Reanimated, {
} from 'react-native-reanimated'; } from 'react-native-reanimated';
import ReText from '@/components/ReText'; import ReText from '@/components/ReText';
import useCurrentTrack from '@/utility/useCurrentTrack'; import useCurrentTrack from '@/utility/useCurrentTrack';
import useDefaultStyles from '@/components/Colors';
const DRAG_HANDLE_SIZE = 20; const DRAG_HANDLE_SIZE = 20;
const PADDING_TOP = 12; const PADDING_TOP = 12;
@@ -43,7 +43,6 @@ const DragHandle = styled(Reanimated.View)`
width: ${DRAG_HANDLE_SIZE}px; width: ${DRAG_HANDLE_SIZE}px;
height: ${DRAG_HANDLE_SIZE}px; height: ${DRAG_HANDLE_SIZE}px;
border-radius: ${DRAG_HANDLE_SIZE}px; border-radius: ${DRAG_HANDLE_SIZE}px;
background-color: ${THEME_COLOR};
position: absolute; position: absolute;
left: -${DRAG_HANDLE_SIZE / 2}px; left: -${DRAG_HANDLE_SIZE / 2}px;
top: ${PADDING_TOP - DRAG_HANDLE_SIZE / 2 + 2.5}px; top: ${PADDING_TOP - DRAG_HANDLE_SIZE / 2 + 2.5}px;
@@ -51,6 +50,7 @@ const DragHandle = styled(Reanimated.View)`
`; `;
function ProgressBar() { function ProgressBar() {
const styles = useDefaultStyles();
const { position, buffered } = useProgress(); const { position, buffered } = useProgress();
const { track } = useCurrentTrack(); const { track } = useCurrentTrack();
@@ -182,16 +182,28 @@ function ProgressBar() {
<ProgressTrackContainer> <ProgressTrackContainer>
<ProgressTrack <ProgressTrack
opacity={0.15} opacity={0.15}
style={styles.themeBackground}
/> />
<ProgressTrack <ProgressTrack
style={bufferStyles} style={[
styles.themeBackground,
bufferStyles
]}
opacity={0.15} opacity={0.15}
/> />
<ProgressTrack <ProgressTrack
style={progressStyles} style={[
progressStyles,
styles.themeBackground,
]}
/> />
</ProgressTrackContainer> </ProgressTrackContainer>
<DragHandle style={dragHandleStyles} /> <DragHandle
style={[
styles.themeBackground,
dragHandleStyles,
]}
/>
<NumberBar style={{ flex: 1 }}> <NumberBar style={{ flex: 1 }}>
<Number text={timePassed} style={timePassedStyles} /> <Number text={timePassed} style={timePassedStyles} />
<Number text={timeRemaining} style={timeRemainingStyles} /> <Number text={timeRemaining} style={timeRemainingStyles} />

View File

@@ -11,7 +11,6 @@ import { Text } from '@/components/Typography';
import RepeatIcon from '@/assets/icons/repeat.svg'; import RepeatIcon from '@/assets/icons/repeat.svg';
import RepeatSingleIcon from '@/assets/icons/repeat.1.svg'; import RepeatSingleIcon from '@/assets/icons/repeat.1.svg';
import Button from '@/components/Button'; import Button from '@/components/Button';
import { THEME_COLOR } from '@/CONSTANTS';
import DownloadIcon from '@/components/DownloadIcon'; import DownloadIcon from '@/components/DownloadIcon';
import Divider from '@/components/Divider'; import Divider from '@/components/Divider';
import ticksToDuration from '@/utility/ticksToDuration'; import ticksToDuration from '@/utility/ticksToDuration';
@@ -123,7 +122,7 @@ export default function Queue({ header }: Props) {
onPress={toggleTrackLoop} onPress={toggleTrackLoop}
> >
<RepeatSingleIcon <RepeatSingleIcon
fill={repeatMode === RepeatMode.Track ? THEME_COLOR : defaultStyles.textHalfOpacity.color} fill={repeatMode === RepeatMode.Track ? defaultStyles.themeColor.color : defaultStyles.textHalfOpacity.color}
width={ICON_SIZE} width={ICON_SIZE}
height={ICON_SIZE} height={ICON_SIZE}
/> />
@@ -133,7 +132,7 @@ export default function Queue({ header }: Props) {
onPress={toggleQueueLoop} onPress={toggleQueueLoop}
> >
<RepeatIcon <RepeatIcon
fill={repeatMode === RepeatMode.Queue ? THEME_COLOR : defaultStyles.textHalfOpacity.color} fill={repeatMode === RepeatMode.Queue ? defaultStyles.themeColor.color : defaultStyles.textHalfOpacity.color}
width={ICON_SIZE} width={ICON_SIZE}
height={ICON_SIZE} height={ICON_SIZE}
/> />
@@ -154,14 +153,14 @@ export default function Queue({ header }: Props) {
> >
<View style={{ flex: 1, marginRight: 16 }}> <View style={{ flex: 1, marginRight: 16 }}>
<Text <Text
style={[currentIndex === index ? { color: THEME_COLOR, fontWeight: '500' } : styles.trackTitle, { marginBottom: 2 }]} style={[currentIndex === index ? { color: defaultStyles.themeColor.color, fontWeight: '500' } : styles.trackTitle, { marginBottom: 2 }]}
numberOfLines={1} numberOfLines={1}
> >
{track.title} {track.title}
</Text> </Text>
{(track.artist || track.album) && ( {(track.artist || track.album) && (
<TextHalfOpacity <TextHalfOpacity
style={currentIndex === index ? { color: THEME_COLOR, fontWeight: '400' } : undefined} style={currentIndex === index ? { color: defaultStyles.themeColor.color, fontWeight: '400' } : undefined}
numberOfLines={1} numberOfLines={1}
> >
{track.artist}{track.album && ' — ' + track.album} {track.artist}{track.album && ' — ' + track.album}
@@ -170,13 +169,13 @@ export default function Queue({ header }: Props) {
</View> </View>
<View style={{ marginLeft: 'auto', marginRight: 8 }}> <View style={{ marginLeft: 'auto', marginRight: 8 }}>
<TextHalfOpacity <TextHalfOpacity
style={currentIndex === index ? { color: THEME_COLOR, fontWeight: '400' } : undefined} style={currentIndex === index ? { color: defaultStyles.themeColor.color, fontWeight: '400' } : undefined}
> >
{ticksToDuration(track.duration || 0)} {ticksToDuration(track.duration || 0)}
</TextHalfOpacity> </TextHalfOpacity>
</View> </View>
<View> <View>
<DownloadIcon trackId={track.backendId} fill={currentIndex === index ? THEME_COLOR + '80' : undefined} /> <DownloadIcon trackId={track.backendId} fill={currentIndex === index ? defaultStyles.themeColor.color + '80' : undefined} />
</View> </View>
</QueueItem> </QueueItem>
</TouchableHandler> </TouchableHandler>

View File

@@ -1,7 +1,6 @@
import React, { useCallback, useEffect, useState } from 'react'; import React, { useCallback, useEffect, useState } from 'react';
import DateTimePickerModal from 'react-native-modal-datetime-picker'; import DateTimePickerModal from 'react-native-modal-datetime-picker';
import styled from 'styled-components/native'; import styled from 'styled-components/native';
import { THEME_COLOR } from '@/CONSTANTS';
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux';
import { useTypedSelector } from '@/store'; import { useTypedSelector } from '@/store';
import TimerIcon from '@/assets/icons/timer.svg'; import TimerIcon from '@/assets/icons/timer.svg';
@@ -109,7 +108,7 @@ export default function Timer() {
<View> <View>
<TimerIcon <TimerIcon
fill={showPicker || date fill={showPicker || date
? THEME_COLOR ? defaultStyles.themeColor.color
: defaultStyles.textHalfOpacity.color : defaultStyles.textHalfOpacity.color
} }
width={16} width={16}
@@ -117,7 +116,7 @@ export default function Timer() {
/> />
<Label <Label
style={{ color: showPicker || date style={{ color: showPicker || date
? THEME_COLOR ? defaultStyles.themeColor.color
: defaultStyles.textHalfOpacity.color : defaultStyles.textHalfOpacity.color
}} }}
> >

View File

@@ -5,7 +5,6 @@ import Input from '@/components/Input';
import { setJellyfinCredentials } from '@/store/settings/actions'; import { setJellyfinCredentials } from '@/store/settings/actions';
import { useNavigation, StackActions } from '@react-navigation/native'; import { useNavigation, StackActions } from '@react-navigation/native';
import CredentialGenerator from './components/CredentialGenerator'; import CredentialGenerator from './components/CredentialGenerator';
import { THEME_COLOR } from '@/CONSTANTS';
import { t } from '@/localisation'; import { t } from '@/localisation';
import useDefaultStyles from '@/components/Colors'; import useDefaultStyles from '@/components/Colors';
import { Text } from '@/components/Typography'; import { Text } from '@/components/Typography';
@@ -55,7 +54,7 @@ export default function SetJellyfinServer() {
title={t('set-jellyfin-server')} title={t('set-jellyfin-server')}
onPress={() => setIsLogginIn(true)} onPress={() => setIsLogginIn(true)}
disabled={!serverUrl?.length} disabled={!serverUrl?.length}
color={THEME_COLOR} color={defaultStyles.themeColor.color}
/> />
</View> </View>
)} )}

View File

@@ -45,7 +45,6 @@ const baseTrackOptions: Record<string, string> = {
export function generateTrack(track: AlbumTrack, credentials: Credentials): Track { export function generateTrack(track: AlbumTrack, credentials: Credentials): Track {
// Also construct the URL for the stream // Also construct the URL for the stream
const url = generateTrackUrl(track.Id, credentials); const url = generateTrackUrl(track.Id, credentials);
console.log(url);
return { return {
url, url,