mirror of
https://github.com/hulthe/inkopslista.git
synced 2026-08-03 23:11:28 +02:00
Load shopping list from server on app startup
This commit is contained in:
Generated
-6186
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,9 @@ version = "0.0.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
reqwest = { version = "0.12.26", features = ["json"] }
|
||||
inkopslista-lib = { path = "../inkopslista-lib" }
|
||||
tokio = { version = "1.48.0", features = ["full"] }
|
||||
|
||||
[dependencies.slint]
|
||||
version = "1.14.1"
|
||||
|
||||
@@ -3,11 +3,48 @@
|
||||
|
||||
use std::error::Error;
|
||||
|
||||
use inkopslista_lib::Item;
|
||||
use slint::{ModelRc, ToSharedString, VecModel};
|
||||
|
||||
slint::include_modules!();
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
// TODO: use anyhow
|
||||
type MagicAnyError = Box<dyn Error>;
|
||||
|
||||
/// GET "/api/list" from the server
|
||||
async fn get_list() -> Result<Vec<Item>, MagicAnyError> {
|
||||
// TODO: don't hardcode url
|
||||
let list = reqwest::get("http://localhost:8000/api/list")
|
||||
.await?
|
||||
.json::<Vec<Item>>()
|
||||
.await?;
|
||||
Ok(list)
|
||||
}
|
||||
|
||||
/// Convert shopping list to slint types
|
||||
fn list_slint_convert(list: Vec<Item>) -> ModelRc<SItem> {
|
||||
let list = list
|
||||
.iter()
|
||||
.map(|item| SItem {
|
||||
name: item.name.to_shared_string(),
|
||||
checked: item.data.checked,
|
||||
})
|
||||
.collect::<VecModel<_>>();
|
||||
ModelRc::new(list)
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), MagicAnyError> {
|
||||
let ui = App::new()?;
|
||||
|
||||
// HACK: load shopping list from server on start
|
||||
match get_list().await {
|
||||
Ok(list) => ui.set_list(list_slint_convert(list)),
|
||||
Err(e) => {
|
||||
eprintln!("{e:?}");
|
||||
}
|
||||
}
|
||||
|
||||
ui.run()?;
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -1,35 +1,57 @@
|
||||
import { TabWidget, AboutSlint, Button, VerticalBox, ListView, CheckBox, ScrollView, HorizontalBox, TextEdit, GridBox } from "std-widgets.slint";
|
||||
import {
|
||||
TabWidget,
|
||||
AboutSlint,
|
||||
Button,
|
||||
VerticalBox,
|
||||
ListView,
|
||||
CheckBox,
|
||||
ScrollView,
|
||||
HorizontalBox,
|
||||
TextEdit,
|
||||
GridBox,
|
||||
} from "std-widgets.slint";
|
||||
|
||||
export struct SItem {
|
||||
name: string,
|
||||
checked: bool,
|
||||
}
|
||||
|
||||
component GoodListItem inherits Rectangle {
|
||||
in property <string> name: "Mjölk";
|
||||
in-out property <bool> checked: false;
|
||||
in-out property <SItem> item;
|
||||
background: #ffffff10;
|
||||
border-radius: 8pt;
|
||||
border-width: 10pt;
|
||||
HorizontalBox {
|
||||
check := CheckBox {
|
||||
checked <=> root.checked;
|
||||
checked: root.item.checked;
|
||||
toggled => {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
opacity: (checked ? 0.5 : 1.0);
|
||||
opacity: (root.item.checked ? 0.5 : 1.0);
|
||||
font-size: 12pt;
|
||||
text: name;
|
||||
text: root.item.name;
|
||||
}
|
||||
}
|
||||
|
||||
input := TouchArea {
|
||||
clicked => {
|
||||
checked = !checked;
|
||||
root.item.checked = !root.item.checked;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component GoodsList {
|
||||
in property <[string]> items: ["Mjölk", "Ost", "Ägg"];
|
||||
in property <[SItem]> items;
|
||||
|
||||
ListView {
|
||||
for item in items: VerticalLayout {
|
||||
GoodListItem {
|
||||
name: item;
|
||||
item: item;
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
height: 4pt;
|
||||
}
|
||||
@@ -49,53 +71,71 @@ component GoodButtons inherits ScrollView {
|
||||
viewport-height: (count-y * (button-height + button-spacing)) * 1pt;
|
||||
|
||||
for item[idx] in favorites: Button {
|
||||
x: floor(mod(idx, count-x)) * (root.button-width + root.button-spacing) * 1pt ;
|
||||
y: floor(idx / count-x) * (root.button-height + root.button-spacing) * 1pt;
|
||||
width: root.button-width * 1pt;
|
||||
x: floor(mod(idx, count-x)) * (root.button-width + root.button-spacing) * 1pt;
|
||||
y: floor(idx / count-x) * (root.button-height + root.button-spacing) * 1pt;
|
||||
width: root.button-width * 1pt;
|
||||
height: root.button-height * 1pt;
|
||||
text: item;
|
||||
}
|
||||
}
|
||||
|
||||
component AddView inherits VerticalBox {
|
||||
goods:= GoodsList {
|
||||
in property <[SItem]> list;
|
||||
goods := GoodsList {
|
||||
items <=> list;
|
||||
}
|
||||
|
||||
HorizontalLayout {
|
||||
height: 50pt;
|
||||
input:= TextEdit {
|
||||
}
|
||||
input := TextEdit { }
|
||||
|
||||
Rectangle {
|
||||
width: 4pt; // spacing
|
||||
}
|
||||
|
||||
Button {
|
||||
width: self.height;
|
||||
text: "+";
|
||||
clicked => {
|
||||
goods.items[goods.items.length] = input.text;
|
||||
}
|
||||
// clicked => {
|
||||
// goods.items[goods.items.length] = input.text;
|
||||
// }
|
||||
}
|
||||
}
|
||||
GoodButtons {
|
||||
|
||||
}
|
||||
GoodButtons { }
|
||||
}
|
||||
|
||||
component ShopView inherits VerticalBox {
|
||||
goods := GoodsList {}
|
||||
in property <[SItem]> list;
|
||||
|
||||
goods := GoodsList {
|
||||
items <=> list;
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "I am done hehe";
|
||||
}
|
||||
}
|
||||
|
||||
export component App inherits Window {
|
||||
in property <[SItem]> list: [
|
||||
{ name: "Test 1", checked: true },
|
||||
{ name: "Test 2", checked: false },
|
||||
{ name: "Test 3", checked: false },
|
||||
];
|
||||
TabWidget {
|
||||
Tab {
|
||||
title: "Add";
|
||||
AddView {}
|
||||
}
|
||||
AddView {
|
||||
list <=> list;
|
||||
}
|
||||
}
|
||||
|
||||
Tab {
|
||||
title: "Shop";
|
||||
ShopView {}
|
||||
}
|
||||
ShopView {
|
||||
list <=> list;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user