window: Support undo

This commit is contained in:
Jamie Gravendeel
2025-12-05 14:19:35 +01:00
parent c1e3c987c1
commit f1a59d402d
5 changed files with 264 additions and 180 deletions

View File

@@ -20,6 +20,11 @@ template $Window: Adw.ApplicationWindow {
action: "action(win.add)";
}
Shortcut {
trigger: "<Control>z";
action: "action(win.undo)";
}
Shortcut {
trigger: "<Control>w";
action: "action(window.close)";
@@ -34,189 +39,191 @@ template $Window: Adw.ApplicationWindow {
"view",
]
child: Adw.ToolbarView {
[top]
Adw.HeaderBar {
title-widget: Adw.Clamp clamp {
tightening-threshold: bind clamp.maximum-size;
child: Adw.ToastOverlay toast_overlay {
child: Adw.ToolbarView {
[top]
Adw.HeaderBar {
title-widget: Adw.Clamp clamp {
tightening-threshold: bind clamp.maximum-size;
child: CenterBox {
hexpand: true;
center-widget: SearchEntry search_entry {
child: CenterBox {
hexpand: true;
placeholder-text: _("Search games");
search-started => $_search_started();
search-changed => $_search_changed();
activate => $_search_activate();
stop-search => $_stop_search();
};
end-widget: MenuButton {
icon-name: "filter-symbolic";
tooltip-text: _("Sort & Filter");
margin-start: 6;
menu-model: menu {
section {
label: _("Sort");
item {
label: _("Last Played");
action: "win.sort-mode";
target: "last_played";
}
item {
label: _("A-Z");
action: "win.sort-mode";
target: "a-z";
}
item {
label: _("Z-A");
action: "win.sort-mode";
target: "z-a";
}
item {
label: _("Newest");
action: "win.sort-mode";
target: "newest";
}
item {
label: _("Oldest");
action: "win.sort-mode";
target: "oldest";
}
}
section {
item (_("Show Hidden Games"), "win.show-hidden")
}
center-widget: SearchEntry search_entry {
hexpand: true;
placeholder-text: _("Search games");
search-started => $_search_started();
search-changed => $_search_changed();
activate => $_search_activate();
stop-search => $_stop_search();
};
};
};
};
[start]
Button {
icon-name: "list-add-symbolic";
tooltip-text: _("Add Game");
action-name: "win.add";
}
end-widget: MenuButton {
icon-name: "filter-symbolic";
tooltip-text: _("Sort & Filter");
margin-start: 6;
[end]
MenuButton {
icon-name: "open-menu-symbolic";
tooltip-text: _("Main Menu");
primary: true;
menu-model: menu {
section {
label: _("Sort");
menu-model: menu {
item (_("Keyboard Shortcuts"), "app.shortcuts")
item (_("About Cartridges"), "app.about")
};
}
}
item {
label: _("Last Played");
action: "win.sort-mode";
target: "last_played";
}
content: Adw.ViewStack {
enable-transitions: true;
visible-child-name: bind $_if_else(grid.model as <NoSelection>.n-items, "grid", $_if_else(template.search-text, "empty-search", $_if_else(template.show-hidden, "empty-hidden", "empty") as <string>) as <string>) as <string>;
item {
label: _("A-Z");
action: "win.sort-mode";
target: "a-z";
}
Adw.ViewStackPage {
name: "grid";
item {
label: _("Z-A");
action: "win.sort-mode";
target: "z-a";
}
child: ScrolledWindow {
hscrollbar-policy: never;
item {
label: _("Newest");
action: "win.sort-mode";
target: "newest";
}
child: GridView grid {
name: "grid";
single-click-activate: true;
activate => $_show_details();
item {
label: _("Oldest");
action: "win.sort-mode";
target: "oldest";
}
}
model: NoSelection {
model: SortListModel {
sorter: $GameSorter sorter {};
model: FilterListModel {
watch-items: true;
filter: EveryFilter {
AnyFilter {
StringFilter {
expression: expr item as <$Game>.name;
search: bind template.search-text;
}
StringFilter {
expression: expr item as <$Game>.developer;
search: bind template.search-text;
}
}
BoolFilter {
expression: expr item as <$Game>.hidden;
invert: bind template.show-hidden inverted;
}
BoolFilter {
expression: expr item as <$Game>.removed;
invert: true;
}
BoolFilter {
expression: expr item as <$Game>.blacklisted;
invert: true;
}
};
model: bind template.games;
};
section {
item (_("Show Hidden Games"), "win.show-hidden")
}
};
};
factory: BuilderListItemFactory {
template ListItem {
child: $GameItem {
game: bind template.item;
position: bind template.position;
};
}
};
};
};
[start]
Button {
icon-name: "list-add-symbolic";
tooltip-text: _("Add Game");
action-name: "win.add";
}
[end]
MenuButton {
icon-name: "open-menu-symbolic";
tooltip-text: _("Main Menu");
primary: true;
menu-model: menu {
item (_("Keyboard Shortcuts"), "app.shortcuts")
item (_("About Cartridges"), "app.about")
};
}
}
Adw.ViewStackPage {
name: "empty-search";
content: Adw.ViewStack {
enable-transitions: true;
visible-child-name: bind $_if_else(grid.model as <NoSelection>.n-items, "grid", $_if_else(template.search-text, "empty-search", $_if_else(template.show-hidden, "empty-hidden", "empty") as <string>) as <string>) as <string>;
child: Adw.StatusPage {
icon-name: "edit-find-symbolic";
title: _("No Games Found");
description: _("Try a different search");
};
}
Adw.ViewStackPage {
name: "grid";
Adw.ViewStackPage {
name: "empty-hidden";
child: ScrolledWindow {
hscrollbar-policy: never;
child: Adw.StatusPage {
icon-name: "view-conceal-symbolic";
title: _("No Hidden Games");
description: _("Games you hide will appear here");
};
}
child: GridView grid {
name: "grid";
single-click-activate: true;
activate => $_show_details();
Adw.ViewStackPage {
name: "empty";
model: NoSelection {
model: SortListModel {
sorter: $GameSorter sorter {};
child: Adw.StatusPage {
icon-name: bind template.application as <Application>.application-id;
title: _("No Games");
description: _("Use the + button to add games");
};
}
model: FilterListModel {
watch-items: true;
filter: EveryFilter {
AnyFilter {
StringFilter {
expression: expr item as <$Game>.name;
search: bind template.search-text;
}
StringFilter {
expression: expr item as <$Game>.developer;
search: bind template.search-text;
}
}
BoolFilter {
expression: expr item as <$Game>.hidden;
invert: bind template.show-hidden inverted;
}
BoolFilter {
expression: expr item as <$Game>.removed;
invert: true;
}
BoolFilter {
expression: expr item as <$Game>.blacklisted;
invert: true;
}
};
model: bind template.games;
};
};
};
factory: BuilderListItemFactory {
template ListItem {
child: $GameItem {
game: bind template.item;
position: bind template.position;
};
}
};
};
};
}
Adw.ViewStackPage {
name: "empty-search";
child: Adw.StatusPage {
icon-name: "edit-find-symbolic";
title: _("No Games Found");
description: _("Try a different search");
};
}
Adw.ViewStackPage {
name: "empty-hidden";
child: Adw.StatusPage {
icon-name: "view-conceal-symbolic";
title: _("No Hidden Games");
description: _("Games you hide will appear here");
};
}
Adw.ViewStackPage {
name: "empty";
child: Adw.StatusPage {
icon-name: bind template.application as <Application>.application-id;
title: _("No Games");
description: _("Use the + button to add games");
};
}
};
};
};
}