Update Pexels and fix binding loops

This commit is contained in:
CanadianBaconBoi 2026-05-08 23:30:01 +02:00
parent 4c7bd2694f
commit 48c493c4f5
4 changed files with 68 additions and 63 deletions

View File

@ -5,7 +5,6 @@ build = "build.rs"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
#slint = { version = "1.16.1", default-features = false, features = [
slint = { git = "https://github.com/slint-ui/slint", branch = "master", default-features = false, features = [ slint = { git = "https://github.com/slint-ui/slint", branch = "master", default-features = false, features = [
"std", "std",
"compat-1-2", "compat-1-2",
@ -20,7 +19,7 @@ greetd_ipc = { version = "0.10.3", features = [
"tokio-codec", "tokio-codec",
] } ] }
i-slint-core = { git = "https://github.com/slint-ui/slint", branch = "master" } i-slint-core = { git = "https://github.com/slint-ui/slint", branch = "master" }
toml = { version = "1.1.2+spec-1.1.0", features = ["serde"] } toml = { version = "1.1.2", features = ["serde"] }
serde = { version = "1.0.228", features = ["derive"] } serde = { version = "1.0.228", features = ["derive"] }
serde-aux = "4.7.0" serde-aux = "4.7.0"
zbus = { version = "5.15.0", features = ["blocking"] } zbus = { version = "5.15.0", features = ["blocking"] }
@ -29,11 +28,11 @@ tokio-stream = {version = "0.1.18", features = ["fs"]}
greetd-stub = "0.3.0" greetd-stub = "0.3.0"
chrono = "0.4.44" chrono = "0.4.44"
pexels-api = "0.0.5" pexels-api = { git = "https://github.com/houseme/pexels", rev = "b0b692a" }
reqwest = { version = "0.13.3", features = ["json", "default-tls"] } reqwest = { version = "0.13.3", features = ["json", "default-tls"] }
magick_rust = "2.0.0" magick_rust = "2.0.0"
rand = "0.9.4"
[build-dependencies] [build-dependencies]
#slint-build = "1.16.1"
slint-build = { git = "https://github.com/slint-ui/slint", branch = "master" } slint-build = { git = "https://github.com/slint-ui/slint", branch = "master" }

View File

@ -8,7 +8,8 @@ use greetd_ipc::codec::TokioCodec;
use i_slint_core::api::{ComponentHandle, Global, Image, Rgba8Pixel, SharedPixelBuffer, Weak}; use i_slint_core::api::{ComponentHandle, Global, Image, Rgba8Pixel, SharedPixelBuffer, Weak};
use i_slint_core::model::{Model, VecModel}; use i_slint_core::model::{Model, VecModel};
use magick_rust::MagickWand; use magick_rust::MagickWand;
use pexels_api::{Pexels, SearchBuilder}; use pexels_api::{PexelsClient, SearchParams};
use rand::seq::SliceRandom;
use tokio::fs::File; use tokio::fs::File;
use tokio::io::{AsyncBufReadExt, BufReader, Lines}; use tokio::io::{AsyncBufReadExt, BufReader, Lines};
use tokio::net::UnixStream; use tokio::net::UnixStream;
@ -273,7 +274,6 @@ pub fn register_wallpaper_callback(data: &GreeterData, display_weak: Weak<Greete
let reqwest_client = match reqwest::ClientBuilder::new() let reqwest_client = match reqwest::ClientBuilder::new()
.tls_backend_rustls() .tls_backend_rustls()
// .timeout(std::time::Duration::from_secs(60))
.http2_prior_knowledge() .http2_prior_knowledge()
.http2_keep_alive_timeout(std::time::Duration::from_secs(10)) .http2_keep_alive_timeout(std::time::Duration::from_secs(10))
.build() { .build() {
@ -285,7 +285,7 @@ pub fn register_wallpaper_callback(data: &GreeterData, display_weak: Weak<Greete
}; };
if let Some(pexels_api_key) = config.pexels_api_key.clone() { if let Some(pexels_api_key) = config.pexels_api_key.clone() {
let pexels_client = Arc::new(Pexels::new(pexels_api_key)); let pexels_client = Arc::new(PexelsClient::new(pexels_api_key));
let pexels_query = config let pexels_query = config
.pexels_query .pexels_query
.clone() .clone()
@ -326,18 +326,15 @@ pub fn register_wallpaper_callback(data: &GreeterData, display_weak: Weak<Greete
} }
drop(file_lines); drop(file_lines);
match tokio::time::timeout( match pexels_client
std::time::Duration::from_secs(30), .search_photos(
pexels_client pexels_query.as_str(),
.search_photos( &SearchParams::new()
SearchBuilder::new() .page(1)
.query(pexels_query.as_str()) .per_page(11)
.page(1) .size(pexels_api::Size::Medium)
.per_page(11) .orientation(pexels_api::Orientation::Landscape)
.size(pexels_api::Size::Medium) ).await
.orientation(pexels_api::Orientation::Landscape),
)
).await?
{ {
Ok(photos) => { Ok(photos) => {
if photos.total_results > 0 { if photos.total_results > 0 {
@ -399,7 +396,7 @@ pub fn register_wallpaper_callback(data: &GreeterData, display_weak: Weak<Greete
drop(pixels); drop(pixels);
data.set_wallpaper_author(photo.photographer.into()); data.set_wallpaper_author(photo.photographer.into());
data.set_wallpaper_alt(photo.alt.into()); data.set_wallpaper_alt(photo.alt.unwrap_or("".into()).into());
data.set_wallpaper_url(photo.url.into()); data.set_wallpaper_url(photo.url.into());
display.invoke_switch_background(); display.invoke_switch_background();
@ -424,7 +421,7 @@ pub fn register_wallpaper_callback(data: &GreeterData, display_weak: Weak<Greete
drop(pixels); drop(pixels);
data.set_wallpaper_author(photo.photographer.into()); data.set_wallpaper_author(photo.photographer.into());
data.set_wallpaper_alt(photo.alt.into()); data.set_wallpaper_alt(photo.alt.unwrap_or("".into()).into());
data.set_wallpaper_url(photo.url.into()); data.set_wallpaper_url(photo.url.into());
display.invoke_switch_background(); display.invoke_switch_background();
@ -449,7 +446,11 @@ pub fn register_wallpaper_callback(data: &GreeterData, display_weak: Weak<Greete
== Some(std::ffi::OsStr::new("png")) == Some(std::ffi::OsStr::new("png"))
} }
Err(_) => false, Err(_) => false,
}); }).collect::<Vec<_>>().await;
photos.shuffle(&mut rand::rng());
let mut photos = tokio_stream::iter(photos);
while let Some(photo) = photos.next().await { while let Some(photo) = photos.next().await {
match photo { match photo {
@ -552,6 +553,13 @@ pub fn register_clean_inactive_wallpaper_callback(data: &GreeterData, display_we
} }
}) })
} }
pub fn register_get_default_font_size(data: &GreeterData, display_weak: Weak<GreeterDisplay>) {
data.on_get_default_font_size(move || {
let display = display_weak.unwrap();
let size = display.window().size();
((size.width as f32).min(size.height as f32)) * 0.01
});
}
pub fn register_callbacks( pub fn register_callbacks(
display: &GreeterDisplay, display: &GreeterDisplay,
@ -568,4 +576,5 @@ pub fn register_callbacks(
register_lock_state_callback(data, data_weak.clone()); register_lock_state_callback(data, data_weak.clone());
register_wallpaper_callback(data, display_weak.clone(), data_weak.clone(), cache_dir, config); register_wallpaper_callback(data, display_weak.clone(), data_weak.clone(), cache_dir, config);
register_clean_inactive_wallpaper_callback(data, display_weak.clone(), data_weak.clone()); register_clean_inactive_wallpaper_callback(data, display_weak.clone(), data_weak.clone());
register_get_default_font_size(data, display_weak.clone());
} }

View File

@ -5,6 +5,8 @@ export global Data {
in-out property <int> error_count; in-out property <int> error_count;
pure callback get-default-font-size() -> length;
callback login(username: string, password: string); callback login(username: string, password: string);
callback loginctl(command: string); callback loginctl(command: string);
callback check-lock-states(); callback check-lock-states();

View File

@ -1,4 +1,4 @@
import { ScrollView, Button } from "std-widgets.slint"; import { ScrollView, Button, TabWidget } from "std-widgets.slint";
import { Data, LoginOptionTileData } from "data.slint"; import { Data, LoginOptionTileData } from "data.slint";
import { LoginOptionTile } from "envtile.slint"; import { LoginOptionTile } from "envtile.slint";
@ -9,7 +9,19 @@ import { IconButton } from "iconbutton.slint";
export { Data as GreeterData } from "data.slint"; export { Data as GreeterData } from "data.slint";
export component GreeterDisplay inherits Window { export component GreeterDisplay inherits Window {
default-font-size: root.width < root.height ? root.width * 0.01 : root.height * 0.01; changed width => {
self.default-font-size = Data.get-default-font-size();
login_manager_underlay.width = max(self.width * 0.33, 640px);
login_manager_underlay.height = self.height;
}
changed height => {
self.default-font-size = Data.get-default-font-size();
login_manager_underlay.width = max(self.width * 0.33, 640px);
login_manager_underlay.height = self.height;
}
default-font-size: Data.get-default-font-size();
in-out property <int> selected_index <=> Data.selected_index; in-out property <int> selected_index <=> Data.selected_index;
@ -39,6 +51,8 @@ export component GreeterDisplay inherits Window {
} }
full-screen: true; full-screen: true;
preferred-width: 1920px;
preferred-height: 1080px;
min-width: 640px; min-width: 640px;
min-height: 480px; min-height: 480px;
@ -62,9 +76,6 @@ export component GreeterDisplay inherits Window {
source: Data.wallpaper-image; source: Data.wallpaper-image;
image-fit: ImageFit.cover; image-fit: ImageFit.cover;
width: parent.width;
height: parent.height;
opacity: background-toggle && self.source.width > 0 ? 1.0 : 0.0; opacity: background-toggle && self.source.width > 0 ? 1.0 : 0.0;
background_timer := Timer { background_timer := Timer {
interval: Data.wallpaper-cooldown * 1s; interval: Data.wallpaper-cooldown * 1s;
@ -95,9 +106,6 @@ export component GreeterDisplay inherits Window {
source: Data.wallpaper-image-1; source: Data.wallpaper-image-1;
image-fit: ImageFit.cover; image-fit: ImageFit.cover;
width: parent.width;
height: parent.height;
opacity: !background-toggle && self.source.width > 0 ? 1.0 : 0.0; opacity: !background-toggle && self.source.width > 0 ? 1.0 : 0.0;
} }
@ -112,7 +120,7 @@ export component GreeterDisplay inherits Window {
x: 1rem; x: 1rem;
y: root.height - 7.5rem; y: root.height - 7.5rem;
height: 6.5rem; height: 6.5rem;
width: parent.width * 0.33; width: 33%;
private property <bool> show_extended; private property <bool> show_extended;
VerticalLayout { VerticalLayout {
@ -174,8 +182,6 @@ export component GreeterDisplay inherits Window {
} }
TouchArea { TouchArea {
height: parent.height;
width: parent.width;
clicked => { clicked => {
show_extended = !show_extended show_extended = !show_extended
} }
@ -185,19 +191,21 @@ export component GreeterDisplay inherits Window {
login_manager_underlay := Rectangle { login_manager_underlay := Rectangle {
background: rgba(0, 0, 0, 0.5); background: rgba(0, 0, 0, 0.5);
drop-shadow-blur: 4rem; drop-shadow-blur: 4rem;
height: parent.height; height: 0px;
width: 0px;
animate width {
duration: 500ms;
easing: ease-in-sine;
}
z: -1; z: -1;
width: max(parent.width * 0.33, 640px);
VerticalLayout { VerticalLayout {
height: parent.height;
width: parent.width;
clock := VerticalLayout { clock := VerticalLayout {
alignment: center; alignment: center;
height: parent.height * 0.15; height: 15%;
HorizontalLayout { HorizontalLayout {
width: parent.width;
alignment: center; alignment: center;
Rectangle { Rectangle {
y: 10rem; y: 10rem;
@ -243,8 +251,7 @@ export component GreeterDisplay inherits Window {
} }
login_model := VerticalLayout { login_model := VerticalLayout {
alignment: center; alignment: center;
height: parent.height * 0.70; height: 70%;
width: parent.width;
spacing: 1rem; spacing: 1rem;
@ -262,8 +269,7 @@ export component GreeterDisplay inherits Window {
} }
environment_selector := FocusScope { environment_selector := FocusScope {
height: max(parent.width * 0.2, parent.height * 0.2); height: 25%;
width: parent.width;
key-pressed(event) => { key-pressed(event) => {
if (event.text == Key.LeftArrow || event.text == "a" || event.text == "A") { if (event.text == Key.LeftArrow || event.text == "a" || event.text == "A") {
if (Data.selected_index == 0) { if (Data.selected_index == 0) {
@ -284,22 +290,17 @@ export component GreeterDisplay inherits Window {
} }
scroll_view := ScrollView { scroll_view := ScrollView {
height: parent.height;
width: min(((self.height + 1rem) * tiles.length) - 1rem, parent.width); width: min(((self.height + 1rem) * tiles.length) - 1rem, parent.width);
animate viewport-x { duration: 250ms; } animate viewport-x { duration: 250ms; }
viewport-width: ((self.height + 1rem) * tiles.length) - 1rem; 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)); 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 { scroll_layout := HorizontalLayout {
height: parent.height; height: parent.height;
for tile[i] in tiles: LoginOptionTile { for tile[i] in tiles: LoginOptionTile {
width: parent.height; width: parent.height;
height: parent.height;
icon: tile.image; icon: tile.image;
label: tile.name; label: tile.name;
index: i; index: i;
@ -313,13 +314,12 @@ export component GreeterDisplay inherits Window {
} }
// Username field // Username field
HorizontalLayout { HorizontalLayout {
width: parent.width;
height: 2.5rem; height: 2.5rem;
alignment: center; alignment: center;
username_box := LineEdit { username_box := LineEdit {
font-size: 2rem; font-size: 2rem;
font-family: "monospace"; font-family: "monospace";
width: parent.width * 0.45; width: 45%;
placeholder-text: "Username"; placeholder-text: "Username";
text: default_username; text: default_username;
border-color: rgba(185, 15, 220, 0.85); border-color: rgba(185, 15, 220, 0.85);
@ -338,13 +338,12 @@ export component GreeterDisplay inherits Window {
} }
// Password field // Password field
HorizontalLayout { HorizontalLayout {
width: parent.width;
height: 2.5rem; height: 2.5rem;
alignment: center; alignment: center;
password_box := LineEdit { password_box := LineEdit {
font-size: 2rem; font-size: 2rem;
font-family: "monospace"; font-family: "monospace";
width: parent.width * 0.45; width: username_box.width;
placeholder-text: "Password"; placeholder-text: "Password";
input-type: password; input-type: password;
border-color: rgba(185, 15, 220, 0.85); border-color: rgba(185, 15, 220, 0.85);
@ -362,11 +361,10 @@ export component GreeterDisplay inherits Window {
} }
// Submit button // Submit button
HorizontalLayout { HorizontalLayout {
width: parent.width;
height: 2.5rem; height: 2.5rem;
alignment: center; alignment: center;
IconButton { IconButton {
width: parent.width * 0.45; //min(parent.width * 0.85, 32rem); width: username_box.width;
icon: @image-url("icons/right_arrow.svg"); icon: @image-url("icons/right_arrow.svg");
icon-width: 4rem; icon-width: 4rem;
icon-height: self.icon-width/3; icon-height: self.icon-width/3;
@ -380,8 +378,7 @@ export component GreeterDisplay inherits Window {
} }
} }
power_model := VerticalLayout { power_model := VerticalLayout {
height: parent.height * 0.15; height: 15%;
width: parent.width;
confirm_prompt := Text { confirm_prompt := Text {
horizontal-alignment: center; horizontal-alignment: center;
@ -401,7 +398,6 @@ export component GreeterDisplay inherits Window {
} }
HorizontalLayout { HorizontalLayout {
width: parent.width;
alignment: center; alignment: center;
Rectangle { Rectangle {
@ -416,7 +412,6 @@ export component GreeterDisplay inherits Window {
private property <string> lastaction; private property <string> lastaction;
padding-top: 0.4rem; padding-top: 0.4rem;
width: parent.width;
alignment: center; alignment: center;
spacing: 0.5rem; spacing: 0.5rem;
@ -477,8 +472,8 @@ export component GreeterDisplay inherits Window {
error_popup := Rectangle { error_popup := Rectangle {
background: rgba(220, 50, 50, 0.85); background: rgba(220, 50, 50, 0.85);
width: min(parent.width * 0.5, 64rem); width: 25%;
height: max(parent.height * 0.125, 6rem); height: 12.5%;
y: (parent.height * 0.025); y: (parent.height * 0.025);
opacity: 0.0; opacity: 0.0;
@ -489,8 +484,8 @@ export component GreeterDisplay inherits Window {
Text { Text {
color: rgba(240, 240, 240, 1); color: rgba(240, 240, 240, 1);
width: parent.width * 0.85; width: 85%;
height: parent.height * 0.85; height: 85%;
vertical-alignment: center; vertical-alignment: center;
horizontal-alignment: center; horizontal-alignment: center;