This commit is contained in:
Jesús Pavón Abián
2026-01-10 19:46:53 +01:00
55 changed files with 1504 additions and 407 deletions
@@ -11,10 +11,10 @@ from datetime import datetime
from multiplatform_widgets import widgets
log = logging.getLogger("wxUI.buffers.atprotosocial.panels")
log = logging.getLogger("wxUI.buffers.blueski.panels")
class ATProtoSocialHomeTimelinePanel(object):
class BlueskiHomeTimelinePanel(object):
"""Minimal Home timeline buffer for Bluesky.
Exposes a .buffer wx.Panel with a List control and provides
@@ -27,6 +27,7 @@ class ATProtoSocialHomeTimelinePanel(object):
self.account = session.get_name()
self.name = name
self.type = "home_timeline"
self.timeline_algorithm = None
self.invisible = True
self.needs_init = True
self.buffer = _HomePanel(parent, name)
@@ -49,17 +50,16 @@ class ATProtoSocialHomeTimelinePanel(object):
# The atproto SDK expects params, not raw kwargs
try:
from atproto import models as at_models # type: ignore
# Home: algorithmic/default timeline
try:
params = at_models.AppBskyFeedGetTimeline.Params(limit=count)
res = api.app.bsky.feed.get_timeline(params)
except Exception:
# Some SDKs may require explicit algorithm for home; try behavioral
params = at_models.AppBskyFeedGetTimeline.Params(limit=count, algorithm="behavioral")
res = api.app.bsky.feed.get_timeline(params)
params = at_models.AppBskyFeedGetTimeline.Params(
limit=count,
algorithm=self.timeline_algorithm
)
res = api.app.bsky.feed.get_timeline(params)
except Exception:
# Fallback to plain dict params if typed models unavailable
res = api.app.bsky.feed.get_timeline({"limit": count})
payload = {"limit": count}
if self.timeline_algorithm:
payload["algorithm"] = self.timeline_algorithm
res = api.app.bsky.feed.get_timeline(payload)
feed = getattr(res, "feed", [])
self.cursor = getattr(res, "cursor", None)
self.items = []
@@ -103,10 +103,17 @@ class ATProtoSocialHomeTimelinePanel(object):
api = self.session._ensure_client()
try:
from atproto import models as at_models # type: ignore
params = at_models.AppBskyFeedGetTimeline.Params(limit=40, cursor=self.cursor)
params = at_models.AppBskyFeedGetTimeline.Params(
limit=40,
cursor=self.cursor,
algorithm=self.timeline_algorithm
)
res = api.app.bsky.feed.get_timeline(params)
except Exception:
res = api.app.bsky.feed.get_timeline({"limit": 40, "cursor": self.cursor})
payload = {"limit": 40, "cursor": self.cursor}
if self.timeline_algorithm:
payload["algorithm"] = self.timeline_algorithm
res = api.app.bsky.feed.get_timeline(payload)
feed = getattr(res, "feed", [])
self.cursor = getattr(res, "cursor", None)
new_items = []
@@ -144,7 +151,7 @@ class ATProtoSocialHomeTimelinePanel(object):
log.exception("Failed to load more Bluesky timeline items")
return 0
# Alias to integrate with mainController expectations for ATProto
# Alias to integrate with mainController expectations for Blueski
def load_more_posts(self, *args, **kwargs):
return self.get_more_items()
@@ -281,12 +288,13 @@ class _HomePanel(wx.Panel):
self.SetSizer(sizer)
class ATProtoSocialFollowingTimelinePanel(ATProtoSocialHomeTimelinePanel):
class BlueskiFollowingTimelinePanel(BlueskiHomeTimelinePanel):
"""Following-only timeline (reverse-chronological)."""
def __init__(self, parent, name: str, session):
super().__init__(parent, name, session)
self.type = "following_timeline"
self.timeline_algorithm = "reverse-chronological"
# Make sure the underlying wx panel also reflects this type
try:
self.buffer.type = "following_timeline"
@@ -302,7 +310,7 @@ class ATProtoSocialFollowingTimelinePanel(ATProtoSocialHomeTimelinePanel):
api = self.session._ensure_client()
# Following timeline via reverse-chronological algorithm on get_timeline
# Use plain dict to avoid typed-model mismatches across SDK versions
res = api.app.bsky.feed.get_timeline({"limit": count, "algorithm": "reverse-chronological"})
res = api.app.bsky.feed.get_timeline({"limit": count, "algorithm": self.timeline_algorithm})
feed = getattr(res, "feed", [])
self.cursor = getattr(res, "cursor", None)
self.items = []
@@ -343,7 +351,11 @@ class ATProtoSocialFollowingTimelinePanel(ATProtoSocialHomeTimelinePanel):
try:
api = self.session._ensure_client()
# Pagination via reverse-chronological algorithm on get_timeline
res = api.app.bsky.feed.get_timeline({"limit": 40, "cursor": self.cursor, "algorithm": "reverse-chronological"})
res = api.app.bsky.feed.get_timeline({
"limit": 40,
"cursor": self.cursor,
"algorithm": self.timeline_algorithm
})
feed = getattr(res, "feed", [])
self.cursor = getattr(res, "cursor", None)
new_items = []
@@ -6,9 +6,9 @@ from pubsub import pub
from approve.translation import translate as _
from approve.notifications import NotificationError
# Assuming controller.atprotosocial.userList.get_user_profile_details and session.util._format_profile_data exist
# Assuming controller.blueski.userList.get_user_profile_details and session.util._format_profile_data exist
# For direct call to util:
# from sessions.atprotosocial import utils as ATProtoSocialUtils
# from sessions.blueski import utils as BlueskiUtils
logger = logging.getLogger(__name__)
@@ -272,7 +272,7 @@ class ShowUserProfileDialog(wx.Dialog):
self.SetTitle(f"{_('User Profile')} - {text}")
```python
# Example of how this dialog might be called from atprotosocial.Handler.user_details:
# Example of how this dialog might be called from blueski.Handler.user_details:
# (This is conceptual, actual integration in handler.py will use the dialog)
#
# async def user_details(self, buffer_panel_or_user_ident):
+4
View File
@@ -8,6 +8,8 @@ class base(wx.Menu):
self.Append(self.boost)
self.reply = wx.MenuItem(self, wx.ID_ANY, _(u"Re&ply"))
self.Append(self.reply)
self.edit = wx.MenuItem(self, wx.ID_ANY, _(u"&Edit"))
self.Append(self.edit)
self.fav = wx.MenuItem(self, wx.ID_ANY, _(u"&Add to favorites"))
self.Append(self.fav)
self.unfav = wx.MenuItem(self, wx.ID_ANY, _(u"R&emove from favorites"))
@@ -36,6 +38,8 @@ class notification(wx.Menu):
self.Append(self.boost)
self.reply = wx.MenuItem(self, wx.ID_ANY, _(u"Re&ply"))
self.Append(self.reply)
self.edit = wx.MenuItem(self, wx.ID_ANY, _(u"&Edit"))
self.Append(self.edit)
self.fav = wx.MenuItem(self, wx.ID_ANY, _(u"&Add to favorites"))
self.Append(self.fav)
self.unfav = wx.MenuItem(self, wx.ID_ANY, _(u"R&emove from favorites"))
+10 -10
View File
@@ -51,7 +51,7 @@ class Post(wx.Dialog):
visibility_sizer.Add(self.visibility, 0, 0, 0)
language_sizer = wx.BoxSizer(wx.HORIZONTAL)
post_actions_sizer.Add(language_sizer, 0, wx.RIGHT, 20)
lang_label = wx.StaticText(self, wx.ID_ANY, _("Language"))
lang_label = wx.StaticText(self, wx.ID_ANY, _("&Language"))
language_sizer.Add(lang_label, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 5)
self.language = wx.ComboBox(self, wx.ID_ANY, choices=languages, style=wx.CB_DROPDOWN | wx.CB_READONLY)
language_sizer.Add(self.language, 0, wx.ALIGN_CENTER_VERTICAL, 0)
@@ -234,9 +234,9 @@ class viewPost(wx.Dialog):
def create_buttons_section(self, panel):
sizer = wx.BoxSizer(wx.HORIZONTAL)
self.mute = wx.Button(panel, wx.ID_ANY, _("Mute conversation"))
self.mute = wx.Button(panel, wx.ID_ANY, _("&Mute conversation"))
self.mute.Enable(False)
self.share = wx.Button(panel, wx.ID_ANY, _("Copy link to clipboard"))
self.share = wx.Button(panel, wx.ID_ANY, _("&Copy link to clipboard"))
self.share.Enable(False)
self.spellcheck = wx.Button(panel, wx.ID_ANY, _("Check &spelling..."))
self.translateButton = wx.Button(panel, wx.ID_ANY, _("&Translate..."))
@@ -295,7 +295,7 @@ class poll(wx.Dialog):
sizer_1 = wx.BoxSizer(wx.VERTICAL)
period_sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer_1.Add(period_sizer, 1, wx.EXPAND, 0)
label_period = wx.StaticText(self, wx.ID_ANY, _("Participation time"))
label_period = wx.StaticText(self, wx.ID_ANY, _("&Participation time"))
period_sizer.Add(label_period, 0, 0, 0)
self.period = wx.ComboBox(self, wx.ID_ANY, choices=[_("5 minutes"), _("30 minutes"), _("1 hour"), _("6 hours"), _("1 day"), _("2 days"), _("3 days"), _("4 days"), _("5 days"), _("6 days"), _("7 days")], style=wx.CB_DROPDOWN | wx.CB_READONLY | wx.CB_SIMPLE)
self.period.SetFocus()
@@ -305,36 +305,36 @@ class poll(wx.Dialog):
sizer_1.Add(sizer_2, 1, wx.EXPAND, 0)
option1_sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer_2.Add(option1_sizer, 1, wx.EXPAND, 0)
label_2 = wx.StaticText(self, wx.ID_ANY, _("Option 1"))
label_2 = wx.StaticText(self, wx.ID_ANY, _("Option &1"))
option1_sizer.Add(label_2, 0, 0, 0)
self.option1 = wx.TextCtrl(self, wx.ID_ANY, "")
self.option1.SetMaxLength(25)
option1_sizer.Add(self.option1, 0, 0, 0)
option2_sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer_2.Add(option2_sizer, 1, wx.EXPAND, 0)
label_3 = wx.StaticText(self, wx.ID_ANY, _("Option 2"))
label_3 = wx.StaticText(self, wx.ID_ANY, _("Option &2"))
option2_sizer.Add(label_3, 0, 0, 0)
self.option2 = wx.TextCtrl(self, wx.ID_ANY, "")
self.option2.SetMaxLength(25)
option2_sizer.Add(self.option2, 0, 0, 0)
option3_sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer_2.Add(option3_sizer, 1, wx.EXPAND, 0)
label_4 = wx.StaticText(self, wx.ID_ANY, _("Option 3"))
label_4 = wx.StaticText(self, wx.ID_ANY, _("Option &3"))
option3_sizer.Add(label_4, 0, 0, 0)
self.option3 = wx.TextCtrl(self, wx.ID_ANY, "")
self.option3.SetMaxLength(25)
option3_sizer.Add(self.option3, 0, 0, 0)
option4_sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer_2.Add(option4_sizer, 1, wx.EXPAND, 0)
label_5 = wx.StaticText(self, wx.ID_ANY, _("Option 4"))
label_5 = wx.StaticText(self, wx.ID_ANY, _("Option &4"))
option4_sizer.Add(label_5, 0, 0, 0)
self.option4 = wx.TextCtrl(self, wx.ID_ANY, "")
self.option4.SetMaxLength(25)
option4_sizer.Add(self.option4, 0, 0, 0)
self.multiple = wx.CheckBox(self, wx.ID_ANY, _("Allow multiple choices per user"))
self.multiple = wx.CheckBox(self, wx.ID_ANY, _("&Allow multiple choices per user"))
self.multiple.SetValue(False)
sizer_1.Add(self.multiple, 0, wx.ALL, 5)
self.hide_votes = wx.CheckBox(self, wx.ID_ANY, _("Hide votes count until the poll expires"))
self.hide_votes = wx.CheckBox(self, wx.ID_ANY, _("&Hide votes count until the poll expires"))
self.hide_votes.SetValue(False)
sizer_1.Add(self.hide_votes, 0, wx.ALL, 5)
btn_sizer = wx.StdDialogButtonSizer()
+2 -2
View File
@@ -141,7 +141,7 @@ class ShowUserProfile(wx.Dialog):
mainSizer.Add(privateSizer, 0, wx.ALL | wx.CENTER)
botSizer = wx.BoxSizer(wx.HORIZONTAL)
botLabel = wx.StaticText(self.panel, label=_("&Bot account: "))
botLabel = wx.StaticText(self.panel, label=_("B&ot account: "))
botText = self.createTextCtrl(bullSwitch[user.bot], (30, 30))
botSizer.Add(botLabel, wx.SizerFlags().Center())
botSizer.Add(botText, wx.SizerFlags().Center())
@@ -154,7 +154,7 @@ class ShowUserProfile(wx.Dialog):
discoverSizer.Add(discoverText, wx.SizerFlags().Center())
mainSizer.Add(discoverSizer, 0, wx.ALL | wx.CENTER)
posts = wx.Button(self.panel, label=_("{} p&osts. Click to open posts timeline").format(user.statuses_count))
posts = wx.Button(self.panel, label=_("{} pos&ts. Click to open posts timeline").format(user.statuses_count))
# posts.SetToolTip(_("Click to open {}'s posts").format(user.display_name))
posts.Bind(wx.EVT_BUTTON, self.onPost)
mainSizer.Add(posts, wx.SizerFlags().Center())
+1 -1
View File
@@ -119,7 +119,7 @@ class UpdateProfileDialog(wx.Dialog):
self.locked = wx.CheckBox(panel, label=_("&Private account"))
self.locked.SetValue(locked)
self.bot = wx.CheckBox(panel, label=_("&Bot account"))
self.bot = wx.CheckBox(panel, label=_("B&ot account"))
self.bot.SetValue(bot)
self.discoverable = wx.CheckBox(panel, label=_("&Discoverable account"))
self.discoverable.SetValue(discoverable)
+1 -1
View File
@@ -26,7 +26,7 @@ class EditTemplateDialog(wx.Dialog):
sizer_3.AddButton(self.button_SAVE)
self.button_CANCEL = wx.Button(self, wx.ID_CANCEL)
sizer_3.AddButton(self.button_CANCEL)
self.button_RESTORE = wx.Button(self, wx.ID_ANY, _("Restore template"))
self.button_RESTORE = wx.Button(self, wx.ID_ANY, _("&Restore template"))
self.button_RESTORE.Bind(wx.EVT_BUTTON, self.on_restore)
sizer_3.AddButton(self.button_CANCEL)
sizer_3.Realize()
+3 -3
View File
@@ -22,11 +22,11 @@ class UserListDialog(wx.Dialog):
user_list_sizer.Add(self.user_list, 1, wx.EXPAND | wx.ALL, 10)
main_sizer.Add(user_list_sizer, 1, wx.EXPAND | wx.ALL, 15)
buttons_sizer = wx.BoxSizer(wx.HORIZONTAL)
self.actions_button = wx.Button(panel, wx.ID_ANY, "Actions")
self.actions_button = wx.Button(panel, wx.ID_ANY, "&Actions")
buttons_sizer.Add(self.actions_button, 0, wx.RIGHT, 10)
self.details_button = wx.Button(panel, wx.ID_ANY, _("View profile"))
self.details_button = wx.Button(panel, wx.ID_ANY, _("&View profile"))
buttons_sizer.Add(self.details_button, 0, wx.RIGHT, 10)
close_button = wx.Button(panel, wx.ID_CANCEL, "Close")
close_button = wx.Button(panel, wx.ID_CANCEL, "&Close")
buttons_sizer.Add(close_button, 0)
main_sizer.Add(buttons_sizer, 0, wx.ALIGN_CENTER | wx.BOTTOM, 15)
panel.SetSizer(main_sizer)
+4 -4
View File
@@ -19,7 +19,7 @@ class mainFrame(wx.Frame):
self.menuitem_search = self.menubar_application.Append(wx.ID_ANY, _(u"&Search"))
self.lists = self.menubar_application.Append(wx.ID_ANY, _(u"&Lists manager"))
self.lists.Enable(False)
self.manageAliases = self.menubar_application.Append(wx.ID_ANY, _("Manage user aliases"))
self.manageAliases = self.menubar_application.Append(wx.ID_ANY, _("M&anage user aliases"))
self.keystroke_editor = self.menubar_application.Append(wx.ID_ANY, _(u"&Edit keystrokes"))
self.account_settings = self.menubar_application.Append(wx.ID_ANY, _(u"Account se&ttings"))
self.prefs = self.menubar_application.Append(wx.ID_PREFERENCES, _(u"&Global settings"))
@@ -56,7 +56,7 @@ class mainFrame(wx.Frame):
self.trends = self.menubar_buffer.Append(wx.ID_ANY, _(u"New &trending topics buffer..."))
self.filter = self.menubar_buffer.Append(wx.ID_ANY, _(u"Create a &filter"))
self.manage_filters = self.menubar_buffer.Append(wx.ID_ANY, _(u"&Manage filters"))
self.find = self.menubar_buffer.Append(wx.ID_ANY, _(u"Find a string in the currently focused buffer..."))
self.find = self.menubar_buffer.Append(wx.ID_ANY, _(u"F&ind a string in the currently focused buffer..."))
self.load_previous_items = self.menubar_buffer.Append(wx.ID_ANY, _(u"&Load previous items"))
self.menubar_buffer.AppendSeparator()
self.mute_buffer = self.menubar_buffer.AppendCheckItem(wx.ID_ANY, _(u"&Mute"))
@@ -66,8 +66,8 @@ class mainFrame(wx.Frame):
# audio menu
self.menubar_audio = wx.Menu()
self.seekLeft = self.menubar_audio.Append(wx.ID_ANY, _(u"&Seek back 5 seconds"))
self.seekRight = self.menubar_audio.Append(wx.ID_ANY, _(u"&Seek forward 5 seconds"))
self.seekLeft = self.menubar_audio.Append(wx.ID_ANY, _(u"Seek &back 5 seconds"))
self.seekRight = self.menubar_audio.Append(wx.ID_ANY, _(u"Seek &forward 5 seconds"))
# Help Menu
self.menubar_help = wx.Menu()