Skip to content

Commit

Permalink
feat: introduce high contrast mode for ios
Browse files Browse the repository at this point in the history
fixes #194
  • Loading branch information
leinelissen committed Feb 11, 2024
1 parent f95c79b commit 82b4223
Show file tree
Hide file tree
Showing 28 changed files with 187 additions and 109 deletions.
8 changes: 8 additions & 0 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,10 @@ PODS:
- React-Mapbuffer (0.73.4):
- glog
- React-debug
- react-native-accessibility-settings (0.1.2):
- glog
- RCT-Folly (= 2022.05.16.00)
- React-Core
- react-native-blur (4.4.0):
- glog
- RCT-Folly (= 2022.05.16.00)
Expand Down Expand Up @@ -1246,6 +1250,7 @@ DEPENDENCIES:
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector-modern`)
- React-logger (from `../node_modules/react-native/ReactCommon/logger`)
- 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-netinfo (from `../node_modules/@react-native-community/netinfo`)"
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
Expand Down Expand Up @@ -1364,6 +1369,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/logger"
React-Mapbuffer:
:path: "../node_modules/react-native/ReactCommon"
react-native-accessibility-settings:
:path: "../node_modules/react-native-accessibility-settings"
react-native-blur:
:path: "../node_modules/@react-native-community/blur"
react-native-netinfo:
Expand Down Expand Up @@ -1481,6 +1488,7 @@ SPEC CHECKSUMS:
React-jsinspector: 9ac353eccf6ab54d1e0a33862ba91221d1e88460
React-logger: 0a57b68dd2aec7ff738195f081f0520724b35dab
React-Mapbuffer: 63913773ed7f96b814a2521e13e6d010282096ad
react-native-accessibility-settings: 9e1c5c6e8268015f8447faa7d34a5834fbaf4d8c
react-native-blur: 27113acc008facbc8accae5fb3a78b8424f64cfd
react-native-netinfo: 8a7fd3f7130ef4ad2fb4276d5c9f8d3f28d2df3d
react-native-safe-area-context: b97eb6f9e3b7f437806c2ce5983f479f8eb5de4b
Expand Down
13 changes: 13 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"react": "^18.2.0",
"react-airplay": "^1.2.0",
"react-native": "^0.73.4",
"react-native-accessibility-settings": "^0.1.2",
"react-native-collapsible": "^1.6.1",
"react-native-dotenv": "^3.4.9",
"react-native-fast-image": "^8.6.3",
Expand Down
3 changes: 1 addition & 2 deletions src/CONSTANTS.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
export const ALBUM_CACHE_AMOUNT_OF_DAYS = 7;
export const PLAYLIST_CACHE_AMOUNT_OF_DAYS = 7;
export const ALPHABET_LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ ';
export const THEME_COLOR = '#FF3C00';
export const ALPHABET_LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ ';
9 changes: 6 additions & 3 deletions src/components/AlphabetScroller.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import React, { useCallback, useState } from 'react';
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 {
PanGestureHandler,
PanGestureHandlerGestureEvent,
TapGestureHandler,
TapGestureHandlerGestureEvent
} from 'react-native-gesture-handler';
import useDefaultStyles from './Colors';

// interface LetterContainerProps {
// onPress: (letter: string) => void;
Expand All @@ -29,7 +30,6 @@ const Letter = styled.Text`
text-align: center;
padding: 1px 0;
font-size: 12px;
color: ${THEME_COLOR};
`;

interface Props {
Expand All @@ -41,6 +41,7 @@ interface Props {
* screen with all letters of the Alphabet.
*/
const AlphabetScroller: React.FC<Props> = ({ onSelect }) => {
const styles = useDefaultStyles();
const [ height, setHeight ] = useState(0);
const [ index, setIndex ] = useState<number>();

Expand Down Expand Up @@ -69,7 +70,9 @@ const AlphabetScroller: React.FC<Props> = ({ onSelect }) => {
key={l}
onLayout={i === 0 ? handleLayout : undefined}
>
<Letter>{l}</Letter>
<Letter style={styles.themeColor}>
{l}
</Letter>
</View>
))}
</View>
Expand Down
11 changes: 5 additions & 6 deletions src/components/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { SvgProps } from 'react-native-svg';
import {
PressableProps, ViewProps, View,
} from 'react-native';
import { THEME_COLOR } from '@/CONSTANTS';
import styled, { css } from 'styled-components/native';
import useDefaultStyles from './Colors';

Expand Down Expand Up @@ -35,7 +34,6 @@ const BaseButton = styled.Pressable<{ size: ButtonSize }>`
`;

const ButtonText = styled.Text<{ active?: boolean, size: ButtonSize }>`
color: ${THEME_COLOR};
font-weight: 500;
font-size: 14px;
flex-shrink: 1;
Expand Down Expand Up @@ -72,16 +70,17 @@ const Button = React.forwardRef<View, ButtonProps>(function Button(props, ref) {
<Icon
width={14}
height={14}
fill={THEME_COLOR}
style={{
marginRight: title ? 8 : 0,
}}
fill={defaultStyles.themeColor.color}
style={[
{ marginRight: title ? 8 : 0 }
]}
/>
}
{title ? (
<ButtonText
active={isPressed}
size={size}
style={defaultStyles.themeColor}
numberOfLines={1}
>
{title}
Expand Down
54 changes: 43 additions & 11 deletions src/components/Colors.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,34 @@
import { BlurView, BlurViewProps } from '@react-native-community/blur';
import { THEME_COLOR } from '@/CONSTANTS';
import React, { PropsWithChildren } from 'react';
import { useContext } from 'react';
import { ColorSchemeName, Platform, StyleSheet, View, useColorScheme } from 'react-native';
import { useTypedSelector } from '@/store';
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;

/**
* Function for generating both the dark and light stylesheets, so that they
* don't have to be generate on every individual component render
*/
function generateStyles(scheme: ColorSchemeName) {
function generateStyles(scheme: ColorSchemeName, highContrast: boolean) {
return StyleSheet.create({
text: {
color: scheme === 'dark' ? '#fff' : '#000',
fontSize: 14,
fontFamily: 'Inter',
},
textHalfOpacity: {
color: scheme === 'dark' ? '#ffffff88' : '#00000088',
color: highContrast
? (scheme === 'dark' ? '#ffffffbb' : '#000000bb')
: (scheme === 'dark' ? '#ffffff88' : '#00000088'),
fontSize: 14,
// fontFamily: 'Inter',
},
textQuarterOpacity: {
color: scheme === 'dark' ? '#ffffff44' : '#00000044',
color: highContrast
? (scheme === 'dark' ? '#ffffff88' : '#00000088')
: (scheme === 'dark' ? '#ffffff44' : '#00000044'),
fontSize: 14,
},
view: {
Expand All @@ -35,7 +38,9 @@ function generateStyles(scheme: ColorSchemeName) {
borderColor: scheme === 'dark' ? '#262626' : '#ddd',
},
activeBackground: {
backgroundColor: `${THEME_COLOR}${scheme === 'dark' ? '26' : '16'}`,
backgroundColor: highContrast
? `#8b513c${scheme === 'dark' ? '26' : '10'}`
: `#FF3C00${scheme === 'dark' ? '26' : '16'}`,
},
imageBackground: {
backgroundColor: scheme === 'dark' ? '#191919' : '#eee',
Expand All @@ -49,7 +54,9 @@ function generateStyles(scheme: ColorSchemeName) {
backgroundColor: scheme === 'dark' ? '#000' : '#fff',
},
button: {
backgroundColor: scheme === 'dark' ? '#ffffff09' : '#00000009',
backgroundColor: highContrast
? (scheme === 'dark' ? '#ffffff0f' : '#0000000f')
: (scheme === 'dark' ? '#ffffff09' : '#00000009'),
},
input: {
backgroundColor: scheme === 'dark' ? '#191919' : '#f3f3f3',
Expand All @@ -67,13 +74,35 @@ function generateStyles(scheme: ColorSchemeName) {
filter: {
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
export const themes: Record<'dark' | 'light', ReturnType<typeof generateStyles>> = {
'dark': generateStyles('dark'),
'light': generateStyles('light'),
export const themes: Record<'dark' | 'light' | 'dark-highcontrast' | 'light-highcontrast', ReturnType<typeof generateStyles>> = {
'dark': generateStyles('dark', false),
'light': generateStyles('light', false),
'dark-highcontrast': generateStyles('dark', true),
'light-highcontrast': generateStyles('light', true),
};

// Create context for supplying the theming information
Expand All @@ -84,9 +113,12 @@ export const ColorSchemeContext = React.createContext(themes.dark);
*/
export function ColorSchemeProvider({ children }: PropsWithChildren<{}>) {
const systemScheme = useColorScheme();
const highContrast = useAccessibilitySetting('darkerSystemColors');
const userScheme = useTypedSelector((state) => state.settings.colorScheme);
const scheme = userScheme === ColorScheme.System ? systemScheme : userScheme;
const theme = themes[scheme || 'light'];
const theme = highContrast
? themes[`${scheme || 'light'}-highcontrast`]
: themes[scheme || 'light'];

return (
<ColorSchemeContext.Provider value={theme}>
Expand Down
13 changes: 7 additions & 6 deletions src/components/DownloadIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ import CloudExclamationMarkIcon from '@/assets/icons/cloud-exclamation-mark.svg'
import InternalDriveIcon from '@/assets/icons/internal-drive.svg';
import useDefaultStyles from './Colors';
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';

interface DownloadIconProps {
trackId: string;
size?: number;
fill?: string;
style?: ViewProps['style'];
}

const DownloadContainer = styled.View`
Expand All @@ -26,7 +27,7 @@ const IconOverlay = styled.View`
transform: scale(0.5);
`;

function DownloadIcon({ trackId, size = 16, fill }: DownloadIconProps) {
function DownloadIcon({ trackId, size = 16, fill, style }: DownloadIconProps) {
// determine styles
const defaultStyles = useDefaultStyles();
const iconFill = fill || defaultStyles.textQuarterOpacity.color;
Expand Down Expand Up @@ -66,19 +67,19 @@ function DownloadIcon({ trackId, size = 16, fill }: DownloadIconProps) {

if (!entity && !isQueued) {
return (
<CloudIcon width={size} height={size} fill={iconFill} />
<CloudIcon width={size} height={size} fill={iconFill} style={style} />
);
}

if (entity?.isComplete) {
return (
<InternalDriveIcon width={size} height={size} fill={iconFill} />
<InternalDriveIcon width={size} height={size} fill={iconFill} style={style} />
);
}

if (entity?.isFailed) {
return (
<CloudExclamationMarkIcon width={size} height={size} fill={iconFill} />
<CloudExclamationMarkIcon width={size} height={size} fill={iconFill} style={style} />
);
}

Expand All @@ -100,7 +101,7 @@ function DownloadIcon({ trackId, size = 16, fill }: DownloadIconProps) {
/>
</Svg>
<IconOverlay>
<CloudDownArrow width={size} height={size} fill={iconFill} />
<CloudDownArrow width={size} height={size} fill={iconFill} style={style} />
</IconOverlay>
</DownloadContainer>
);
Expand Down
12 changes: 8 additions & 4 deletions src/components/ListButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import React, { useCallback, useState } from 'react';
import { TouchableOpacityProps } from 'react-native';
import ChevronRight from '@/assets/icons/chevron-right.svg';
import styled from 'styled-components/native';
import { THEME_COLOR } from '@/CONSTANTS';
import useDefaultStyles from './Colors';

const BUTTON_SIZE = 14;
Expand All @@ -17,7 +16,6 @@ const Container = styled.Pressable<{ active?: boolean }>`
`;

const Label = styled.Text<{ active?: boolean }>`
color: ${THEME_COLOR};
font-size: 16px;
`;

Expand All @@ -37,8 +35,14 @@ const ListButton: React.FC<TouchableOpacityProps> = ({ children, ...props }) =>
isPressed ? defaultStyles.activeBackground : undefined
]}
>
<Label>{children}</Label>
<ChevronRight width={BUTTON_SIZE} height={BUTTON_SIZE} fill={THEME_COLOR} />
<Label style={defaultStyles.themeColor}>
{children}
</Label>
<ChevronRight
width={BUTTON_SIZE}
height={BUTTON_SIZE}
fill={defaultStyles.themeColor.color}
/>
</Container>
);
};
Expand Down
2 changes: 0 additions & 2 deletions src/components/Progresstrack.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { THEME_COLOR } from '@/CONSTANTS';
import styled from 'styled-components/native';
import Animated from 'react-native-reanimated';

Expand Down Expand Up @@ -51,7 +50,6 @@ const ProgressTrack = styled(Animated.View)<ProgressTrackProps>`
left: 0;
right: 0;
height: ${(props) => props.stroke ? props.stroke + 'px' : '100%'};
background-color: ${THEME_COLOR};
opacity: ${(props) => props.opacity || 1};
border-radius: 99px;
`;
Expand Down
5 changes: 3 additions & 2 deletions src/screens/Downloads/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import FastImage from 'react-native-fast-image';
import { useGetImage } from '@/utility/JellyfinApi';
import { ShadowWrapper } from '@/components/Shadow';
import { SafeFlatList } from '@/components/SafeNavigatorView';
import { THEME_COLOR } from '@/CONSTANTS';
import { t } from '@/localisation';

const DownloadedTrack = styled.View`
Expand Down Expand Up @@ -165,7 +164,9 @@ function Downloads() {
</DownloadedTrack>
{entities[item]?.error && (
<ErrorWrapper>
<Text style={{ color: THEME_COLOR }}>{entities[item]?.error}</Text>
<Text style={defaultStyles.themeColor}>
{entities[item]?.error}
</Text>
</ErrorWrapper>
)}
</>
Expand Down
Loading

0 comments on commit 82b4223

Please sign in to comment.