Channel context menu: long-press/right-click a row → rename, favorite/unfavorite, add/change/remove icon (color or image), delete; removed star/delete row buttons; favorite + icon/color synced across devices

This commit is contained in:
ARIA committed 2026-08-20 20:55:24 +02:00
1 parent 079ef664a2
commit 49b7a3f577
12 files changed
+574 -68

No files matched your search

+50 -3
View File
@@ -64,10 +64,25 @@ class ChannelDirectory:
parent_chat_id TEXT,
is_default INTEGER NOT NULL DEFAULT 0,
archived INTEGER NOT NULL DEFAULT 0,
created REAL NOT NULL DEFAULT 0
created REAL NOT NULL DEFAULT 0,
favorite INTEGER NOT NULL DEFAULT 0,
icon TEXT,
color TEXT
)
"""
)
# Migrate existing DBs: add the cosmetic columns if missing.
existing = {
row[1] for row in self._conn.execute("PRAGMA table_info(channels)")
}
if "favorite" not in existing:
self._conn.execute(
"ALTER TABLE channels ADD COLUMN favorite INTEGER NOT NULL DEFAULT 0"
)
if "icon" not in existing:
self._conn.execute("ALTER TABLE channels ADD COLUMN icon TEXT")
if "color" not in existing:
self._conn.execute("ALTER TABLE channels ADD COLUMN color TEXT")
self._conn.execute(
"""
CREATE TABLE IF NOT EXISTS counters (
@@ -206,6 +221,35 @@ class ChannelDirectory:
self._conn.commit()
return self.get(chat_id)
def set_favorite(self, chat_id: str, on: bool) -> Optional[Dict[str, Any]]:
"""Toggle the cosmetic favorite flag (sorts to the top of the list)."""
with self._lock:
cur = self._conn.execute(
"UPDATE channels SET favorite = ? WHERE chat_id = ? AND archived = 0",
(1 if on else 0, chat_id),
)
self._conn.commit()
if cur.rowcount == 0:
return None
return self.get(chat_id)
def set_icon(self, chat_id: str, icon: Optional[str], color: Optional[str]) -> Optional[Dict[str, Any]]:
"""Set the channel's cosmetic icon (base64 image) and/or avatar color.
``icon`` is a base64-encoded image (or ``None`` to clear it); ``color``
is a ``#RRGGBB`` hex string (or ``None`` to clear it). Both are purely
cosmetic and independent of the name / default flag.
"""
with self._lock:
cur = self._conn.execute(
"UPDATE channels SET icon = ?, color = ? WHERE chat_id = ? AND archived = 0",
(icon, color, chat_id),
)
self._conn.commit()
if cur.rowcount == 0:
return None
return self.get(chat_id)
def delete(self, chat_id: str) -> Optional[Dict[str, Any]]:
"""Soft-delete (archive) a channel. History stays for search.
@@ -234,11 +278,11 @@ class ChannelDirectory:
return _row_to_entry(row) if row else None
def list(self, include_archived: bool = False) -> List[Dict[str, Any]]:
"""Directory listing. Default channel first, then creation order."""
"""Directory listing. Default first, then favorites, then creation order."""
sql = "SELECT * FROM channels"
if not include_archived:
sql += " WHERE archived = 0"
sql += " ORDER BY is_default DESC, created ASC"
sql += " ORDER BY is_default DESC, favorite DESC, created ASC"
with self._lock:
rows = self._conn.execute(sql).fetchall()
return [_row_to_entry(r) for r in rows]
@@ -318,6 +362,9 @@ def _row_to_entry(row: sqlite3.Row) -> Dict[str, Any]:
"is_default": bool(row["is_default"]),
"archived": bool(row["archived"]),
"created": row["created"],
"favorite": bool(row["favorite"]),
"icon": row["icon"],
"color": row["color"],
}