feat(channels): sort sidebar by latest activity, with favorite tier

Channels in the sidebar and mobile dropdown now sort by most recent
message first, with favorited channels pinned above non-favorites.
Reordering is push-driven via the existing new_message socket event:
the affected item is moved to the top of its tier in the DOM, no full
re-render. Favorites are toggled via a star icon in Manage Channels
and persisted in read_status.is_favorite for cross-device sync.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
MarekWo
2026-04-29 22:48:33 +02:00
parent a335f521e4
commit a2d3111e1c
5 changed files with 215 additions and 8 deletions
+30 -1
View File
@@ -30,6 +30,7 @@ def load_read_status():
channels = {}
dm = {}
muted_channels = []
favorite_channels = []
for key, row in rows.items():
if key.startswith('chan_'):
@@ -40,6 +41,11 @@ def load_read_status():
muted_channels.append(int(chan_idx))
except ValueError:
pass
if row.get('is_favorite'):
try:
favorite_channels.append(int(chan_idx))
except ValueError:
pass
elif key.startswith('dm_'):
conv_id = key[3:] # "dm_name_User1" -> "name_User1"
dm[conv_id] = row['last_seen_ts']
@@ -48,11 +54,12 @@ def load_read_status():
'channels': channels,
'dm': dm,
'muted_channels': muted_channels,
'favorite_channels': favorite_channels,
}
except Exception as e:
logger.error(f"Error loading read status: {e}")
return {'channels': {}, 'dm': {}, 'muted_channels': []}
return {'channels': {}, 'dm': {}, 'muted_channels': [], 'favorite_channels': []}
def save_read_status(status):
@@ -126,6 +133,28 @@ def set_channel_muted(channel_idx, muted):
return False
def get_favorite_channels():
"""Get list of favorite channel indices."""
try:
db = _get_db()
return db.get_favorite_channels()
except Exception as e:
logger.error(f"Error getting favorite channels: {e}")
return []
def set_channel_favorite(channel_idx, favorite):
"""Set favorite state for a channel."""
try:
db = _get_db()
db.set_channel_favorite(int(channel_idx), favorite)
logger.info(f"Channel {channel_idx} {'favorited' if favorite else 'unfavorited'}")
return True
except Exception as e:
logger.error(f"Error setting favorite for channel {channel_idx}: {e}")
return False
def mark_all_channels_read(channel_timestamps):
"""Mark all channels as read in bulk.