import { Palette, Button, VerticalBox, HorizontalBox, ScrollView, ListView, StandardListView } from "std-widgets.slint"; export struct ChangeData { hash: string, // TODO display all authors // authors: [string], author: string, timestamp: string, message: string, } export struct ChannelsData { names: [string], active: int, } component DeltasList { in property <string> delta; VerticalBox { Text { vertical-stretch: 0; text: "change"; } ScrollView { vertical-stretch: 1; viewport-width <=> text.width; viewport-height <=> text.height; text := Text { width: 100%; text: delta; } } } } component DiffEntry inherits Rectangle { in property <int> files-count; VerticalBox { label := Text { text: "\{files-count} files changed"; } } in-out property <bool> is-selected: false; in property <bool> has-hover; states [ selected when root.is-selected: { root.background: Palette.selection-background; label.color: Palette.selection-foreground; } lowlighted when root.has-hover: { root.background: Palette.alternate-background; label.color: Palette.alternate-foreground; } ] } component ChangeEntry inherits Rectangle { in-out property <string> hash; in-out property <string> author; in-out property <string> timestamp; in-out property <string> message; // Each text element is given default text, in case it's empty // 1) it looks nicer // 2) it makes empty entries the same height as filled entries // -> uniform-height entries are more performant in a ListView VerticalBox { spacing: 5px; msg-text := Text { text: message == "" ? "(no message)" : "\{root.message}"; overflow: elide; font-italic: message == ""; } author-text := Text { text: author == "" ? "(no author)" : "\{root.author}"; overflow: elide; font-italic: true; } } in-out property <bool> is-selected: false; in property <bool> has-hover; states [ selected when root.is-selected: { root.background: Palette.selection-background; msg-text.color: Palette.selection-foreground; author-text.color: Palette.selection-foreground; } lowlighted when root.has-hover: { root.background: Palette.alternate-background; msg-text.color: Palette.alternate-foreground; author-text.color: Palette.alternate-foreground; } ] } component Changelog inherits Rectangle { in-out property <int> count-files-changed; in-out property <[ChangeData]> changes_log: []; in-out property <int> selected: -2; public function deselect() { root.selected = -1; } callback selection-changed(/*new selection*/ int); VerticalBox { Text { vertical-stretch: 0; text: "log"; } diff-entry := DiffEntry { files-count: count-files-changed; is-selected: root.selected == -1; has-hover: touch0.has-hover; touch0 := TouchArea { clicked => { root.selected = -1; root.selection-changed(-1); } } } // TODO convert to a StandardListView? ListView { // preferred-width: 400px; for change[index] in root.changes_log: ce := ChangeEntry { hash: change.hash; author: change.author; timestamp: change.timestamp; message: change.message; is-selected: root.selected == index; has-hover: touch.has-hover; touch := TouchArea { clicked => { root.selected = index; root.selection-changed(index); } } } } } } component ChannelsList { in-out property <[string]> channels; in-out property <int> active; VerticalBox { alignment: start; spacing: 0; preferred-width: 150px; Text { text: "channels"; for ch in channels: Text { text: "\{ch}"; } } } } component ChannelEntry inherits Rectangle { in property <string> name; in property <bool> active; HorizontalBox { alignment: start; spacing: 5px; padding: 0; active-marker := Rectangle { width: 10px; height: 100%; border-radius: 5px; visible: root.active; background: Palette.accent-background; } label-backdrop := Rectangle { label := Text { text: "\{name}"; } } } in property <bool> is-selected: false; in property <bool> has-hover: false; states [ selected when is-selected: { label-backdrop.background: Palette.selection-background; label.color: Palette.selection-foreground; } lowlighted when has-hover: { label-backdrop.background: Palette.alternate-background; label.color: Palette.alternate-foreground; } off when true: { label-backdrop.background: Palette.background; label.color: Palette.foreground; } ] } component ChannelsList { in-out property <ChannelsData> data; in-out property <int> selected: -1; public function deselect() { root.selected = -1; } callback selection-changed(/*new selection*/ int); VerticalBox { Text { vertical-stretch: 0; text: "channels"; } // TODO convert to a StandardListView? ListView { for ch[index] in data.names: ChannelEntry { name: ch; active: data.active == index; is-selected: selected == index; has-hover: touch.has-hover; touch := TouchArea { clicked => { root.selected = index; root.selection-changed(index); } } } } } } export component AppWindow inherits Window { in-out property <[string]> channels <=> chs.channels; in-out property <int> active-channel <=> chs.active; preferred-width: 960px; preferred-height: 720px; in property <string> exe_path; in property <string> repo_path; in-out property <ChannelsData> channels <=> chs.data; in-out property <[ChangeData]> changes_log <=> log.changes_log; in-out property <int> count-files-changed <=> log.count-files-changed; in-out property <string> delta <=> deltas.delta; callback request-channel-list(); callback request-change-delta(string); callback request-diff-summary(string); callback request-diff-delta(string); function fill-chs() { chs.deselect(); root.request-channel-list(); } function fill-log() { log.deselect(); root.request-changes-log(chs.data.names[chs.selected]); root.request-diff-summary(chs.data.names[chs.selected]); } function fill-diff-view() { if log.selected >= 0 && log.selected < log.changes_log.length { } else { } } VerticalBox { Button { vertical-stretch: 0; text: "Refresh"; clicked => { fill-chs(); fill-log(); fill-diff-view(); } } HorizontalBox { vertical-stretch: 1; chs := ChannelsList { channels: []; active: 0; preferred-width: 500px; chs := ChannelsList { horizontal-stretch: 0; selection-changed => { fill-log(); fill-diff-view(); } } log := Changelog { horizontal-stretch: 2; selection-changed => { fill-diff-view(); } } deltas := DeltasList { horizontal-stretch: 3; } } } }