Fancy new buttons and more consistent colors

This commit is contained in:
Lei Nelissen
2021-02-11 23:43:21 +01:00
parent 42eb7a169b
commit 7adc96ba12
34 changed files with 15540 additions and 452 deletions

View File

@@ -9,10 +9,10 @@ import {
TapGestureHandlerGestureEvent
} from 'react-native-gesture-handler';
interface LetterContainerProps {
onPress: (letter: string) => void;
letter: string;
}
// interface LetterContainerProps {
// onPress: (letter: string) => void;
// letter: string;
// }
const Container = styled.View`
position: absolute;

View File

@@ -1,8 +1,7 @@
import React, { Component } from 'react';
import React, { useEffect } from 'react';
import { Provider } from 'react-redux';
import TrackPlayer from 'react-native-track-player';
import { PersistGate } from 'redux-persist/integration/react';
import { AppearanceProvider, Appearance, AppearanceListener } from 'react-native-appearance';
import Routes from '../screens';
import store, { persistedStore } from 'store';
import {
@@ -10,60 +9,36 @@ import {
DefaultTheme,
DarkTheme,
} from '@react-navigation/native';
import { useColorScheme } from 'react-native';
interface State {
isReady: boolean;
colorScheme?: string;
}
export default function App(): JSX.Element {
const colorScheme = useColorScheme();
// const colorScheme = 'dark';
export default class App extends Component<{}, State> {
state: State = {
isReady: false,
};
subscription = null;
async componentDidMount() {
await TrackPlayer.setupPlayer();
await TrackPlayer.updateOptions({
capabilities: [
TrackPlayer.CAPABILITY_PLAY,
TrackPlayer.CAPABILITY_PAUSE,
TrackPlayer.CAPABILITY_SKIP_TO_NEXT,
TrackPlayer.CAPABILITY_SKIP_TO_PREVIOUS,
TrackPlayer.CAPABILITY_STOP,
TrackPlayer.CAPABILITY_SEEK_TO,
]
});
this.subscription = Appearance.addChangeListener(this.setScheme);
this.setState({ isReady: true, colorScheme: Appearance.getColorScheme() });
}
componentWillUnmount() {
this.subscription?.remove();
}
setScheme: AppearanceListener = ({ colorScheme }) => {
this.setState({ colorScheme });
}
render() {
const { isReady, colorScheme } = this.state;
if (!isReady) {
return null;
useEffect(() => {
async function setupTrackPlayer() {
await TrackPlayer.setupPlayer();
await TrackPlayer.updateOptions({
capabilities: [
TrackPlayer.CAPABILITY_PLAY,
TrackPlayer.CAPABILITY_PAUSE,
TrackPlayer.CAPABILITY_SKIP_TO_NEXT,
TrackPlayer.CAPABILITY_SKIP_TO_PREVIOUS,
TrackPlayer.CAPABILITY_STOP,
TrackPlayer.CAPABILITY_SEEK_TO,
]
});
}
setupTrackPlayer();
}, []);
return (
<Provider store={store}>
<PersistGate loading={null} persistor={persistedStore}>
<AppearanceProvider>
<NavigationContainer theme={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
<Routes />
</NavigationContainer>
</AppearanceProvider>
</PersistGate>
</Provider>
);
}
return (
<Provider store={store}>
<PersistGate loading={null} persistor={persistedStore}>
<NavigationContainer theme={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
<Routes />
</NavigationContainer>
</PersistGate>
</Provider>
);
}

69
src/components/Button.tsx Normal file
View File

@@ -0,0 +1,69 @@
import React, { useCallback, useState } from 'react';
import { SvgProps } from 'react-native-svg';
import {
PressableProps,
} from 'react-native';
import { THEME_COLOR } from 'CONSTANTS';
import styled, { css } from 'styled-components/native';
import useDefaultStyles from './Colors';
interface ButtonProps extends PressableProps {
icon?: React.FC<SvgProps>;
title: string;
}
interface PressableStyleProps {
active: boolean;
}
const BaseButton = styled.Pressable<PressableStyleProps>`
padding: 16px;
border-radius: 8px;
flex-direction: row;
align-items: center;
justify-content: center;
flex-grow: 1;
${props => props.active && css`
background-color: ${THEME_COLOR};
`}
`;
const ButtonText = styled.Text<{ active?: boolean }>`
color: ${THEME_COLOR};
font-weight: 600;
${props => props.active && css`
color: white;
`}
`;
export default function Button(props: ButtonProps) {
const { icon: Icon, title, ...rest } = props;
const defaultStyles = useDefaultStyles();
const [isPressed, setPressed] = useState(false);
const handlePressIn = useCallback(() => setPressed(true), []);
const handlePressOut = useCallback(() => setPressed(false), []);
return (
<BaseButton
{...rest}
onPressIn={handlePressIn}
onPressOut={handlePressOut}
active={isPressed}
style={[ defaultStyles.button, props.style ]}
>
{Icon &&
<Icon
width={12}
height={12}
fill={isPressed ? '#fff' : THEME_COLOR}
style={{
marginRight: 8,
}}
/>
}
<ButtonText active={isPressed}>{title}</ButtonText>
</BaseButton>
);
}

View File

@@ -1,26 +0,0 @@
import { StyleSheet, PlatformColor } from 'react-native';
import { THEME_COLOR } from 'CONSTANTS';
export const colors = StyleSheet.create({
text: {
color: PlatformColor('?attr/colorOnBackground'),
},
view: {
backgroundColor: PlatformColor('?android:colorBackground'),
},
border: {
borderColor: '#88888844'
},
activeBackground: {
backgroundColor: `${THEME_COLOR}44`,
},
imageBackground: {
backgroundColor: PlatformColor('?attr/colorBackgroundFloating'),
},
modal: {
backgroundColor: PlatformColor('?attr/colorBackgroundFloating'),
},
input: {
backgroundColor: PlatformColor('?attr/colorBackgroundFloating'),
}
});

View File

@@ -1,27 +0,0 @@
import { StyleSheet, PlatformColor, DynamicColorIOS } from 'react-native';
import { THEME_COLOR } from 'CONSTANTS';
export const colors = StyleSheet.create({
text: {
color: PlatformColor('label'),
},
view: {
backgroundColor: PlatformColor('systemBackground'),
},
border: {
borderColor: PlatformColor('systemGray5Color'),
},
activeBackground: {
backgroundColor: DynamicColorIOS({ light: `${THEME_COLOR}16`, dark: `${THEME_COLOR}66` })
},
imageBackground: {
backgroundColor: PlatformColor('systemGray5Color')
},
modal: {
backgroundColor: DynamicColorIOS({ light: '#eeeeeeee', dark: '#222222ee' })
},
input: {
backgroundColor: PlatformColor('systemGray5Color'),
color: PlatformColor('label'),
}
});

55
src/components/Colors.ts Normal file
View File

@@ -0,0 +1,55 @@
import { THEME_COLOR } from 'CONSTANTS';
import { StyleSheet, useColorScheme } from 'react-native';
export default function useDefaultStyles() {
const scheme = useColorScheme();
// const scheme = 'dark';
return StyleSheet.create({
text: {
color: scheme === 'dark' ? '#fff' : '#000',
},
textHalfOpacity: {
color: scheme === 'dark' ? '#ffffff88' : '#00000088',
},
view: {
backgroundColor: scheme === 'dark' ? '#111' : '#eee',
},
border: {
borderColor: scheme === 'dark' ? '#262626' : '#ddd',
},
activeBackground: {
backgroundColor: `${THEME_COLOR}${scheme === 'dark' ? '66' : '16'}`,
},
imageBackground: {
backgroundColor: scheme === 'dark' ? '#333' : '#ddd',
},
modal: {
backgroundColor: scheme === 'dark' ? '#222222ee' : '#eeeeeeee',
},
modalInner: {
backgroundColor: scheme === 'dark' ? '#000' : '#fff',
},
button: {
backgroundColor: scheme === 'dark' ? '#161616' : '#e6e6e6',
},
input: {
backgroundColor: scheme === 'dark' ? '#161616' : '#e6e6e6',
color: scheme === 'dark' ? '#fff' : '#000',
},
sectionHeading: {
backgroundColor: scheme === 'dark' ? '#111' : '#eee',
borderColor: scheme === 'dark' ? '#333' : '#ddd',
}
});
}
interface DefaultStylesProviderProps {
children: (defaultStyles: ReturnType<typeof useDefaultStyles>) => JSX.Element;
}
export function DefaultStylesProvider(props: DefaultStylesProviderProps) {
const defaultStyles = useDefaultStyles();
return props.children(defaultStyles);
}

View File

@@ -2,7 +2,7 @@ import styled from 'styled-components/native';
const Input = styled.TextInput`
margin: 10px 0;
border-radius: 5px;
border-radius: 8px;
padding: 15px;
`;

View File

@@ -1,24 +1,48 @@
import React from 'react';
import { TouchableOpacityProps, Text } from 'react-native';
import React, { useCallback, useState } from 'react';
import { TouchableOpacityProps } from 'react-native';
import ChevronRight from 'assets/chevron-right.svg';
import styled from 'styled-components/native';
import styled, { css } from 'styled-components/native';
import { THEME_COLOR } from 'CONSTANTS';
import { colors } from './Colors';
import useDefaultStyles from './Colors';
const BUTTON_SIZE = 14;
const Container = styled.TouchableOpacity`
padding: 18px 0;
const Container = styled.Pressable<{ active?: boolean }>`
padding: 18px 20px;
border-bottom-width: 1px;
flex-direction: row;
justify-content: space-between;
${props => props.active && css`
background-color: ${THEME_COLOR};
`}
`;
const Label = styled.Text<{ active?: boolean }>`
color: ${THEME_COLOR};
font-size: 16px;
${props => props.active && css`
color: white;
`}
`;
const ListButton: React.FC<TouchableOpacityProps> = ({ children, ...props }) => {
const defaultStyles = useDefaultStyles();
const [isPressed, setPressed] = useState(false);
const handlePressIn = useCallback(() => setPressed(true), []);
const handlePressOut = useCallback(() => setPressed(false), []);
return (
<Container {...props} style={colors.border}>
<Text style={{ color: THEME_COLOR, fontSize: 16 }}>{children}</Text>
<ChevronRight width={BUTTON_SIZE} height={BUTTON_SIZE} fill={THEME_COLOR} />
<Container
{...props}
onPressIn={handlePressIn}
onPressOut={handlePressOut}
style={defaultStyles.border}
active={isPressed}
>
<Label active={isPressed}>{children}</Label>
<ChevronRight width={BUTTON_SIZE} height={BUTTON_SIZE} fill={isPressed ? '#fff' : THEME_COLOR} />
</Container>
);
};

View File

@@ -1,8 +1,8 @@
import React, { useCallback } from 'react';
import styled, { css } from 'styled-components/native';
import { SafeAreaView, Pressable } from 'react-native';
import { colors } from './Colors';
import { useNavigation, StackActions } from '@react-navigation/native';
import useDefaultStyles from './Colors';
interface Props {
fullSize?: boolean;
@@ -24,15 +24,16 @@ const Container = styled(Pressable)<Pick<Props, 'fullSize'>>`
`;
const Modal: React.FC<Props> = ({ children, fullSize = true }) => {
const defaultStyles = useDefaultStyles();
const navigation = useNavigation();
const closeModal = useCallback(() => {
navigation.dispatch(StackActions.popToTop());
}, [navigation]);
return (
<Background style={colors.modal} onPress={closeModal}>
<Background style={defaultStyles.modal} onPress={closeModal}>
<SafeAreaView style={{ flex: 1 }}>
<Container style={colors.view} fullSize={fullSize}>
<Container style={defaultStyles.modalInner} fullSize={fullSize}>
{children}
</Container>
</SafeAreaView>

11
src/components/Text.tsx Normal file
View File

@@ -0,0 +1,11 @@
import React, { PropsWithChildren } from 'react';
import { Text as BaseText, TextProps } from 'react-native';
import useDefaultStyles from './Colors';
export default function Text(props: PropsWithChildren<TextProps>) {
const defaultStyles = useDefaultStyles();
return (
<BaseText {...props} style={[defaultStyles.text, props.style]} />
);
}

View File

@@ -1,12 +1,13 @@
import styled from 'styled-components/native';
import Text from './Text';
export const Header = styled.Text`
export const Header = styled(Text)`
margin: 24px 0 12px 0;
font-size: 36px;
font-weight: bold;
`;
export const SubHeader = styled.Text`
export const SubHeader = styled(Text)`
font-size: 24px;
margin: 12px 0;
`;