From 6d505c6fe7fde6772f7bfcb32dc4b9c3bd30d435 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 8 Nov 2021 16:11:09 -0600 Subject: [PATCH] Added new code for Tweet GUI and attachment of photos and gifts --- src/controller/messages.py | 253 +++++----- src/wxUI/dialogs/twitterDialogs/__init__.py | 1 + .../dialogs/twitterDialogs/tweetDialogs.py | 457 ++++++++++++++++++ 3 files changed, 601 insertions(+), 110 deletions(-) create mode 100644 src/wxUI/dialogs/twitterDialogs/__init__.py create mode 100644 src/wxUI/dialogs/twitterDialogs/tweetDialogs.py diff --git a/src/controller/messages.py b/src/controller/messages.py index a748464d..9417ad90 100644 --- a/src/controller/messages.py +++ b/src/controller/messages.py @@ -1,123 +1,67 @@ # -*- coding: utf-8 -*- -import re -import platform +import os import arrow import languageHandler -system = platform.system() +import wx import widgetUtils import output -import url_shortener import sound import config from pubsub import pub from twitter_text import parse_tweet -if system == "Windows": - from wxUI.dialogs import message, urlList - from wxUI import commonMessageDialogs - from extra import translator, SpellChecker, autocompletionUsers - from extra.AudioUploader import audioUploader -elif system == "Linux": - from gtkUI.dialogs import message +from wxUI.dialogs import twitterDialogs, urlList +#from wxUI.dialogs import twitterDialogs +from wxUI import commonMessageDialogs +from extra import translator, SpellChecker, autocompletionUsers +from extra.AudioUploader import audioUploader from sessions.twitter import utils -from . import attach class basicTweet(object): """ This class handles the tweet main features. Other classes should derive from this class.""" - def __init__(self, session, title, caption, text, messageType="tweet", max=280, *args, **kwargs): + def __init__(self, session, title, caption, text="", messageType="tweet", max=280, *args, **kwargs): super(basicTweet, self).__init__() self.max = max self.title = title self.session = session - self.message = getattr(message, messageType)(title, caption, text, *args, **kwargs) + self.message = getattr(twitterDialogs, messageType)(title=title, caption=caption, message=text, *args, **kwargs) widgetUtils.connect_event(self.message.spellcheck, widgetUtils.BUTTON_PRESSED, self.spellcheck) - widgetUtils.connect_event(self.message.attach, widgetUtils.BUTTON_PRESSED, self.attach) + widgetUtils.connect_event(self.message.add_audio, widgetUtils.BUTTON_PRESSED, self.attach) widgetUtils.connect_event(self.message.text, widgetUtils.ENTERED_TEXT, self.text_processor) - widgetUtils.connect_event(self.message.shortenButton, widgetUtils.BUTTON_PRESSED, self.shorten) - widgetUtils.connect_event(self.message.unshortenButton, widgetUtils.BUTTON_PRESSED, self.unshorten) - widgetUtils.connect_event(self.message.translateButton, widgetUtils.BUTTON_PRESSED, self.translate) - if hasattr(self.message, "long_tweet"): - widgetUtils.connect_event(self.message.long_tweet, widgetUtils.CHECKBOX, self.text_processor) - if config.app["app-settings"]["remember_mention_and_longtweet"]: - self.message.long_tweet.SetValue(config.app["app-settings"]["longtweet"]) + widgetUtils.connect_event(self.message.translate, widgetUtils.BUTTON_PRESSED, self.translate) + if hasattr(self.message, "add"): + widgetUtils.connect_event(self.message.add, widgetUtils.BUTTON_PRESSED, self.on_attach) self.attachments = [] def translate(self, event=None): dlg = translator.gui.translateDialog() if dlg.get_response() == widgetUtils.OK: - text_to_translate = self.message.get_text() + text_to_translate = self.message.text.GetValue() language_dict = translator.translator.available_languages() for k in language_dict: if language_dict[k] == dlg.dest_lang.GetStringSelection(): dst = k msg = translator.translator.translate(text=text_to_translate, target=dst) - self.message.set_text(msg) + self.message.text.ChangeValue(msg) self.text_processor() - self.message.text_focus() + self.message.text.SetFocus() output.speak(_(u"Translated")) else: return - def shorten(self, event=None): - urls = utils.find_urls_in_text(self.message.get_text()) - if len(urls) == 0: - output.speak(_(u"There's no URL to be shortened")) - self.message.text_focus() - elif len(urls) == 1: - self.message.set_text(self.message.get_text().replace(urls[0], url_shortener.shorten(urls[0]))) - output.speak(_(u"URL shortened")) - self.text_processor() - self.message.text_focus() - elif len(urls) > 1: - list_urls = urlList.urlList() - list_urls.populate_list(urls) - if list_urls.get_response() == widgetUtils.OK: - self.message.set_text(self.message.get_text().replace(urls[list_urls.get_item()], url_shortener.shorten(list_urls.get_string()))) - output.speak(_(u"URL shortened")) - self.text_processor() - self.message.text_focus() - - def unshorten(self, event=None): - urls = utils.find_urls_in_text(self.message.get_text()) - if len(urls) == 0: - output.speak(_(u"There's no URL to be expanded")) - self.message.text_focus() - elif len(urls) == 1: - self.message.set_text(self.message.get_text().replace(urls[0], url_shortener.unshorten(urls[0]))) - output.speak(_(u"URL expanded")) - self.text_processor() - self.message.text_focus() - elif len(urls) > 1: - list_urls = urlList.urlList() - list_urls.populate_list(urls) - if list_urls.get_response() == widgetUtils.OK: - self.message.set_text(self.message.get_text().replace(urls[list_urls.get_item()], url_shortener.unshorten(list_urls.get_string()))) - output.speak(_(u"URL expanded")) - self.text_processor() - self.message.text_focus() - def text_processor(self, *args, **kwargs): - if len(self.message.get_text()) > 1: - self.message.enable_button("shortenButton") - self.message.enable_button("unshortenButton") - else: - self.message.disable_button("shortenButton") - self.message.disable_button("unshortenButton") - if self.message.get("long_tweet") == False and hasattr(self, "max"): - text = self.message.get_text() - results = parse_tweet(text) - self.message.set_title(_(u"%s - %s of %d characters") % (self.title, results.weightedLength, self.max)) - if results.weightedLength > self.max: - self.session.sound.play("max_length.ogg") - else: - self.message.set_title(_(u"%s - %s characters") % (self.title, len(self.message.get_text()))) + text = self.message.text.GetValue() + results = parse_tweet(text) + self.message.SetTitle(_("%s - %s of %d characters") % (self.title, results.weightedLength, self.max)) + if results.weightedLength > self.max: + self.session.sound.play("max_length.ogg") def spellcheck(self, event=None): - text = self.message.get_text() + text = self.message.text.GetValue() checker = SpellChecker.spellchecker.spellChecker(text, "") if hasattr(checker, "fixed_text"): - self.message.set_text(checker.fixed_text) + self.message.text.ChangeValue(checker.fixed_text) self.text_processor() - self.message.text_focus() + self.message.text.SetFocus() def attach(self, *args, **kwargs): def completed_callback(dlg): @@ -125,48 +69,145 @@ class basicTweet(object): pub.unsubscribe(dlg.uploaderDialog.update, "uploading") dlg.uploaderDialog.destroy() if "sndup.net/" in url: - self.message.set_text(self.message.get_text()+url+" #audio") + self.message.text.ChangeValue(self.message.text.GetValue()+url+" #audio") self.text_processor() else: commonMessageDialogs.common_error(url) - dlg.cleanup() dlg = audioUploader.audioUploader(self.session.settings, completed_callback) - self.message.text_focus() + self.message.text.SetFocus() + + def can_attach(self): + if len(self.attachments) == 0: + return True + elif len(self.attachments) == 1 and (self.attachments[0]["type"] == "video" or self.attachments[0]["type"] == "gif"): + return False + elif len(self.attachments) < 4: + return True + return False + + def on_attach(self, *args, **kwargs): + can_attach = self.can_attach() + menu = self.message.attach_menu(can_attach) + self.message.Bind(wx.EVT_MENU, self.on_attach_image, self.message.add_image) + self.message.Bind(wx.EVT_MENU, self.on_attach_video, self.message.add_video) + self.message.Bind(wx.EVT_MENU, self.on_attach_poll, self.message.add_poll) + self.message.PopupMenu(menu, self.message.add.GetPosition()) + + def on_attach_image(self, *args, **kwargs): + image, description = self.message.get_image() + if image != None: + if image.endswith("gif"): + image_type = "gif" + else: + image_type = "photo" + imageInfo = {"type": image_type, "file": image, "description": description} + if len(self.attachments) > 0 and image_type == "gif": + return self.message.unable_to_attach_file() + self.attachments.append(imageInfo) + self.message.add_item(item=[os.path.basename(imageInfo["file"]), imageInfo["type"], imageInfo["description"]]) + self.text_processor() + + def on_attach_video(self, *args, **kwargs): + video = self.message.get_video() + if video != None: + videoInfo = {"type": "video", "file": video, "description": ""} + if len(self.attachments) > 0: + return self.message.unable_to_attach_file() + self.attachments.append(videoInfo) + self.message.add_item(item=[os.path.basename(videoInfo["file"]), videoInfo["type"], videoInfo["description"]]) + self.text_processor() + + def on_attach_poll(self, *args, **kwargs): + pass class tweet(basicTweet): def __init__(self, session, title, caption, text, max=280, messageType="tweet", *args, **kwargs): + self.thread = [] super(tweet, self).__init__(session, title, caption, text, messageType, max, *args, **kwargs) self.image = None - widgetUtils.connect_event(self.message.upload_image, widgetUtils.BUTTON_PRESSED, self.upload_image) - widgetUtils.connect_event(self.message.autocompletionButton, widgetUtils.BUTTON_PRESSED, self.autocomplete_users) + widgetUtils.connect_event(self.message.autocomplete_users, widgetUtils.BUTTON_PRESSED, self.autocomplete_users) + if hasattr(self.message, "add_tweet"): + widgetUtils.connect_event(self.message.add_tweet, widgetUtils.BUTTON_PRESSED, self.add_tweet) + widgetUtils.connect_event(self.message.remove_tweet, widgetUtils.BUTTON_PRESSED, self.remove_tweet) + widgetUtils.connect_event(self.message.remove_attachment, widgetUtils.BUTTON_PRESSED, self.remove_attachment) self.text_processor() - def upload_image(self, *args, **kwargs): - a = attach.attach() - if len(a.attachments) != 0: - self.attachments = a.attachments - def autocomplete_users(self, *args, **kwargs): c = autocompletionUsers.completion.autocompletionUsers(self.message, self.session.session_id) c.show_menu() + def add_tweet(self, event, update_gui=True, *args, **kwargs): + text = self.message.text.GetValue() + attachments = self.attachments[::] + tweetdata = dict(text=text, attachments=attachments) + self.thread.append(tweetdata) + if update_gui: + self.message.reset_controls() + self.message.add_item(item=[text, len(attachments)], list_type="tweet") + self.message.text.SetFocus() + self.text_processor() + + def get_tweet_data(self): + self.add_tweet(event=None, update_gui=False) + return self.thread + + def text_processor(self, *args, **kwargs): + super(tweet, self).text_processor(*args, **kwargs) + if len(self.thread) > 0: + self.message.tweets.Enable(True) + self.message.remove_tweet.Enable(True) + else: + self.message.tweets.Enable(False) + self.message.remove_tweet.Enable(False) + if len(self.attachments) > 0: + self.message.attachments.Enable(True) + self.message.remove_attachment.Enable(True) + else: + self.message.attachments.Enable(False) + self.message.remove_attachment.Enable(False) + + def remove_tweet(self, *args, **kwargs): + tweet = self.message.tweets.GetFocusedItem() + if tweet > -1 and len(self.thread) > tweet: + self.thread.pop(tweet) + self.message.remove_item(list_type="tweet") + self.text_processor() + self.message.text.SetFocus() + + def remove_attachment(self, *args, **kwargs): + attachment = self.message.attachments.GetFocusedItem() + if attachment > -1 and len(self.attachments) > attachment: + self.attachments.pop(attachment) + self.message.remove_item(list_type="attachment") + self.text_processor() + self.message.text.SetFocus() + class reply(tweet): def __init__(self, session, title, caption, text, users=[], ids=[]): super(reply, self).__init__(session, title, caption, text, messageType="reply", users=users) self.ids = ids self.users = users if len(users) > 0: - widgetUtils.connect_event(self.message.mentionAll, widgetUtils.CHECKBOX, self.mention_all) - self.message.enable_button("mentionAll") + widgetUtils.connect_event(self.message.mention_all, widgetUtils.CHECKBOX, self.mention_all) + self.message.mention_all.Enable(True) if config.app["app-settings"]["remember_mention_and_longtweet"]: - self.message.mentionAll.SetValue(config.app["app-settings"]["mention_all"]) + self.message.mention_all.SetValue(config.app["app-settings"]["mention_all"]) self.mention_all() - self.message.set_cursor_at_end() + self.message.text.SetInsertionPoint(len(self.message.text.GetValue())) self.text_processor() + def text_processor(self, *args, **kwargs): + super(tweet, self).text_processor(*args, **kwargs) + if len(self.attachments) > 0: + self.message.attachments.Enable(True) + self.message.remove_attachment.Enable(True) + else: + self.message.attachments.Enable(False) + self.message.remove_attachment.Enable(False) + def mention_all(self, *args, **kwargs): - if self.message.mentionAll.GetValue() == True: + if self.message.mention_all.GetValue() == True: for i in self.message.checkboxes: i.SetValue(True) i.Hide() @@ -190,14 +231,14 @@ class reply(tweet): return people class dm(basicTweet): - def __init__(self, session, title, caption, text): - super(dm, self).__init__(session, title, caption, text, messageType="dm", max=10000) - widgetUtils.connect_event(self.message.autocompletionButton, widgetUtils.BUTTON_PRESSED, self.autocomplete_users) + def __init__(self, session, title, caption, users): + super(dm, self).__init__(session, title, caption, messageType="dm", max=10000, users=users) + widgetUtils.connect_event(self.message.autocomplete_users, widgetUtils.BUTTON_PRESSED, self.autocomplete_users) self.text_processor() widgetUtils.connect_event(self.message.cb, widgetUtils.ENTERED_TEXT, self.user_changed) def user_changed(self, *args, **kwargs): - self.title = _("Direct message to %s") % (self.message.get_user()) + self.title = _("Direct message to %s") % (self.message.cb.GetValue()) self.text_processor() def autocomplete_users(self, *args, **kwargs): @@ -264,29 +305,21 @@ class viewTweet(basicTweet): for z in tweet.retweeted_status.extended_entities["media"]: if "ext_alt_text" in z and z["ext_alt_text"] != None: image_description.append(z["ext_alt_text"]) - self.message = message.viewTweet(text, rt_count, favs_count, source, date) + self.message = twitterDialogs.viewTweet(text, rt_count, favs_count, source, date) results = parse_tweet(text) self.message.set_title(results.weightedLength) [self.message.set_image_description(i) for i in image_description] else: self.title = _(u"View item") text = tweet - self.message = message.viewNonTweet(text, date) + self.message = twitterDialogs.viewNonTweet(text, date) widgetUtils.connect_event(self.message.spellcheck, widgetUtils.BUTTON_PRESSED, self.spellcheck) if item_url != "": self.message.enable_button("share") widgetUtils.connect_event(self.message.share, widgetUtils.BUTTON_PRESSED, self.share) self.item_url = item_url widgetUtils.connect_event(self.message.translateButton, widgetUtils.BUTTON_PRESSED, self.translate) - if self.contain_urls() == True: - self.message.enable_button("unshortenButton") - widgetUtils.connect_event(self.message.unshortenButton, widgetUtils.BUTTON_PRESSED, self.unshorten) - self.message.get_response() - - def contain_urls(self): - if len(utils.find_urls_in_text(self.message.get_text())) > 0: - return True - return False + self.message.ShowModal() def clear_text(self, text): urls = utils.find_urls_in_text(text) diff --git a/src/wxUI/dialogs/twitterDialogs/__init__.py b/src/wxUI/dialogs/twitterDialogs/__init__.py new file mode 100644 index 00000000..c6b568e0 --- /dev/null +++ b/src/wxUI/dialogs/twitterDialogs/__init__.py @@ -0,0 +1 @@ +from .tweetDialogs import tweet, reply, dm, viewTweet, viewNonTweet \ No newline at end of file diff --git a/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py b/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py new file mode 100644 index 00000000..d07f10da --- /dev/null +++ b/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py @@ -0,0 +1,457 @@ +""" GUI dialogs for tweet writing and displaying. """ +import wx +from typing import List + +class tweet(wx.Dialog): + def __init__(self, title: str, caption: str, message: str = "", max_length: int = 280, thread_mode: bool = True, *args, **kwds) -> None: + """ Creates the basic Tweet dialog. This might be considered the base class for other dialogs. + title str: title to be used in the dialog. + caption str: This is the text to be placed alongside the text field. + message str: Text to be inserted in the tweet. + max_length int: Maximum amount of characters the tweet will accept. By default is 280 chahracters. + thread_mode bool: If set to False, disables the button that allows to make threads by adding more tweets. + """ + super(tweet, self).__init__(parent=None, *args, **kwds) + self.SetTitle(title) + self.create_controls(max_length=max_length, caption=caption, message=message, thread_mode=thread_mode) + + def create_controls(self, message: str, caption: str, max_length: int, thread_mode: bool) -> None: + panel = wx.Panel(self) + mainBox = wx.BoxSizer(wx.VERTICAL) + text_sizer = wx.BoxSizer(wx.VERTICAL) + mainBox.Add(text_sizer, 1, wx.EXPAND, 0) + label_1 = wx.StaticText(panel, wx.ID_ANY, caption) + text_sizer.Add(label_1, 0, 0, 0) + self.text = wx.TextCtrl(panel, wx.ID_ANY, "", style=wx.TE_MULTILINE|wx.TE_PROCESS_ENTER) + self.Bind(wx.EVT_CHAR_HOOK, self.handle_keys, self.text) + self.text.SetMinSize((1000, 158)) + self.text.SetMaxLength(max_length) + text_sizer.Add(self.text, 1, wx.EXPAND, 0) + list_sizer = wx.BoxSizer(wx.HORIZONTAL) + mainBox.Add(list_sizer, 1, wx.EXPAND, 0) + Attachment_sizer = wx.BoxSizer(wx.VERTICAL) + list_sizer.Add(Attachment_sizer, 1, wx.EXPAND, 0) + label_2 = wx.StaticText(panel, wx.ID_ANY, _("Attachments")) + Attachment_sizer.Add(label_2, 0, 0, 0) + self.attachments = wx.ListCtrl(panel, wx.ID_ANY, style=wx.BORDER_SUNKEN | wx.LC_HRULES | wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_VRULES) + self.attachments.AppendColumn(_("File")) + self.attachments.AppendColumn(_("Type")) + self.attachments.AppendColumn(_("Description")) + Attachment_sizer.Add(self.attachments, 1, wx.EXPAND, 0) + self.remove_attachment = wx.Button(panel, wx.ID_ANY, _("Delete attachment")) + self.remove_attachment.Enable(False) + Attachment_sizer.Add(self.remove_attachment, 0, 0, 0) + tweet_sizer = wx.BoxSizer(wx.VERTICAL) + list_sizer.Add(tweet_sizer, 1, wx.EXPAND, 0) + label_3 = wx.StaticText(panel, wx.ID_ANY, _("Added Tweets")) + tweet_sizer.Add(label_3, 0, 0, 0) + self.tweets = wx.ListCtrl(panel, wx.ID_ANY, style=wx.BORDER_SUNKEN | wx.LC_HRULES | wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_VRULES) + self.tweets.AppendColumn(_("Text")) + self.tweets.AppendColumn(_("Attachments")) + self.tweets.Enable(False) + tweet_sizer.Add(self.tweets, 1, wx.EXPAND, 0) + self.remove_tweet = wx.Button(panel, wx.ID_ANY, _("Delete tweet")) + self.remove_tweet.Enable(False) + tweet_sizer.Add(self.remove_tweet, 0, 0, 0) + btn_sizer_1 = wx.BoxSizer(wx.HORIZONTAL) + mainBox.Add(btn_sizer_1, 1, wx.EXPAND, 0) + self.add = wx.Button(panel, wx.ID_ANY, _("A&dd...")) + btn_sizer_1.Add(self.add, 0, 0, 0) + self.add_tweet = wx.Button(panel, wx.ID_ANY, _("Add tweet")) + self.add_tweet.Enable(thread_mode) + btn_sizer_1.Add(self.add_tweet, 0, 0, 0) + self.add_audio = wx.Button(panel, wx.ID_ANY, _("&Attach audio...")) + btn_sizer_1.Add(self.add_audio, 0, 0, 0) + btn_sizer_2 = wx.BoxSizer(wx.HORIZONTAL) + mainBox.Add(btn_sizer_2, 1, wx.EXPAND, 0) + self.autocomplete_users = wx.Button(panel, wx.ID_ANY, _("Auto&complete users")) + btn_sizer_2.Add(self.autocomplete_users, 0, 0, 0) + self.spellcheck = wx.Button(panel, wx.ID_ANY, _("Check &spelling...")) + btn_sizer_2.Add(self.spellcheck, 0, 0, 0) + self.translate = wx.Button(panel, wx.ID_ANY, _("&Translate")) + btn_sizer_2.Add(self.translate, 0, 0, 0) + ok_cancel_sizer = wx.StdDialogButtonSizer() + mainBox.Add(ok_cancel_sizer, 0, wx.ALIGN_RIGHT | wx.ALL, 4) + self.send = wx.Button(panel, wx.ID_OK, _("Sen&d")) + self.send.SetDefault() + ok_cancel_sizer.Add(self.send, 0, 0, 0) + self.cancel = wx.Button(panel, wx.ID_CANCEL, "") + ok_cancel_sizer.AddButton(self.cancel) + ok_cancel_sizer.Realize() + panel.SetSizer(mainBox) + self.Fit() + self.SetAffirmativeId(self.send.GetId()) + self.SetEscapeId(self.cancel.GetId()) + self.Layout() + + def handle_keys(self, event: wx.Event, *args, **kwargs) -> None: + """ Allows to react to certain keyboard events from the text control. """ + shift=event.ShiftDown() + if event.GetKeyCode() == wx.WXK_RETURN and shift==False and hasattr(self,'send'): + self.EndModal(wx.ID_OK) + else: + event.Skip() + + def reset_controls(self) -> None: + """ Resetss text control and attachments to their default, empty values. This is used while adding more tweets in a thread. """ + self.text.ChangeValue("") + self.attachments.DeleteAllItems() + + def add_item(self, list_type: str = "attachment", item: List[str] = []) -> None: + """ Adds an item to a list control. Item should be a list with the same amount of items for each column present in the ListCtrl. """ + if list_type == "attachment": + self.attachments.Append(item) + else: + self.tweets.Append(item) + + def remove_item(self, list_type: str = "attachment") -> None: + if list_type == "attachment": + item = self.attachments.GetFocusedItem() + if item > -1: + self.attachments.DeleteItem(item) + else: + item = self.tweets.GetFocusedItem() + if item > -1: + self.tweets.DeleteItem(item) + + def attach_menu(self, event=None, enabled=True, *args, **kwargs): + menu = wx.Menu() + self.add_image = menu.Append(wx.ID_ANY, _("Image")) + self.add_image.Enable(enabled) + self.add_video = menu.Append(wx.ID_ANY, _("Video")) + self.add_video.Enable(enabled) + self.add_poll = menu.Append(wx.ID_ANY, _("Poll")) + self.add_poll.Enable(enabled) + return menu + + def ask_description(self): + dlg = wx.TextEntryDialog(self, _(u"please provide a description"), _(u"Description")) + dlg.ShowModal() + result = dlg.GetValue() + dlg.Destroy() + return result + + def get_image(self): + openFileDialog = wx.FileDialog(self, _(u"Select the picture to be uploaded"), "", "", _("Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif"), wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) + if openFileDialog.ShowModal() == wx.ID_CANCEL: + return (None, None) + dsc = self.ask_description() + return (openFileDialog.GetPath(), dsc) + + def get_video(self): + openFileDialog = wx.FileDialog(self, _("Select the video to be uploaded"), "", "", _("Video files (*.mp4)|*.mp4"), wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) + if openFileDialog.ShowModal() == wx.ID_CANCEL: + return None + return openFileDialog.GetPath() + + def unable_to_attach_file(self, *args, **kwargs): + return wx.MessageDialog(self, _("You need to delete other attachments first, as Videos and GIF's cannot be added with other attachments."), _("Error adding attachment"), wx.ICON_ERROR).ShowModal() + +class reply(tweet): + + def __init__(self, users: List[str] = [], *args, **kwargs) -> None: + self.users = users + super(reply, self).__init__(*args, **kwargs) + + def create_controls(self, message: str, caption: str, max_length: int, thread_mode: bool) -> None: + panel = wx.Panel(self) + mainBox = wx.BoxSizer(wx.VERTICAL) + text_sizer = wx.BoxSizer(wx.VERTICAL) + mainBox.Add(text_sizer, 1, wx.EXPAND, 0) + label_1 = wx.StaticText(panel, wx.ID_ANY, caption) + text_sizer.Add(label_1, 0, 0, 0) + self.text = wx.TextCtrl(panel, wx.ID_ANY, "", style=wx.TE_MULTILINE|wx.TE_PROCESS_ENTER) + self.Bind(wx.EVT_CHAR_HOOK, self.handle_keys, self.text) + self.text.SetMinSize((1000, 158)) + self.text.SetMaxLength(max_length) + text_sizer.Add(self.text, 1, wx.EXPAND, 0) + list_sizer = wx.BoxSizer(wx.HORIZONTAL) + mainBox.Add(list_sizer, 1, wx.EXPAND, 0) + Attachment_sizer = wx.BoxSizer(wx.VERTICAL) + list_sizer.Add(Attachment_sizer, 1, wx.EXPAND, 0) + label_2 = wx.StaticText(panel, wx.ID_ANY, _("Attachments")) + Attachment_sizer.Add(label_2, 0, 0, 0) + self.attachments = wx.ListCtrl(panel, wx.ID_ANY, style=wx.BORDER_SUNKEN | wx.LC_HRULES | wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_VRULES) + self.attachments.AppendColumn(_("File")) + self.attachments.AppendColumn(_("Type")) + self.attachments.AppendColumn(_("Description")) + Attachment_sizer.Add(self.attachments, 1, wx.EXPAND, 0) + self.remove_attachment = wx.Button(panel, wx.ID_ANY, _("Delete attachment")) + self.remove_attachment.Enable(False) + Attachment_sizer.Add(self.remove_attachment, 0, 0, 0) + user_sizer = wx.BoxSizer(wx.VERTICAL) + list_sizer.Add(user_sizer, 0, 0, 0) + self.mention_all = wx.CheckBox(panel, -1, _(u"&Mention to all"), size=wx.DefaultSize) + self.mention_all.Disable() + user_sizer.Add(self.mention_all, 0, wx.ALL, 5) + self.checkboxes = [] + for i in self.users: + user_checkbox = wx.CheckBox(panel, -1, "@"+i, size=wx.DefaultSize) + self.checkboxes.append(user_checkbox) + user_sizer.Add(self.checkboxes[-1], 0, wx.ALL, 5) + btn_sizer_1 = wx.BoxSizer(wx.HORIZONTAL) + mainBox.Add(btn_sizer_1, 1, wx.EXPAND, 0) + self.add = wx.Button(panel, wx.ID_ANY, _("A&dd...")) + btn_sizer_1.Add(self.add, 0, 0, 0) + self.add_audio = wx.Button(panel, wx.ID_ANY, _("&Attach audio...")) + btn_sizer_1.Add(self.add_audio, 0, 0, 0) + btn_sizer_2 = wx.BoxSizer(wx.HORIZONTAL) + mainBox.Add(btn_sizer_2, 1, wx.EXPAND, 0) + self.autocomplete_users = wx.Button(panel, wx.ID_ANY, _("Auto&complete users")) + btn_sizer_2.Add(self.autocomplete_users, 0, 0, 0) + self.spellcheck = wx.Button(panel, wx.ID_ANY, _("Check &spelling...")) + btn_sizer_2.Add(self.spellcheck, 0, 0, 0) + self.translate = wx.Button(panel, wx.ID_ANY, _("&Translate")) + btn_sizer_2.Add(self.translate, 0, 0, 0) + ok_cancel_sizer = wx.StdDialogButtonSizer() + mainBox.Add(ok_cancel_sizer, 0, wx.ALIGN_RIGHT | wx.ALL, 4) + self.send = wx.Button(panel, wx.ID_OK, _("Sen&d")) + self.send.SetDefault() + ok_cancel_sizer.Add(self.send, 0, 0, 0) + self.cancel = wx.Button(panel, wx.ID_CANCEL, "") + ok_cancel_sizer.AddButton(self.cancel) + ok_cancel_sizer.Realize() + panel.SetSizer(mainBox) + self.Fit() + self.SetAffirmativeId(self.send.GetId()) + self.SetEscapeId(self.cancel.GetId()) + self.Layout() + +class dm(tweet): + + def __init__(self, users: List[str] = [], *args, **kwargs) -> None: + self.users = users + super(dm, self).__init__(*args, **kwargs) + + def create_controls(self, message: str, caption: str, max_length: int, thread_mode: bool) -> None: + panel = wx.Panel(self) + mainBox = wx.BoxSizer(wx.VERTICAL) + label_recipient = wx.StaticText(panel, -1, _(u"&Recipient")) + self.cb = wx.ComboBox(panel, -1, choices=self.users, value=self.users[0], size=wx.DefaultSize) + self.autocomplete_users = wx.Button(panel, -1, _(u"Auto&complete users")) + recipient_sizer = wx.BoxSizer(wx.HORIZONTAL) + recipient_sizer.Add(label_recipient, 0, 0, 0) + recipient_sizer.Add(self.cb, 1, wx.EXPAND, 0) + mainBox.Add(recipient_sizer, 0, wx.EXPAND, 0) + text_sizer = wx.BoxSizer(wx.VERTICAL) + mainBox.Add(text_sizer, 1, wx.EXPAND, 0) + label_1 = wx.StaticText(panel, wx.ID_ANY, caption) + text_sizer.Add(label_1, 0, 0, 0) + self.text = wx.TextCtrl(panel, wx.ID_ANY, "", style=wx.TE_MULTILINE|wx.TE_PROCESS_ENTER) + self.Bind(wx.EVT_CHAR_HOOK, self.handle_keys, self.text) + self.text.SetMinSize((1000, 158)) + self.text.SetMaxLength(max_length) + self.text.SetFocus() + text_sizer.Add(self.text, 1, wx.EXPAND, 0) + list_sizer = wx.BoxSizer(wx.HORIZONTAL) + mainBox.Add(list_sizer, 1, wx.EXPAND, 0) + Attachment_sizer = wx.BoxSizer(wx.VERTICAL) + list_sizer.Add(Attachment_sizer, 1, wx.EXPAND, 0) + label_2 = wx.StaticText(panel, wx.ID_ANY, _("Attachments")) + Attachment_sizer.Add(label_2, 0, 0, 0) + self.attachments = wx.ListCtrl(panel, wx.ID_ANY, style=wx.BORDER_SUNKEN | wx.LC_HRULES | wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_VRULES) + self.attachments.AppendColumn(_("File")) + self.attachments.AppendColumn(_("Type")) + self.attachments.AppendColumn(_("Description")) + Attachment_sizer.Add(self.attachments, 1, wx.EXPAND, 0) + self.remove_attachment = wx.Button(panel, wx.ID_ANY, _("Delete attachment")) + self.remove_attachment.Enable(False) + Attachment_sizer.Add(self.remove_attachment, 0, 0, 0) + btn_sizer_1 = wx.BoxSizer(wx.HORIZONTAL) + mainBox.Add(btn_sizer_1, 1, wx.EXPAND, 0) + self.add = wx.Button(panel, wx.ID_ANY, _("A&dd...")) + btn_sizer_1.Add(self.add, 0, 0, 0) + self.add_audio = wx.Button(panel, wx.ID_ANY, _("&Attach audio...")) + btn_sizer_1.Add(self.add_audio, 0, 0, 0) + btn_sizer_2 = wx.BoxSizer(wx.HORIZONTAL) + mainBox.Add(btn_sizer_2, 1, wx.EXPAND, 0) + self.spellcheck = wx.Button(panel, wx.ID_ANY, _("Check &spelling...")) + btn_sizer_2.Add(self.spellcheck, 0, 0, 0) + self.translate = wx.Button(panel, wx.ID_ANY, _("&Translate")) + btn_sizer_2.Add(self.translate, 0, 0, 0) + ok_cancel_sizer = wx.StdDialogButtonSizer() + mainBox.Add(ok_cancel_sizer, 0, wx.ALIGN_RIGHT | wx.ALL, 4) + self.send = wx.Button(panel, wx.ID_OK, _("Sen&d")) + self.send.SetDefault() + ok_cancel_sizer.Add(self.send, 0, 0, 0) + self.cancel = wx.Button(panel, wx.ID_CANCEL, "") + ok_cancel_sizer.AddButton(self.cancel) + ok_cancel_sizer.Realize() + panel.SetSizer(mainBox) + self.Fit() + self.SetAffirmativeId(self.send.GetId()) + self.SetEscapeId(self.cancel.GetId()) + self.Layout() + +class viewTweet(wx.Dialog): + def set_title(self, lenght): + self.SetTitle(_(u"Tweet - %i characters ") % (lenght,)) + + def __init__(self, text, rt_count, favs_count, source, date="", *args, **kwargs): + super(viewTweet, self).__init__(None, size=(850,850)) + panel = wx.Panel(self) + label = wx.StaticText(panel, -1, _(u"Tweet")) + self.text = wx.TextCtrl(panel, -1, text, style=wx.TE_READONLY|wx.TE_MULTILINE, size=(250, 180)) + dc = wx.WindowDC(self.text) + dc.SetFont(self.text.GetFont()) + (x, y) = dc.GetMultiLineTextExtent("W"*280) + self.text.SetSize((x, y)) + self.text.SetFocus() + textBox = wx.BoxSizer(wx.HORIZONTAL) + textBox.Add(label, 0, wx.ALL, 5) + textBox.Add(self.text, 1, wx.EXPAND, 5) + mainBox = wx.BoxSizer(wx.VERTICAL) + mainBox.Add(textBox, 0, wx.ALL, 5) + label2 = wx.StaticText(panel, -1, _(u"Image description")) + self.image_description = wx.TextCtrl(panel, -1, style=wx.TE_READONLY|wx.TE_MULTILINE, size=(250, 180)) + dc = wx.WindowDC(self.image_description) + dc.SetFont(self.image_description.GetFont()) + (x, y) = dc.GetMultiLineTextExtent("0"*450) + self.image_description.SetSize((x, y)) + self.image_description.Enable(False) + iBox = wx.BoxSizer(wx.HORIZONTAL) + iBox.Add(label2, 0, wx.ALL, 5) + iBox.Add(self.image_description, 1, wx.EXPAND, 5) + mainBox.Add(iBox, 0, wx.ALL, 5) + rtCountLabel = wx.StaticText(panel, -1, _(u"Retweets: ")) + rtCount = wx.TextCtrl(panel, -1, rt_count, size=wx.DefaultSize, style=wx.TE_READONLY|wx.TE_MULTILINE) + rtBox = wx.BoxSizer(wx.HORIZONTAL) + rtBox.Add(rtCountLabel, 0, wx.ALL, 5) + rtBox.Add(rtCount, 0, wx.ALL, 5) + favsCountLabel = wx.StaticText(panel, -1, _(u"Likes: ")) + favsCount = wx.TextCtrl(panel, -1, favs_count, size=wx.DefaultSize, style=wx.TE_READONLY|wx.TE_MULTILINE) + favsBox = wx.BoxSizer(wx.HORIZONTAL) + favsBox.Add(favsCountLabel, 0, wx.ALL, 5) + favsBox.Add(favsCount, 0, wx.ALL, 5) + sourceLabel = wx.StaticText(panel, -1, _(u"Source: ")) + sourceTweet = wx.TextCtrl(panel, -1, source, size=wx.DefaultSize, style=wx.TE_READONLY|wx.TE_MULTILINE) + sourceBox = wx.BoxSizer(wx.HORIZONTAL) + sourceBox.Add(sourceLabel, 0, wx.ALL, 5) + sourceBox.Add(sourceTweet, 0, wx.ALL, 5) + dateLabel = wx.StaticText(panel, -1, _(u"Date: ")) + dateTweet = wx.TextCtrl(panel, -1, date, size=wx.DefaultSize, style=wx.TE_READONLY|wx.TE_MULTILINE) + dc = wx.WindowDC(dateTweet) + dc.SetFont(dateTweet.GetFont()) + (x, y) = dc.GetTextExtent("0"*100) + dateTweet.SetSize((x, y)) + dateBox = wx.BoxSizer(wx.HORIZONTAL) + dateBox.Add(dateLabel, 0, wx.ALL, 5) + dateBox.Add(dateTweet, 0, wx.ALL, 5) + infoBox = wx.BoxSizer(wx.HORIZONTAL) + infoBox.Add(rtBox, 0, wx.ALL, 5) + infoBox.Add(favsBox, 0, wx.ALL, 5) + infoBox.Add(sourceBox, 0, wx.ALL, 5) + mainBox.Add(infoBox, 0, wx.ALL, 5) + mainBox.Add(dateBox, 0, wx.ALL, 5) + self.share = wx.Button(panel, wx.ID_ANY, _("Copy link to clipboard")) + self.share.Enable(False) + self.spellcheck = wx.Button(panel, -1, _("Check &spelling..."), size=wx.DefaultSize) + self.translateButton = wx.Button(panel, -1, _(u"&Translate..."), size=wx.DefaultSize) + cancelButton = wx.Button(panel, wx.ID_CANCEL, _(u"C&lose"), size=wx.DefaultSize) + cancelButton.SetDefault() + buttonsBox = wx.BoxSizer(wx.HORIZONTAL) + buttonsBox.Add(self.share, 0, wx.ALL, 5) + buttonsBox.Add(self.spellcheck, 0, wx.ALL, 5) + buttonsBox.Add(self.translateButton, 0, wx.ALL, 5) + buttonsBox.Add(cancelButton, 0, wx.ALL, 5) + mainBox.Add(buttonsBox, 0, wx.ALL, 5) + selectId = wx.ID_ANY + self.Bind(wx.EVT_MENU, self.onSelect, id=selectId) + self.accel_tbl = wx.AcceleratorTable([ + (wx.ACCEL_CTRL, ord('A'), selectId), + ]) + self.SetAcceleratorTable(self.accel_tbl) + panel.SetSizer(mainBox) + self.SetClientSize(mainBox.CalcMin()) + + def set_text(self, text): + self.text.ChangeValue(text) + + def get_text(self): + return self.text.GetValue() + + def set_image_description(self, desc): + self.image_description.Enable(True) + if len(self.image_description.GetValue()) == 0: + self.image_description.SetValue(desc) + else: + self.image_description.SetValue(self.image_description.GetValue()+"\n"+desc) + + def text_focus(self): + self.text.SetFocus() + + def onSelect(self, ev): + self.text.SelectAll() + + def enable_button(self, buttonName): + if hasattr(self, buttonName): + return getattr(self, buttonName).Enable() + +class viewNonTweet(wx.Dialog): + + def __init__(self, text, date="", *args, **kwargs): + super(viewNonTweet, self).__init__(None, size=(850,850)) + self.SetTitle(_(u"View")) + panel = wx.Panel(self) + label = wx.StaticText(panel, -1, _(u"Item")) + self.text = wx.TextCtrl(parent=panel, id=-1, value=text, style=wx.TE_READONLY|wx.TE_MULTILINE, size=(250, 180)) + dc = wx.WindowDC(self.text) + dc.SetFont(self.text.GetFont()) + (x, y) = dc.GetMultiLineTextExtent("0"*140) + self.text.SetSize((x, y)) + self.text.SetFocus() + textBox = wx.BoxSizer(wx.HORIZONTAL) + textBox.Add(label, 0, wx.ALL, 5) + textBox.Add(self.text, 1, wx.EXPAND, 5) + mainBox = wx.BoxSizer(wx.VERTICAL) + mainBox.Add(textBox, 0, wx.ALL, 5) + if date != "": + dateLabel = wx.StaticText(panel, -1, _(u"Date: ")) + date = wx.TextCtrl(panel, -1, date, size=wx.DefaultSize, style=wx.TE_READONLY|wx.TE_MULTILINE) + dc = wx.WindowDC(date) + dc.SetFont(date.GetFont()) + (x, y) = dc.GetTextExtent("0"*100) + date.SetSize((x, y)) + dateBox = wx.BoxSizer(wx.HORIZONTAL) + dateBox.Add(dateLabel, 0, wx.ALL, 5) + dateBox.Add(date, 0, wx.ALL, 5) + mainBox.Add(dateBox, 0, wx.ALL, 5) + self.share = wx.Button(panel, wx.ID_ANY, _("Copy link to clipboard")) + self.share.Enable(False) + self.spellcheck = wx.Button(panel, -1, _("Check &spelling..."), size=wx.DefaultSize) + self.unshortenButton = wx.Button(panel, -1, _(u"&Expand URL"), size=wx.DefaultSize) + self.unshortenButton.Disable() + self.translateButton = wx.Button(panel, -1, _(u"&Translate..."), size=wx.DefaultSize) + cancelButton = wx.Button(panel, wx.ID_CANCEL, _(u"C&lose"), size=wx.DefaultSize) + cancelButton.SetDefault() + buttonsBox = wx.BoxSizer(wx.HORIZONTAL) + buttonsBox.Add(self.share, 0, wx.ALL, 5) + buttonsBox.Add(self.spellcheck, 0, wx.ALL, 5) + buttonsBox.Add(self.unshortenButton, 0, wx.ALL, 5) + buttonsBox.Add(self.translateButton, 0, wx.ALL, 5) + buttonsBox.Add(cancelButton, 0, wx.ALL, 5) + mainBox.Add(buttonsBox, 0, wx.ALL, 5) + selectId = wx.ID_ANY + self.Bind(wx.EVT_MENU, self.onSelect, id=selectId) + self.accel_tbl = wx.AcceleratorTable([ + (wx.ACCEL_CTRL, ord('A'), selectId), + ]) + self.SetAcceleratorTable(self.accel_tbl) + panel.SetSizer(mainBox) + self.SetClientSize(mainBox.CalcMin()) + + def onSelect(self, ev): + self.text.SelectAll() + + def set_text(self, text): + self.text.ChangeValue(text) + + def get_text(self): + return self.text.GetValue() + + def text_focus(self): + self.text.SetFocus() + + def enable_button(self, buttonName): + if hasattr(self, buttonName): + return getattr(self, buttonName).Enable()