refactor: allow entering username

This commit is contained in:
Ashley Wulber 2025-06-26 15:14:43 -04:00 committed by Ashley Wulber
parent 7aa41f6a16
commit abc591db6d
5 changed files with 692 additions and 464 deletions

1068
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -45,13 +45,13 @@ xdg = "2.5.2"
tokio = { workspace = true, features = ["full"] }
wayland-client = "0.31.8"
# For network status using networkmanager feature
cosmic-dbus-networkmanager = { git = "https://github.com/pop-os/dbus-settings-bindings", rev = "badfc6a", optional = true }
cosmic-dbus-networkmanager = { git = "https://github.com/pop-os/dbus-settings-bindings", optional = true }
# For logind integration using logind feature
logind-zbus = { version = "4", optional = true }
logind-zbus = { version = "5", optional = true }
# Fix zbus compilation by manually adding nix with user feature
nix = { workspace = true, optional = true }
# For power status with upower feature
upower_dbus = { git = "https://github.com/pop-os/dbus-settings-bindings", rev = "badfc6a", optional = true }
upower_dbus = { git = "https://github.com/pop-os/dbus-settings-bindings", optional = true }
# Required for some features
zbus = { workspace = true, optional = true }
# CLI arguments
@ -102,7 +102,7 @@ pwd = "1.4.0"
ron = "0.10.1"
serde = "1"
tokio = "1.39.1"
zbus = "4"
zbus = "5"
[workspace.dependencies.cosmic-applets-config]
git = "https://github.com/pop-os/cosmic-applets"

View file

@ -1,6 +1,6 @@
use cosmic_greeter_daemon::UserData;
use std::{env, error::Error, future::pending, io, path::Path};
use zbus::{ConnectionBuilder, DBusError};
use zbus::{connection::Builder, DBusError};
//IMPORTANT: this function is critical to the security of this proxy. It must ensure that the
// callback is executed with the permissions of the specified user id. A good test is to see if
@ -101,7 +101,7 @@ impl GreeterProxy {
async fn main() -> Result<(), Box<dyn Error>> {
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("warn")).init();
let _conn = ConnectionBuilder::system()?
let _conn = Builder::system()?
.name("com.system76.CosmicGreeter")?
.serve_at("/com/system76/CosmicGreeter", GreeterProxy)?
.build()

View file

@ -1,5 +1,7 @@
cancel = Cancel
caps-lock = Caps Lock is active.
enter-user = Enter name manually...
type-username = Username:
keyboard-layout = Keyboard layout
restart = Restart
restart-now = Restart now?

View file

@ -30,6 +30,7 @@ use cosmic::{
use cosmic_greeter_config::Config as CosmicGreeterConfig;
use cosmic_greeter_daemon::UserData;
use greetd_ipc::Request;
use std::sync::LazyLock;
use std::{
collections::{HashMap, hash_map},
error::Error,
@ -49,6 +50,8 @@ use crate::{
fl,
};
static USERNAME_ID: LazyLock<iced::id::Id> = LazyLock::new(|| iced::id::Id::new("username-id"));
#[proxy(
interface = "com.system76.CosmicGreeter",
default_service = "com.system76.CosmicGreeter",
@ -351,6 +354,7 @@ pub enum Message {
Surface(surface::Action),
Suspend,
Username(String),
EnterUser(bool, String),
}
impl From<common::Message> for Message {
@ -372,10 +376,12 @@ pub struct App {
dialog_page_opt: Option<DialogPage>,
dropdown_opt: Option<Dropdown>,
heartbeat_handle: Option<cosmic::iced::task::Handle>,
entering_name: bool,
}
impl App {
fn menu(&self, id: SurfaceId) -> Element<Message> {
const DEFAULT_MENU_ITEM_HEIGHT: f32 = 36.;
let window_width = self
.common
.window_size
@ -430,8 +436,20 @@ impl App {
.on_press(message),
)
};
let dropdown_menu = |items| {
widget::container(widget::column::with_children(items))
let dropdown_menu = |items: Vec<_>| {
let item_cnt = items.len();
let items = widget::column::with_children(items);
let items = if item_cnt > 7 {
Element::from(
widget::scrollable(items)
.height(Length::Fixed(DEFAULT_MENU_ITEM_HEIGHT * 7.)),
)
} else {
Element::from(items)
};
widget::container(items)
.padding(1)
//TODO: move style to libcosmic
.class(theme::Container::custom(|theme| {
@ -485,7 +503,29 @@ impl App {
Message::Username(name.clone()),
));
}
user_button = user_button.popup(dropdown_menu(items));
let item_cnt = items.len();
let menu_button = widget::menu::menu_button(vec![
Element::from(widget::Space::with_width(Length::Fixed(25.0))),
widget::text(fl!("enter-user"))
.align_x(iced::alignment::Horizontal::Left)
.into(),
])
.on_press(Message::EnterUser(true, String::new()))
.into();
let items = if item_cnt >= 6 {
dropdown_menu(vec![
widget::scrollable(widget::column::with_children(items))
.height(Length::Fixed(DEFAULT_MENU_ITEM_HEIGHT * 6.))
.into(),
widget::divider::horizontal::light().into(),
menu_button,
])
} else {
items.push(menu_button);
dropdown_menu(items)
};
user_button = user_button.popup(items);
}
let mut session_button = widget::popover(
@ -575,7 +615,8 @@ impl App {
}
SocketState::Open => {
for user_data in &self.flags.user_datas {
if user_data.name == self.selected_username.username {
if !self.entering_name && user_data.name == self.selected_username.username
{
match &user_data.icon_opt {
Some(icon) => {
column = column.push(
@ -600,6 +641,17 @@ impl App {
);
}
}
if self.entering_name {
column = column.push(
widget::text_input(
fl!("type-username"),
self.selected_username.username.as_str(),
)
.id(USERNAME_ID.clone())
.on_input(|input| Message::EnterUser(false, input))
.on_submit(|v| Message::Username(v)),
)
}
match &self.common.prompt_opt {
Some((prompt, secret, value_opt)) => match value_opt {
Some(value) => {
@ -875,6 +927,7 @@ impl cosmic::Application for App {
dialog_page_opt: None,
dropdown_opt: None,
heartbeat_handle: None,
entering_name: false,
};
(app, common_task)
}
@ -1035,11 +1088,22 @@ impl cosmic::Application for App {
self.dropdown_opt = None;
}
}
Message::EnterUser(focus_input, username) => {
self.entering_name = true;
self.selected_username = NameIndexPair {
data_idx: Self::user_data_index(&self.flags.user_datas, &username),
username,
};
if focus_input {
return widget::text_input::focus(USERNAME_ID.clone());
}
}
Message::Username(username) => {
if self.dropdown_opt == Some(Dropdown::User) {
self.dropdown_opt = None;
}
if username != self.selected_username.username {
if self.entering_name || username != self.selected_username.username {
self.entering_name = false;
let data_idx = Self::user_data_index(&self.flags.user_datas, &username);
self.selected_username = NameIndexPair { username, data_idx };
self.common.surface_images.clear();