From 3ae192b3c1cc3970457d8ae5a7ef1b2b934f8e77 Mon Sep 17 00:00:00 2001 From: matt1432 Date: Tue, 6 Feb 2024 15:50:56 -0500 Subject: [PATCH] feat(greetd): add list of all normal users as dropdown --- modules/ags/config/.eslintrc.json | 3 -- modules/ags/config/greeter.ts | 79 ++++++++++++++++++++++++++---- modules/ags/config/test-greeter.js | 4 ++ 3 files changed, 73 insertions(+), 13 deletions(-) create mode 100644 modules/ags/config/test-greeter.js diff --git a/modules/ags/config/.eslintrc.json b/modules/ags/config/.eslintrc.json index ec0212ba..3f1d0c84 100644 --- a/modules/ags/config/.eslintrc.json +++ b/modules/ags/config/.eslintrc.json @@ -22,9 +22,6 @@ "block-scoped-var": ["error"], - "capitalized-comments": ["warn", "always", { - "ignoreConsecutiveComments": true - }], "class-methods-use-this": ["error"], "curly": ["warn"], "default-case-last": ["warn"], diff --git a/modules/ags/config/greeter.ts b/modules/ags/config/greeter.ts index aac71ab8..c5ea5c58 100644 --- a/modules/ags/config/greeter.ts +++ b/modules/ags/config/greeter.ts @@ -1,17 +1,76 @@ -const { idle } = Utils; +const { Box, Button, Entry, Label, Menu, MenuItem, Window } = Widget; +const { idle, readFileAsync } = Utils; + const greetd = await Service.import('greetd'); -const name = Widget.Entry({ - placeholder_text: 'Username', - on_accept: () => password.grab_focus(), +const { Gdk } = imports.gi; + +const DEFAULT_NAME = 'matt'; +const name = Label(DEFAULT_NAME); +let menu; + +const dropdown = Button({ + child: name, + setup: () => { + idle(() => { + readFileAsync('/etc/passwd').then((out) => { + const users = out.split('\n') + .map((u) => { + const user = u.split(':'); + let i = 2; + + return { + name: user[0], + uid: Number(user[i++]), + gid: Number(user[i++]), + desc: user[i++], + home: user[i++], + shell: user[i], + }; + }) + .filter((u) => { + return u.uid >= 1000 && + !u.name.includes('nixbld') && + u.name !== 'nobody'; + }); + + // FIXME: make menu scrollable + menu = Menu({ + attach_widget: dropdown, + children: users.map((u) => MenuItem({ + on_activate: () => { + name.label = u.name; + }, + + child: Label({ + label: u.name, + justification: 'center', + css: ` + min-width: ${dropdown.get_allocated_width() / 2}px; + `, + }), + })), + }); + }).catch(print); + }); + }, + + on_primary_click_release: (_, event) => { + menu.popup_at_widget( + dropdown, + Gdk.Gravity.SOUTH, + Gdk.Gravity.NORTH, + event, + ); + }, }); -const password = Widget.Entry({ +const password = Entry({ placeholder_text: 'Password', visibility: false, on_accept: () => { greetd.login( - name.text || '', + name.label || '', password.text || '', 'Hyprland', @@ -21,9 +80,9 @@ const password = Widget.Entry({ }, }); -const response = Widget.Label(); +const response = Label(); -const win = Widget.Window({ +const win = Window({ name: 'greeter', css: 'background-color: transparent;', anchor: ['top', 'left', 'right', 'bottom'], @@ -35,14 +94,14 @@ const win = Widget.Window({ }); }, - child: Widget.Box({ + child: Box({ vertical: true, hpack: 'center', vpack: 'center', hexpand: true, vexpand: true, children: [ - name, + dropdown, password, response, ], diff --git a/modules/ags/config/test-greeter.js b/modules/ags/config/test-greeter.js new file mode 100644 index 00000000..057bfb14 --- /dev/null +++ b/modules/ags/config/test-greeter.js @@ -0,0 +1,4 @@ +// Delete /tmp/ags-greeter before and after using this +import { transpileTypeScript } from './js/utils.js'; + +export default (await transpileTypeScript('greeter')).default;