Add the Identity screen
A third top-level screen beside the library and develop, because naming a cluster and pulling a stranger out of it are tasks with their own rhythm and need the whole window. The screen is designed around the clustering being wrong, which is FR-CULL-10 rather than pessimism: grouping over-merges on siblings, on parents and children, and on the same person a decade apart. So Split off sits next to Confirm all rather than behind a menu, the confirm/reject pair is on the face itself, and a group the system found is drawn differently from a person the user has vouched for. Splitting rejects before it confirms. Without that the next clustering pass suggests the face straight back and the user's correction becomes an argument they keep having. Face crops come from the proxies the grid already built, one decode per image rather than per face -- a group photograph holding six faces of one family is one JPEG. Where the calibration is not fitted the screen says confidence is unavailable instead of printing a percentage that looks measured, which is FR-CULL-9's rule at the point it becomes visible. The verdict controls use drawn icons, not tick and cross characters: ui/icons.slint exists because those render as tofu on Android. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+63
-3
@@ -2,6 +2,7 @@ import { Theme } from "theme.slint";
|
||||
import { AdjustPanel, GeometryPanel, ModeStrip, ParamRow, TransferPanel, ViewMode } from "adjust.slint";
|
||||
import { GradientHandle, HandleRole, MaskPanel, MaskRow, SubjectRow } from "masks.slint";
|
||||
import { LaunchScreen } from "launch.slint";
|
||||
import { IdentityScreen, IdentityPerson, IdentityFace } from "identity.slint";
|
||||
import { LibraryGrid, LibraryCell, TimelineBar, PhotoRoll, KeywordRow } from "library.slint";
|
||||
import { Button, PanelHeading, Label, Value, Caption, Panel, EmptyState, ProgressBar, ActivityRow } from "widgets.slint";
|
||||
import { CollectionsPanel, CollectionRow, OfflinePrompt } from "collections.slint";
|
||||
@@ -516,6 +517,36 @@ export component AppWindow inherits Window {
|
||||
/// the page is reachable from the launch screen too.
|
||||
in property <bool> library-thumbnailing: false;
|
||||
in property <bool> library-open: false;
|
||||
|
||||
// --- people and faces (FR-CULL-8 … FR-CULL-12) ---
|
||||
//
|
||||
// A third top-level screen rather than a panel: naming a cluster and
|
||||
// pulling a stranger out of it are tasks with their own rhythm, and they
|
||||
// need the whole window. Gated the same way the other screens are, so
|
||||
// exactly one is ever up.
|
||||
in property <bool> show-identity: false;
|
||||
in property <[IdentityPerson]> identity-people;
|
||||
in property <[IdentityFace]> identity-faces;
|
||||
in property <int> identity-selected: -1;
|
||||
in property <string> identity-selected-name;
|
||||
in property <int> identity-unassigned: 0;
|
||||
in property <bool> identity-calibrated: false;
|
||||
in property <bool> identity-indexing: false;
|
||||
in property <string> identity-indexing-status;
|
||||
in property <bool> identity-model-missing: false;
|
||||
in property <int> identity-picked: 0;
|
||||
|
||||
callback identity-open();
|
||||
callback identity-close();
|
||||
callback identity-person-picked(int);
|
||||
callback identity-rename(string);
|
||||
callback identity-confirm-face(int);
|
||||
callback identity-reject-face(int);
|
||||
callback identity-toggle-pick(int);
|
||||
callback identity-confirm-all();
|
||||
callback identity-split-picked();
|
||||
callback identity-recluster();
|
||||
callback identity-delete-all();
|
||||
callback library-thumbnail-all();
|
||||
in-out property <length> library-cell-size: 180px;
|
||||
/// Whether this session is a touch one, which decides if the rating strip
|
||||
@@ -1236,9 +1267,37 @@ in property <bool> panel-visible: true;
|
||||
reset-defaults() => { root.settings-reset(); }
|
||||
}
|
||||
|
||||
// Like the launch screen, this replaces the window rather than
|
||||
// overlaying it — see `show-identity`.
|
||||
if !root.show-import && !root.show-settings && root.show-identity: IdentityScreen {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
people: root.identity-people;
|
||||
faces: root.identity-faces;
|
||||
selected-person: root.identity-selected;
|
||||
selected-name: root.identity-selected-name;
|
||||
unassigned: root.identity-unassigned;
|
||||
calibrated: root.identity-calibrated;
|
||||
indexing: root.identity-indexing;
|
||||
indexing-status: root.identity-indexing-status;
|
||||
model-missing: root.identity-model-missing;
|
||||
picked-count: root.identity-picked;
|
||||
|
||||
person-picked(id) => { root.identity-person-picked(id); }
|
||||
rename(name) => { root.identity-rename(name); }
|
||||
confirm-face(id) => { root.identity-confirm-face(id); }
|
||||
reject-face(id) => { root.identity-reject-face(id); }
|
||||
toggle-pick(id) => { root.identity-toggle-pick(id); }
|
||||
confirm-all() => { root.identity-confirm-all(); }
|
||||
split-picked() => { root.identity-split-picked(); }
|
||||
recluster() => { root.identity-recluster(); }
|
||||
delete-all-face-data() => { root.identity-delete-all(); }
|
||||
close() => { root.identity-close(); }
|
||||
}
|
||||
|
||||
// The launch screen replaces the whole window rather than overlaying it:
|
||||
// there is no library to look at until an account is configured.
|
||||
if !root.show-import && !root.show-settings && root.show-launch: LaunchScreen {
|
||||
if !root.show-import && !root.show-settings && !root.show-identity && root.show-launch: LaunchScreen {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
signed-in: root.launch-signed-in;
|
||||
@@ -1278,7 +1337,7 @@ in property <bool> panel-visible: true;
|
||||
// has been opened but no image chosen yet. The collections sidebar and the
|
||||
// grid are siblings here rather than the sidebar living inside the grid,
|
||||
// because the drag that connects them has to be owned above both.
|
||||
if !root.show-import && !root.show-settings && !root.show-launch && root.show-library: Rectangle {
|
||||
if !root.show-import && !root.show-settings && !root.show-identity && !root.show-launch && root.show-library: Rectangle {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: Theme.ground;
|
||||
@@ -1421,6 +1480,7 @@ in property <bool> panel-visible: true;
|
||||
can-import: root.import-supported;
|
||||
open-import() => { root.import-open(); }
|
||||
open-settings() => { root.settings-open(); }
|
||||
open-people() => { root.identity-open(); }
|
||||
|
||||
cell-pressed(i, ctrl, shift) => {
|
||||
root.library-cell-pressed(i, ctrl, shift);
|
||||
@@ -1486,7 +1546,7 @@ in property <bool> panel-visible: true;
|
||||
}
|
||||
}
|
||||
|
||||
if !root.show-import && !root.show-settings && !root.show-launch && !root.show-library: VerticalLayout {
|
||||
if !root.show-import && !root.show-settings && !root.show-identity && !root.show-launch && !root.show-library: VerticalLayout {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user