From 8426d8acd7b88d74540d12c66752ccacfba8656a Mon Sep 17 00:00:00 2001 From: Triston Armstrong Date: Sun, 17 Mar 2024 03:15:04 -0500 Subject: [PATCH] refactor(app.tsx): refactore out logic and elemnts into their own components/files BREAKING CHANGE: buttons dont route to appropriate pages fix #1 --- bun.lockb | Bin 65717 -> 113866 bytes package.json | 6 +- src/App.tsx | 227 +++-------------------------- src/ProviderWrapper.tsx | 13 ++ src/hooks/useNavigator.ts | 2 + src/main.ts | 10 +- src/pages/Add.tsx | 45 ++++++ src/pages/Main.tsx | 47 ++++++ src/pages/Player.tsx | 34 +++++ src/providers/StationsProvider.tsx | 37 +++++ src/providers/StorageProvider.tsx | 52 +++++++ 11 files changed, 261 insertions(+), 212 deletions(-) create mode 100644 src/ProviderWrapper.tsx create mode 100644 src/pages/Add.tsx create mode 100644 src/pages/Main.tsx create mode 100644 src/pages/Player.tsx create mode 100644 src/providers/StationsProvider.tsx create mode 100644 src/providers/StorageProvider.tsx diff --git a/bun.lockb b/bun.lockb index 09b303c7581bd7254443191fb7934f44f8ecbf06..b66914bdb1d980cc9b835bce17e9f0ed737cb16a 100755 GIT binary patch delta 38837 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 KOFlpF;Qs(`AVL2C delta 9746 zcmeHNdt6o3ww`kd%7#!8LU3b%fG-5uY+j1)t)VEOsTueRaSI420uY6`cvWJhOsi%a}#K*DJlX-4+txU7`@s!?gtcTQ%&acz)cmKNc=eNEw#vF6Z zx#pN_uEn0#{k`elSsqJbJCFJFNu@YuQO!Jg--zb>uAcLcToiiH{O*j9mjhluzR1HT zig89|8(TX3fex-Ms)EbdlA@TY<&^~!93|xw3d>j;Y%Lgb$ASHqt}?swn=sZEhJN4> zaA#fj0|!IDsW27>J_CLLybIh8ybK%)cIuoBrurmZZv&=ycQ7t9_$#n4xT4%ymG5-2 zZCsmVd{o!BgIhyiq1)$x{n-TOF4rA$!PH@fu3NzrAPh_c@B!Zs{@$c@a0N{DCv<&3 znA*3;)WX$`yJi@Z+c`PE(%~#*?~8Dywd*yEjjUD0g=HnJ^gv81e|!r^p&0v#Q>i*%A~-Jst$pdg>Lf**8O{tW*{{ z%S)#evgPfxb-4gc!<`PMVH7)@SXopU&zNCP zh}KrZIES-p653Z5PIl55zlGi3g$A#5(N=&GqopEJZ%|M=h5BPV^%3V6mrp1ua8yQpezNLR3nmR=wP z;>8y2i9#M6rH+Ea+0bc<%fK|16qN#)6SO_)N2`|W55Tnd><1&g?v>y$@N~U?44C$! zG%)RToxoV-ZXYX)QX9rR@Ll%E?7}myKkd4`Cd-^ZZN;QMK8KYROS-S0H}>(6h~3`L zc!-)-SA8GG2$Inf#Jojs|7hX%_u|#U6kz8^MYX@3hlmWwQ$#hc2Ssgw-P4Vobd)#| zkm`96(g;;b@GxwPAq`b+e}m*ur8G~*a#g7YQlTn&Hf1bNl?v`kMq8iuNL~W4WbPJnq58MYA^^wWEkH`qN^EskA*zP$OndvJQ1*dw} zLF%VUen?J+DvgAs)vmc~y9!D3>xyJ)wN;R`76%~>RNH#vDbZ|0Aq`S(>mX^hHy~+I zl8|D}&jm?~ckHgsx24fyBqXiHT1Z)Hylap$#K6!V9$1iC;MtJ0aBo9W!y!r4p>{r2 z)Z#ixn8NJJ7ycqM%*Jh^I?T?iL@lmIg(=+5eMJVYX`&j}S)vwK*xT88Takh53Q^t8 zuG|O|b?t1tgD^!<)C^p=iRuWu=N;@^eZ+~NR0J?Z+WB)LBhqfVge|!{Cf`fc2PN|w zQ48D0*lj5xO~ulPWK%R&CuyFf@gh+jWjEErmIGT8N|`AXd!S8=0WDY8JjBxQWY5je z9u$irQk8GaqOQG-#|cvhyJQ5|hJZN=7~sk!1tzJW$TxmemU znfDbLUF@bk*!0J#Hkzwo>CrOPAKF8x^H6Vh1++LVYG|_QO=y&7w8Nya_Sz_rqljeB3}|YO zOba3Pg;xu8GOz1i>Vs+O+`)+FXHW5hGFa^jc`yq*nP4;Z!P|s7#2tkudp-uuCQfun<*x`+qMdt* zj6}OBwTl)MKJ74IXfz`ja6q!@2((^md%A7En7i4I!h(Wk*F5ngtq`?IcGEG~v~2rz z#H_~}%gPS}O#g*86B*sK)b1i+T>U-l_&qv zaR3#AT_jMTBAtuDREVj;cv4V^n*tR84ZsOdyDESRG1;e*g7R}FzsCS#^}|?a_`BG2 zydeL1%JU2~Z&>$29pQ_zh{?ViAiq5Tm4C)w zsNWBe{{fv3f~kOAYQRI9&VJ7HOuVVv8)KTUI)D;(LicNoy-{~wum3euR#1Lj@z3p4 zdr$ULz5jc;(W)bl(8jOEr5S3k>;IcwWM~ca)E)kh*>z7l{@3?Y%zvJK=Z!Hv9R&cb z`fWi1o?&gLlVm}qq_ zM_JFrc+dtWj(|2Y(dI8X$_q?Xf;KTx2inX;yYo597A77CZDr#0`K{bf%y_SZ=MJo? z7JIH-8piQcl1E$PSMVgfN}A)lhgP8Ri}+)E!Y}MsxbL37UP@I=??0gZ{P$lX{PIQK zUHo);4S#dbst*@)&u=>62R6jqug3JIulD;8>sVLO{Cawz@oQUtX-VvOr?$u!TlS2< zekI)J_!dePV;i8?*gZQ zdf+s01~?0x1O5UWV)A4c9%zby90l~0H@k4FYXHQ70L{lBU@$NQco?AJ(w|yL5_=0c z4%7nl5%n_g3h+9x3849*QPbS51)c|J&szb|p1BNo3RndEComLvgnm}dhL8gc1BL@5 zfc7#tmXGobfEXyJ#bTIs5GkefT}G2aGr9&?3_J;h=^mjDX@H!uq*21)>WYZd^xzy@G9ef!OZFbDV#U_4L?lmSHmy@cihGk}@EWMDcl z4VVhhpBa0BEx^+Nt*MDXIZy>m0kGiJKVv3=D|Maf$bR@m6Rs#ByO?~^!o!ss_UaA` zzokr|&++E~n(Ai&`aYs?_XA|7Ia&=+I#vNxPi-hwG#pABrSAoRQb+eob3}7ZX&g+G zh0^{lCSOYCxn|>>>`}+bx@!ZxW_j_^DX|H$)7W{Row!UyqLmE{PVc>+xyb4BNw&b+p}8$A0UTyZyX4!T5aVR=lipEY-=_6B*5G$jS&@n{7)O!zW<$nR z&aW+Ka4-%l+de*se?0x1yP>9^9GHqO@?}vfxAL`eB{Z{s=ID+-x4yD|!tO^EKH7r0 zipQTL@?AJ28Ao}?n+=xfS0^6v;Bm2*Zn$A)9QHkII~5($)^Afo&G#nxKo1^dHjW2Z zo8$JK`80oIgGZPg(gS0$$_XH|alCkhUGLZaQ>9mfU#?sOheYE%^5UFv>6R52-e_>p zjx3pb-Ikf-uX{zEZm3xyzo6L08E5_4mTix9{B%%*!%-RD6Jt0pQ$c3qjC5?^kERx( z0pB(Faaj(BMB`9(zQ^|BJiqRbH8>c@t|IkX#P~(e&2OmbE)P;{vhjg@r*zt|jE%!9i+w}X^f`WQkQ!^OH5RM;sC1`vvK@4Vq3&#zH_G>fJ2hzV3k+Wd9du#izo2S($Nc}IV7Lxh2?cz zzSIjtd|&=V#v1AB4caCxM6b!L-aOjGu~A@qcWaf2+F>Yj2e)cf`bb2Jv+Cfn7O}Ag zs_z5$;WklC_velI5H<0b2;6Y7JVB8r!J!QzEtLF09_(+N2Y-2NM#b~z-#Mf3b20`M zcm1B1gP+fwP3{2Bdc4~cq)7-EVy&`6d9U^ z*aE6AREzh`&pW3FcqrTj3tm5WPl+GudSqR2-O&K_N_oMA1j>nM$}{ARG#=;yL%3W^ zhD~xm$ZQ;2Z!fpJTzWl!H5y{sP(!svaH4U3J$6!L&t5()Qs5A;CDb_4t{=YjRK_=J zK34cl3+^<5u?w;%-A|)ap)MBfhIzPLNPfmq_lP%>9{w!z@7K@;b`=`KCV2=B7`!?^ zDfnc=d)_^GX6b=TyY_5{U$QpVH0j$H3#m@_?u&)AN-pk;u$#lQ$-8p<#Ey;$zR$oN zd7!m=Q2M3w)=lErd-AX3X&i=+$;kI?PnXeHyJq81e9q3ocRP0* z^tu{ReOWA*dFdFyNhye`Wce^mHgc{mda~c&j~DSCaz;N?pOU-!;jTWCZ};P~c(J^h z$pgaBVZ#}A&#w>fs%x28tluGOqU5apXfsu=BpN68_UG0_jua09?FVf$FoyFI8-Z2%Hd@Zh-~-IRjzod*)Ua3N7a8bLkrNDpp_#oWLv%__fyN0M=lZvOjC_riCAa~eF1 zllGw#N4T9|Em_`Bv(hSUqtVtloB!r@>xBN7{_$ahhjDtJKk&%Yju78x8)|;E%BRpa z$~f=;;L!e%olm~ezrmy8Eo2xa?l_aRqj@=RDZAzI(D31{v_FpIZR>-jJF{Au;X_Ye z<`1={o;TJ%GF(oBTfa$#^jgAH&VbRgRL9v_}?T|(<<;E87fOEs-~1w z6~(null) - const [titleRef, title,] = useModel('') - const [streamRef, streamUrl,] = useModel('') - const [avatarRef, avatarUrl,] = useModel('') - const [selectedStation, setSelectedStation] = useState(null) - const appDataDirRef = useRef(null) + const { setStations } = useStationsProvider() + const { getStationsFile } = useStorageContext() + const { nav } = useNavigator() useEffect(() => { - appDataDir() - .then(async (res) => { - const path = `${res}/stations.json` - if (await exists(path)) { - console.log("file exists: ", path); - const jsonString = await readTextFile(path) - const json = JSON.parse(jsonString) as Station[] - console.log(json) - setStations(json) - appDataDirRef.current = path - return - } - - console.error("File does not exist... creating") - writeTextFile(path, "[]", { append: false }) - }) - .catch(err => console.error(err)) - - + getStationsFile() + .then(res => res && setStations(res)) + .catch() }, []) - function _handleStationAdd() { - console.log({ title, streamUrl, avatarUrl }) - const data: Station = { - url: streamUrl, - avatar: avatarUrl, - title: title - } - setStations(prev => { - const newStations = [...(prev ?? []), data] - // write file - writeTextFile(appDataDirRef.current!, JSON.stringify(newStations)) - return newStations - }) - console.log("Added station: ", data) - setNavitation(Navs.MAIN) + + switch (nav) { + case Navs.MAIN: + return

+ case Navs.ADD: + return + case Navs.PLAYER: + return + default: + return

404 Not Found

} - - function _handleStationClick(station: Station) { - return function() { - setSelectedStation(station) - setNavitation(Navs.PLAYER) - } - } - - if (nav === Navs.MAIN) { - if (!stations?.length) { - return ( -
-

No Stations Added

- -
- ) - } - return ( -
-
- -
- - -
- {stations.map((s) => ( - -
- - ))} - -
- - ) - - } - - if (nav === Navs.ADD) { - return ( -
- -
- - - - -
-
- ) - } - - function _handlePlayerBackClick() { - setNavitation(Navs.MAIN) - setSelectedStation(null) - } - - if (nav === Navs.PLAYER) { - return ( -
- -
-
- {/**/} - {selectedStation?.title} - {/**/} -

{selectedStation?.title}

- {/**/} -

Live Radio

-
- -
-
-
- ) - } - - return ( -
Not a navigation
- ) } -//
-// -//
-// -//

{selectedStation?.title}

-//

Live

-//
-// {/* progress bar */} -//
-// -//
-// {/* play pause button */} -//
-//
-//
-// -// -// -//{/**/} -//
-// -// -// -//
-// {/**/} -//
-//
-//
-// {/**/} -//
-// 1:57 -// 3:53 -//
+ diff --git a/src/ProviderWrapper.tsx b/src/ProviderWrapper.tsx new file mode 100644 index 0000000..ed4c810 --- /dev/null +++ b/src/ProviderWrapper.tsx @@ -0,0 +1,13 @@ +import { App } from "./App"; +import { StationsContextProvider } from "./providers/StationsProvider"; +import { StorageContextProvider } from "./providers/StorageProvider"; + +export default function ProviderWrapper() { + return ( + + + + + + ) +} diff --git a/src/hooks/useNavigator.ts b/src/hooks/useNavigator.ts index 65e173f..cddf300 100644 --- a/src/hooks/useNavigator.ts +++ b/src/hooks/useNavigator.ts @@ -7,9 +7,11 @@ export enum Navs { export function useNavigator() { const [nav, setNav] = useState(Navs.MAIN) + function _setNavitation(newNav: Navs) { setNav(newNav) } + return { nav, setNavitation: _setNavitation, diff --git a/src/main.ts b/src/main.ts index 364e6b6..7e87a77 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,6 +1,6 @@ -import "./styles.css"; -import { mount } from "kaioken"; -import { App } from "./App"; +import "./styles.css" +import { mount } from "kaioken" +import ProviderWrapper from "./ProviderWrapper" -const root = document.getElementById("root")!; -mount(App, root); +const root = document.getElementById("root")! +mount(ProviderWrapper, root) diff --git a/src/pages/Add.tsx b/src/pages/Add.tsx new file mode 100644 index 0000000..b50313d --- /dev/null +++ b/src/pages/Add.tsx @@ -0,0 +1,45 @@ +import { writeTextFile } from "@tauri-apps/api/fs" +import { Navs, useNavigator } from "../hooks/useNavigator" +import { Station, useStationsProvider } from "../providers/StationsProvider" +import { useModel } from "kaioken" +import { useStorageContext } from "../providers/StorageProvider" + +export default function Add() { + const { setNavitation } = useNavigator() + const { setStations } = useStationsProvider() + const { appDataDirRef } = useStorageContext() + const [titleRef, title,] = useModel('') + const [streamRef, streamUrl,] = useModel('') + const [avatarRef, avatarUrl,] = useModel('') + + function _handleStationAdd() { + const data: Station = { + url: streamUrl, + avatar: avatarUrl, + title: title + } + setStations(prev => { + const newStations = [...(prev ?? []), data] + // write file + writeTextFile(appDataDirRef.current!, JSON.stringify(newStations)) + return newStations + }) + setNavitation(Navs.MAIN) + } + + return ( +
+ +
+ + + + +
+
+ ) +} diff --git a/src/pages/Main.tsx b/src/pages/Main.tsx new file mode 100644 index 0000000..62e583b --- /dev/null +++ b/src/pages/Main.tsx @@ -0,0 +1,47 @@ +import { Navs, useNavigator } from "../hooks/useNavigator" +import { Station, useStationsProvider } from "../providers/StationsProvider" + +export default function Main() { + const { setSelectedStation, stations } = useStationsProvider() + const { setNavitation } = useNavigator() + + function _handleStationClick(station: Station) { + setSelectedStation(station) + setNavitation(Navs.PLAYER) + } + + if (!stations?.length) { + return ( +
+

No Stations Added

+ +
+ ) + } + + return ( +
+
+ +
+ + +
+ {stations.map((s) => ( + +
+ + ))} + +
+ + ) +} diff --git a/src/pages/Player.tsx b/src/pages/Player.tsx new file mode 100644 index 0000000..61162b4 --- /dev/null +++ b/src/pages/Player.tsx @@ -0,0 +1,34 @@ +import { Navs, useNavigator } from "../hooks/useNavigator" +import { useStationsProvider } from "../providers/StationsProvider" + +export default function Player() { + const { setNavitation } = useNavigator() + const { setSelectedStation, selectedStation } = useStationsProvider() + + function _handlePlayerBackClick() { + setNavitation(Navs.MAIN) + setSelectedStation(null) + } + + return ( +
+ +
+
+ {/**/} + {selectedStation?.title} + {/**/} +

{selectedStation?.title}

+ {/**/} +

Live Radio

+
+ +
+
+
+ ) +} diff --git a/src/providers/StationsProvider.tsx b/src/providers/StationsProvider.tsx new file mode 100644 index 0000000..2eff1d9 --- /dev/null +++ b/src/providers/StationsProvider.tsx @@ -0,0 +1,37 @@ +import { createContext, useContext, useState } from 'kaioken'; + +interface StationsContextType { + stations: Station[] | null + setStations: (value: Kaioken.StateSetter) => void + selectedStation: Station | null + setSelectedStation: (value: Kaioken.StateSetter) => void +} + +const StationsContext = createContext({} as StationsContextType); + +export const useStationsProvider = () => useContext(StationsContext) + +interface MyContextProviderProps { + children?: Kaioken.VNode | Kaioken.VNode[] +} +export function StationsContextProvider(props: MyContextProviderProps) { + const [stations, setStations] = useState(null) + const [selectedStation, setSelectedStation] = useState(null) + + const value = { + stations, setStations, + selectedStation, setSelectedStation + }; + + return ( + + {props.children} + + ); +} + +export interface Station { + url: string + avatar: string + title: string +} diff --git a/src/providers/StorageProvider.tsx b/src/providers/StorageProvider.tsx new file mode 100644 index 0000000..37e6ec3 --- /dev/null +++ b/src/providers/StorageProvider.tsx @@ -0,0 +1,52 @@ +import { exists, readTextFile, writeTextFile } from '@tauri-apps/api/fs'; +import { appDataDir } from '@tauri-apps/api/path'; +import { createContext, useContext, useRef } from 'kaioken'; +import { Station } from './StationsProvider'; + +interface StorageContextType { + appDataDirRef: Kaioken.Ref, + getStationsFile: () => Promise +} + +const StorageContext = createContext({} as StorageContextType); + +export const useStorageContext = () => useContext(StorageContext) + +export function StorageContextProvider(props: any) { + const appDataDirRef = useRef(null) + + async function _getStationsFile(): Promise { + let dir: null | string = null + try { + dir = await appDataDir() + } catch (err) { + console.error(err) + return undefined + } + if (!dir) return undefined + const path = `${dir}/stations.json` + if (!(await exists(path))) + return await _createStationsFile(path) + const jsonString = await readTextFile(path) + const json = JSON.parse(jsonString) as Station[] + appDataDirRef.current = path + return json + } + + async function _createStationsFile(path: string): Promise { + await writeTextFile(path, "[]", { append: false }) + return [] + } + + + const value: StorageContextType = { + appDataDirRef, + getStationsFile: _getStationsFile + }; + + return ( + + {props.children} + + ); +}