mirror of
https://github.com/MCV-Software/TWBlue.git
synced 2026-01-12 05:10:05 +01:00
feat(mastodon): Add support for scheduled posts
- Added UI controls (checkbox, date/time pickers) to Post dialog - Implemented validation logic (min 5 mins future) - Updated session handler to pass scheduled_at to API
This commit is contained in:
@@ -65,6 +65,13 @@ class post(messages.basicMessage):
|
|||||||
postdata = dict(text=text, attachments=attachments, sensitive=self.message.sensitive.GetValue(), spoiler_text=None)
|
postdata = dict(text=text, attachments=attachments, sensitive=self.message.sensitive.GetValue(), spoiler_text=None)
|
||||||
if postdata.get("sensitive") == True:
|
if postdata.get("sensitive") == True:
|
||||||
postdata.update(spoiler_text=self.message.spoiler.GetValue())
|
postdata.update(spoiler_text=self.message.spoiler.GetValue())
|
||||||
|
|
||||||
|
# Check for scheduled post
|
||||||
|
if hasattr(self.message, 'get_scheduled_at'):
|
||||||
|
scheduled_at = self.message.get_scheduled_at()
|
||||||
|
if scheduled_at:
|
||||||
|
postdata['scheduled_at'] = scheduled_at
|
||||||
|
|
||||||
self.thread.append(postdata)
|
self.thread.append(postdata)
|
||||||
self.attachments = []
|
self.attachments = []
|
||||||
if update_gui:
|
if update_gui:
|
||||||
|
|||||||
@@ -222,9 +222,10 @@ class Session(base.baseSession):
|
|||||||
in_reply_to_id = reply_to
|
in_reply_to_id = reply_to
|
||||||
for obj in posts:
|
for obj in posts:
|
||||||
text = obj.get("text")
|
text = obj.get("text")
|
||||||
|
scheduled_at = obj.get("scheduled_at")
|
||||||
if len(obj["attachments"]) == 0:
|
if len(obj["attachments"]) == 0:
|
||||||
try:
|
try:
|
||||||
item = self.api_call(call_name="status_post", status=text, _sound="tweet_send.ogg", in_reply_to_id=in_reply_to_id, visibility=visibility, sensitive=obj["sensitive"], spoiler_text=obj["spoiler_text"], language=language)
|
item = self.api_call(call_name="status_post", status=text, _sound="tweet_send.ogg", in_reply_to_id=in_reply_to_id, visibility=visibility, sensitive=obj["sensitive"], spoiler_text=obj["spoiler_text"], language=language, scheduled_at=scheduled_at)
|
||||||
# If it fails, let's basically send an event with all passed info so we will catch it later.
|
# If it fails, let's basically send an event with all passed info so we will catch it later.
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
pub.sendMessage("mastodon.error_post", name=self.get_name(), reply_to=reply_to, visibility=visibility, posts=posts, lang=language)
|
pub.sendMessage("mastodon.error_post", name=self.get_name(), reply_to=reply_to, visibility=visibility, posts=posts, lang=language)
|
||||||
@@ -241,7 +242,7 @@ class Session(base.baseSession):
|
|||||||
for i in obj["attachments"]:
|
for i in obj["attachments"]:
|
||||||
media = self.api_call("media_post", media_file=i["file"], description=i["description"], synchronous=True)
|
media = self.api_call("media_post", media_file=i["file"], description=i["description"], synchronous=True)
|
||||||
media_ids.append(media.id)
|
media_ids.append(media.id)
|
||||||
item = self.api_call(call_name="status_post", status=text, _sound="tweet_send.ogg", in_reply_to_id=in_reply_to_id, media_ids=media_ids, visibility=visibility, poll=poll, sensitive=obj["sensitive"], spoiler_text=obj["spoiler_text"], language=language)
|
item = self.api_call(call_name="status_post", status=text, _sound="tweet_send.ogg", in_reply_to_id=in_reply_to_id, media_ids=media_ids, visibility=visibility, poll=poll, sensitive=obj["sensitive"], spoiler_text=obj["spoiler_text"], language=language, scheduled_at=scheduled_at)
|
||||||
if item != None:
|
if item != None:
|
||||||
in_reply_to_id = item["id"]
|
in_reply_to_id = item["id"]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import wx
|
import wx
|
||||||
|
import wx.adv
|
||||||
|
import datetime
|
||||||
|
|
||||||
class Post(wx.Dialog):
|
class Post(wx.Dialog):
|
||||||
def __init__(self, caption=_("Post"), text="", languages=[], *args, **kwds):
|
def __init__(self, caption=_("Post"), text="", languages=[], *args, **kwds):
|
||||||
@@ -60,6 +62,28 @@ class Post(wx.Dialog):
|
|||||||
self.sensitive.SetValue(False)
|
self.sensitive.SetValue(False)
|
||||||
self.sensitive.Bind(wx.EVT_CHECKBOX, self.on_sensitivity_changed)
|
self.sensitive.Bind(wx.EVT_CHECKBOX, self.on_sensitivity_changed)
|
||||||
main_sizer.Add(self.sensitive, 0, wx.ALL, 5)
|
main_sizer.Add(self.sensitive, 0, wx.ALL, 5)
|
||||||
|
|
||||||
|
# Scheduled post section
|
||||||
|
scheduled_box = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
self.scheduled = wx.CheckBox(self, wx.ID_ANY, _("Schedule &post"))
|
||||||
|
self.scheduled.SetValue(False)
|
||||||
|
self.scheduled.Bind(wx.EVT_CHECKBOX, self.on_schedule_changed)
|
||||||
|
scheduled_box.Add(self.scheduled, 0, wx.ALL, 5)
|
||||||
|
|
||||||
|
# Default to now + 6 minutes to be safe for the 5 minute minimum
|
||||||
|
future_dt = wx.DateTime.Now()
|
||||||
|
future_dt.Add(wx.TimeSpan(0, 6, 0, 0))
|
||||||
|
|
||||||
|
self.date_picker = wx.adv.DatePickerCtrl(self, wx.ID_ANY, dt=future_dt, style=wx.adv.DP_DROPDOWN | wx.adv.DP_SHOWCENTURY)
|
||||||
|
self.date_picker.Enable(False)
|
||||||
|
scheduled_box.Add(self.date_picker, 0, wx.ALL, 5)
|
||||||
|
|
||||||
|
self.time_picker = wx.adv.TimePickerCtrl(self, wx.ID_ANY, dt=future_dt)
|
||||||
|
self.time_picker.Enable(False)
|
||||||
|
scheduled_box.Add(self.time_picker, 0, wx.ALL, 5)
|
||||||
|
|
||||||
|
main_sizer.Add(scheduled_box, 0, wx.ALL, 5)
|
||||||
|
|
||||||
spoiler_box = wx.BoxSizer(wx.HORIZONTAL)
|
spoiler_box = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
spoiler_label = wx.StaticText(self, wx.ID_ANY, _("Content warning"))
|
spoiler_label = wx.StaticText(self, wx.ID_ANY, _("Content warning"))
|
||||||
self.spoiler = wx.TextCtrl(self, wx.ID_ANY)
|
self.spoiler = wx.TextCtrl(self, wx.ID_ANY)
|
||||||
@@ -80,8 +104,9 @@ class Post(wx.Dialog):
|
|||||||
text_actions_sizer.Add(self.translate, 0, 0, 0)
|
text_actions_sizer.Add(self.translate, 0, 0, 0)
|
||||||
btn_sizer = wx.StdDialogButtonSizer()
|
btn_sizer = wx.StdDialogButtonSizer()
|
||||||
main_sizer.Add(btn_sizer, 0, wx.ALIGN_RIGHT | wx.ALL, 4)
|
main_sizer.Add(btn_sizer, 0, wx.ALIGN_RIGHT | wx.ALL, 4)
|
||||||
self.send = wx.Button(self, wx.ID_OK, "")
|
self.send = wx.Button(self, wx.ID_ANY, _("&Send"))
|
||||||
self.send.SetDefault()
|
self.send.SetDefault()
|
||||||
|
self.send.Bind(wx.EVT_BUTTON, self.validate_and_send)
|
||||||
btn_sizer.AddButton(self.send)
|
btn_sizer.AddButton(self.send)
|
||||||
self.close = wx.Button(self, wx.ID_CLOSE, "")
|
self.close = wx.Button(self, wx.ID_CLOSE, "")
|
||||||
btn_sizer.AddButton(self.close)
|
btn_sizer.AddButton(self.close)
|
||||||
@@ -95,13 +120,50 @@ class Post(wx.Dialog):
|
|||||||
""" Allows to react to certain keyboard events from the text control. """
|
""" Allows to react to certain keyboard events from the text control. """
|
||||||
shift=event.ShiftDown()
|
shift=event.ShiftDown()
|
||||||
if event.GetKeyCode() == wx.WXK_RETURN and shift==False and hasattr(self,'send'):
|
if event.GetKeyCode() == wx.WXK_RETURN and shift==False and hasattr(self,'send'):
|
||||||
self.EndModal(wx.ID_OK)
|
self.validate_and_send()
|
||||||
else:
|
else:
|
||||||
event.Skip()
|
event.Skip()
|
||||||
|
|
||||||
|
def validate_and_send(self, event=None):
|
||||||
|
scheduled_at = self.get_scheduled_at()
|
||||||
|
if scheduled_at:
|
||||||
|
min_time = datetime.datetime.now() + datetime.timedelta(minutes=5)
|
||||||
|
if scheduled_at < min_time:
|
||||||
|
wx.MessageDialog(self,
|
||||||
|
_("Scheduled posts must be set at least 5 minutes in the future. Please adjust the time."),
|
||||||
|
_("Invalid scheduled time"),
|
||||||
|
wx.ICON_ERROR | wx.OK).ShowModal()
|
||||||
|
return
|
||||||
|
self.EndModal(wx.ID_OK)
|
||||||
|
|
||||||
def on_sensitivity_changed(self, *args, **kwargs):
|
def on_sensitivity_changed(self, *args, **kwargs):
|
||||||
self.spoiler.Enable(self.sensitive.GetValue())
|
self.spoiler.Enable(self.sensitive.GetValue())
|
||||||
|
|
||||||
|
def on_schedule_changed(self, *args, **kwargs):
|
||||||
|
enabled = self.scheduled.GetValue()
|
||||||
|
self.date_picker.Enable(enabled)
|
||||||
|
self.time_picker.Enable(enabled)
|
||||||
|
|
||||||
|
def get_scheduled_at(self):
|
||||||
|
if not self.scheduled.GetValue():
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Get date from date picker
|
||||||
|
wx_date = self.date_picker.GetValue()
|
||||||
|
# Get time from time picker
|
||||||
|
wx_time = self.time_picker.GetValue()
|
||||||
|
|
||||||
|
# Combine into a python datetime object
|
||||||
|
dt = datetime.datetime(
|
||||||
|
wx_date.GetYear(),
|
||||||
|
wx_date.GetMonth() + 1, # wx.DateTime months are 0-11
|
||||||
|
wx_date.GetDay(),
|
||||||
|
wx_time.GetHour(),
|
||||||
|
wx_time.GetMinute(),
|
||||||
|
wx_time.GetSecond()
|
||||||
|
)
|
||||||
|
return dt
|
||||||
|
|
||||||
def set_title(self, chars):
|
def set_title(self, chars):
|
||||||
self.SetTitle(_("Post - {} characters").format(chars))
|
self.SetTitle(_("Post - {} characters").format(chars))
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user