diff --git a/bun.lockb b/bun.lockb index 09b303c..b66914b 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index c86c054..06424e2 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ }, "dependencies": { "@tauri-apps/api": "^1", - "kaioken": "^0.10.0" + "kaioken": "^0.10.5", + "vite-plugin-kaioken": "^0.0.7" }, "devDependencies": { "@tauri-apps/cli": "^1", @@ -21,8 +22,7 @@ "postcss": "^8.4.35", "tailwindcss": "^3.4.1", "typescript": "^5.0.2", - "vite": "^5.0.0", - "vite-plugin-kaioken": "^0.0.7" + "vite": "^5.0.0" }, "config": { "commitizen": { diff --git a/src/App.tsx b/src/App.tsx index 4be92ac..ddc955e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,212 +1,31 @@ -import { exists, readTextFile, writeTextFile } from "@tauri-apps/api/fs" import { Navs, useNavigator } from "./hooks/useNavigator" -import { appDataDir } from "@tauri-apps/api/path" -import { useEffect, useModel, useRef, useState } from "kaioken" +import { useEffect } from "kaioken" +import { useStationsProvider } from "./providers/StationsProvider" +import Main from "./pages/Main" +import Player from "./pages/Player" +import { useStorageContext } from "./providers/StorageProvider" +import Add from "./pages/Add" -interface Station { - url: string - avatar: string - title: string -} export function App() { - const { nav, setNavitation } = useNavigator() - const [stations, setStations] = useState(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} + + ); +}