some cleanup

This commit is contained in:
2026-10-07 15:35:04 +02:00
parent c7e7e615c2
commit 8e3abca9d7
13 changed files with 179 additions and 121 deletions
@@ -1,48 +1,54 @@
import { createSignal, For } from "solid-js";
import { createSignal, For, onCleanup, onMount, Show } from "solid-js";
import { createRouter, Todo } from "@<@var(context.project.name)>/rpc"
import { createEffect } from 'solid-js'
import "./app.css";
const router = createRouter("http://127.0.0.1:8080")
// Changes made elsewhere (another tab, the mobile app) show up within this interval.
const syncIntervalMs = 2000
export default function App() {
const router = createRouter("http://127.0.0.1:8080")
const [todos, setTodos] = createSignal<Todo[]>([]);
const [offline, setOffline] = createSignal(false);
const [todoToCreateTask, setTodoToCreateTask] = createSignal<string>("");
const fetchTodos = () => {
router.todos.listTodos({}).then((r) => {
setTodos(r.todos)
})
setOffline(false)
// Polling returns the same list most of the time; keep the old array so <For> keeps its rows.
if (JSON.stringify(todos()) !== JSON.stringify(r.todos)) setTodos(r.todos)
}).catch(() => setOffline(true))
}
createEffect(() => {
onMount(() => {
fetchTodos()
const interval = setInterval(fetchTodos, syncIntervalMs)
onCleanup(() => clearInterval(interval))
})
const setTodoDone = (id: string, task: string) => {
return async (event : Event & { currentTarget: HTMLInputElement }) => {
await router.todos.updateTodo({ todo: { id, task, done: event.currentTarget.checked } })
fetchTodos()
const setTodoDone = (id: string, task: string) => {
return (event: Event & { currentTarget: HTMLInputElement }) => {
router.todos.updateTodo({ todo: { id, task, done: event.currentTarget.checked } }).then(fetchTodos, () => setOffline(true))
}
}
const deleteTodo = (id: string) => {
return async () => {
await router.todos.deleteTodo({ todo: { id } })
fetchTodos()
return () => {
router.todos.deleteTodo({ todo: { id } }).then(fetchTodos, () => setOffline(true))
}
}
const createTodo = () => {
router.todos.createTodo({ todo: { id: crypto.randomUUID(), task: todoToCreateTask() } }).then((r) => {
console.log(r)
const task = todoToCreateTask().trim()
if (!task) return
router.todos.createTodo({ todo: { id: crypto.randomUUID(), task } }).then(() => {
setTodoToCreateTask("")
fetchTodos()
}).catch((e) => {
console.log(e)
})
}, () => setOffline(true))
}
return (
<div>
<p>Create Todo</p>
<input value={todoToCreateTask()} onInput={(e) => setTodoToCreateTask(e.currentTarget.value)} type="text"/>
<Show when={offline()}><p style={{ color: "#d32f2f" }}>Can't reach the API, retrying…</p></Show>
<input value={todoToCreateTask()} onInput={(e) => setTodoToCreateTask(e.currentTarget.value)} type="text" placeholder="What needs to be done?"/>
<button onclick={createTodo}> create </button>
<For each={todos()}>
{(item:Todo) =>
@@ -1,50 +1,55 @@
<script lang="ts">
import { createRouter, type Todo } from "@<@var(context.project.name)>/rpc"
import type { ChangeEventHandler } from "svelte/elements";
const router = createRouter("http://127.0.0.1:8080");
// Changes made elsewhere (another tab, the mobile app) show up within this interval.
const syncIntervalMs = 2000
let todos = $state<Todo[]>([])
let offline = $state(false)
let todoToCreateTask = $state<string>("")
const fetchTodos = () => {
router.todos.listTodos({}).then((r) => {
todos = r.todos;
})
offline = false
// Polling returns the same list most of the time; skip re-rendering it.
if (JSON.stringify($state.snapshot(todos)) !== JSON.stringify(r.todos)) todos = r.todos
}).catch(() => offline = true)
}
$effect(() => {
fetchTodos()
const interval = setInterval(fetchTodos, syncIntervalMs)
return () => clearInterval(interval)
})
const setTodoDone = (id: string, task: string) => {
return async (event : Event & { currentTarget: HTMLInputElement }) => {
await router.todos.updateTodo({ todo: { id, task, done: event.currentTarget.checked } })
fetchTodos()
const setTodoDone = (id: string, task: string) => {
return (event: Event & { currentTarget: HTMLInputElement }) => {
router.todos.updateTodo({ todo: { id, task, done: event.currentTarget.checked } }).then(fetchTodos, () => offline = true)
}
}
const deleteTodo = (id: string) => {
return async () => {
await router.todos.deleteTodo({ todo: { id } })
fetchTodos()
return () => {
router.todos.deleteTodo({ todo: { id } }).then(fetchTodos, () => offline = true)
}
}
const createTodo = () => {
router.todos.createTodo({ todo: { id: crypto.randomUUID(), task: todoToCreateTask } }).then((r) => {
console.log(r)
const task = todoToCreateTask.trim()
if (!task) return
router.todos.createTodo({ todo: { id: crypto.randomUUID(), task } }).then(() => {
todoToCreateTask = ""
fetchTodos()
}).catch((e) => {
console.log(e)
})
}, () => offline = true)
}
</script>
<div>
<h1>Create Todo</h1>
<input bind:value={todoToCreateTask} type="text"/>
{#if offline}<p style="color: #d32f2f">Can't reach the API, retrying…</p>{/if}
<input bind:value={todoToCreateTask} type="text" placeholder="What needs to be done?"/>
<button onclick={createTodo}> create </button>
{#each todos as todo (todo.id)}
<div>
{todo.task}
<input type='checkbox' onchange={setTodoDone(todo.id || "",todo.task)}/>
<input type='checkbox' checked={todo.done} onchange={setTodoDone(todo.id || "",todo.task)}/>
<button onclick={deleteTodo(todo.id || "")}>delete</button>
</div>
{/each}
@@ -1,3 +1,3 @@
# Expo HAS CHANGED
Read the exact versioned docs at https://docs.expo.dev/versions/v56.0.0/ before writing any code.
Read the exact versioned docs at https://docs.expo.dev/versions/v57.0.0/ before writing any code.
@@ -8,8 +8,10 @@ import * as Crypto from "expo-crypto"
import { background, colorInvert, controlSize, padding as iosPadding, shapes } from "@expo/ui/swift-ui/modifiers";
// No numeric width() on Android: @expo/ui 57 can't convert it natively and crashes.
import { fillMaxWidth, padding, weight } from "@expo/ui/jetpack-compose/modifiers";
// The Android emulator reaches the host via 10.0.2.2; the iOS simulator shares the host's network.
const apiUrl = Platform.OS === "android" ? "http://10.0.2.2:8080" : "http://127.0.0.1:8080"
// The iOS simulator shares the host's network; devenv runs `adb reverse` so Android devices do too.
const router = createRouter("http://127.0.0.1:8080")
// Changes made elsewhere (another device, the web app) show up within this interval.
const syncIntervalMs = 2000
// SwiftUI clips a border to its corner radius, cutting off the corners, so on iOS the
// border is an outer rounded fill showing 1pt around an inner one.
@@ -38,38 +40,42 @@ function AnimatedRow({ children }: { children: React.ReactNode }) {
}
export default function Index() {
const router = createRouter(apiUrl)
const [todos, setTodos] = useState<Array<Todo>>([])
const [offline, setOffline] = useState(false)
const todoToCreateTask = useNativeState<string>("")
const colorScheme = useColorScheme()
const fetchTodos = () => {
router.todos.listTodos({}).then((r) => {
setTodos(r.todos)
})
setOffline(false)
// Polling returns the same list most of the time; keep the old array to skip re-rendering.
setTodos((current) => JSON.stringify(current) === JSON.stringify(r.todos) ? current : r.todos)
}).catch(() => setOffline(true))
}
useEffect(() => {
fetchTodos();
fetchTodos()
const interval = setInterval(fetchTodos, syncIntervalMs)
return () => clearInterval(interval)
}, [])
const setTodoDone = (id: string, task: string) => {
return (done: boolean) => {
router.todos.updateTodo({ todo: { id, task, done } }).then(fetchTodos)
router.todos.updateTodo({ todo: { id, task, done } }).then(fetchTodos, () => setOffline(true))
}
}
const deleteTodo = (id: string) => {
return () => {
router.todos.deleteTodo({ todo: { id } }).then(fetchTodos)
router.todos.deleteTodo({ todo: { id } }).then(fetchTodos, () => setOffline(true))
}
}
const createTodo = () => {
router.todos.createTodo({ todo: { id: Crypto.randomUUID(), task: todoToCreateTask.value } }).then((r) => {
console.log(r)
const task = todoToCreateTask.value.trim()
if (!task) return
router.todos.createTodo({ todo: { id: Crypto.randomUUID(), task } }).then(() => {
todoToCreateTask.value = ""
fetchTodos()
}).catch((e) => {
console.log(e)
})
}, () => setOffline(true))
}
const updateTodoToCreateTask = (task: string) => {
@@ -81,6 +87,7 @@ export default function Index() {
<Host matchContents={{ vertical: true }}>
<Column alignment="center" modifiers={[fillMaxWidth()]}>
<Text textStyle={{fontSize:30}}> Create Todo </Text>
{offline && <Text textStyle={{ color: "#FF3B30" }}>Can't reach the API, retrying…</Text>}
<TextInput
value={todoToCreateTask}
onChangeText={updateTodoToCreateTask}