feat(r2): C6 the review, and C7
- The zoom route becomes the review for image, video AND audio: the native player on the stage for sound and video, the Fit/1:1 toggle for pictures only. The judgment rail, the tape and the filmstrip are each a data-region. The stage never is, so a playing track survives an in-place save. - The rail shows the whole-set number, K of M in the review ring and the position in the group; then the caption, and the flag and notes, landing back here (back=view). A pick targeting this item is answerable in place. On the last item the end-of-set block lists what was seen, the flags, and every other open question. - The keys are ← → Space F N Esc. Every one is ignored in an editable field, and Esc returns to the grid at the tile you were on. - _marks.html gains picks_only/back_view, so a pick form has one renderer wherever it sits. - In-place swaps now carry an unsaved draft across. A half-typed note survives a flag, except in the form that was just sent. - The filmstrip keeps the current frame in view. - C7: no emblem in the chrome, pinned. Browser tests cover: F typed into the note stays a letter and does not flag; F outside the note flags in place and the draft survives; Space moves; Esc lands on the grid tile. 706 passed.
This commit is contained in:
+48
-11
@@ -1706,19 +1706,56 @@ def create_app(
|
||||
"flagged": any(m.shape == "flag" for m in item_marks),
|
||||
}
|
||||
|
||||
if item is not None and item.kind == "image":
|
||||
# prev/next ring (wraps; only when there is more than one item in
|
||||
# it). R2 C2: the ring is `review_chain` — the item order filtered to
|
||||
# MEDIA — so a set that mixes pictures and sound steps through both.
|
||||
names = review_chain(items)
|
||||
if item is not None and item.kind in REVIEW_KINDS:
|
||||
# THE REVIEW (R2 C6): images, video and audio at full size with the
|
||||
# judgment on screen. The ring is `review_chain` — the item order
|
||||
# filtered to MEDIA — and the prev/next, the filmstrip and the tape
|
||||
# all read that ONE list, so they cannot disagree about "next".
|
||||
ring = review_chain(items)
|
||||
by_rel = {it.rel: it for it in items}
|
||||
pos = ring.index(f)
|
||||
prev_url = next_url = None
|
||||
if f in names and len(names) > 1:
|
||||
i = names.index(f)
|
||||
prev_url = quote(names[(i - 1) % len(names)], safe="/")
|
||||
next_url = quote(names[(i + 1) % len(names)], safe="/")
|
||||
if len(ring) > 1:
|
||||
prev_url = quote(ring[(pos - 1) % len(ring)], safe="/")
|
||||
next_url = quote(ring[(pos + 1) % len(ring)], safe="/")
|
||||
flagged_rels = {m.target for m in marks
|
||||
if m.shape == "flag" and m.error is None}
|
||||
# recorded above, before this read: the current item counts as seen
|
||||
seen = read_seen(booth) & set(ring)
|
||||
film = [{"name": r, "url": by_rel[r].url, "ordinal": by_rel[r].ordinal,
|
||||
"kind": by_rel[r].kind, "blurred": by_rel[r].blurred,
|
||||
"flagged": r in flagged_rels, "seen": r in seen,
|
||||
"current": r == f} for r in ring]
|
||||
# Position within the group, only when there IS grouping: two or
|
||||
# more groups among the ring. One group for everything says nothing.
|
||||
group = None
|
||||
ring_groups = {by_rel[r].group for r in ring if by_rel[r].group}
|
||||
if item.group and len(ring_groups) > 1:
|
||||
members = [r for r in ring if by_rel[r].group == item.group]
|
||||
group = {"key": item.group, "k": members.index(f) + 1, "n": len(members)}
|
||||
open_now = open_marks(marks)
|
||||
return templates.TemplateResponse(
|
||||
request, "view.html", {**common, "prev_url": prev_url, "next_url": next_url}
|
||||
)
|
||||
request, "view.html", {
|
||||
**common,
|
||||
"kind": item.kind,
|
||||
"ordinal": item.ordinal,
|
||||
"ord_width": len(str(len(items))),
|
||||
"ring_k": pos + 1,
|
||||
"ring_m": len(ring),
|
||||
"prev_url": prev_url,
|
||||
"next_url": next_url,
|
||||
"film": film,
|
||||
"seen_n": len(seen),
|
||||
"group": group,
|
||||
# a question ABOUT this item is answerable here; the rest are
|
||||
# a count and a link — until the last item, where the end of
|
||||
# the set offers them all
|
||||
"item_picks": [m for m in open_now if m.target == f],
|
||||
"other_picks": [m for m in open_now if m.target != f],
|
||||
"is_last": pos == len(ring) - 1,
|
||||
"tray": [x for x in film if x["flagged"]],
|
||||
"back_url": f"/b/{quote(name, safe='')}/#item-{item.url}",
|
||||
})
|
||||
|
||||
# .md renders, .txt/.log show as text — viewable in-booth, no download
|
||||
if item is not None:
|
||||
|
||||
Reference in New Issue
Block a user