Files
SaraFem/Bookmarks.py
T
2026-09-24 22:03:58 +02:00

87 lines
3.0 KiB
Python

"""Sidebar bookmarks, stored in ~/.config/SaraFem/.sfem_bookmarks.toml."""
from dataclasses import dataclass
from pathlib import Path
import toml
from Core import BookmarksPath, ConfigDir
DefaultIcon = "BOOKMARK_OUTLINE"
TrashPath = Path.home() / ".local" / "share" / "Trash" / "files"
# One-time marker: without it, re-adding the Trash bookmark to old files (see
# LoadBookmarks) would run on every load and undo the user removing it.
_TrashMigrationMarker = ConfigDir / ".trash_bookmark_migrated"
# A small curated set for the icon picker, rather than the whole Material set.
IconChoices = [
"BOOKMARK_OUTLINE", "HOME_OUTLINED", "FOLDER_OUTLINED", "DESCRIPTION_OUTLINED",
"DOWNLOAD_OUTLINED", "IMAGE_OUTLINED", "MUSIC_NOTE_OUTLINED", "VIDEOCAM_OUTLINED",
"CODE_OUTLINED", "STAR_OUTLINE", "FAVORITE_OUTLINE", "WORK_OUTLINE",
]
@dataclass
class Bookmark:
Name: str
Path: Path
Icon: str = DefaultIcon
def DefaultBookmarks() -> list[Bookmark]:
return [
Bookmark("Home", Path.home(), "HOME_OUTLINED"),
Bookmark("Documents", Path.home() / "Documents", "DESCRIPTION_OUTLINED"),
Bookmark("Downloads", Path.home() / "Downloads", "DOWNLOAD_OUTLINED"),
Bookmark("Pictures", Path.home() / "Pictures", "IMAGE_OUTLINED"),
Bookmark("Trash", TrashPath, "DELETE_OUTLINE"),
]
def SaveBookmarks(Bookmarks: list[Bookmark]) -> None:
ConfigDir.mkdir(parents=True, exist_ok=True)
Data = {"Bookmark": [{"Name": B.Name, "Path": str(B.Path), "Icon": B.Icon} for B in Bookmarks]}
BookmarksPath.write_text(toml.dumps(Data))
def LoadBookmarks() -> list[Bookmark]:
if not BookmarksPath.exists():
Bookmarks = DefaultBookmarks()
SaveBookmarks(Bookmarks)
return Bookmarks
try:
Data = toml.loads(BookmarksPath.read_text())
except toml.TomlDecodeError:
return DefaultBookmarks()
Entries = Data.get("Bookmark", [])
Bookmarks = [
Bookmark(Entry["Name"], Path(Entry["Path"]), Entry.get("Icon", DefaultIcon))
for Entry in Entries
if "Name" in Entry and "Path" in Entry
]
if not Bookmarks:
return DefaultBookmarks()
# Trash used to be a hardcoded Sidebar entry, not a real bookmark (so it
# couldn't be edited). Migrate existing bookmark files that predate that —
# but only once, so deliberately removing Trash afterwards actually sticks.
if not _TrashMigrationMarker.exists():
if not any(B.Path == TrashPath for B in Bookmarks):
Bookmarks.append(Bookmark("Trash", TrashPath, "DELETE_OUTLINE"))
SaveBookmarks(Bookmarks)
ConfigDir.mkdir(parents=True, exist_ok=True)
_TrashMigrationMarker.touch()
return Bookmarks
def AddBookmark(Name: str, TargetPath: Path, Icon: str = DefaultIcon) -> None:
Bookmarks = LoadBookmarks()
if any(B.Path == TargetPath for B in Bookmarks):
return # already bookmarked
Bookmarks.append(Bookmark(Name, TargetPath, Icon))
SaveBookmarks(Bookmarks)