forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {createContext, use, useEffect, useState} from 'react'
2import {AppState} from 'react-native'
3import {
4 getPalette,
5 getPaletteSync,
6 type MaterialYouPalette,
7} from '@assembless/react-native-material-you'
8
9let palette = getPaletteSync() as MaterialYouPalette
10
11export function getMaterialYouColor(
12 palette: MaterialYouPalette,
13 color: [
14 'system_accent1',
15 'system_accent2',
16 'system_accent3',
17 'system_neutral1',
18 'system_neutral2',
19 'system_error',
20 ][number],
21 shade: [0, 10, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000][number],
22 fallback: string = '#000000',
23): string {
24 const shades = [0, 10, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000]
25 let shadeIndex = shades.findIndex(s => s === shade)
26 if (shadeIndex === -1) {
27 throw new Error(
28 `Invalid shade: ${shade}. Valid shades are: ${shades.join(', ')}`,
29 )
30 }
31
32 return palette[color]?.[shadeIndex] || fallback
33}
34
35const colorsChangedCallbacks = new Set<() => void>()
36
37AppState.addEventListener('focus', () => {
38 getPalette()
39 .then((newPalette: MaterialYouPalette) => {
40 // check if colors changed
41 const colorsChanged = Object.keys(newPalette).some(key => {
42 const colorKey = key as keyof MaterialYouPalette
43 return newPalette[colorKey]?.some(
44 (color, index) => color !== palette[colorKey]?.[index],
45 )
46 })
47 if (colorsChanged) {
48 palette = newPalette
49 for (const callback of colorsChangedCallbacks) {
50 callback()
51 }
52 }
53 })
54 .catch(err => {
55 console.error('Failed to get Material You palette:', err)
56 })
57})
58
59function onMaterialYouPaletteChange(callback: () => void) {
60 colorsChangedCallbacks.add(callback)
61 return () => {
62 colorsChangedCallbacks.delete(callback)
63 }
64}
65
66const PaletteProvider = createContext(palette)
67
68export function MaterialYouPaletteProvider({
69 children,
70}: React.PropsWithChildren) {
71 const [thePalette, setThePalette] = useState(palette)
72 useEffect(() => {
73 const unsubscribe = onMaterialYouPaletteChange(() => {
74 setThePalette(() => palette)
75 })
76
77 return unsubscribe
78 }, [])
79
80 return (
81 <PaletteProvider.Provider value={thePalette}>
82 {children}
83 </PaletteProvider.Provider>
84 )
85}
86
87export function useMaterialYouPalette() {
88 return use(PaletteProvider)
89}