Files
spoopyghosty0--frameport/tests/test_context_menus.py
T
spoopyghosty0 27694243f2 Screenshots: copy an image to the clipboard; holiday showers; perfect pacing stays
- Screenshots tab: Copy image (a button on the card under the pointer, the right-click menu and the viewer) puts
  the full-size screenshot on this PC's clipboard (core/clipboard.py: Windows/WSL PowerShell bitmap + file,
  macOS osascript, Linux wl-copy/xclip; Flet's set_image in web mode)
- Clicking a holiday badge showers the window: New Year confetti, winter snow, Valentine hearts, digits of pi,
  clovers, hopping eggs, bouncing pumpkins (moved like the confetti: one page update per phase)
- Perfect pacing after 2.5 minutes on target; the Perfect pacing pill and line stay until the rate slips
- Full charge: only the ring pulses (with a glow behind it), the percentage stays put
- Upload hop a little slower
2026-10-09 15:59:02 -04:00

131 lines
5.2 KiB
Python

"""Right-click menus in the Files and Screenshots tabs: what they offer, and that a right-click on one of several
selected items acts on the whole selection (as in a file manager)."""
from types import SimpleNamespace
from frameport.install.files import Entry
from frameport.ui import components as C
from frameport.ui.views.files import FilesView
from frameport.ui.views.screenshots import ALL, ScreenshotsView
class FakeApp(SimpleNamespace):
def __init__(self):
super().__init__(copied=[], page=SimpleNamespace(run_task=lambda fn, *a, **k: None))
def copy(self, text):
self.copied.append(text)
def labels(actions):
return [a[0] if a else "—" for a in actions]
def test_menu_targets_selection_or_single():
assert C.menu_targets("a", ["a", "b"]) == ["a", "b"]
assert C.menu_targets("c", ["a", "b"]) == ["c"] # outside the selection: only the clicked item
assert C.menu_targets("a", ["a"]) == ["a"]
def files_view():
v = FilesView(FakeApp())
v.loc = {"id": "videos", "label": "Videos", "path": "/home/x/Videos", "android": "/sdcard/Movies"}
v.path = "/home/x/Videos/trips"
v.entries = [Entry("clips", "/home/x/Videos/trips/clips", True, 0, 0),
Entry("a.mp4", "/home/x/Videos/trips/a.mp4", False, 10, 0),
Entry("b.mp4", "/home/x/Videos/trips/b.mp4", False, 20, 0)]
return v
def test_files_menu_single_entry_and_folder_space():
v = files_view()
folder = labels(v.menu_actions(v.entries[0]))
assert folder[:4] == ["Open", "Download to this PC…", "Rename…", "Copy path"]
assert "Select" in folder and folder[-1] == "Delete…"
actions = v.menu_actions(v.entries[1])
assert "Open" not in labels(actions)
dict((a[0], a[2]) for a in actions if a)["Copy path"](None)
assert v.app.copied == ["/sdcard/Movies/trips/a.mp4"] # as games see it
space = labels(v.menu_actions(None))
assert space[:3] == ["Upload files…", "Upload folder…", "New folder…"] and "Refresh" in space
def test_files_menu_on_a_selection_acts_on_all_of_it():
v = files_view()
v.selected = {v.entries[1].path, v.entries[2].path}
multi = labels(v.menu_actions(v.entries[2]))
assert "Download 2 items to this PC…" in multi and "Delete 2 items…" in multi
assert "Rename…" not in multi and "Clear selection" in multi
assert "Download to this PC…" in labels(v.menu_actions(v.entries[0])) # not in the selection: just that one
def test_files_menu_keeps_lepton_links_safe():
v = files_view()
v.loc = {"id": "app:x", "label": "Game", "path": "/base/external", "android": "/sdcard"}
v.path = "/base/external"
link = Entry("Movies", "/base/external/Movies", True, 0, 0, link=True)
v.entries = [link]
got = labels(v.menu_actions(link))
assert "Rename…" not in got and "Delete…" not in got and "Select" not in got
def screenshots_view():
v = ScreenshotsView(FakeApp())
v.shots = [{"path": f"/s/{i}.jpg", "package": "com.x" if i < 2 else "", "title": "X", "time": 1} for i in range(3)]
v._fill_dropdown()
return v
def test_screenshots_menu():
v = screenshots_view()
v.games = [{"package": "com.x", "title": "X", "count": 2}, {"package": "", "count": 1}]
v._fill_dropdown()
one = labels(v.menu_actions(v.shots[0]))
assert one[:4] == ["View", "Copy image", "Download…", "Show only this game's screenshots"]
assert one[-1] == "Delete…"
assert "Show only screenshots not from a FramePort game" in labels(v.menu_actions(v.shots[2]))
v.filter = "com.x"
assert not any("Show only" in x for x in labels(v.menu_actions(v.shots[0])))
v.filter = ALL
v.selected = {v.shots[0]["path"], v.shots[1]["path"]}
multi = labels(v.menu_actions(v.shots[1]))
assert "Download 2 screenshots…" in multi and "Delete 2 screenshots…" in multi and "View" not in multi
assert "Copy image" not in multi # (the clipboard holds one picture)
assert labels(v.menu_actions(None))[:2] == ["Download all (3)…", "Select all"]
def test_drag_select_paints_a_selection():
sel = set()
d = C.DragSelect(lambda k: k in sel, lambda k, on: (sel.add if on else sel.discard)(k),
can_select=lambda k: k != "locked")
d.hover("a", True) # just hovering: nothing happens
assert sel == set()
d.start() # press on "a" and drag
for k in ("b", "locked", "c"):
d.hover(k, True)
d.hover("b", True) # passing an item again doesn't flip it back
d.end()
assert sel == {"a", "b", "c"}
d.hover("d", True) # after the drag: hover only
assert "d" not in sel
def test_drag_select_from_a_selected_item_deselects():
sel = {"a", "b", "c"}
d = C.DragSelect(lambda k: k in sel, lambda k, on: (sel.add if on else sel.discard)(k))
d.hover("b", True)
d.start()
d.hover("c", True)
d.end()
assert sel == {"a"}
def test_drag_select_from_empty_space_selects_and_calls_on_start():
sel, started = set(), []
d = C.DragSelect(lambda k: k in sel, lambda k, on: (sel.add if on else sel.discard)(k),
on_start=lambda: started.append(1))
d.hover("a", True)
d.hover("a", False) # left the item: the drag starts on empty space
d.start()
d.hover("x", True)
assert sel == {"x"} and started == [1]