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:
1 parent
079ef664a2
commit
49b7a3f577
12 files changed
+574
-68
No files matched your search
@@ -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"],
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user