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"] } tokio = { workspace = true, features = ["full"] }
wayland-client = "0.31.8" wayland-client = "0.31.8"
# For network status using networkmanager feature # 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 # 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 # Fix zbus compilation by manually adding nix with user feature
nix = { workspace = true, optional = true } nix = { workspace = true, optional = true }
# For power status with upower feature # 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 # Required for some features
zbus = { workspace = true, optional = true } zbus = { workspace = true, optional = true }
# CLI arguments # CLI arguments
@ -102,7 +102,7 @@ pwd = "1.4.0"
ron = "0.10.1" ron = "0.10.1"
serde = "1" serde = "1"
tokio = "1.39.1" tokio = "1.39.1"
zbus = "4" zbus = "5"
[workspace.dependencies.cosmic-applets-config] [workspace.dependencies.cosmic-applets-config]
git = "https://github.com/pop-os/cosmic-applets" git = "https://github.com/pop-os/cosmic-applets"

View file

@ -1,6 +1,6 @@
use cosmic_greeter_daemon::UserData; use cosmic_greeter_daemon::UserData;
use std::{env, error::Error, future::pending, io, path::Path}; 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 //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 // 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>> { async fn main() -> Result<(), Box<dyn Error>> {
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("warn")).init(); 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")? .name("com.system76.CosmicGreeter")?
.serve_at("/com/system76/CosmicGreeter", GreeterProxy)? .serve_at("/com/system76/CosmicGreeter", GreeterProxy)?
.build() .build()

View file

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

View file

@ -30,6 +30,7 @@ use cosmic::{
use cosmic_greeter_config::Config as CosmicGreeterConfig; use cosmic_greeter_config::Config as CosmicGreeterConfig;
use cosmic_greeter_daemon::UserData; use cosmic_greeter_daemon::UserData;
use greetd_ipc::Request; use greetd_ipc::Request;
use std::sync::LazyLock;
use std::{ use std::{
collections::{HashMap, hash_map}, collections::{HashMap, hash_map},
error::Error, error::Error,
@ -49,6 +50,8 @@ use crate::{
fl, fl,
}; };
static USERNAME_ID: LazyLock<iced::id::Id> = LazyLock::new(|| iced::id::Id::new("username-id"));
#[proxy( #[proxy(
interface = "com.system76.CosmicGreeter", interface = "com.system76.CosmicGreeter",
default_service = "com.system76.CosmicGreeter", default_service = "com.system76.CosmicGreeter",
@ -351,6 +354,7 @@ pub enum Message {
Surface(surface::Action), Surface(surface::Action),
Suspend, Suspend,
Username(String), Username(String),
EnterUser(bool, String),
} }
impl From<common::Message> for Message { impl From<common::Message> for Message {
@ -372,10 +376,12 @@ pub struct App {
dialog_page_opt: Option<DialogPage>, dialog_page_opt: Option<DialogPage>,
dropdown_opt: Option<Dropdown>, dropdown_opt: Option<Dropdown>,
heartbeat_handle: Option<cosmic::iced::task::Handle>, heartbeat_handle: Option<cosmic::iced::task::Handle>,
entering_name: bool,
} }
impl App { impl App {
fn menu(&self, id: SurfaceId) -> Element<Message> { fn menu(&self, id: SurfaceId) -> Element<Message> {
const DEFAULT_MENU_ITEM_HEIGHT: f32 = 36.;
let window_width = self let window_width = self
.common .common
.window_size .window_size
@ -430,8 +436,20 @@ impl App {
.on_press(message), .on_press(message),
) )
}; };
let dropdown_menu = |items| { let dropdown_menu = |items: Vec<_>| {
widget::container(widget::column::with_children(items)) 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) .padding(1)
//TODO: move style to libcosmic //TODO: move style to libcosmic
.class(theme::Container::custom(|theme| { .class(theme::Container::custom(|theme| {
@ -485,7 +503,29 @@ impl App {
Message::Username(name.clone()), 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( let mut session_button = widget::popover(
@ -575,7 +615,8 @@ impl App {
} }
SocketState::Open => { SocketState::Open => {
for user_data in &self.flags.user_datas { 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 { match &user_data.icon_opt {
Some(icon) => { Some(icon) => {
column = column.push( 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 { match &self.common.prompt_opt {
Some((prompt, secret, value_opt)) => match value_opt { Some((prompt, secret, value_opt)) => match value_opt {
Some(value) => { Some(value) => {
@ -875,6 +927,7 @@ impl cosmic::Application for App {
dialog_page_opt: None, dialog_page_opt: None,
dropdown_opt: None, dropdown_opt: None,
heartbeat_handle: None, heartbeat_handle: None,
entering_name: false,
}; };
(app, common_task) (app, common_task)
} }
@ -1035,11 +1088,22 @@ impl cosmic::Application for App {
self.dropdown_opt = None; 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) => { Message::Username(username) => {
if self.dropdown_opt == Some(Dropdown::User) { if self.dropdown_opt == Some(Dropdown::User) {
self.dropdown_opt = None; 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); let data_idx = Self::user_data_index(&self.flags.user_datas, &username);
self.selected_username = NameIndexPair { username, data_idx }; self.selected_username = NameIndexPair { username, data_idx };
self.common.surface_images.clear(); self.common.surface_images.clear();