Files
inkopslista/gui/ui/app.slint
T

394 lines
8.8 KiB
Plaintext

import {
TabWidget,
AboutSlint,
Button,
LineEdit,
ListView,
CheckBox,
ScrollView,
GridBox,
HorizontalBox,
ComboBox,
Palette,
Spinner,
SpinBox,
} from "std-widgets.slint";
import { SettingsView } from "settings.slint";
import { ConnectionStatus, State, SItem, SButtonItem } from "state.slint";
export { ConnectionStatus, State, SItem }
component GoodListItem inherits Rectangle {
in-out property <SItem> item;
background: Palette.alternate-background;
border-radius: 8pt;
border-width: 10pt;
HorizontalLayout {
spacing: 8px;
padding: 8px;
check := CheckBox {
checked: root.item.checked;
toggled() => {
State.check-item(item.name);
debug("CheckBox checked: ", self.checked);
}
}
Text {
opacity: (root.item.checked ? 0.5 : 1.0);
font-size: 12pt;
text: root.item.amount;
width: 30px;
}
Text {
opacity: (root.item.checked ? 0.5 : 1.0);
font-size: 12pt;
text: root.item.name;
}
}
input := TouchArea {
clicked => {
//root.item.checked = !root.item.checked;
State.check-item(item.name);
}
mouse-cursor: pointer;
}
}
component PlusMinus inherits HorizontalLayout {
in property <SItem> item;
plus := Rectangle {
Text {
text: "+";
font-weight: 800;
font-size: 16pt;
}
background: #ffffff10;
border-top-left-radius: 10px;
border-bottom-left-radius: 10px;
border-color: #00000070;
border-width: 1px;
width: self.height;
plusta := TouchArea {
clicked => {
State.inc-amount(item.name);
}
mouse-cursor: pointer;
}
}
minus := Rectangle {
Text {
text: "-";
font-weight: 800;
font-size: 16pt;
}
background: #ffffff10;
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
border-color: #00000070;
border-width: 1px;
height: 30px;
width: self.height;
minusta := TouchArea {
clicked => {
State.dec-amount(item.name);
}
mouse-cursor: pointer;
}
}
states [
plushov when plusta.has-hover: {
plus.background: #ffffff30;
}
minoshov when minusta.has-hover: {
minus.background: #ffffff30;
}
]
}
component GoodListItemAdd inherits Rectangle {
in-out property <SItem> item;
// Animate when this item appears.
transform-scale: item.just-added ? 90% : 100%;
opacity: item.just-added ? 0 : 100%;
init => {
self.transform-scale = 100%;
self.opacity = 100%;
item.just-added = false;
}
animate transform-scale {
duration: 500ms;
easing: ease-out-bounce;
}
animate opacity {
duration: 300ms;
easing: ease-out;
}
background: Palette.alternate-background;
border-radius: 8pt;
border-width: 10pt;
HorizontalLayout {
spacing: 8px;
padding: 8px;
alignment: start;
PlusMinus {
item: item;
}
Rectangle {
height: 30px;
Text {
text: root.item.amount;
font-size: 12pt;
}
}
Rectangle {
height: 30px;
Text {
opacity: (root.item.checked ? 0.5 : 1.0);
font-size: 12pt;
text: root.item.name;
}
}
}
}
component GoodsList {
in property <[SItem]> items;
ListView {
mouse-drag-pan-enabled: true;
for item in items: VerticalLayout {
GoodListItem {
item: item;
}
Rectangle {
height: 4pt;
}
}
}
}
component GoodsListAdd {
in property <[SItem]> items;
ListView {
mouse-drag-pan-enabled: true;
for item in items: VerticalLayout {
GoodListItemAdd {
item <=> item;
}
Rectangle {
height: 4pt;
}
}
}
}
component GoodButtons inherits ScrollView {
in property <length> button-min-width: 100pt;
in property <length> button-height: 60pt;
in property <length> button-spacing: 10pt;
property <int> count-x: floor(root.width / (button-min-width + button-spacing));
property <int> count-y: ceil(State.favorites.length / count-x);
property <length> button-width: ((root.width + button-spacing) / count-x) - button-spacing;
content-height: (count-y * (button-height + button-spacing));
mouse-drag-pan-enabled: true;
vertical-scrollbar-policy: always-off;
FlexboxLayout {
spacing: button-spacing;
for item in State.favorites: Button {
width: root.button-width;
height: root.button-height;
text: item.name;
clicked => {
State.add-to-list(item.name);
}
}
}
}
component ConnStatusIndicator inherits Rectangle {
width: 18px;
Image {
states [
idle when State.connection-status == ConnectionStatus.Idle: {
opacity: 0%;
}
syncing when State.connection-status == ConnectionStatus.Syncing: {
colorize: green;
opacity: 75% + 25% * sin(360deg * animation-tick() / 1s);
}
error when State.connection-status == ConnectionStatus.Error: {
colorize: red;
opacity: 100%;
}
]
source: @image-url("../images/arrow-down-up.svg");
width: 24px;
height: self.width;
}
}
component RefreshButton inherits HorizontalLayout {
spacing: 8px;
alignment: center;
Button {
text: "Refresh";
width: 40%;
clicked() => {
State.refresh-list();
}
}
ConnStatusIndicator { }
}
component AddView inherits VerticalLayout {
in property <[SItem]> list;
padding: 8px;
spacing: 8px;
RefreshButton { }
goods := GoodsListAdd {
items <=> list;
}
HorizontalLayout {
height: 42px;
input := LineEdit {
font-size: 20px;
accepted(text) => {
if text != "" {
State.add-to-list(text);
input.text = "";
}
}
}
Rectangle {
width: 4pt; // spacing
}
Button {
width: self.height;
text: "+";
clicked => {
if input.text != "" {
State.add-to-list(input.text);
input.text = "";
}
input.clear-focus()
}
}
}
GoodButtons { }
}
component ShopView inherits ScrollView {
in property <[SItem]> list;
mouse-drag-pan-enabled: true;
VerticalLayout {
RefreshButton { }
padding: 8px;
spacing: 8px;
goods := GoodsList {
items <=> list;
}
HorizontalLayout {
padding: 12px;
Button {
text: "I am done hehe";
clicked => {
State.delete-checked();
}
}
}
}
}
component CatItem inherits HorizontalBox {
in-out property <SButtonItem> item;
Text {
text: item.name;
vertical-alignment: center;
font-size: 16px;
}
ComboBox {
model: ["kyl", "skafferi", "frys", "övrigt"];
current-value: item.category;
width: 60%;
selected(category) => { State.set-cat(item.name, category) }
}
}
component CatView inherits ScrollView {
in-out property <[SButtonItem]> cats;
mouse-drag-pan-enabled: true;
VerticalLayout {
for item in cats: CatItem {
item: item;
}
}
}
export component App inherits Window {
in property <int> prefered-start-tab: 0;
title: "Inköpslista";
icon: @image-url("../images/icon.svg");
preferred-height: 700px;
preferred-width: 480px;
tabs := TabWidget {
current-index: prefered-start-tab;
Tab {
title: "Add";
AddView {
list <=> State.list;
}
}
Tab {
title: "Shop";
ShopView {
list <=> State.list;
}
}
Tab {
title: "Categories";
CatView {
cats <=> State.favorites;
}
}
Tab {
title: "Settings";
SettingsView { }
}
}
}