514 lines
20 KiB
Plaintext
514 lines
20 KiB
Plaintext
import { ScrollView, Button } from "std-widgets.slint";
|
|
import { Data, LoginOptionTileData } from "data.slint";
|
|
import { LoginOptionTile } from "envtile.slint";
|
|
|
|
import { LineEdit } from "widgets/fluent/lineedit.slint";
|
|
|
|
import { IconButton } from "iconbutton.slint";
|
|
|
|
export { Data as GreeterData } from "data.slint";
|
|
|
|
export component GreeterDisplay inherits Window {
|
|
default-font-size: root.width < root.height ? root.width * 0.01 : root.height * 0.01;
|
|
|
|
in-out property <int> selected_index <=> Data.selected_index;
|
|
|
|
in-out property <int> error_count <=> Data.error_count;
|
|
|
|
in-out property <string> error_content <=> error_popup.content;
|
|
|
|
in property <[LoginOptionTileData]> tiles;
|
|
in property <string> default_username;
|
|
|
|
out property <bool> background-toggle;
|
|
|
|
public function set_error(message: string) {
|
|
error_popup.content = message;
|
|
error_count += 1;
|
|
error_popup.opacity = 1.0;
|
|
error_popup_timer.start();
|
|
error_popup_timer.restart();
|
|
}
|
|
|
|
public function switch_background() {
|
|
background-toggle = !background-toggle;
|
|
background_timer.start();
|
|
clear_inactive_wallpaper_timer.start();
|
|
background_timer.restart();
|
|
clear_inactive_wallpaper_timer.restart();
|
|
}
|
|
|
|
full-screen: true;
|
|
min-width: 640px;
|
|
min-height: 480px;
|
|
|
|
TouchArea {
|
|
clicked => {
|
|
confirm_prompt.visible = false;
|
|
}
|
|
|
|
backdrop := Rectangle { // Almost black backdrop, in case background can't load
|
|
background: rgba(20, 20, 40);
|
|
z: -3;
|
|
}
|
|
|
|
background := Image { // Image background
|
|
z: -2;
|
|
animate opacity {
|
|
duration: 1000ms;
|
|
easing: ease-in-out;
|
|
}
|
|
|
|
source: Data.wallpaper-image;
|
|
image-fit: ImageFit.cover;
|
|
|
|
width: parent.width;
|
|
height: parent.height;
|
|
|
|
opacity: background-toggle && self.source.width > 0 ? 1.0 : 0.0;
|
|
background_timer := Timer {
|
|
interval: Data.wallpaper-cooldown * 1s;
|
|
running: true;
|
|
triggered() => {
|
|
Data.get-new-wallpaper();
|
|
self.running = false;
|
|
}
|
|
}
|
|
|
|
clear_inactive_wallpaper_timer := Timer {
|
|
interval: 1200ms;
|
|
running: false;
|
|
triggered() => {
|
|
Data.clear-inactive-wallpaper();
|
|
self.running = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
background_1 := Image { // Background (secondary), needed for smooth opacity transitions
|
|
z: -2;
|
|
animate opacity {
|
|
duration: 1000ms;
|
|
easing: ease-in-out;
|
|
}
|
|
|
|
source: Data.wallpaper-image-1;
|
|
image-fit: ImageFit.cover;
|
|
|
|
width: parent.width;
|
|
height: parent.height;
|
|
|
|
opacity: !background-toggle && self.source.width > 0 ? 1.0 : 0.0;
|
|
}
|
|
|
|
background_overlay := Rectangle { // Background overlay
|
|
background: rgba(0, 0, 0, 0.5);
|
|
opacity: background.opacity > 0 || background_1.opacity > 0 ? 1.0 : 0.0;
|
|
z: -1;
|
|
}
|
|
|
|
image_info := Rectangle {
|
|
opacity: 0.6;
|
|
x: 1rem;
|
|
y: root.height - 7.5rem;
|
|
height: 6.5rem;
|
|
width: parent.width * 0.33;
|
|
|
|
private property <bool> show_extended;
|
|
VerticalLayout {
|
|
alignment: end;
|
|
spacing: 1rem;
|
|
img_link_info := HorizontalLayout {
|
|
visible: show_extended;
|
|
spacing: 0.5rem;
|
|
|
|
Image {
|
|
source: @image-url("icons/link.svg");
|
|
height: 1.25rem;
|
|
width: 1.25rem;
|
|
}
|
|
|
|
Text {
|
|
text: Data.wallpaper-url;
|
|
font-size: 1.25rem;
|
|
font-family: "monospace";
|
|
color: rgba(240, 240, 240, 1);
|
|
}
|
|
}
|
|
|
|
img_text_info := HorizontalLayout {
|
|
visible: show_extended;
|
|
spacing: 0.5rem;
|
|
|
|
Image {
|
|
source: @image-url("icons/text.svg");
|
|
height: 1.25rem;
|
|
width: 1.25rem;
|
|
}
|
|
|
|
Text {
|
|
text: Data.wallpaper-alt;
|
|
font-size: 1.25rem;
|
|
font-family: "monospace";
|
|
color: rgba(240, 240, 240, 1);
|
|
}
|
|
}
|
|
|
|
img_author_info := HorizontalLayout {
|
|
visible: true;
|
|
spacing: 0.5rem;
|
|
|
|
Image {
|
|
source: @image-url("icons/person.svg");
|
|
height: 1.25rem;
|
|
width: 1.25rem;
|
|
}
|
|
|
|
Text {
|
|
text: Data.wallpaper-author;
|
|
font-size: 1.25rem;
|
|
font-family: "monospace";
|
|
color: Data.wallpaper-author == "Error" ? rgba(255, 0, 0, 1) : rgba(240, 240, 240, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
TouchArea {
|
|
height: parent.height;
|
|
width: parent.width;
|
|
clicked => {
|
|
show_extended = !show_extended
|
|
}
|
|
}
|
|
}
|
|
|
|
login_manager_underlay := Rectangle {
|
|
background: rgba(0, 0, 0, 0.5);
|
|
drop-shadow-blur: 4rem;
|
|
height: parent.height;
|
|
z: -1;
|
|
width: max(parent.width * 0.33, 640px);
|
|
|
|
VerticalLayout {
|
|
height: parent.height;
|
|
width: parent.width;
|
|
|
|
clock := VerticalLayout {
|
|
alignment: center;
|
|
height: parent.height * 0.15;
|
|
HorizontalLayout {
|
|
width: parent.width;
|
|
alignment: center;
|
|
Rectangle {
|
|
y: 10rem;
|
|
|
|
width: 32rem;
|
|
height: 12rem;
|
|
|
|
VerticalLayout {
|
|
padding-top: 1rem;
|
|
Rectangle {
|
|
Text {
|
|
x: time_text.x - 0.1rem; // Offset
|
|
y: time_text.y + 0.1rem; // Offset
|
|
text: Data.current-time;
|
|
font-size: 6.4rem;
|
|
horizontal-alignment: center;
|
|
color: rgba(0, 0, 0, 1);
|
|
}
|
|
time_text := Text {
|
|
text: Data.current-time;
|
|
font-size: 6.4rem;
|
|
horizontal-alignment: center;
|
|
}
|
|
}
|
|
Rectangle {
|
|
Text {
|
|
x: date_text.x - 0.1rem; // Offset
|
|
y: date_text.y + 0.1rem; // Offset
|
|
text: date_text.text;
|
|
font-size: date_text.font-size;
|
|
horizontal-alignment: date_text.horizontal-alignment;
|
|
color: rgba(0, 0, 0, 1);
|
|
}
|
|
date_text := Text {
|
|
text: Data.current-date;
|
|
font-size: 1.6rem;
|
|
horizontal-alignment: center;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
login_model := VerticalLayout {
|
|
alignment: center;
|
|
height: parent.height * 0.70;
|
|
width: parent.width;
|
|
|
|
spacing: 1rem;
|
|
|
|
init_timer := Timer {
|
|
interval: 0s;
|
|
running: true;
|
|
triggered => {
|
|
if (!Data.has-default-username) {
|
|
username_box.focus();
|
|
} else {
|
|
password_box.focus();
|
|
}
|
|
self.running = false;
|
|
}
|
|
}
|
|
|
|
environment_selector := FocusScope {
|
|
height: max(parent.width * 0.2, parent.height * 0.2);
|
|
width: parent.width;
|
|
key-pressed(event) => {
|
|
if (event.text == Key.LeftArrow || event.text == "a" || event.text == "A") {
|
|
if (Data.selected_index == 0) {
|
|
Data.selected_index = tiles.length - 1;
|
|
} else {
|
|
Data.selected_index -= 1;
|
|
}
|
|
accept
|
|
} else if (event.text == Key.RightArrow || event.text == "d" || event.text == "D") {
|
|
if (Data.selected_index + 1 == tiles.length) {
|
|
Data.selected_index = 0;
|
|
} else {
|
|
Data.selected_index += 1;
|
|
}
|
|
accept
|
|
}
|
|
reject
|
|
}
|
|
|
|
scroll_view := ScrollView {
|
|
height: parent.height;
|
|
width: min(((self.height + 1rem) * tiles.length) - 1rem, parent.width);
|
|
|
|
animate viewport-x { duration: 250ms; }
|
|
|
|
viewport-width: ((self.height + 1rem) * tiles.length) - 1rem;
|
|
// viewport-x: -(Data.selected_index * self.height) + (self.height / 2);
|
|
viewport-x: (self.viewport-width - self.height) / 2 - (Data.selected_index * (self.height));
|
|
|
|
//x: self.viewport-width < self.width ? ((self.width - self.viewport-width) / 2) : 0;
|
|
|
|
scroll_layout := HorizontalLayout {
|
|
height: parent.height;
|
|
for tile[i] in tiles: LoginOptionTile {
|
|
width: parent.height;
|
|
height: parent.height;
|
|
icon: tile.image;
|
|
label: tile.name;
|
|
index: i;
|
|
has_focus: environment_selector.has-focus;
|
|
on_click => {
|
|
Data.selected_index = self.index;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Username field
|
|
HorizontalLayout {
|
|
width: parent.width;
|
|
height: 2.5rem;
|
|
alignment: center;
|
|
username_box := LineEdit {
|
|
font-size: 2rem;
|
|
font-family: "monospace";
|
|
width: parent.width * 0.45;
|
|
placeholder-text: "Username";
|
|
text: default_username;
|
|
border-color: rgba(185, 15, 220, 0.85);
|
|
|
|
on-focus-change => {
|
|
Data.check-lock-states()
|
|
}
|
|
key-released => {
|
|
Data.check-lock-states();
|
|
return EventResult.accept;
|
|
}
|
|
accepted(text) => {
|
|
Data.login(username_box.text, password_box.text)
|
|
}
|
|
}
|
|
}
|
|
// Password field
|
|
HorizontalLayout {
|
|
width: parent.width;
|
|
height: 2.5rem;
|
|
alignment: center;
|
|
password_box := LineEdit {
|
|
font-size: 2rem;
|
|
font-family: "monospace";
|
|
width: parent.width * 0.45;
|
|
placeholder-text: "Password";
|
|
input-type: password;
|
|
border-color: rgba(185, 15, 220, 0.85);
|
|
on-focus-change => {
|
|
Data.check-lock-states()
|
|
}
|
|
key-released => {
|
|
Data.check-lock-states();
|
|
return EventResult.accept;
|
|
}
|
|
accepted(text) => {
|
|
Data.login(username_box.text, password_box.text)
|
|
}
|
|
}
|
|
}
|
|
// Submit button
|
|
HorizontalLayout {
|
|
width: parent.width;
|
|
height: 2.5rem;
|
|
alignment: center;
|
|
IconButton {
|
|
width: parent.width * 0.45; //min(parent.width * 0.85, 32rem);
|
|
icon: @image-url("icons/right_arrow.svg");
|
|
icon-width: 4rem;
|
|
icon-height: self.icon-width/3;
|
|
icon-align: LayoutAlignment.end;
|
|
text: "Login";
|
|
font-size: 1.5rem;
|
|
clicked => {
|
|
Data.login(username_box.text, password_box.text);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
power_model := VerticalLayout {
|
|
height: parent.height * 0.15;
|
|
width: parent.width;
|
|
|
|
confirm_prompt := Text {
|
|
horizontal-alignment: center;
|
|
font-size: 1.5rem;
|
|
text: "Press again to confirm ";
|
|
visible: false;
|
|
vertical-alignment: bottom;
|
|
|
|
confirm_prompt_timer := Timer {
|
|
interval: 5s;
|
|
running: false;
|
|
triggered() => {
|
|
confirm_prompt.visible = false;
|
|
self.running = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
HorizontalLayout {
|
|
width: parent.width;
|
|
alignment: center;
|
|
|
|
Rectangle {
|
|
background: rgba(0, 0, 0, 0.6);
|
|
border-top-left-radius: 4px;
|
|
border-top-right-radius: 4px;
|
|
|
|
width: 16.3rem;
|
|
height: 5.8rem;
|
|
// Power action buttons
|
|
HorizontalLayout {
|
|
private property <string> lastaction;
|
|
|
|
padding-top: 0.4rem;
|
|
width: parent.width;
|
|
alignment: center;
|
|
spacing: 0.5rem;
|
|
|
|
function power_action(action: string, command: string) {
|
|
if (lastaction != action || confirm_prompt.visible == false) {
|
|
lastaction = action;
|
|
confirm_prompt.text = "Press again to confirm " + action;
|
|
confirm_prompt.visible = true;
|
|
confirm_prompt_timer.start();
|
|
confirm_prompt_timer.restart();
|
|
} else {
|
|
if (lastaction == action) {
|
|
Data.loginctl(command)
|
|
} else {
|
|
confirm_prompt.visible = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
IconButton {
|
|
width: 4.8rem;
|
|
height: 4.8rem;
|
|
icon: @image-url("icons/power.svg");
|
|
icon-width: self.width * 0.5;
|
|
icon-height: self.width * 0.5;
|
|
clicked => {
|
|
power_action("poweroff", "poweroff")
|
|
}
|
|
}
|
|
|
|
IconButton {
|
|
width: 4.8rem;
|
|
height: 4.8rem;
|
|
icon: @image-url("icons/restart.svg");
|
|
icon-width: self.width * 0.5;
|
|
icon-height: self.width * 0.5;
|
|
clicked => {
|
|
power_action("restart", "reboot")
|
|
}
|
|
}
|
|
|
|
IconButton {
|
|
width: 4.8rem;
|
|
height: 4.8rem;
|
|
icon: @image-url("icons/sleep.svg");
|
|
icon-width: self.width * 0.5;
|
|
icon-height: self.width * 0.5;
|
|
clicked => {
|
|
power_action("sleep", "suspend")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
error_popup := Rectangle {
|
|
background: rgba(220, 50, 50, 0.85);
|
|
width: min(parent.width * 0.5, 64rem);
|
|
height: max(parent.height * 0.125, 6rem);
|
|
y: (parent.height * 0.025);
|
|
|
|
opacity: 0.0;
|
|
|
|
animate opacity { duration: 250ms; }
|
|
|
|
in-out property <string> content;
|
|
|
|
Text {
|
|
color: rgba(240, 240, 240, 1);
|
|
width: parent.width * 0.85;
|
|
height: parent.height * 0.85;
|
|
vertical-alignment: center;
|
|
horizontal-alignment: center;
|
|
|
|
font-family: "monospace";
|
|
font-size: max(1rem, scroll_view.height * 0.125);
|
|
|
|
text: "[" + Data.error_count + "] " + content;
|
|
}
|
|
}
|
|
|
|
error_popup_timer := Timer {
|
|
interval: 5s;
|
|
running: false;
|
|
triggered() => {
|
|
error_popup.opacity = 0.0;
|
|
self.running = false;
|
|
}
|
|
}
|
|
}
|
|
}
|