Implement design items
This commit is contained in:
parent
bec5cb5b7d
commit
7cb1c89474
4 changed files with 221 additions and 42 deletions
55
Cargo.lock
generated
55
Cargo.lock
generated
|
|
@ -94,6 +94,12 @@ version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3aa2999eb46af81abb65c2d30d446778d7e613b60bbf4e174a027e80f90a3c14"
|
checksum = "3aa2999eb46af81abb65c2d30d446778d7e613b60bbf4e174a027e80f90a3c14"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "android-tzdata"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "android_system_properties"
|
name = "android_system_properties"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
|
|
@ -575,6 +581,20 @@ version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
|
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono"
|
||||||
|
version = "0.4.31"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
|
||||||
|
dependencies = [
|
||||||
|
"android-tzdata",
|
||||||
|
"iana-time-zone",
|
||||||
|
"js-sys",
|
||||||
|
"num-traits",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"windows-targets 0.48.5",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clang-sys"
|
name = "clang-sys"
|
||||||
version = "1.6.1"
|
version = "1.6.1"
|
||||||
|
|
@ -729,6 +749,7 @@ dependencies = [
|
||||||
name = "cosmic-greeter"
|
name = "cosmic-greeter"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
"env_logger 0.10.0",
|
"env_logger 0.10.0",
|
||||||
"freedesktop_entry_parser",
|
"freedesktop_entry_parser",
|
||||||
"greetd_ipc",
|
"greetd_ipc",
|
||||||
|
|
@ -1546,7 +1567,7 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"winapi",
|
"winapi",
|
||||||
"windows",
|
"windows 0.44.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1682,6 +1703,29 @@ version = "2.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iana-time-zone"
|
||||||
|
version = "0.1.57"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613"
|
||||||
|
dependencies = [
|
||||||
|
"android_system_properties",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"iana-time-zone-haiku",
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"windows 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iana-time-zone-haiku"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced"
|
name = "iced"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
|
|
@ -4443,6 +4487,15 @@ dependencies = [
|
||||||
"windows-targets 0.42.2",
|
"windows-targets 0.42.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.48.5",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.42.0"
|
version = "0.42.0"
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
chrono = "0.4"
|
||||||
env_logger = "0.10"
|
env_logger = "0.10"
|
||||||
freedesktop_entry_parser = "1"
|
freedesktop_entry_parser = "1"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
|
|
||||||
|
|
@ -439,7 +439,7 @@ impl cosmic::Application for App {
|
||||||
widget::cosmic_container::container(column)
|
widget::cosmic_container::container(column)
|
||||||
.layer(cosmic::cosmic_theme::Layer::Primary)
|
.layer(cosmic::cosmic_theme::Layer::Primary)
|
||||||
.padding(16)
|
.padding(16)
|
||||||
.style(cosmic::theme::Container::Primary),
|
.style(cosmic::theme::Container::Card),
|
||||||
)
|
)
|
||||||
.on_press(Message::Username(socket.clone(), user.name.clone())),
|
.on_press(Message::Username(socket.clone(), user.name.clone())),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
205
src/locker.rs
205
src/locker.rs
|
|
@ -5,7 +5,7 @@ use cosmic::app::{message, Command, Core, Settings};
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
executor,
|
executor,
|
||||||
iced::{
|
iced::{
|
||||||
self,
|
self, alignment,
|
||||||
event::wayland::{Event as WaylandEvent, OutputEvent},
|
event::wayland::{Event as WaylandEvent, OutputEvent},
|
||||||
futures::{self, SinkExt},
|
futures::{self, SinkExt},
|
||||||
subscription,
|
subscription,
|
||||||
|
|
@ -15,16 +15,17 @@ use cosmic::{
|
||||||
destroy_layer_surface, get_layer_surface, Anchor, KeyboardInteractivity, Layer,
|
destroy_layer_surface, get_layer_surface, Anchor, KeyboardInteractivity, Layer,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Subscription,
|
Length, Subscription,
|
||||||
},
|
},
|
||||||
iced_runtime::core::window::Id as SurfaceId,
|
iced_runtime::core::window::Id as SurfaceId,
|
||||||
widget, Element,
|
style, widget, Element,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
ffi::{CStr, CString},
|
ffi::{CStr, CString},
|
||||||
fs,
|
fs,
|
||||||
path::Path,
|
path::Path,
|
||||||
|
process,
|
||||||
};
|
};
|
||||||
use tokio::{sync::mpsc, task, time};
|
use tokio::{sync::mpsc, task, time};
|
||||||
use wayland_client::{protocol::wl_output::WlOutput, Proxy};
|
use wayland_client::{protocol::wl_output::WlOutput, Proxy};
|
||||||
|
|
@ -145,6 +146,7 @@ pub struct Flags {
|
||||||
/// Messages that are used specifically by our [`App`].
|
/// Messages that are used specifically by our [`App`].
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Message {
|
pub enum Message {
|
||||||
|
None,
|
||||||
OutputEvent(OutputEvent, WlOutput),
|
OutputEvent(OutputEvent, WlOutput),
|
||||||
Channel(mpsc::Sender<String>),
|
Channel(mpsc::Sender<String>),
|
||||||
Prompt(String, bool, String),
|
Prompt(String, bool, String),
|
||||||
|
|
@ -216,22 +218,17 @@ impl cosmic::Application for App {
|
||||||
/// Handle application events here.
|
/// Handle application events here.
|
||||||
fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
|
fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
|
||||||
match message {
|
match message {
|
||||||
|
Message::None => {}
|
||||||
Message::OutputEvent(output_event, output) => match output_event {
|
Message::OutputEvent(output_event, output) => match output_event {
|
||||||
OutputEvent::Created(_output_info_opt) => {
|
OutputEvent::Created(_output_info_opt) => {
|
||||||
log::info!("output {}: created", output.id());
|
log::info!("output {}: created", output.id());
|
||||||
|
|
||||||
//TODO: COVER ALL OUTPUTS AFTER FIXING FOCUS BUG
|
|
||||||
if !self.surface_ids.is_empty() {
|
|
||||||
log::error!("COVER ALL OUTPUTS AFTER FIXING FOCUS BUG");
|
|
||||||
return Command::none();
|
|
||||||
}
|
|
||||||
|
|
||||||
let surface_id = self.next_surface_id;
|
let surface_id = self.next_surface_id;
|
||||||
self.next_surface_id.0 += 1;
|
self.next_surface_id.0 += 1;
|
||||||
|
|
||||||
match self.surface_ids.insert(output.clone(), surface_id) {
|
match self.surface_ids.insert(output.clone(), surface_id) {
|
||||||
Some(old_surface_id) => {
|
Some(old_surface_id) => {
|
||||||
//TODO: remove old surface
|
//TODO: remove old surface?
|
||||||
log::warn!(
|
log::warn!(
|
||||||
"output {}: already had surface ID {}",
|
"output {}: already had surface ID {}",
|
||||||
output.id(),
|
output.id(),
|
||||||
|
|
@ -244,7 +241,7 @@ impl cosmic::Application for App {
|
||||||
return Command::batch([
|
return Command::batch([
|
||||||
get_layer_surface(SctkLayerSurfaceSettings {
|
get_layer_surface(SctkLayerSurfaceSettings {
|
||||||
id: surface_id,
|
id: surface_id,
|
||||||
layer: Layer::Top,
|
layer: Layer::Overlay,
|
||||||
keyboard_interactivity: KeyboardInteractivity::Exclusive,
|
keyboard_interactivity: KeyboardInteractivity::Exclusive,
|
||||||
pointer_interactivity: true,
|
pointer_interactivity: true,
|
||||||
anchor: Anchor::TOP | Anchor::BOTTOM | Anchor::LEFT | Anchor::RIGHT,
|
anchor: Anchor::TOP | Anchor::BOTTOM | Anchor::LEFT | Anchor::RIGHT,
|
||||||
|
|
@ -258,10 +255,7 @@ impl cosmic::Application for App {
|
||||||
right: 0,
|
right: 0,
|
||||||
},
|
},
|
||||||
exclusive_zone: 0,
|
exclusive_zone: 0,
|
||||||
size_limits: iced::Limits::NONE
|
size_limits: iced::Limits::NONE.min_width(1.0).min_height(1.0),
|
||||||
.min_width(1.0)
|
|
||||||
.min_height(1.0)
|
|
||||||
.max_width(600.0),
|
|
||||||
}),
|
}),
|
||||||
widget::text_input::focus(self.text_input_id.clone()),
|
widget::text_input::focus(self.text_input_id.clone()),
|
||||||
]);
|
]);
|
||||||
|
|
@ -309,7 +303,14 @@ impl cosmic::Application for App {
|
||||||
}
|
}
|
||||||
Message::Exit => {
|
Message::Exit => {
|
||||||
self.exited = true;
|
self.exited = true;
|
||||||
return iced::window::close();
|
|
||||||
|
let mut commands = Vec::new();
|
||||||
|
for (_output, surface_id) in self.surface_ids.drain() {
|
||||||
|
commands.push(destroy_layer_surface(surface_id));
|
||||||
|
}
|
||||||
|
//TODO: cleaner method to exit?
|
||||||
|
commands.push(Command::perform(async { process::exit(0) }, |x| x));
|
||||||
|
return Command::batch(commands);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Command::none()
|
Command::none()
|
||||||
|
|
@ -321,40 +322,164 @@ impl cosmic::Application for App {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a view after each update.
|
/// Creates a view after each update.
|
||||||
fn view_window(&self, id: SurfaceId) -> Element<Self::Message> {
|
fn view_window(&self, _id: SurfaceId) -> Element<Self::Message> {
|
||||||
let mut column = widget::column::with_capacity(3)
|
let left_element = {
|
||||||
.max_width(280.0)
|
let date_time_column = {
|
||||||
|
let mut column = widget::column::with_capacity(2).padding(16.0).spacing(12.0);
|
||||||
|
|
||||||
|
let dt = chrono::Local::now();
|
||||||
|
|
||||||
|
//TODO: localized format
|
||||||
|
let date = dt.format("%A, %B %-d");
|
||||||
|
column = column
|
||||||
|
.push(widget::text::title2(format!("{}", date)).style(style::Text::Accent));
|
||||||
|
|
||||||
|
//TODO: localized format
|
||||||
|
let time = dt.format("%R");
|
||||||
|
column = column.push(
|
||||||
|
widget::text(format!("{}", time))
|
||||||
|
.size(112.0)
|
||||||
|
.style(style::Text::Accent),
|
||||||
|
);
|
||||||
|
|
||||||
|
column
|
||||||
|
};
|
||||||
|
|
||||||
|
//TODO: get actual status
|
||||||
|
let status_row = iced::widget::row![
|
||||||
|
widget::icon::from_name("network-wireless-signal-ok-symbolic",),
|
||||||
|
iced::widget::row![
|
||||||
|
widget::icon::from_name("battery-level-50-symbolic"),
|
||||||
|
widget::text("50%"),
|
||||||
|
]
|
||||||
|
]
|
||||||
|
.padding(16.0)
|
||||||
.spacing(12.0);
|
.spacing(12.0);
|
||||||
|
|
||||||
match &self.prompt_opt {
|
//TODO: implement these buttons
|
||||||
Some((prompt, secret, value)) => {
|
let button_row = iced::widget::row![
|
||||||
let mut text_input = widget::text_input(&prompt, &value)
|
widget::button(widget::icon::from_name(
|
||||||
.id(self.text_input_id.clone())
|
"applications-accessibility-symbolic"
|
||||||
.on_input(|value| Message::Prompt(prompt.clone(), *secret, value))
|
))
|
||||||
.on_submit(Message::Submit);
|
.padding(12.0)
|
||||||
|
.on_press(Message::None),
|
||||||
|
widget::button(widget::icon::from_name("input-keyboard-symbolic"))
|
||||||
|
.padding(12.0)
|
||||||
|
.on_press(Message::None),
|
||||||
|
widget::button(widget::icon::from_name("system-users-symbolic"))
|
||||||
|
.padding(12.0)
|
||||||
|
.on_press(Message::None),
|
||||||
|
widget::button(widget::icon::from_name("system-suspend-symbolic"))
|
||||||
|
.padding(12.0)
|
||||||
|
.on_press(Message::None),
|
||||||
|
]
|
||||||
|
.padding([16.0, 0.0, 0.0, 0.0])
|
||||||
|
.spacing(8.0);
|
||||||
|
|
||||||
if *secret {
|
widget::container(iced::widget::column![
|
||||||
text_input = text_input.password()
|
date_time_column,
|
||||||
|
widget::divider::horizontal::default(),
|
||||||
|
status_row,
|
||||||
|
widget::divider::horizontal::default(),
|
||||||
|
button_row,
|
||||||
|
])
|
||||||
|
.width(Length::Fill)
|
||||||
|
.align_x(alignment::Horizontal::Left)
|
||||||
|
};
|
||||||
|
|
||||||
|
let right_element = {
|
||||||
|
let mut column = widget::column::with_capacity(2)
|
||||||
|
.spacing(12.0)
|
||||||
|
.max_width(280.0);
|
||||||
|
|
||||||
|
match &self.flags.icon_opt {
|
||||||
|
Some(icon) => {
|
||||||
|
column = column.push(
|
||||||
|
widget::container(
|
||||||
|
widget::Image::new(icon.clone())
|
||||||
|
.width(Length::Fixed(78.0))
|
||||||
|
.height(Length::Fixed(78.0)),
|
||||||
|
)
|
||||||
|
.width(Length::Fill)
|
||||||
|
.align_x(alignment::Horizontal::Center),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
None => {}
|
||||||
column = column.push(text_input);
|
}
|
||||||
|
match &self.flags.current_user.gecos {
|
||||||
|
Some(gecos) => {
|
||||||
|
column = column.push(
|
||||||
|
widget::container(widget::text::title4(gecos))
|
||||||
|
.width(Length::Fill)
|
||||||
|
.align_x(alignment::Horizontal::Center),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
}
|
}
|
||||||
None => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(error) = &self.error_opt {
|
match &self.prompt_opt {
|
||||||
column = column.push(widget::text(error));
|
Some((prompt, secret, value)) => {
|
||||||
}
|
let mut text_input = widget::text_input(&prompt, &value)
|
||||||
|
.id(self.text_input_id.clone())
|
||||||
|
.leading_icon(widget::icon::from_name("system-lock-screen-symbolic").into())
|
||||||
|
.trailing_icon(
|
||||||
|
widget::icon::from_name("document-properties-symbolic").into(),
|
||||||
|
)
|
||||||
|
.on_input(|value| Message::Prompt(prompt.clone(), *secret, value))
|
||||||
|
.on_submit(Message::Submit);
|
||||||
|
|
||||||
let centered = widget::container(column)
|
if *secret {
|
||||||
.width(iced::Length::Fill)
|
text_input = text_input.password()
|
||||||
.height(iced::Length::Fill)
|
}
|
||||||
.align_x(iced::alignment::Horizontal::Center)
|
|
||||||
.align_y(iced::alignment::Vertical::Center);
|
|
||||||
|
|
||||||
Element::from(centered)
|
column = column.push(text_input);
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(error) = &self.error_opt {
|
||||||
|
column = column.push(widget::text(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
widget::container(column)
|
||||||
|
.align_x(alignment::Horizontal::Center)
|
||||||
|
.width(Length::Fill)
|
||||||
|
};
|
||||||
|
|
||||||
|
widget::container(
|
||||||
|
widget::cosmic_container::container(
|
||||||
|
iced::widget::row![left_element, right_element]
|
||||||
|
.align_items(alignment::Alignment::Center),
|
||||||
|
)
|
||||||
|
.layer(cosmic::cosmic_theme::Layer::Background)
|
||||||
|
.padding(16)
|
||||||
|
.style(cosmic::theme::Container::Custom(Box::new(
|
||||||
|
|theme: &cosmic::Theme| {
|
||||||
|
// Use background appearance as the base
|
||||||
|
let mut appearance = widget::container::StyleSheet::appearance(
|
||||||
|
theme,
|
||||||
|
&cosmic::theme::Container::Background,
|
||||||
|
);
|
||||||
|
appearance.border_radius = 16.0.into();
|
||||||
|
appearance
|
||||||
|
},
|
||||||
|
)))
|
||||||
|
.width(Length::Fixed(800.0)),
|
||||||
|
)
|
||||||
|
.padding([32.0, 0.0, 0.0, 0.0])
|
||||||
|
.width(Length::Fill)
|
||||||
|
.height(Length::Fill)
|
||||||
|
.align_x(alignment::Horizontal::Center)
|
||||||
|
.align_y(alignment::Vertical::Top)
|
||||||
|
.style(cosmic::theme::Container::Custom(Box::new(|_| {
|
||||||
|
let mut appearance = widget::container::Appearance::default();
|
||||||
|
appearance.background = Some(iced::Background::Color(iced::Color::BLACK));
|
||||||
|
appearance
|
||||||
|
})))
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: subscription for date/time
|
||||||
fn subscription(&self) -> Subscription<Self::Message> {
|
fn subscription(&self) -> Subscription<Self::Message> {
|
||||||
if self.exited {
|
if self.exited {
|
||||||
return Subscription::none();
|
return Subscription::none();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue