aboutsummaryrefslogtreecommitdiffstats
path: root/docs/superpowers/specs/2026-10-16-user-details-design.md
blob: 2b2819b2a34a64bf6957faa6beb4bfbcf511246e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# User details in the drawer

## Goal

Edit the user's own details from the drawer and write them where other
applications already look for them, so LibreOffice, KDE apps, SDDM and git
pick them up without being told.

## Where the details live

Measured on this machine:

- **AccountsService** (`org.freedesktop.Accounts`, D-Bus activated, not a
  running daemon until called): `RealName`, `Email`, `IconFile`, `Language`,
  `Location`. Read by KDE's Users settings, GNOME and SDDM. `SetRealName`
  also rewrites the GECOS field of `/etc/passwd`.
- **GECOS** is what LibreOffice's `libdesktopbe1lo.so` reads to prefill its
  user data (`givenname`). Name only, never email.
- **`~/.config/emaildefaults`** (KEMailSettings, `[PROFILE_Default]`):
  `FullName`, `EmailAddress`. Read by KDE mail apps.
- **git** global config (`~/.gitconfig`): `user.name`, `user.email`.

Polkit's `org.freedesktop.accounts.change-own-user-data` is implicit `yes` for
any, inactive and active sessions, so no write prompts for a password.

## Drawer row

A row at the top of the drawer's grid view, above the notification list:
the avatar in a circle, `Hello <login>` (the login name, `$USER`, which is
fixed and not editable), and the real name as a smaller sub-line under it.
Clicking it opens the user page; Escape and the mouse back button step out
as on every page.

## Module: `desktop/modules/user/`

- `UserModule.qml`: name `user`, label `User`, a `page`. It sets
  `tiled: false`, a new `Module` property (default `true`) that the drawer's
  tile grid filters on, so the module has a page and no tile.
- `UserRow.qml`: the drawer row. `Drawer.qml` places it above
  `NotificationList` and calls `show("user")` on click.
- `UserPage.qml`: the form. Avatar (click to choose a file with
  `QtQuick.Dialogs.FileDialog`, as the KDE Connect module already does; shown
  cropped to a circle, no cropping tool), name, email, language (a combo from
  `locale -a`, UTF-8 entries only), location (free text), and a line previewing
  what git will carry: `git: Jane D. <jane@example.org>`. A Save button sends
  only the fields that changed.
- `userctl`: bash, the only writer, like `statusctl`.

The page reads values when it opens. The row reads them when the drawer
opens.

## `userctl`

    userctl get              # key=value lines: name, email, avatar, language, location
    userctl set <key> <val>  # writes one field everywhere it lives

| Field | Writes |
| --- | --- |
| name | AccountsService `SetRealName`, emaildefaults `FullName`, git `user.name` (shortened) |
| email | AccountsService `SetEmail`, emaildefaults `EmailAddress`, git `user.email` |
| avatar | AccountsService `SetIconFile` (the daemon copies the file in) |
| language | AccountsService `SetLanguage` |
| location | AccountsService `SetLocation` |

AccountsService is called with `busctl --system`, emaildefaults with
`kwriteconfig6 --file emaildefaults --group PROFILE_Default`, git with
`git config --global`.

**Git name shortening.** The last whitespace-separated word becomes its first
character and a dot: `Jane Doèr` becomes `Jane D.`. A single-word name
is unchanged. The first character is taken by character, not byte, so an
accented initial survives.

`set` exits non-zero on the first failing write and prints the failing
command's stderr. The page shows that text under the field, and leaves the
field marked changed so Save retries it.

## Extending

A new detail is one entry in the field list in `UserPage.qml` and one `case`
in `userctl`. No settings framework.

## Testing

`test-userctl.sh`: stub `busctl`, `kwriteconfig6` and `git` on `PATH` that log
their arguments. Checks the shortening (two words, three words, one word,
accented initial), that each field reaches exactly its stores, and that a
failing stub makes `set` exit non-zero. It never calls the real
AccountsService or touches the real git config.

## Ceilings

- Values are read on open; a change made elsewhere while the page is open is
  not seen until it reopens.
- No `~/.face.icon`: SDDM reads the AccountsService icon.
- No vCard, no social links, no GPG key: nothing on the desktop reads them.
  The field list is where they would go.