mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-06-08 12:13:31 -04:00
164 lines
5.6 KiB
QML
164 lines
5.6 KiB
QML
pragma Singleton
|
|
|
|
import QtQuick
|
|
import Quickshell
|
|
import Quickshell.Io
|
|
import qs.Common
|
|
|
|
Singleton {
|
|
id: root
|
|
|
|
readonly property var log: Log.scoped("GreeterUsersService")
|
|
|
|
readonly property string greetCfgDir: Quickshell.env("DMS_GREET_CFG_DIR") || "/var/cache/dms-greeter"
|
|
readonly property string usersCacheDir: greetCfgDir + "/users"
|
|
|
|
property var users: []
|
|
property var usernames: []
|
|
property var profileImageMap: ({})
|
|
property bool loaded: false
|
|
property bool refreshing: false
|
|
|
|
Component.onCompleted: refresh()
|
|
|
|
function refresh() {
|
|
if (refreshing)
|
|
return;
|
|
refreshing = true;
|
|
_loadUsers();
|
|
}
|
|
|
|
function displayName(username) {
|
|
const u = _findUser(username);
|
|
if (!u)
|
|
return username || "";
|
|
const gecos = (u.gecos || "").trim();
|
|
return gecos.length > 0 ? gecos : username;
|
|
}
|
|
|
|
function optionLabel(username) {
|
|
const label = displayName(username);
|
|
return label !== username ? label : username;
|
|
}
|
|
|
|
function usernameFromOptionLabel(label) {
|
|
for (let i = 0; i < users.length; i++) {
|
|
if (root.optionLabel(users[i].username) === label)
|
|
return users[i].username;
|
|
}
|
|
return label;
|
|
}
|
|
|
|
function hasSyncedTheme(username) {
|
|
if (!username)
|
|
return false;
|
|
return syncedThemePaths[username] === true;
|
|
}
|
|
|
|
property var syncedThemePaths: ({})
|
|
|
|
function userCacheDir(username) {
|
|
if (!username)
|
|
return "";
|
|
return usersCacheDir + "/" + username;
|
|
}
|
|
|
|
function syncedSettingsPath(username) {
|
|
const dir = userCacheDir(username);
|
|
return dir ? dir + "/settings.json" : "";
|
|
}
|
|
|
|
function _findUser(name) {
|
|
for (let i = 0; i < users.length; i++) {
|
|
if (users[i].username === name)
|
|
return users[i];
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function _loadUsers() {
|
|
Proc.runCommand("greeterUsersService-loadUsers", ["sh", "-c", "getent passwd | awk -F: '$3>=1000 && $3<60000 && $1!=\"nobody\" && $7!~/(nologin|false)$/ && $6!=\"/var/empty\" {print $1\":\"$3\":\"$5\":\"$6\":\"$7}'"], (output, exitCode) => {
|
|
const lines = (output || "").trim().split("\n").filter(l => l.length > 0);
|
|
const list = [];
|
|
const names = [];
|
|
for (let i = 0; i < lines.length; i++) {
|
|
const parts = lines[i].split(":");
|
|
if (parts.length < 5)
|
|
continue;
|
|
const username = parts[0];
|
|
list.push({
|
|
username,
|
|
uid: parseInt(parts[1], 10),
|
|
gecos: (parts[2] || "").split(",")[0],
|
|
home: parts[3] || "",
|
|
shell: parts[4] || ""
|
|
});
|
|
names.push(username);
|
|
}
|
|
list.sort((a, b) => a.username.localeCompare(b.username));
|
|
names.sort((a, b) => a.localeCompare(b));
|
|
root.users = list;
|
|
root.usernames = names;
|
|
root.loaded = true;
|
|
root.refreshing = false;
|
|
_refreshSyncedThemeFlags();
|
|
_loadProfileIcons();
|
|
}, 0);
|
|
}
|
|
|
|
function _refreshSyncedThemeFlags() {
|
|
if (usernames.length === 0) {
|
|
syncedThemePaths = ({});
|
|
return;
|
|
}
|
|
const checks = usernames.map(u => `[ -f "${syncedSettingsPath(u)}" ] && echo "${u}:1" || echo "${u}:0"`).join("; ");
|
|
Proc.runCommand("greeterUsersService-syncedThemes", ["sh", "-c", checks], (output, exitCode) => {
|
|
const map = {};
|
|
const lines = (output || "").trim().split("\n").filter(l => l.length > 0);
|
|
for (let i = 0; i < lines.length; i++) {
|
|
const parts = lines[i].split(":");
|
|
if (parts.length >= 2)
|
|
map[parts[0]] = parts[1] === "1";
|
|
}
|
|
root.syncedThemePaths = map;
|
|
}, 0);
|
|
}
|
|
|
|
function profileImagePath(username) {
|
|
if (!username)
|
|
return "";
|
|
return profileImageMap[username] || "";
|
|
}
|
|
|
|
function _loadProfileIcons() {
|
|
if (users.length === 0) {
|
|
profileImageMap = ({});
|
|
return;
|
|
}
|
|
const script = users.map(u => {
|
|
const safeUser = u.username.replace(/'/g, "'\\''");
|
|
const safeHome = (u.home || "").replace(/'/g, "'\\''");
|
|
const cacheDir = usersCacheDir + "/" + u.username;
|
|
return `( icon=""; for f in "${cacheDir}/profile.jpg" "${cacheDir}/profile.jpeg" "${cacheDir}/profile.png" "${cacheDir}/profile.webp" "/var/lib/AccountsService/icons/${safeUser}" "${safeHome}/.face" "${safeHome}/.face.icon"; do if [ -f "$f" ] && [ -r "$f" ]; then icon="$f"; break; fi; done; echo "${u.username}:$icon" )`;
|
|
}).join("; ");
|
|
Proc.runCommand("greeterUsersService-profileIcons", ["sh", "-c", script], (output, exitCode) => {
|
|
const map = {};
|
|
const lines = (output || "").trim().split("\n").filter(l => l.length > 0);
|
|
for (let i = 0; i < lines.length; i++) {
|
|
const idx = lines[i].indexOf(":");
|
|
if (idx <= 0)
|
|
continue;
|
|
const user = lines[i].substring(0, idx);
|
|
const icon = lines[i].substring(idx + 1).trim();
|
|
map[user] = icon && icon.length > 0 ? icon : "";
|
|
}
|
|
for (let j = 0; j < users.length; j++) {
|
|
const u = users[j].username;
|
|
if (!(u in map))
|
|
map[u] = "";
|
|
}
|
|
root.profileImageMap = map;
|
|
}, 0);
|
|
}
|
|
}
|