Split up dark and light color settings
Previously it was possible to choose a color combination that was almost impossible to read (due to contrast). Now we have prevented this from happening, as well as giving the user more customizability.
This commit is contained in:
parent
0c5a221e0f
commit
dc27ae9868
32
App.tsx
32
App.tsx
|
@ -43,10 +43,12 @@ const App = () => {
|
||||||
const [snackbar, setSnackbar] = useState('')
|
const [snackbar, setSnackbar] = useState('')
|
||||||
const [theme, setTheme] = useState('system')
|
const [theme, setTheme] = useState('system')
|
||||||
|
|
||||||
const [color, setColor] = useState<string>(
|
const [lightColor, setLightColor] = useState<string>(
|
||||||
isDark
|
CombinedDefaultTheme.colors.primary,
|
||||||
? CombinedDarkTheme.colors.primary
|
)
|
||||||
: CombinedDefaultTheme.colors.primary,
|
|
||||||
|
const [darkColor, setDarkColor] = useState<string>(
|
||||||
|
CombinedDarkTheme.colors.primary,
|
||||||
)
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -55,7 +57,7 @@ const App = () => {
|
||||||
const settings = await settingsRepo.findOne({where: {}})
|
const settings = await settingsRepo.findOne({where: {}})
|
||||||
console.log(`${App.name}.useEffect:`, {gotSettings: settings})
|
console.log(`${App.name}.useEffect:`, {gotSettings: settings})
|
||||||
setTheme(settings.theme)
|
setTheme(settings.theme)
|
||||||
if (settings.color) setColor(settings.color)
|
if (settings.lightColor) setLightColor(settings.lightColor)
|
||||||
setInitialized(true)
|
setInitialized(true)
|
||||||
}
|
}
|
||||||
init()
|
init()
|
||||||
|
@ -70,23 +72,23 @@ const App = () => {
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const paperTheme = useMemo(() => {
|
const paperTheme = useMemo(() => {
|
||||||
const darkTheme = color
|
const darkTheme = lightColor
|
||||||
? {
|
? {
|
||||||
...CombinedDarkTheme,
|
...CombinedDarkTheme,
|
||||||
colors: {...CombinedDarkTheme.colors, primary: color},
|
colors: {...CombinedDarkTheme.colors, primary: darkColor},
|
||||||
}
|
}
|
||||||
: CombinedDarkTheme
|
: CombinedDarkTheme
|
||||||
const lightTheme = color
|
const lightTheme = lightColor
|
||||||
? {
|
? {
|
||||||
...CombinedDefaultTheme,
|
...CombinedDefaultTheme,
|
||||||
colors: {...CombinedDefaultTheme.colors, primary: color},
|
colors: {...CombinedDefaultTheme.colors, primary: lightColor},
|
||||||
}
|
}
|
||||||
: CombinedDefaultTheme
|
: CombinedDefaultTheme
|
||||||
let value = isDark ? darkTheme : lightTheme
|
let value = isDark ? darkTheme : lightTheme
|
||||||
if (theme === 'dark') value = darkTheme
|
if (theme === 'dark') value = darkTheme
|
||||||
else if (theme === 'light') value = lightTheme
|
else if (theme === 'light') value = lightTheme
|
||||||
return value
|
return value
|
||||||
}, [isDark, theme, color])
|
}, [isDark, theme, lightColor, darkColor])
|
||||||
|
|
||||||
const action = useMemo(
|
const action = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
|
@ -103,7 +105,15 @@ const App = () => {
|
||||||
settings={{icon: props => <MaterialIcon {...props} />}}>
|
settings={{icon: props => <MaterialIcon {...props} />}}>
|
||||||
<NavigationContainer theme={paperTheme}>
|
<NavigationContainer theme={paperTheme}>
|
||||||
{initialized && (
|
{initialized && (
|
||||||
<ThemeContext.Provider value={{theme, setTheme, color, setColor}}>
|
<ThemeContext.Provider
|
||||||
|
value={{
|
||||||
|
theme,
|
||||||
|
setTheme,
|
||||||
|
lightColor,
|
||||||
|
setLightColor,
|
||||||
|
darkColor,
|
||||||
|
setDarkColor,
|
||||||
|
}}>
|
||||||
<Routes />
|
<Routes />
|
||||||
</ThemeContext.Provider>
|
</ThemeContext.Provider>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
import {ComponentProps} from 'react'
|
import {ComponentProps} from 'react'
|
||||||
import {FAB} from 'react-native-paper'
|
import {FAB, useTheme} from 'react-native-paper'
|
||||||
import {CombinedDarkTheme, CombinedDefaultTheme} from './App'
|
import {CombinedDarkTheme, CombinedDefaultTheme} from './App'
|
||||||
import {lightColors} from './colors'
|
import {lightColors} from './colors'
|
||||||
import {useTheme} from './use-theme'
|
|
||||||
|
|
||||||
export default function MassiveFab(props: Partial<ComponentProps<typeof FAB>>) {
|
export default function MassiveFab(props: Partial<ComponentProps<typeof FAB>>) {
|
||||||
const {color} = useTheme()
|
const {colors} = useTheme()
|
||||||
|
|
||||||
const fabColor = lightColors.includes(color)
|
const fabColor = lightColors.includes(colors.primary)
|
||||||
? CombinedDarkTheme.colors.background
|
? CombinedDarkTheme.colors.background
|
||||||
: CombinedDefaultTheme.colors.background
|
: CombinedDefaultTheme.colors.background
|
||||||
|
|
||||||
|
@ -19,7 +18,7 @@ export default function MassiveFab(props: Partial<ComponentProps<typeof FAB>>) {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
right: 20,
|
right: 20,
|
||||||
bottom: 20,
|
bottom: 20,
|
||||||
backgroundColor: color,
|
backgroundColor: colors.primary,
|
||||||
}}
|
}}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -40,7 +40,10 @@ export default function Select({
|
||||||
anchor={
|
anchor={
|
||||||
<Button
|
<Button
|
||||||
onPress={() => setShow(true)}
|
onPress={() => setShow(true)}
|
||||||
style={{alignSelf: 'flex-start', marginTop: MARGIN}}>
|
style={{
|
||||||
|
alignSelf: 'flex-start',
|
||||||
|
marginTop: MARGIN,
|
||||||
|
}}>
|
||||||
{selected?.label}
|
{selected?.label}
|
||||||
</Button>
|
</Button>
|
||||||
}>
|
}>
|
||||||
|
|
|
@ -36,7 +36,8 @@ export default function SettingsPage() {
|
||||||
const [showUnit, setShowUnit] = useState(false)
|
const [showUnit, setShowUnit] = useState(false)
|
||||||
const [steps, setSteps] = useState(false)
|
const [steps, setSteps] = useState(false)
|
||||||
const [date, setDate] = useState('P')
|
const [date, setDate] = useState('P')
|
||||||
const {theme, setTheme, color, setColor} = useTheme()
|
const {theme, setTheme, lightColor, setLightColor, darkColor, setDarkColor} =
|
||||||
|
useTheme()
|
||||||
const [showDate, setShowDate] = useState(false)
|
const [showDate, setShowDate] = useState(false)
|
||||||
const [noSound, setNoSound] = useState(false)
|
const [noSound, setNoSound] = useState(false)
|
||||||
const [formatOptions, setFormatOptions] = useState<string[]>(defaultFormats)
|
const [formatOptions, setFormatOptions] = useState<string[]>(defaultFormats)
|
||||||
|
@ -45,6 +46,7 @@ export default function SettingsPage() {
|
||||||
useFocusEffect(
|
useFocusEffect(
|
||||||
useCallback(() => {
|
useCallback(() => {
|
||||||
settingsRepo.findOne({where: {}}).then(settings => {
|
settingsRepo.findOne({where: {}}).then(settings => {
|
||||||
|
console.log(`${SettingsPage.name}.focus:`, settings)
|
||||||
setAlarm(settings.alarm)
|
setAlarm(settings.alarm)
|
||||||
setVibrate(settings.vibrate)
|
setVibrate(settings.vibrate)
|
||||||
setSound(settings.sound)
|
setSound(settings.sound)
|
||||||
|
@ -193,12 +195,20 @@ export default function SettingsPage() {
|
||||||
return ': ' + split.pop()
|
return ': ' + split.pop()
|
||||||
}, [sound])
|
}, [sound])
|
||||||
|
|
||||||
const changeColor = useCallback(
|
const changeDarkColor = useCallback(
|
||||||
(value: string) => {
|
(value: string) => {
|
||||||
setColor(value)
|
setDarkColor(value)
|
||||||
settingsRepo.update({}, {color: value})
|
settingsRepo.update({}, {darkColor: value})
|
||||||
},
|
},
|
||||||
[setColor],
|
[setDarkColor],
|
||||||
|
)
|
||||||
|
|
||||||
|
const changeLightColor = useCallback(
|
||||||
|
(value: string) => {
|
||||||
|
setLightColor(value)
|
||||||
|
settingsRepo.update({}, {lightColor: value})
|
||||||
|
},
|
||||||
|
[setLightColor],
|
||||||
)
|
)
|
||||||
|
|
||||||
const renderItem = useCallback(
|
const renderItem = useCallback(
|
||||||
|
@ -247,10 +257,21 @@ export default function SettingsPage() {
|
||||||
)}
|
)}
|
||||||
{'color'.includes(term.toLowerCase()) && (
|
{'color'.includes(term.toLowerCase()) && (
|
||||||
<Select
|
<Select
|
||||||
value={color}
|
value={darkColor}
|
||||||
onChange={changeColor}
|
onChange={changeDarkColor}
|
||||||
items={lightColors.concat(darkColors).map(colorOption => ({
|
items={lightColors.map(colorOption => ({
|
||||||
label: 'Primary color',
|
label: 'Dark color',
|
||||||
|
value: colorOption,
|
||||||
|
color: colorOption,
|
||||||
|
}))}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{'color'.includes(term.toLowerCase()) && (
|
||||||
|
<Select
|
||||||
|
value={lightColor}
|
||||||
|
onChange={changeLightColor}
|
||||||
|
items={darkColors.map(colorOption => ({
|
||||||
|
label: 'Light color',
|
||||||
value: colorOption,
|
value: colorOption,
|
||||||
color: colorOption,
|
color: colorOption,
|
||||||
}))}
|
}))}
|
||||||
|
|
10
colors.ts
10
colors.ts
|
@ -1,4 +1,7 @@
|
||||||
|
import {DarkTheme, DefaultTheme} from 'react-native-paper'
|
||||||
|
|
||||||
export const lightColors = [
|
export const lightColors = [
|
||||||
|
DarkTheme.colors.primary,
|
||||||
'#B3E5FC',
|
'#B3E5FC',
|
||||||
'#FA8072',
|
'#FA8072',
|
||||||
'#FFC0CB',
|
'#FFC0CB',
|
||||||
|
@ -6,7 +9,12 @@ export const lightColors = [
|
||||||
'#BBA1CE',
|
'#BBA1CE',
|
||||||
]
|
]
|
||||||
|
|
||||||
export const darkColors = ['#8156A7', '#007AFF', '#000000', '#CD5C5C']
|
export const darkColors = [
|
||||||
|
DefaultTheme.colors.primary,
|
||||||
|
'#007AFF',
|
||||||
|
'#000000',
|
||||||
|
'#CD5C5C',
|
||||||
|
]
|
||||||
|
|
||||||
export const colorShade = (color: any, amount: number) => {
|
export const colorShade = (color: any, amount: number) => {
|
||||||
color = color.replace(/^#/, '')
|
color = color.replace(/^#/, '')
|
||||||
|
|
|
@ -23,6 +23,7 @@ import {addShowSets1667186443614} from './migrations/1667186443614-add-show-sets
|
||||||
import {addSetsCreated1667186451005} from './migrations/1667186451005-add-sets-created'
|
import {addSetsCreated1667186451005} from './migrations/1667186451005-add-sets-created'
|
||||||
import {addNoSound1667186456118} from './migrations/1667186456118-add-no-sound'
|
import {addNoSound1667186456118} from './migrations/1667186456118-add-no-sound'
|
||||||
import {dropMigrations1667190214743} from './migrations/1667190214743-drop-migrations'
|
import {dropMigrations1667190214743} from './migrations/1667190214743-drop-migrations'
|
||||||
|
import {splitColor1669420187764} from './migrations/1669420187764-split-color'
|
||||||
import {Plan} from './plan'
|
import {Plan} from './plan'
|
||||||
import Settings from './settings'
|
import Settings from './settings'
|
||||||
|
|
||||||
|
@ -57,5 +58,6 @@ export const AppDataSource = new DataSource({
|
||||||
addSetsCreated1667186451005,
|
addSetsCreated1667186451005,
|
||||||
addNoSound1667186456118,
|
addNoSound1667186456118,
|
||||||
dropMigrations1667190214743,
|
dropMigrations1667190214743,
|
||||||
|
splitColor1669420187764,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
24
migrations/1669420187764-split-color.ts
Normal file
24
migrations/1669420187764-split-color.ts
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import {MigrationInterface, QueryRunner, TableColumn} from 'typeorm'
|
||||||
|
|
||||||
|
export class splitColor1669420187764 implements MigrationInterface {
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.addColumn(
|
||||||
|
'settings',
|
||||||
|
new TableColumn({name: 'lightColor', type: 'text', isNullable: true}),
|
||||||
|
)
|
||||||
|
await queryRunner.addColumn(
|
||||||
|
'settings',
|
||||||
|
new TableColumn({name: 'darkColor', type: 'text', isNullable: true}),
|
||||||
|
)
|
||||||
|
await queryRunner.dropColumn('settings', 'color')
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.dropColumn('settings', 'darkColor')
|
||||||
|
await queryRunner.dropColumn('settings', 'lightColor')
|
||||||
|
await queryRunner.addColumn(
|
||||||
|
'settings',
|
||||||
|
new TableColumn({name: 'color', type: 'text', isNullable: true}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,7 +21,10 @@ export default class Settings {
|
||||||
showUnit: boolean
|
showUnit: boolean
|
||||||
|
|
||||||
@Column('text')
|
@Column('text')
|
||||||
color?: string
|
lightColor?: string
|
||||||
|
|
||||||
|
@Column('text')
|
||||||
|
darkColor?: string
|
||||||
|
|
||||||
@Column('boolean')
|
@Column('boolean')
|
||||||
steps: boolean
|
steps: boolean
|
||||||
|
|
13
use-theme.ts
13
use-theme.ts
|
@ -1,15 +1,20 @@
|
||||||
import {createContext, useContext} from 'react'
|
import {createContext, useContext} from 'react'
|
||||||
|
import {DarkTheme, DefaultTheme} from 'react-native-paper'
|
||||||
|
|
||||||
export const ThemeContext = createContext<{
|
export const ThemeContext = createContext<{
|
||||||
theme: string
|
theme: string
|
||||||
color: string
|
lightColor: string
|
||||||
setTheme: (value: string) => void
|
setTheme: (value: string) => void
|
||||||
setColor: (value: string) => void
|
setLightColor: (value: string) => void
|
||||||
|
darkColor: string
|
||||||
|
setDarkColor: (value: string) => void
|
||||||
}>({
|
}>({
|
||||||
theme: 'system',
|
theme: 'system',
|
||||||
color: '',
|
lightColor: DefaultTheme.colors.primary,
|
||||||
setTheme: () => null,
|
setTheme: () => null,
|
||||||
setColor: () => null,
|
setLightColor: () => null,
|
||||||
|
darkColor: DarkTheme.colors.primary,
|
||||||
|
setDarkColor: () => null,
|
||||||
})
|
})
|
||||||
|
|
||||||
export function useTheme() {
|
export function useTheme() {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user