119 lines
2.8 KiB
TypeScript
119 lines
2.8 KiB
TypeScript
|
import { idle, readFile } from 'astal';
|
||
|
import { Astal, Gtk, Widget } from 'astal/gtk3';
|
||
|
|
||
|
import AstalGreet from 'gi://AstalGreet';
|
||
|
|
||
|
|
||
|
const DEFAULT_NAME = 'matt';
|
||
|
const PARSED_INDEX = {
|
||
|
name: 0,
|
||
|
uid: 2,
|
||
|
gid: 3,
|
||
|
desc: 4,
|
||
|
home: 5,
|
||
|
shell: 6,
|
||
|
};
|
||
|
|
||
|
const parsePasswd = (fileContent: string) => {
|
||
|
const splitUsers = fileContent.split('\n');
|
||
|
const parsedUsers = splitUsers.map((u) => {
|
||
|
const user = u.split(':');
|
||
|
|
||
|
return {
|
||
|
name: user[PARSED_INDEX.name],
|
||
|
uid: Number(user[PARSED_INDEX.uid]),
|
||
|
gid: Number(user[PARSED_INDEX.gid]),
|
||
|
desc: user[PARSED_INDEX.desc],
|
||
|
home: user[PARSED_INDEX.home],
|
||
|
shell: user[PARSED_INDEX.shell],
|
||
|
};
|
||
|
});
|
||
|
|
||
|
// Filter out system users, nixbld users and nobody
|
||
|
return parsedUsers.filter((u) => {
|
||
|
return u.uid >= 1000 &&
|
||
|
!u.name.includes('nixbld') &&
|
||
|
u.name !== 'nobody';
|
||
|
});
|
||
|
};
|
||
|
|
||
|
const users = parsePasswd(readFile('/etc/passwd'));
|
||
|
|
||
|
const dropdown = new Gtk.ComboBoxText();
|
||
|
|
||
|
dropdown.show_all();
|
||
|
|
||
|
users.forEach((u) => {
|
||
|
dropdown.append(null, u.name);
|
||
|
});
|
||
|
|
||
|
const response = <label /> as Widget.Label;
|
||
|
|
||
|
const password = (
|
||
|
<entry
|
||
|
placeholderText="Password"
|
||
|
visibility={false}
|
||
|
|
||
|
setup={(self) => idle(() => {
|
||
|
self.grab_focus();
|
||
|
})}
|
||
|
|
||
|
onActivate={(self) => {
|
||
|
AstalGreet.login(
|
||
|
dropdown.get_active_text() ?? '',
|
||
|
self.text || '',
|
||
|
'Hyprland',
|
||
|
(_, res) => {
|
||
|
try {
|
||
|
AstalGreet.login_finish(res);
|
||
|
}
|
||
|
catch (error) {
|
||
|
response.label = JSON.stringify(error);
|
||
|
}
|
||
|
},
|
||
|
);
|
||
|
}}
|
||
|
/>
|
||
|
);
|
||
|
|
||
|
|
||
|
export default () => (
|
||
|
<window
|
||
|
name="greeter"
|
||
|
keymode={Astal.Keymode.ON_DEMAND}
|
||
|
>
|
||
|
<box
|
||
|
vertical
|
||
|
halign={Gtk.Align.CENTER}
|
||
|
valign={Gtk.Align.CENTER}
|
||
|
hexpand
|
||
|
vexpand
|
||
|
className="base"
|
||
|
>
|
||
|
<box
|
||
|
vertical
|
||
|
halign={Gtk.Align.CENTER}
|
||
|
valign={Gtk.Align.CENTER}
|
||
|
hexpand
|
||
|
vexpand
|
||
|
className="linked"
|
||
|
|
||
|
setup={() => {
|
||
|
idle(() => {
|
||
|
const usernames = users.map((u) => u.name);
|
||
|
|
||
|
if (usernames.includes(DEFAULT_NAME)) {
|
||
|
dropdown.set_active(usernames.indexOf(DEFAULT_NAME));
|
||
|
}
|
||
|
});
|
||
|
}}
|
||
|
>
|
||
|
{dropdown}
|
||
|
{password}
|
||
|
</box>
|
||
|
|
||
|
{response}
|
||
|
</box>
|
||
|
</window>
|
||
|
);
|