This commit is contained in:
Jesús Pavón Abián
2026-01-11 20:13:56 +01:00
parent 9d9d86160d
commit 932e44a9c9
391 changed files with 120828 additions and 1090 deletions

View File

View File

@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
import wx
class BaseWXDialog(wx.Dialog):
def __init__(self, *args, **kwargs):
super(BaseWXDialog, self).__init__(*args, **kwargs)
def get_response(self):
return self.ShowModal()
def get(self, control):
if hasattr(self, control):
control = getattr(self, control)
if hasattr(control, "GetValue"): return getattr(control, "GetValue")()
elif hasattr(control, "GetLabel"): return getattr(control, "GetLabel")()
else: return -1
else: return 0
def set(self, control, text):
if hasattr(self, control):
control = getattr(self, control)
if hasattr(control, "SetValue"): return getattr(control, "SetValue")(text)
elif hasattr(control, "SetLabel"): return getattr(control, "SetLabel")(text)
elif hasattr(control, "ChangeValue"): return getattr(control, "ChangeValue")(text)
else: return -1
else: return 0
def set_title(self, title):
self.SetTitle(title)

View File

@@ -0,0 +1,269 @@
# -*- coding: utf-8 -*-
import logging as original_logger
import wx
import application
import output
import config
import widgetUtils
from . import baseDialog
from multiplatform_widgets import widgets
class general(wx.Panel, baseDialog.BaseWXDialog):
def __init__(self, parent, languages,keymaps):
super(general, self).__init__(parent)
sizer = wx.BoxSizer(wx.VERTICAL)
language = wx.StaticText(self, -1, _(u"&Language"))
self.language = wx.ListBox(self, -1, choices=languages)
self.language.SetSize(self.language.GetBestSize())
langBox = wx.BoxSizer(wx.HORIZONTAL)
langBox.Add(language, 0, wx.ALL, 5)
langBox.Add(self.language, 0, wx.ALL, 5)
sizer.Add(langBox, 0, wx.ALL, 5)
self.ask_at_exit = wx.CheckBox(self, -1, _(U"&Ask before exiting {0}").format(application.name,))
sizer.Add(self.ask_at_exit, 0, wx.ALL, 5)
self.no_streaming = wx.CheckBox(self, -1, _(U"&Disable Streaming functions"))
sizer.Add(self.no_streaming, 0, wx.ALL, 5)
updatePeriodBox = wx.BoxSizer(wx.HORIZONTAL)
updatePeriodBox.Add(wx.StaticText(self, -1, _(u"&Buffer update interval, in minutes")), 0, wx.ALL, 5)
self.update_period = wx.SpinCtrl(self, wx.ID_ANY)
self.update_period.SetRange(1, 30)
self.update_period.SetSize(self.update_period.GetBestSize())
updatePeriodBox.Add(self.update_period, 0, wx.ALL, 5)
sizer.Add(updatePeriodBox, 0, wx.ALL, 5)
self.play_ready_sound = wx.CheckBox(self, -1, _(U"Pla&y a sound when {0} launches").format(application.name,))
sizer.Add(self.play_ready_sound, 0, wx.ALL, 5)
self.speak_ready_msg = wx.CheckBox(self, -1, _(U"Sp&eak a message when {0} launches").format(application.name,))
sizer.Add(self.speak_ready_msg, 0, wx.ALL, 5)
self.use_invisible_shorcuts = wx.CheckBox(self, -1, _(u"&Use invisible interface's keyboard shortcuts while GUI is visible"))
sizer.Add(self.use_invisible_shorcuts, 0, wx.ALL, 5)
self.disable_sapi5 = wx.CheckBox(self, -1, _(u"A&ctivate Sapi5 when any other screen reader is not being run"))
sizer.Add(self.disable_sapi5, 0, wx.ALL, 5)
self.hide_gui = wx.CheckBox(self, -1, _(u"&Hide GUI on launch"))
sizer.Add(self.hide_gui, 0, wx.ALL, 5)
self.read_long_posts_in_gui = wx.CheckBox(self, wx.ID_ANY, _("&Read long posts in GUI"))
sizer.Add(self.read_long_posts_in_gui, 0, wx.ALL, 5)
kmbox = wx.BoxSizer(wx.VERTICAL)
km_label = wx.StaticText(self, -1, _(u"&Keymap"))
self.km = wx.ComboBox(self, -1, choices=keymaps, style=wx.CB_READONLY)
self.km.SetSize(self.km.GetBestSize())
kmbox.Add(km_label, 0, wx.ALL, 5)
kmbox.Add(self.km, 0, wx.ALL, 5)
self.check_for_updates = wx.CheckBox(self, -1, _(U"Check for u&pdates when {0} launches").format(application.name,))
sizer.Add(self.check_for_updates, 0, wx.ALL, 5)
sizer.Add(kmbox, 0, wx.ALL, 5)
self.SetSizer(sizer)
class proxy(wx.Panel, baseDialog.BaseWXDialog):
def __init__(self, parent, proxyTypes):
super(proxy, self).__init__(parent)
sizer = wx.BoxSizer(wx.VERTICAL)
type=wx.StaticText(self, wx.ID_ANY, _(u"Proxy &type: "))
self.type=wx.ComboBox(self, -1, choices=proxyTypes, style=wx.CB_READONLY)
self.type.SetSize(self.type.GetBestSize())
typeBox = wx.BoxSizer(wx.HORIZONTAL)
typeBox.Add(type, 0, wx.ALL, 5)
typeBox.Add(self.type, 0, wx.ALL, 5)
sizer.Add(typeBox, 0, wx.ALL, 5)
lbl = wx.StaticText(self, wx.ID_ANY, _(u"Proxy s&erver: "))
self.server = wx.TextCtrl(self, -1)
serverBox = wx.BoxSizer(wx.HORIZONTAL)
serverBox.Add(lbl, 0, wx.ALL, 5)
serverBox.Add(self.server, 0, wx.ALL, 5)
sizer.Add(serverBox, 0, wx.ALL, 5)
lbl = wx.StaticText(self, wx.ID_ANY, _(u"&Port: "))
self.port = wx.SpinCtrl(self, wx.ID_ANY, min=1, max=65535)
portBox = wx.BoxSizer(wx.HORIZONTAL)
portBox.Add(lbl, 0, wx.ALL, 5)
portBox.Add(self.port, 0, wx.ALL, 5)
sizer.Add(portBox, 0, wx.ALL, 5)
lbl = wx.StaticText(self, wx.ID_ANY, _(u"&User: "))
self.user = wx.TextCtrl(self, wx.ID_ANY)
userBox = wx.BoxSizer(wx.HORIZONTAL)
userBox.Add(lbl, 0, wx.ALL, 5)
userBox.Add(self.user, 0, wx.ALL, 5)
sizer.Add(userBox, 0, wx.ALL, 5)
lbl = wx.StaticText(self, wx.ID_ANY, _(u"P&assword: "))
self.password = wx.TextCtrl(self, wx.ID_ANY, style=wx.TE_PASSWORD)
passwordBox = wx.BoxSizer(wx.HORIZONTAL)
passwordBox.Add(lbl, 0, wx.ALL, 5)
passwordBox.Add(self.password, 0, wx.ALL, 5)
sizer.Add(serverBox, 0, wx.ALL, 5)
self.SetSizer(sizer)
class reporting(wx.Panel, baseDialog.BaseWXDialog):
def __init__(self, parent):
super(reporting, self).__init__(parent)
sizer = wx.BoxSizer(wx.VERTICAL)
self.speech_reporting = wx.CheckBox(self, wx.ID_ANY, _(U"Enable automatic s&peech feedback"))
sizer.Add(self.speech_reporting, 0, wx.ALL, 5)
self.braille_reporting = wx.CheckBox(self, wx.ID_ANY, _(U"Enable automatic &Braille feedback"))
sizer.Add(self.braille_reporting, 0, wx.ALL, 5)
self.SetSizer(sizer)
class other_buffers(wx.Panel):
def __init__(self, parent):
super(other_buffers, self).__init__(parent)
sizer = wx.BoxSizer(wx.VERTICAL)
self.buffers = widgets.list(self, _(u"Buffer"), _(u"Name"), _(u"Status"), style=wx.LC_SINGLE_SEL|wx.LC_REPORT)
sizer.Add(self.buffers.list, 0, wx.ALL, 5)
btnSizer = wx.BoxSizer(wx.HORIZONTAL)
self.toggle_state = wx.Button(self, -1, _(u"S&how/hide"))
self.up = wx.Button(self, -1, _(u"Move &up"))
self.down = wx.Button(self, -1, _(u"Move &down"))
btnSizer.Add(self.toggle_state, 0, wx.ALL, 5)
btnSizer.Add(self.up, 0, wx.ALL, 5)
btnSizer.Add(self.down, 0, wx.ALL, 5)
sizer.Add(btnSizer, 0, wx.ALL, 5)
self.SetSizer(sizer)
def insert_buffers(self, buffers):
for i in buffers:
if i[2] == True:
self.buffers.insert_item(False, *[i[0], i[1], _(u"Show")])
else:
self.buffers.insert_item(False, *[i[0], i[1], _(u"Hide")])
def connect_hook_func(self, func):
self.buffers.list.Bind(wx.EVT_CHAR_HOOK, func)
def move_up(self, *args, **kwargs):
current = self.buffers.get_selected()
if current == -1:
output.speak(_(u"Select a buffer first."), True)
return False
if self.buffers.get_text_column(current, 2) == _(u"Hide"):
output.speak(_(u"The buffer is hidden, show it first."), True)
return False
if current <= 0:
output.speak(_(u"The buffer is already at the top of the list."), True)
return False
current_text = self.buffers.get_text_column(self.buffers.get_selected(), 0)
current_name = self.buffers.get_text_column(self.buffers.get_selected(), 1)
current_text_state = self.buffers.get_text_column(self.buffers.get_selected(), 2)
text_above = self.buffers.get_text_column(self.buffers.get_selected()-1, 0)
name_above = self.buffers.get_text_column(self.buffers.get_selected()-1, 1)
text_above_state = self.buffers.get_text_column(self.buffers.get_selected()-1, 2)
self.buffers.set_text_column(self.buffers.get_selected()-1, 0, current_text)
self.buffers.set_text_column(self.buffers.get_selected()-1, 1, current_name)
self.buffers.set_text_column(self.buffers.get_selected()-1, 2, current_text_state)
self.buffers.set_text_column(self.buffers.get_selected(), 0, text_above)
self.buffers.set_text_column(self.buffers.get_selected(), 1, name_above)
self.buffers.set_text_column(self.buffers.get_selected(), 2, text_above_state)
def move_down(self, *args, **kwargs):
current = self.buffers.get_selected()
if current == -1:
output.speak(_(u"Select a buffer first."), True)
return False
if self.buffers.get_text_column(current, 2) == _(u"Hide"):
output.speak(_(u"The buffer is hidden, show it first."), True)
return False
if current+1 >= self.buffers.get_count():
output.speak(_(u"The buffer is already at the bottom of the list."), True)
return False
current_text = self.buffers.get_text_column(self.buffers.get_selected(), 0)
current_name = self.buffers.get_text_column(self.buffers.get_selected(), 1)
current_text_state = self.buffers.get_text_column(self.buffers.get_selected(), 2)
text_below = self.buffers.get_text_column(self.buffers.get_selected()+1, 0)
name_below = self.buffers.get_text_column(self.buffers.get_selected()+1, 1)
text_below_state = self.buffers.get_text_column(self.buffers.get_selected()+1, 2)
self.buffers.set_text_column(self.buffers.get_selected()+1, 0, current_text)
self.buffers.set_text_column(self.buffers.get_selected()+1, 1, current_name)
self.buffers.set_text_column(self.buffers.get_selected()+1, 2, current_text_state)
self.buffers.set_text_column(self.buffers.get_selected(), 0, text_below)
self.buffers.set_text_column(self.buffers.get_selected(), 1, name_below)
self.buffers.set_text_column(self.buffers.get_selected(), 2, text_below_state)
def get_event(self, ev):
if ev.GetKeyCode() == wx.WXK_SPACE:
return True
else:
ev.Skip()
return False
def change_selected_item(self):
current = self.buffers.get_selected()
text = self.buffers.get_text_column(current, 2)
if text == _(u"Show"):
self.buffers.set_text_column(current, 2, _(u"Hide"))
else:
self.buffers.set_text_column(current, 2, _(u"Show"))
output.speak(self.buffers.get_text_column(current, 2),True)
def get_list(self):
buffers_list = []
for i in range(0, self.buffers.get_count()):
if self.buffers.get_text_column(i, 2) == _(u"Show"):
buffers_list.append(self.buffers.get_text_column(i, 0))
return buffers_list
class TranslatorPanel(wx.Panel, baseDialog.BaseWXDialog):
def __init__(self, parent):
super(TranslatorPanel, self).__init__(parent)
sizer = wx.BoxSizer(wx.VERTICAL)
lbl_libre_url = wx.StaticText(self, wx.ID_ANY, _(u"&LibreTranslate API URL: "))
self.libre_api_url = wx.TextCtrl(self, wx.ID_ANY)
libreUrlBox = wx.BoxSizer(wx.HORIZONTAL)
libreUrlBox.Add(lbl_libre_url, 0, wx.ALL, 5)
libreUrlBox.Add(self.libre_api_url, 1, wx.ALL | wx.EXPAND, 5)
sizer.Add(libreUrlBox, 0, wx.ALL | wx.EXPAND, 5)
lbl_libre_api_key = wx.StaticText(self, wx.ID_ANY, _(u"LibreTranslate API &Key (optional): "))
self.libre_api_key = wx.TextCtrl(self, wx.ID_ANY)
libreApiKeyBox = wx.BoxSizer(wx.HORIZONTAL)
libreApiKeyBox.Add(lbl_libre_api_key, 0, wx.ALL, 5)
libreApiKeyBox.Add(self.libre_api_key, 1, wx.ALL | wx.EXPAND, 5)
sizer.Add(libreApiKeyBox, 0, wx.ALL | wx.EXPAND, 5)
lbl_deepL_api_key = wx.StaticText(self, wx.ID_ANY, _(u"&DeepL API Key: "))
self.deepL_api_key = wx.TextCtrl(self, wx.ID_ANY)
deepLApiKeyBox = wx.BoxSizer(wx.HORIZONTAL)
deepLApiKeyBox.Add(lbl_deepL_api_key, 0, wx.ALL, 5)
deepLApiKeyBox.Add(self.deepL_api_key, 1, wx.ALL | wx.EXPAND, 5)
sizer.Add(deepLApiKeyBox, 0, wx.ALL | wx.EXPAND, 5)
self.SetSizer(sizer)
class configurationDialog(baseDialog.BaseWXDialog):
def set_title(self, title):
self.SetTitle(title)
def __init__(self):
super(configurationDialog, self).__init__(None, -1)
self.panel = wx.Panel(self)
self.SetTitle(_(u"{0} preferences").format(application.name,))
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.notebook = wx.Notebook(self.panel)
def create_general(self, languageList,keymaps):
self.general = general(self.notebook, languageList,keymaps)
self.notebook.AddPage(self.general, _(u"General"))
self.general.SetFocus()
def create_proxy(self, proxyTypes):
self.proxy = proxy(self.notebook, proxyTypes)
self.notebook.AddPage(self.proxy, _(u"Proxy"))
def create_translator_panel(self):
self.translator_panel= TranslatorPanel(self.notebook)
self.notebook.AddPage(self.translator_panel, _("Translation services"))
def realize(self):
self.sizer.Add(self.notebook, 0, wx.ALL, 5)
ok_cancel_box = wx.BoxSizer(wx.HORIZONTAL)
ok = wx.Button(self.panel, wx.ID_OK, _(u"&Save"))
ok.SetDefault()
cancel = wx.Button(self.panel, wx.ID_CANCEL, _(u"&Close"))
self.SetEscapeId(cancel.GetId())
ok_cancel_box.Add(ok, 0, wx.ALL, 5)
ok_cancel_box.Add(cancel, 0, wx.ALL, 5)
self.sizer.Add(ok_cancel_box, 0, wx.ALL, 5)
self.panel.SetSizer(self.sizer)
self.SetClientSize(self.sizer.CalcMin())
def get_value(self, panel, key):
p = getattr(self, panel)
return getattr(p, key).GetValue()
def set_value(self, panel, key, value):
p = getattr(self, panel)
control = getattr(p, key)
getattr(control, "SetValue")(value)

View File

@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import unicode_literals
# -*- coding: utf-8 -*-
from . import baseDialog
import wx
class findDialog(baseDialog.BaseWXDialog):
def __init__(self, value=""):
super(findDialog, self).__init__(None, -1)
panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
self.SetTitle(_(u"Find in current buffer"))
label = wx.StaticText(panel, -1, _(u"String"))
self.string = wx.TextCtrl(panel, -1, value)
dc = wx.WindowDC(self.string)
dc.SetFont(self.string.GetFont())
self.string.SetSize(dc.GetTextExtent("0"*40))
sizer.Add(label, 0, wx.ALL, 5)
sizer.Add(self.string, 0, wx.ALL, 5)
ok = wx.Button(panel, wx.ID_OK, _(u"OK"))
ok.SetDefault()
cancel = wx.Button(panel, wx.ID_CANCEL, _(u"Cancel"))
btnsizer = wx.BoxSizer()
btnsizer.Add(ok, 0, wx.ALL, 5)
btnsizer.Add(cancel, 0, wx.ALL, 5)
sizer.Add(btnsizer, 0, wx.ALL, 5)
panel.SetSizer(sizer)
self.SetClientSize(sizer.CalcMin())

View File

@@ -0,0 +1,38 @@
# -*- coding: utf-8 -*-
import wx
class CommunityTimeline(wx.Dialog):
def __init__(self, *args, **kwargs):
super(CommunityTimeline, self).__init__(parent=None, *args, **kwargs)
panel = wx.Panel(self)
communitySizer = wx.BoxSizer()
self.SetTitle(_("Create community timeline"))
communityLabel = wx.StaticText(panel, -1, _("Community URL"))
self.url = wx.TextCtrl(panel, -1)
self.url.SetFocus()
communitySizer.Add(communityLabel, 0, wx.ALL, 5)
communitySizer.Add(self.url, 0, wx.ALL, 5)
actionSizer = wx.BoxSizer(wx.VERTICAL)
label2 = wx.StaticText(panel, -1, _(u"Buffer type"))
self.local= wx.RadioButton(panel, -1, _("&Local timeline"), style=wx.RB_GROUP)
self.federated= wx.RadioButton(panel, -1, _("&Federated Timeline"))
hSizer = wx.BoxSizer(wx.HORIZONTAL)
hSizer.Add(label2, 0, wx.ALL, 5)
actionSizer.Add(self.local, 0, wx.ALL, 5)
actionSizer.Add(self.federated, 0, wx.ALL, 5)
hSizer.Add(actionSizer, 0, wx.ALL, 5)
sizer = wx.BoxSizer(wx.VERTICAL)
ok = wx.Button(panel, wx.ID_OK, _(u"&OK"))
ok.SetDefault()
cancel = wx.Button(panel, wx.ID_CANCEL, _(u"&Close"))
btnsizer = wx.BoxSizer()
btnsizer.Add(ok)
btnsizer.Add(cancel)
sizer.Add(communitySizer)
sizer.Add(hSizer, 0, wx.ALL, 5)
sizer.Add(btnsizer)
panel.SetSizer(sizer)
def get_action(self):
if self.local.GetValue() == True: return "local"
elif self.federated.GetValue() == True: return "federated"

View File

@@ -0,0 +1,188 @@
# -*- coding: utf-8 -*-
import wx
import widgetUtils
from wxUI.dialogs import baseDialog
# As some panels are the same than those used in Twitter sessions, let's import them directly.
from wxUI.dialogs.configuration import reporting, other_buffers
from multiplatform_widgets import widgets
class generalAccount(wx.Panel, baseDialog.BaseWXDialog):
def __init__(self, parent):
super(generalAccount, self).__init__(parent)
sizer = wx.BoxSizer(wx.VERTICAL)
userAutocompletionBox = wx.StaticBox(self, label=_("User autocompletion settings"))
self.userAutocompletionScan = wx.Button(self, wx.ID_ANY, _("Scan acc&ount and add followers and following users to the user autocompletion database"))
self.userAutocompletionManage = wx.Button(self, wx.ID_ANY, _("&Manage autocompletion database"))
autocompletionSizer = wx.StaticBoxSizer(userAutocompletionBox, wx.HORIZONTAL)
autocompletionSizer.Add(self.userAutocompletionScan, 0, wx.ALL, 5)
autocompletionSizer.Add(self.userAutocompletionManage, 0, wx.ALL, 5)
sizer.Add(autocompletionSizer, 0, wx.ALL, 5)
self.disable_streaming = wx.CheckBox(self, wx.ID_ANY, _("&Disable Streaming API endpoints"))
sizer.Add(self.disable_streaming, 0, wx.ALL, 5)
self.relative_time = wx.CheckBox(self, wx.ID_ANY, _("&Relative timestamps"))
sizer.Add(self.relative_time, 0, wx.ALL, 5)
self.read_preferences_from_instance = wx.CheckBox(self, wx.ID_ANY, _("R&ead preferences from instance (default visibility when publishing and displaying sensitive content)"))
sizer.Add(self.read_preferences_from_instance, 0, wx.ALL, 5)
itemsPerCallBox = wx.BoxSizer(wx.HORIZONTAL)
itemsPerCallBox.Add(wx.StaticText(self, -1, _("&Items on each API call")), 0, wx.ALL, 5)
self.itemsPerApiCall = wx.SpinCtrl(self, wx.ID_ANY)
self.itemsPerApiCall.SetRange(0, 40)
self.itemsPerApiCall.SetSize(self.itemsPerApiCall.GetBestSize())
itemsPerCallBox.Add(self.itemsPerApiCall, 0, wx.ALL, 5)
sizer.Add(itemsPerCallBox, 0, wx.ALL, 5)
self.reverse_timelines = wx.CheckBox(self, wx.ID_ANY, _("I&nverted buffers: The newest items will be shown at the beginning while the oldest at the end"))
sizer.Add(self.reverse_timelines, 0, wx.ALL, 5)
self.ask_before_boost = wx.CheckBox(self, wx.ID_ANY, _("&Ask confirmation before boosting a post"))
sizer.Add(self.ask_before_boost, 0, wx.ALL, 5)
self.show_screen_names = wx.CheckBox(self, wx.ID_ANY, _("S&how screen names instead of full names"))
sizer.Add(self.show_screen_names, 0, wx.ALL, 5)
self.hide_emojis = wx.CheckBox(self, wx.ID_ANY, _("Hide e&mojis in usernames"))
sizer.Add(self.hide_emojis, 0, wx.ALL, 5)
PersistSizeLabel = wx.StaticText(self, -1, _("&Number of items per buffer to cache in database (0 to disable caching, blank for unlimited)"))
self.persist_size = wx.TextCtrl(self, -1)
sizer.Add(PersistSizeLabel, 0, wx.ALL, 5)
sizer.Add(self.persist_size, 0, wx.ALL, 5)
self.load_cache_in_memory = wx.CheckBox(self, wx.NewId(), _("&Load cache for items in memory (much faster in big datasets but requires more RAM)"))
self.SetSizer(sizer)
class templates(wx.Panel, baseDialog.BaseWXDialog):
def __init__(self, parent, post_template, conversation_template, person_template):
super(templates, self).__init__(parent)
sizer = wx.BoxSizer(wx.VERTICAL)
self.post = wx.Button(self, wx.ID_ANY, _("Edit template for &posts. Current template: {}").format(post_template))
sizer.Add(self.post, 0, wx.ALL, 5)
self.conversation = wx.Button(self, wx.ID_ANY, _("Edit template for c&onversations. Current template: {}").format(conversation_template))
sizer.Add(self.conversation, 0, wx.ALL, 5)
self.person = wx.Button(self, wx.ID_ANY, _("Edit template for p&ersons. Current template: {}").format(person_template))
sizer.Add(self.person, 0, wx.ALL, 5)
self.SetSizer(sizer)
class sound(wx.Panel):
def __init__(self, parent, input_devices, output_devices, soundpacks):
wx.Panel.__init__(self, parent)
sizer = wx.BoxSizer(wx.VERTICAL)
volume = wx.StaticText(self, -1, _(u"&Volume"))
self.volumeCtrl = wx.Slider(self)
# Connect a key handler here to handle volume slider being inverted when moving with up and down arrows.
# see https://github.com/manuelcortez/TWBlue/issues/261
widgetUtils.connect_event(self.volumeCtrl, widgetUtils.KEYPRESS, self.on_keypress)
self.volumeCtrl.SetRange(0, 100)
self.volumeCtrl.SetSize(self.volumeCtrl.GetBestSize())
volumeBox = wx.BoxSizer(wx.HORIZONTAL)
volumeBox.Add(volume, 0, wx.ALL, 5)
volumeBox.Add(self.volumeCtrl, 0, wx.ALL, 5)
sizer.Add(volumeBox, 0, wx.ALL, 5)
self.session_mute = wx.CheckBox(self, -1, _(u"S&ession mute"))
sizer.Add(self.session_mute, 0, wx.ALL, 5)
output_label = wx.StaticText(self, -1, _(u"&Output device"))
self.output = wx.ComboBox(self, -1, choices=output_devices, style=wx.CB_READONLY)
self.output.SetSize(self.output.GetBestSize())
outputBox = wx.BoxSizer(wx.HORIZONTAL)
outputBox.Add(output_label, 0, wx.ALL, 5)
outputBox.Add(self.output, 0, wx.ALL, 5)
sizer.Add(outputBox, 0, wx.ALL, 5)
input_label = wx.StaticText(self, -1, _(u"&Input device"))
self.input = wx.ComboBox(self, -1, choices=input_devices, style=wx.CB_READONLY)
self.input.SetSize(self.input.GetBestSize())
inputBox = wx.BoxSizer(wx.HORIZONTAL)
inputBox.Add(input_label, 0, wx.ALL, 5)
inputBox.Add(self.input, 0, wx.ALL, 5)
sizer.Add(inputBox, 0, wx.ALL, 5)
soundBox = wx.BoxSizer(wx.VERTICAL)
soundpack_label = wx.StaticText(self, -1, _(u"Sound &pack"))
self.soundpack = wx.ComboBox(self, -1, choices=soundpacks, style=wx.CB_READONLY)
self.soundpack.SetSize(self.soundpack.GetBestSize())
soundBox.Add(soundpack_label, 0, wx.ALL, 5)
soundBox.Add(self.soundpack, 0, wx.ALL, 5)
sizer.Add(soundBox, 0, wx.ALL, 5)
self.indicate_audio = wx.CheckBox(self, -1, _("Indicate &audio or video in posts with sound"))
sizer.Add(self.indicate_audio, 0, wx.ALL, 5)
self.indicate_img = wx.CheckBox(self, -1, _("Indicate posts containing i&mages with sound"))
sizer.Add(self.indicate_img, 0, wx.ALL, 5)
self.SetSizer(sizer)
def on_keypress(self, event, *args, **kwargs):
""" Invert movement of up and down arrow keys when dealing with a wX Slider.
See https://github.com/manuelcortez/TWBlue/issues/261
and http://trac.wxwidgets.org/ticket/2068
"""
keycode = event.GetKeyCode()
if keycode == wx.WXK_UP:
return self.volumeCtrl.SetValue(self.volumeCtrl.GetValue()+1)
elif keycode == wx.WXK_DOWN:
return self.volumeCtrl.SetValue(self.volumeCtrl.GetValue()-1)
event.Skip()
def get(self, control):
return getattr(self, control).GetStringSelection()
class extrasPanel(wx.Panel):
def __init__(self, parent, ocr_languages=[], translation_languages=[]):
super(extrasPanel, self).__init__(parent)
mainSizer = wx.BoxSizer(wx.VERTICAL)
OCRBox = wx.StaticBox(self, label=_(u"&Language for OCR"))
self.ocr_lang = wx.ListBox(self, -1, choices=ocr_languages)
self.ocr_lang.SetSize(self.ocr_lang.GetBestSize())
ocrLanguageSizer = wx.StaticBoxSizer(OCRBox, wx.HORIZONTAL)
ocrLanguageSizer.Add(self.ocr_lang, 0, wx.ALL, 5)
mainSizer.Add(ocrLanguageSizer, 0, wx.ALL, 5)
self.SetSizer(mainSizer)
class configurationDialog(baseDialog.BaseWXDialog):
def set_title(self, title):
self.SetTitle(title)
def __init__(self):
super(configurationDialog, self).__init__(None, -1)
self.panel = wx.Panel(self)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.notebook = wx.Notebook(self.panel)
def create_general_account(self):
self.general = generalAccount(self.notebook)
self.notebook.AddPage(self.general, _(u"General"))
self.general.SetFocus()
def create_reporting(self):
self.reporting = reporting(self.notebook)
self.notebook.AddPage(self.reporting, _(u"Feedback"))
def create_other_buffers(self):
self.buffers = other_buffers(self.notebook)
self.notebook.AddPage(self.buffers, _(u"Buffers"))
def create_templates(self, post_template, conversation_template, person_template):
self.templates = templates(self.notebook, post_template=post_template, conversation_template=conversation_template, person_template=person_template)
self.notebook.AddPage(self.templates, _("Templates"))
def create_sound(self, output_devices, input_devices, soundpacks):
self.sound = sound(self.notebook, output_devices, input_devices, soundpacks)
self.notebook.AddPage(self.sound, _(u"Sound"))
def create_extras(self, ocr_languages=[], translator_languages=[]):
self.extras = extrasPanel(self.notebook, ocr_languages, translator_languages)
self.notebook.AddPage(self.extras, _(u"Extras"))
def realize(self):
self.sizer.Add(self.notebook, 0, wx.ALL, 5)
ok_cancel_box = wx.BoxSizer(wx.HORIZONTAL)
ok = wx.Button(self.panel, wx.ID_OK, _(u"&Save"))
ok.SetDefault()
cancel = wx.Button(self.panel, wx.ID_CANCEL, _(u"&Close"))
self.SetEscapeId(cancel.GetId())
ok_cancel_box.Add(ok, 0, wx.ALL, 5)
ok_cancel_box.Add(cancel, 0, wx.ALL, 5)
self.sizer.Add(ok_cancel_box, 0, wx.ALL, 5)
self.panel.SetSizer(self.sizer)
self.SetClientSize(self.sizer.CalcMin())
def get_value(self, panel, key):
p = getattr(self, panel)
return getattr(p, key).GetValue()
def set_value(self, panel, key, value):
p = getattr(self, panel)
control = getattr(p, key)
getattr(control, "SetValue")(value)

View File

@@ -0,0 +1,62 @@
# -*- coding: utf-8 -*-
import wx
import application
def boost_question():
result = False
dlg = wx.MessageDialog(None, _("Would you like to share this post?"), _("Boost"), wx.YES_NO|wx.ICON_QUESTION)
if dlg.ShowModal() == wx.ID_YES:
result = True
dlg.Destroy()
return result
def delete_post_dialog():
result = False
dlg = wx.MessageDialog(None, _("Do you really want to delete this post? It will be deleted from the instance as well."), _("Delete"), wx.ICON_QUESTION|wx.YES_NO)
if dlg.ShowModal() == wx.ID_YES:
result = True
dlg.Destroy()
return result
def delete_notification_dialog():
result = False
dlg = wx.MessageDialog(None, _("Are you sure you want to dismiss this notification? If you dismiss a mention notification, it also disappears from your mentions buffer. The post is not going to be deleted from the instance, though."), _("Dismiss"), wx.ICON_QUESTION|wx.YES_NO)
if dlg.ShowModal() == wx.ID_YES:
result = True
dlg.Destroy()
return result
def clear_list():
result = False
dlg = wx.MessageDialog(None, _("Do you really want to empty this buffer? It's items will be removed from the list but not from the instance"), _(u"Empty buffer"), wx.ICON_QUESTION|wx.YES_NO)
if dlg.ShowModal() == wx.ID_YES:
result = True
dlg.Destroy()
return result
def no_posts():
dlg = wx.MessageDialog(None, _("This user has no posts. {0} can't create a timeline.").format(application.name), _(u"Error"), wx.ICON_ERROR)
dlg.ShowModal()
dlg.Destroy()
def no_favs():
dlg = wx.MessageDialog(None, _(u"This user has no favorited posts. {0} can't create a timeline.").format(application.name), _(u"Error"), wx.ICON_ERROR)
dlg.ShowModal()
dlg.Destroy()
def no_followers():
dlg = wx.MessageDialog(None, _(u"This user has no followers yet. {0} can't create a timeline.").format(application.name), _(u"Error"), wx.ICON_ERROR)
dlg.ShowModal()
dlg.Destroy()
def no_following():
dlg = wx.MessageDialog(None, _("This user is not following anyone. {0} can't create a timeline.").format(application.name), _(u"Error"), wx.ICON_ERROR)
dlg.ShowModal()
dlg.Destroy()
dlg.Destroy()
def no_user():
dlg = wx.MessageDialog(None, _("The focused item has no user in it. {} ca't open a user profile").format(application.name), _(u"Error"), wx.ICON_ERROR)
dlg.ShowModal()
dlg.Destroy()

View File

@@ -0,0 +1,146 @@
# -*- coding: utf-8 -*-
import wx
class FilterKeywordPanel(wx.Panel):
"""panel to handle filter's keywords. """
def __init__(self, parent):
super(FilterKeywordPanel, self).__init__(parent)
self.keywords = []
# Add widgets
list_panel = wx.Panel(self)
self.keyword_list = wx.ListCtrl(list_panel, wx.ID_ANY, style=wx.LC_REPORT | wx.LC_SINGLE_SEL)
self.keyword_list.InsertColumn(0, _("Keyword"))
self.keyword_list.InsertColumn(1, _("Whole word"))
self.keyword_list.SetColumnWidth(0, wx.LIST_AUTOSIZE_USEHEADER)
self.keyword_list.SetColumnWidth(1, wx.LIST_AUTOSIZE_USEHEADER)
list_sizer = wx.BoxSizer(wx.VERTICAL)
list_sizer.Add(self.keyword_list, 1, wx.EXPAND)
list_panel.SetSizer(list_sizer)
keyword_label = wx.StaticText(self, wx.ID_ANY, label=_("Keyword:"))
self.keyword_text = wx.TextCtrl(self, wx.ID_ANY)
keyword_sizer = wx.BoxSizer(wx.VERTICAL)
keyword_sizer.Add(keyword_label, 0, wx.RIGHT, 5)
keyword_sizer.Add(self.keyword_text, 0, wx.EXPAND)
self.whole_word_checkbox = wx.CheckBox(self, wx.ID_ANY, label=_("Whole word"))
self.add_button = wx.Button(self, wx.ID_ANY, label=_("Add"))
self.remove_button = wx.Button(self, wx.ID_ANY, label=_("Remove"))
input_sizer = wx.BoxSizer(wx.HORIZONTAL)
input_sizer.Add(keyword_sizer, 1, wx.RIGHT, 5)
input_sizer.Add(self.whole_word_checkbox, 0)
button_sizer = wx.BoxSizer(wx.HORIZONTAL)
button_sizer.Add(self.add_button, 0, wx.RIGHT, 5)
button_sizer.Add(self.remove_button, 0)
main_sizer = wx.BoxSizer(wx.VERTICAL)
main_sizer.Add(wx.StaticText(self, label=_("Keywords to filter:")), 0, wx.BOTTOM, 5)
main_sizer.Add(list_panel, 1, wx.EXPAND | wx.BOTTOM, 5)
main_sizer.Add(input_sizer, 0, wx.EXPAND | wx.BOTTOM, 5)
main_sizer.Add(button_sizer, 0, wx.ALIGN_RIGHT)
self.SetSizer(main_sizer)
def add_keyword(self, keyword, whole_word=False):
""" Adds a keyword to the list. """
index = self.keyword_list.InsertItem(self.keyword_list.GetItemCount(), keyword)
self.keyword_list.SetItem(index, 1, _("Yes") if whole_word else _("No"))
self.keyword_list.SetColumnWidth(0, wx.LIST_AUTOSIZE)
self.keyword_list.SetColumnWidth(1, wx.LIST_AUTOSIZE_USEHEADER)
self.keyword_text.Clear()
self.whole_word_checkbox.SetValue(False)
def remove_keyword(self):
""" Remove a keyword from the list. """
selection = self.keyword_list.GetFirstSelected()
if selection != -1:
self.keyword_list.DeleteItem(selection)
return selection
def set_keywords(self, keywords):
""" Set the list of keyword. """
self.keyword_list.DeleteAllItems()
for keyword_data in keywords:
if isinstance(keyword_data, dict):
kw = keyword_data.get('keyword', '')
whole_word = keyword_data.get('whole_word', False)
self.keywords.append({'keyword': kw, 'whole_word': whole_word})
index = self.keyword_list.InsertItem(self.keyword_list.GetItemCount(), kw)
self.keyword_list.SetItem(index, 1, _("Yes") if whole_word else _("No"))
else:
self.keywords.append({'keyword': keyword_data, 'whole_word': False})
index = self.keyword_list.InsertItem(self.keyword_list.GetItemCount(), keyword_data)
self.keyword_list.SetItem(index, 1, _("No"))
self.keyword_list.SetColumnWidth(0, wx.LIST_AUTOSIZE)
self.keyword_list.SetColumnWidth(1, wx.LIST_AUTOSIZE_USEHEADER)
class CreateFilterDialog(wx.Dialog):
def __init__(self, parent, title=_("New filter")):
super(CreateFilterDialog, self).__init__(parent, title=title, style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
self.contexts = ["home", "public", "notifications", "thread", "account"]
self.context_labels = {
"home": _("Home timeline"),
"public": _("Public statuses"),
"notifications": _("Notifications"),
"thread": _("Threads"),
"account": _("Profiles")
}
self.actions = ["hide", "warn"]
self.action_labels = {
"hide": _("Hide posts"),
"warn": _("Set a content warning to posts")
}
self.expiration_options = [
("never", _("Never")),
("hours", _("Hours")),
("days", _("Days")),
("weeks", _("Weeks")),
("months", _("months"))
]
main_sizer = wx.BoxSizer(wx.VERTICAL)
name_label = wx.StaticText(self, wx.ID_ANY, label=_("Title:"))
self.name_ctrl = wx.TextCtrl(self, wx.ID_ANY)
name_sizer = wx.BoxSizer(wx.HORIZONTAL)
name_sizer.Add(name_label, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 5)
name_sizer.Add(self.name_ctrl, 1, wx.EXPAND)
main_sizer.Add(name_sizer, 0, wx.EXPAND | wx.ALL, 10)
static_box = wx.StaticBox(self, wx.ID_ANY, label=_("Apply to:"))
context_sizer = wx.StaticBoxSizer(static_box, wx.VERTICAL)
self.context_checkboxes = {}
context_grid = wx.FlexGridSizer(rows=3, cols=2, vgap=5, hgap=10)
for context in self.contexts:
checkbox = wx.CheckBox(static_box, wx.ID_ANY, label=self.context_labels[context])
self.context_checkboxes[context] = checkbox
context_grid.Add(checkbox)
context_sizer.Add(context_grid, 0, wx.ALL, 10)
main_sizer.Add(context_sizer, 0, wx.EXPAND | wx.ALL, 10)
action_label = wx.StaticText(self, wx.ID_ANY, label=_("Action:"))
self.action_choice = wx.Choice(self, wx.ID_ANY)
for action in self.actions:
self.action_choice.Append(self.action_labels[action])
action_sizer = wx.BoxSizer(wx.HORIZONTAL)
action_sizer.Add(action_label, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 5)
action_sizer.Add(self.action_choice, 1)
main_sizer.Add(action_sizer, 0, wx.EXPAND | wx.ALL, 10)
expiration_label = wx.StaticText(self, wx.ID_ANY, label=_("Expires in:"))
self.expiration_choice = wx.Choice(self, wx.ID_ANY)
for e, label in self.expiration_options:
self.expiration_choice.Append(label)
self.expiration_value = wx.SpinCtrl(self, wx.ID_ANY, min=1, max=9999, initial=1)
self.expiration_value.Enable(False)
self.expiration_choice.Bind(wx.EVT_CHOICE, self.on_expiration_changed)
expiration_sizer = wx.BoxSizer(wx.HORIZONTAL)
expiration_sizer.Add(expiration_label, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 5)
expiration_sizer.Add(self.expiration_choice, 1, wx.RIGHT, 5)
expiration_sizer.Add(self.expiration_value, 0)
main_sizer.Add(expiration_sizer, 0, wx.EXPAND | wx.ALL, 10)
self.keyword_panel = FilterKeywordPanel(self)
main_sizer.Add(self.keyword_panel, 1, wx.EXPAND | wx.ALL, 10)
button_sizer = self.CreateButtonSizer(wx.OK | wx.CANCEL)
main_sizer.Add(button_sizer, 0, wx.EXPAND | wx.ALL, 10)
self.SetSizer(main_sizer)
self.SetSize((450, 550))
self.action_choice.SetSelection(0)
self.expiration_choice.SetSelection(0)
wx.CallAfter(self.name_ctrl.SetFocus)
def on_expiration_changed(self, event):
selection = self.expiration_choice.GetSelection()
self.expiration_value.Enable(selection != 0)

View File

@@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
import wx
class ManageFiltersDialog(wx.Dialog):
"""
A dialog that displays a list of Mastodon filters and provides controls
to add, edit and remove them.
"""
def __init__(self, parent, title=_("Filters"), *args, **kwargs):
"""Initialize the filters view dialog. """
super(ManageFiltersDialog, self).__init__(parent, title=title, *args, **kwargs)
main_sizer = wx.BoxSizer(wx.VERTICAL)
self.filter_list = wx.ListCtrl(self, style=wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.BORDER_SUNKEN)
self.filter_list.InsertColumn(0, _("Title"), width=150)
self.filter_list.InsertColumn(1, _("Keywords"), width=80)
self.filter_list.InsertColumn(2, _("Contexts"), width=150)
self.filter_list.InsertColumn(3, _("Action"), width=100)
self.filter_list.InsertColumn(4, _("Expires"), width=150)
main_sizer.Add(self.filter_list, 1, wx.EXPAND | wx.ALL, 10)
button_sizer = wx.BoxSizer(wx.HORIZONTAL)
self.add_button = wx.Button(self, label=_("Add"))
self.edit_button = wx.Button(self, label=_("Edit"))
self.remove_button = wx.Button(self, label=_("Remove"))
close_button = wx.Button(self, wx.ID_CLOSE)
self.edit_button.Disable()
self.remove_button.Disable()
button_sizer.Add(self.add_button, 0, wx.RIGHT, 5)
button_sizer.Add(self.edit_button, 0, wx.RIGHT, 5)
button_sizer.Add(self.remove_button, 0, wx.RIGHT, 5)
button_sizer.Add((0, 0), 1, wx.EXPAND) # Spacer to push close button to right
button_sizer.Add(close_button, 0)
self.SetEscapeId(close_button.GetId())
main_sizer.Add(button_sizer, 0, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, 10)
self.SetSizer(main_sizer)

View File

@@ -0,0 +1,62 @@
# -*- coding: utf-8 -*-
import wx
class base(wx.Menu):
def __init__(self):
super(base, self).__init__()
self.boost = wx.MenuItem(self, wx.ID_ANY, _("&Boost"))
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"))
self.Append(self.unfav)
self.mute = wx.MenuItem(self, wx.ID_ANY, _(u"Mute/Unmute conversation"))
self.Append(self.mute)
self.openUrl = wx.MenuItem(self, wx.ID_ANY, _("&Open URL"))
self.Append(self.openUrl)
self.openInBrowser = wx.MenuItem(self, wx.ID_ANY, _(u"&Open in instance"))
self.Append(self.openInBrowser)
self.play = wx.MenuItem(self, wx.ID_ANY, _(u"&Play audio"))
self.Append(self.play)
self.view = wx.MenuItem(self, wx.ID_ANY, _(u"&Show post"))
self.Append(self.view)
self.copy = wx.MenuItem(self, wx.ID_ANY, _(u"&Copy to clipboard"))
self.Append(self.copy)
self.remove = wx.MenuItem(self, wx.ID_ANY, _(u"&Delete"))
self.Append(self.remove)
self.userActions = wx.MenuItem(self, wx.ID_ANY, _(u"&User actions..."))
self.Append(self.userActions)
class notification(wx.Menu):
def __init__(self, item="status"):
super(notification, self).__init__()
valid_types = ["status", "mention", "reblog", "favourite", "update", "poll"]
if item in valid_types:
self.boost = wx.MenuItem(self, wx.ID_ANY, _("&Boost"))
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"))
self.Append(self.unfav)
self.openUrl = wx.MenuItem(self, wx.ID_ANY, _("&Open URL"))
self.Append(self.openUrl)
self.play = wx.MenuItem(self, wx.ID_ANY, _(u"&Play audio"))
self.Append(self.play)
self.openInBrowser = wx.MenuItem(self, wx.ID_ANY, _(u"&Open in instance"))
self.Append(self.openInBrowser)
self.view = wx.MenuItem(self, wx.ID_ANY, _(u"&Show post"))
self.Append(self.view)
self.copy = wx.MenuItem(self, wx.ID_ANY, _(u"&Copy to clipboard"))
self.Append(self.copy)
self.remove = wx.MenuItem(self, wx.ID_ANY, _(u"&Dismiss"))
self.Append(self.remove)
self.userActions = wx.MenuItem(self, wx.ID_ANY, _(u"&User actions..."))
self.Append(self.userActions)

View File

@@ -0,0 +1,465 @@
# -*- coding: utf-8 -*-
import wx
import wx.adv
import datetime
class Post(wx.Dialog):
def __init__(self, caption=_("Post"), text="", languages=[], *args, **kwds):
super(Post, self).__init__(parent=None, id=wx.ID_ANY, *args, **kwds)
main_sizer = wx.BoxSizer(wx.VERTICAL)
post_sizer = wx.WrapSizer(wx.VERTICAL)
main_sizer.Add(post_sizer, 1, wx.EXPAND, 0)
post_label = wx.StaticText(self, wx.ID_ANY, caption)
post_sizer.Add(post_label, 0, 0, 0)
self.text = wx.TextCtrl(self, wx.ID_ANY, text, style=wx.TE_MULTILINE)
self.Bind(wx.EVT_CHAR_HOOK, self.handle_keys, self.text)
self.text.SetMinSize((350, -1))
post_sizer.Add(self.text, 0, 0, 0)
lists_sizer = wx.BoxSizer(wx.HORIZONTAL)
main_sizer.Add(lists_sizer, 1, wx.EXPAND, 0)
attachments_sizer = wx.WrapSizer(wx.VERTICAL)
lists_sizer.Add(attachments_sizer, 1, wx.EXPAND, 0)
attachments_label = wx.StaticText(self, wx.ID_ANY, _("Attachments"))
attachments_sizer.Add(attachments_label, 0, 0, 0)
self.attachments = wx.ListCtrl(self, wx.ID_ANY, style=wx.LC_HRULES | wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_VRULES)
self.attachments.Enable(False)
self.attachments.AppendColumn(_("File"), format=wx.LIST_FORMAT_LEFT, width=-1)
self.attachments.AppendColumn(_("Type"), format=wx.LIST_FORMAT_LEFT, width=-1)
self.attachments.AppendColumn(_("Description"), format=wx.LIST_FORMAT_LEFT, width=-1)
attachments_sizer.Add(self.attachments, 1, wx.EXPAND, 0)
self.remove_attachment = wx.Button(self, wx.ID_ANY, _("Remove Attachment"))
self.remove_attachment.Enable(False)
attachments_sizer.Add(self.remove_attachment, 0, 0, 0)
posts_sizer = wx.WrapSizer(wx.VERTICAL)
lists_sizer.Add(posts_sizer, 1, wx.EXPAND, 0)
posts_label = wx.StaticText(self, wx.ID_ANY, _("Post in the thread"))
posts_sizer.Add(posts_label, 0, 0, 0)
self.posts = wx.ListCtrl(self, wx.ID_ANY, style=wx.LC_HRULES | wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_VRULES)
self.posts.Enable(False)
self.posts.AppendColumn(_("Text"), format=wx.LIST_FORMAT_LEFT, width=-1)
self.posts.AppendColumn(_("Attachments"), format=wx.LIST_FORMAT_LEFT, width=-1)
posts_sizer.Add(self.posts, 1, wx.EXPAND, 0)
self.remove_post = wx.Button(self, wx.ID_ANY, _("Remove post"))
self.remove_post.Enable(False)
posts_sizer.Add(self.remove_post, 0, 0, 0)
post_actions_sizer = wx.BoxSizer(wx.HORIZONTAL)
main_sizer.Add(post_actions_sizer, 1, wx.EXPAND, 0)
visibility_sizer = wx.BoxSizer(wx.HORIZONTAL)
post_actions_sizer.Add(visibility_sizer, 1, wx.EXPAND, 0)
label_1 = wx.StaticText(self, wx.ID_ANY, _("&Visibility"))
visibility_sizer.Add(label_1, 0, 0, 0)
self.visibility = wx.ComboBox(self, wx.ID_ANY, choices=[_("Public"), _("Not listed"), _("Followers only"), _("Direct")], style=wx.CB_DROPDOWN | wx.CB_READONLY | wx.CB_SIMPLE)
self.visibility.SetSelection(0)
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"))
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)
self.add = wx.Button(self, wx.ID_ANY, _("A&dd"))
self.sensitive = wx.CheckBox(self, wx.ID_ANY, _("S&ensitive content"))
self.sensitive.SetValue(False)
self.sensitive.Bind(wx.EVT_CHECKBOX, self.on_sensitivity_changed)
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_label = wx.StaticText(self, wx.ID_ANY, _("Content warning"))
self.spoiler = wx.TextCtrl(self, wx.ID_ANY)
self.spoiler.Enable(False)
spoiler_box.Add(spoiler_label, 0, wx.ALL, 5)
spoiler_box.Add(self.spoiler, 0, wx.ALL, 10)
main_sizer.Add(spoiler_box, 0, wx.ALL, 5)
post_actions_sizer.Add(self.add, 0, 0, 0)
self.add_post = wx.Button(self, wx.ID_ANY, _("Add p&ost"))
post_actions_sizer.Add(self.add_post, 0, 0, 0)
text_actions_sizer = wx.BoxSizer(wx.HORIZONTAL)
main_sizer.Add(text_actions_sizer, 1, wx.EXPAND, 0)
self.autocomplete_users = wx.Button(self, wx.ID_ANY, _("Auto&complete users"))
text_actions_sizer.Add(self.autocomplete_users, 0, 0, 0)
self.spellcheck = wx.Button(self, wx.ID_ANY, _("Check &spelling"))
text_actions_sizer.Add(self.spellcheck, 0, 0, 0)
self.translate = wx.Button(self, wx.ID_ANY, _("&Translate"))
text_actions_sizer.Add(self.translate, 0, 0, 0)
btn_sizer = wx.StdDialogButtonSizer()
main_sizer.Add(btn_sizer, 0, wx.ALIGN_RIGHT | wx.ALL, 4)
self.send = wx.Button(self, wx.ID_ANY, _("&Send"))
self.send.SetDefault()
self.send.Bind(wx.EVT_BUTTON, self.validate_and_send)
btn_sizer.AddButton(self.send)
self.close = wx.Button(self, wx.ID_CLOSE, "")
btn_sizer.AddButton(self.close)
btn_sizer.Realize()
self.SetSizer(main_sizer)
main_sizer.Fit(self)
self.SetEscapeId(self.close.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.validate_and_send()
else:
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):
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):
self.SetTitle(_("Post - {} characters").format(chars))
def reset_controls(self):
self.text.ChangeValue("")
self.attachments.DeleteAllItems()
def add_item(self, list_type="attachment", item=[]):
if list_type == "attachment":
self.attachments.Append(item)
else:
self.posts.Append(item)
def remove_item(self, list_type="attachment"):
if list_type == "attachment":
item = self.attachments.GetFocusedItem()
if item > -1:
self.attachments.DeleteItem(item)
else:
item = self.posts.GetFocusedItem()
if item > -1:
self.posts.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_audio = menu.Append(wx.ID_ANY, _("Audio"))
self.add_audio.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, *.mov, *.m4v, *.webm)| *.mp4; *.m4v; *.mov; *.webm"), 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_audio(self):
openFileDialog = wx.FileDialog(self, _("Select the audio file to be uploaded"), "", "", _("Audio files (*.mp3, *.ogg, *.wav, *.flac, *.opus, *.aac, *.m4a, *.3gp)|*.mp3; *.ogg; *.wav; *.flac; *.opus; *.aac; *.m4a; *.3gp"), 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 unable_to_attach_file(self, *args, **kwargs):
return wx.MessageDialog(self, _("It is not possible to add more attachments. Please take into account that You can add only a maximum of 4 images, or one audio, video or poll per post. Please remove other attachments before continuing."), _("Error adding attachment"), wx.ICON_ERROR).ShowModal()
def unable_to_attach_poll(self, *args, **kwargs):
return wx.MessageDialog(self, _("You can add a poll or media files. In order to add your poll, please remove other attachments first."), _("Error adding poll"), wx.ICON_ERROR).ShowModal()
class viewPost(wx.Dialog):
def set_title(self, length):
self.SetTitle(_("Post - %i characters ") % length)
def __init__(self, text="", boosts_count=0, favs_count=0, source="", date="", privacy="", *args, **kwargs):
super(viewPost, self).__init__(parent=None, id=wx.ID_ANY, size=(850, 850))
self.init_ui(text, boosts_count, favs_count, source, date, privacy)
def init_ui(self, text, boosts_count, favs_count, source, date, privacy):
panel = wx.Panel(self)
main_sizer = wx.BoxSizer(wx.VERTICAL)
main_sizer.Add(self.create_text_section(panel, text), 1, wx.EXPAND | wx.ALL, 5)
main_sizer.Add(self.create_image_description_section(panel), 1, wx.EXPAND | wx.ALL, 5)
main_sizer.Add(self.create_info_section(panel, privacy, boosts_count, favs_count, source, date), 0, wx.EXPAND | wx.ALL, 5)
main_sizer.Add(self.create_buttons_section(panel), 0, wx.ALIGN_RIGHT | wx.ALL, 5)
panel.SetSizer(main_sizer)
self.SetClientSize(main_sizer.CalcMin())
def create_text_section(self, panel, text):
sizer = wx.StaticBoxSizer(wx.StaticBox(panel, wx.ID_ANY, _("Post")), wx.VERTICAL)
self.text = wx.TextCtrl(panel, -1, text, style=wx.TE_READONLY | wx.TE_MULTILINE)
sizer.Add(self.text, 1, wx.EXPAND | wx.ALL, 5)
return sizer
def create_image_description_section(self, panel):
sizer = wx.StaticBoxSizer(wx.StaticBox(panel, wx.ID_ANY, _("Image description")), wx.VERTICAL)
self.image_description = wx.TextCtrl(panel, -1, style=wx.TE_READONLY | wx.TE_MULTILINE)
self.image_description.Enable(False)
sizer.Add(self.image_description, 1, wx.EXPAND | wx.ALL, 5)
return sizer
def create_info_section(self, panel, privacy, boosts_count, favs_count, source, date):
sizer = wx.StaticBoxSizer(wx.StaticBox(panel, wx.ID_ANY, _("Information")), wx.VERTICAL)
flex_sizer = wx.FlexGridSizer(cols=3, hgap=10, vgap=10)
flex_sizer.AddGrowableCol(1)
flex_sizer.Add(wx.StaticText(panel, -1, _("Privacy")), 0, wx.ALIGN_CENTER_VERTICAL)
flex_sizer.Add(wx.TextCtrl(panel, -1, privacy, style=wx.TE_READONLY | wx.TE_MULTILINE), 1, wx.EXPAND)
flex_sizer.Add(self.create_boosts_section(panel, boosts_count), 1, wx.EXPAND | wx.ALL, 5)
flex_sizer.Add(self.create_favorites_section(panel, favs_count), 1, wx.EXPAND | wx.ALL, 5)
flex_sizer.Add(wx.StaticText(panel, -1, _("Source")), 0, wx.ALIGN_CENTER_VERTICAL)
flex_sizer.Add(wx.TextCtrl(panel, -1, source, style=wx.TE_READONLY | wx.TE_MULTILINE), 1, wx.EXPAND)
flex_sizer.Add(wx.StaticText(panel, -1, _("Date")), 0, wx.ALIGN_CENTER_VERTICAL)
flex_sizer.Add(wx.TextCtrl(panel, -1, date, style=wx.TE_READONLY | wx.TE_MULTILINE), 1, wx.EXPAND)
sizer.Add(flex_sizer, 1, wx.EXPAND | wx.ALL, 5)
return sizer
def create_boosts_section(self, panel, boosts_count):
sizer = wx.StaticBoxSizer(wx.StaticBox(panel, wx.ID_ANY, _("Boosts")), wx.VERTICAL)
self.boosts_button = wx.Button(panel, -1, str(boosts_count))
self.boosts_button.SetToolTip(_("View users who boosted this post"))
sizer.Add(self.boosts_button, 1, wx.EXPAND | wx.ALL, 5)
return sizer
def create_favorites_section(self, panel, favs_count):
sizer = wx.StaticBoxSizer(wx.StaticBox(panel, wx.ID_ANY, _("Favorites")), wx.VERTICAL)
self.favorites_button = wx.Button(panel, -1, str(favs_count))
self.favorites_button.SetToolTip(_("View users who favorited this post"))
sizer.Add(self.favorites_button, 1, wx.EXPAND | wx.ALL, 5)
return sizer
def create_buttons_section(self, panel):
sizer = wx.BoxSizer(wx.HORIZONTAL)
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.Enable(False)
self.spellcheck = wx.Button(panel, wx.ID_ANY, _("Check &spelling..."))
self.translateButton = wx.Button(panel, wx.ID_ANY, _("&Translate..."))
cancelButton = wx.Button(panel, wx.ID_CANCEL, _("C&lose"))
cancelButton.SetDefault()
sizer.Add(self.mute, 0, wx.ALL, 5)
sizer.Add(self.share, 0, wx.ALL, 5)
sizer.Add(self.spellcheck, 0, wx.ALL, 5)
sizer.Add(self.translateButton, 0, wx.ALL, 5)
sizer.Add(cancelButton, 0, wx.ALL, 5)
return sizer
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 onSelect(self, ev):
self.text.SelectAll()
def enable_button(self, buttonName):
if hasattr(self, buttonName):
return getattr(self, buttonName).Enable()
class viewText(wx.Dialog):
def __init__(self, title="", text="", *args, **kwargs):
super(viewText, self).__init__(parent=None, id=wx.ID_ANY, size=(850,850), title=title)
panel = wx.Panel(self)
label = wx.StaticText(panel, -1, _("Text"))
self.text = wx.TextCtrl(panel, -1, text, style=wx.TE_READONLY|wx.TE_MULTILINE, size=(250, 180))
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)
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.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)
panel.SetSizer(mainBox)
self.SetClientSize(mainBox.CalcMin())
class poll(wx.Dialog):
def __init__(self, *args, **kwds):
super(poll, self).__init__(parent=None, id=wx.NewId(), title=_("Add a poll"))
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"))
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()
self.period.SetSelection(0)
period_sizer.Add(self.period, 0, 0, 0)
sizer_2 = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, _("Choices")), wx.VERTICAL)
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"))
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"))
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"))
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"))
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.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.SetValue(False)
sizer_1.Add(self.hide_votes, 0, wx.ALL, 5)
btn_sizer = wx.StdDialogButtonSizer()
sizer_1.Add(btn_sizer, 0, wx.ALIGN_RIGHT | wx.ALL, 4)
self.button_OK = wx.Button(self, wx.ID_OK)
self.button_OK.SetDefault()
self.button_OK.Bind(wx.EVT_BUTTON, self.validate_data)
btn_sizer.AddButton(self.button_OK)
self.button_CANCEL = wx.Button(self, wx.ID_CANCEL, "")
btn_sizer.AddButton(self.button_CANCEL)
btn_sizer.Realize()
self.SetSizer(sizer_1)
sizer_1.Fit(self)
self.SetAffirmativeId(self.button_OK.GetId())
self.SetEscapeId(self.button_CANCEL.GetId())
self.Layout()
def get_options(self):
controls = [self.option1, self.option2, self.option3, self.option4]
options = [option.GetValue() for option in controls if option.GetValue() != ""]
return options
def validate_data(self, *args, **kwargs):
options = self.get_options()
if len(options) < 2:
return wx.MessageDialog(self, _("Please make sure you have provided at least two options for the poll."), _("Not enough information"), wx.ICON_ERROR).ShowModal()
self.EndModal(wx.ID_OK)
class attachedPoll(wx.Dialog):
def __init__(self, poll_options, multiple=False, *args, **kwds):
super(attachedPoll, self).__init__(parent=None, id=wx.NewId(), title=_("Vote in this poll"))
self.poll_options = poll_options
sizer_1 = wx.BoxSizer(wx.VERTICAL)
sizer_2 = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, _("Options")), wx.VERTICAL)
sizer_1.Add(sizer_2, 1, wx.EXPAND, 0)
if multiple == False:
for option in range(len(self.poll_options)):
if option == 0:
setattr(self, "option{}".format(option), wx.RadioButton(self, wx.ID_ANY, poll_options[option], style=wx.RB_GROUP))
else:
setattr(self, "option{}".format(option), wx.RadioButton(self, wx.ID_ANY, poll_options[option]))
else:
for option in range(len(self.poll_options)):
setattr(self, "option{}".format(option), wx.CheckBox(self, wx.ID_ANY, poll_options[option]))
sizer_2.Add(getattr(self, "option{}".format(option)), 1, wx.EXPAND, 0)
btn_sizer = wx.StdDialogButtonSizer()
sizer_1.Add(btn_sizer, 0, wx.ALIGN_RIGHT | wx.ALL, 4)
self.button_OK = wx.Button(self, wx.ID_OK)
self.button_OK.SetDefault()
btn_sizer.AddButton(self.button_OK)
self.button_CANCEL = wx.Button(self, wx.ID_CANCEL, "")
btn_sizer.AddButton(self.button_CANCEL)
btn_sizer.Realize()
self.SetSizer(sizer_1)
sizer_1.Fit(self)
self.SetAffirmativeId(self.button_OK.GetId())
self.SetEscapeId(self.button_CANCEL.GetId())
self.Layout()
def get_selected(self):
options = []
for option in range(len(self.poll_options)):
if getattr(self, "option{}".format(option)).GetValue() == True:
options.append(option)
return options

View File

@@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
import wx
class searchDialog(wx.Dialog):
def __init__(self, value=""):
super(searchDialog, self).__init__(parent=None, id=wx.ID_ANY)
panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
self.SetTitle(_("Search"))
label = wx.StaticText(panel, wx.ID_ANY, _("&Search"))
self.term = wx.TextCtrl(panel, wx.ID_ANY, value)
self.term.SetFocus()
dc = wx.WindowDC(self.term)
dc.SetFont(self.term.GetFont())
self.term.SetSize(dc.GetTextExtent("0"*40))
sizer.Add(label, 0, wx.ALL, 5)
sizer.Add(self.term, 0, wx.ALL, 5)
self.posts = wx.RadioButton(panel, wx.ID_ANY, _("Posts"), style=wx.RB_GROUP)
self.users = wx.RadioButton(panel, wx.ID_ANY, _("Users"))
radioSizer = wx.BoxSizer(wx.HORIZONTAL)
radioSizer.Add(self.posts, 0, wx.ALL, 5)
radioSizer.Add(self.users, 0, wx.ALL, 5)
sizer.Add(radioSizer, 0, wx.ALL, 5)
ok = wx.Button(panel, wx.ID_OK, _(u"&OK"))
ok.SetDefault()
cancel = wx.Button(panel, wx.ID_CANCEL, _("&Close"))
self.SetEscapeId(cancel.GetId())
btnsizer = wx.BoxSizer()
btnsizer.Add(ok, 0, wx.ALL, 5)
btnsizer.Add(cancel, 0, wx.ALL, 5)
sizer.Add(btnsizer, 0, wx.ALL, 5)
panel.SetSizer(sizer)
self.SetClientSize(sizer.CalcMin())

View File

@@ -0,0 +1,239 @@
# -*- coding: utf-8 -*-
"""Wx dialogs for showing a user's profile."""
from io import BytesIO
from pubsub import pub
from typing import Tuple
import requests
import wx
from logging import getLogger
from threading import Thread
from sessions.mastodon.utils import html_filter
log = getLogger(__name__)
def selectUserDialog(users: list) -> tuple:
"""Choose a user from a possible list of users"""
if len(users) == 1:
return users[0]
dlg = wx.Dialog(None, title=_("Select user"))
label = wx.StaticText(dlg, label="Select a user: ")
choiceList = []
for user in users:
if len(user) == 3: # (display_name, username, id)
choiceList.append(f"{user[0]}: @{user[1]}")
else: # (acct, id)
choiceList.append(f"{user[0]}")
choice = wx.Choice(dlg, choices=choiceList)
ok = wx.Button(dlg, wx.ID_OK, _("OK"))
ok.SetDefault()
cancel = wx.Button(dlg, wx.ID_CANCEL, _("Cancel"))
dlg.SetEscapeId(cancel.GetId())
#sizers
sizer = wx.GridSizer(2, 2, 5, 5)
sizer.Add(label, wx.SizerFlags().Center())
sizer.Add(choice, wx.SizerFlags().Center())
sizer.Add(ok, wx.SizerFlags().Center())
sizer.Add(cancel, wx.SizerFlags().Center())
if dlg.ShowModal() == wx.ID_CANCEL:
return ()
# return the selected user
return users[choice.GetSelection()]
def returnTrue():
return True
class ShowUserProfile(wx.Dialog):
"""
A dialog for Showing user profile
layout is:
```
header
avatar
name
bio
meta data
```
"""
def __init__(self, user):
"""Initialize update profile dialog
Parameters:
- user: user dictionary
"""
super().__init__(parent=None)
self.user = user
self.SetTitle(_("{}'s Profile").format(user.display_name))
self.panel = wx.Panel(self)
wrapperSizer = wx.BoxSizer(wx.VERTICAL)
mainSizer = wx.GridSizer(2, 5, 5)
# create widgets
nameLabel = wx.StaticText(self.panel, label=_("&Name: "))
name = self.createTextCtrl(user.display_name, size=(200, 30))
mainSizer.Add(nameLabel, wx.SizerFlags().Center())
mainSizer.Add(name, wx.SizerFlags().Center())
urlLabel = wx.StaticText(self.panel, label=_("&URL: "))
url = self.createTextCtrl(user.url, size=(200, 30))
mainSizer.Add(urlLabel, wx.SizerFlags().Center())
mainSizer.Add(url, wx.SizerFlags().Center())
bioLabel = wx.StaticText(self.panel, label=_("&Bio: "))
bio = self.createTextCtrl(html_filter(user.note), (400, 60))
mainSizer.Add(bioLabel, wx.SizerFlags().Center())
mainSizer.Add(bio, wx.SizerFlags().Center())
joinLabel = wx.StaticText(self.panel, label=_("&Joined at: "))
joinText = self.createTextCtrl(user.created_at.strftime('%d %B, %Y'), (80, 30))
mainSizer.Add(joinLabel, wx.SizerFlags().Center())
mainSizer.Add(joinText, wx.SizerFlags().Center())
actions = wx.Button(self.panel, label=_("&Actions"))
actions.Bind(wx.EVT_BUTTON, self.onAction)
mainSizer.Add(actions, wx.SizerFlags().Center())
# header
headerLabel = wx.StaticText(self.panel, label=_("Header: "))
# Create empty image
self.headerImage = wx.StaticBitmap(self.panel)
self.headerImage.AcceptsFocusFromKeyboard = returnTrue
mainSizer.Add(headerLabel, wx.SizerFlags().Center())
mainSizer.Add(self.headerImage, wx.SizerFlags().Center())
# avatar
avatarLabel = wx.StaticText(self.panel, label=_("Avatar: "))
# Create empty image
self.avatarImage = wx.StaticBitmap(self.panel)
self.avatarImage.AcceptsFocusFromKeyboard = returnTrue
mainSizer.Add(avatarLabel, wx.SizerFlags().Center())
mainSizer.Add(self.avatarImage, wx.SizerFlags().Center())
self.fields = []
for num, field in enumerate(user.fields):
labelSizer = wx.BoxSizer(wx.HORIZONTAL)
labelLabel = wx.StaticText(self.panel, label=_("Field &{} - Label: ").format(num + 1))
labelSizer.Add(labelLabel, wx.SizerFlags().Center().Border(wx.ALL, 5))
labelText = self.createTextCtrl(html_filter(field.name), (230, 30), True)
labelSizer.Add(labelText, wx.SizerFlags().Expand().Border(wx.ALL, 5))
mainSizer.Add(labelSizer, 0, wx.CENTER)
contentSizer = wx.BoxSizer(wx.HORIZONTAL)
contentLabel = wx.StaticText(self.panel, label=_("Content: "))
contentSizer.Add(contentLabel, wx.SizerFlags().Center())
contentText = self.createTextCtrl(html_filter(field.value), (400, 60), True)
contentSizer.Add(contentText, wx.SizerFlags().Center())
mainSizer.Add(contentSizer, 0, wx.CENTER | wx.LEFT, 10)
bullSwitch = {True: _('Yes'), False: _('No'), None: _('No')}
privateSizer = wx.BoxSizer(wx.HORIZONTAL)
privateLabel = wx.StaticText(self.panel, label=_("&Private account: "))
private = self.createTextCtrl(bullSwitch[user.locked], (30, 30))
privateSizer.Add(privateLabel, wx.SizerFlags().Center())
privateSizer.Add(private, wx.SizerFlags().Center())
mainSizer.Add(privateSizer, 0, wx.ALL | wx.CENTER)
botSizer = wx.BoxSizer(wx.HORIZONTAL)
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())
mainSizer.Add(botSizer, 0, wx.ALL | wx.CENTER)
discoverSizer = wx.BoxSizer(wx.HORIZONTAL)
discoverLabel = wx.StaticText(self.panel, label=_("&Discoverable account: "))
discoverText = self.createTextCtrl(bullSwitch[user.discoverable], (30, 30))
discoverSizer.Add(discoverLabel, wx.SizerFlags().Center())
discoverSizer.Add(discoverText, wx.SizerFlags().Center())
mainSizer.Add(discoverSizer, 0, wx.ALL | wx.CENTER)
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())
following = wx.Button(self.panel, label=_("{} &following. Click to open Following timeline").format(user.following_count))
mainSizer.Add(following, wx.SizerFlags().Center())
following.Bind(wx.EVT_BUTTON, self.onFollowing)
followers = wx.Button(self.panel, label=_("{} fo&llowers. Click to open followers timeline").format(user.followers_count))
mainSizer.Add(followers, wx.SizerFlags().Center())
followers.Bind(wx.EVT_BUTTON, self.onFollowers)
close = wx.Button(self.panel, wx.ID_CLOSE, _("&Close"))
self.SetEscapeId(close.GetId())
close.SetDefault()
wrapperSizer.Add(mainSizer, 0, wx.CENTER)
wrapperSizer.Add(close, wx.SizerFlags().Center())
self.panel.SetSizer(wrapperSizer)
wrapperSizer.Fit(self.panel)
self.panel.Center()
mainSizer.Fit(self)
self.Center()
imageDownloaderThread = Thread(target=self._getImages)
imageDownloaderThread.start()
def createTextCtrl(self, text: str, size: Tuple[int, int], multiline: bool = False) -> wx.TextCtrl:
"""Creates a wx.TextCtrl and returns it
Parameters:
text: The value of the wx.TextCtrl
size: The size of the wx.TextCtrl
Returns: the created wx.TextCtrl object
"""
if not multiline:
style= wx.TE_PROCESS_ENTER | wx.TE_PROCESS_TAB | wx.TE_READONLY
else:
style= wx.TE_PROCESS_ENTER | wx.TE_PROCESS_TAB | wx.TE_READONLY | wx.TE_MULTILINE
textCtrl = wx.TextCtrl(self.panel, value=text, size=size, style=style)
textCtrl.AcceptsFocusFromKeyboard = returnTrue
return textCtrl
def onAction(self, *args):
"""Opens the Open timeline dialog"""
pub.sendMessage('execute-action', action='follow')
def onPost(self, *args):
"""Open this user's timeline"""
pub.sendMessage('execute-action', action='openPostTimeline', kwargs=dict(user=self.user))
def onFollowing(self, *args):
"""Open following timeline for this user"""
pub.sendMessage('execute-action', action='openFollowingTimeline', kwargs=dict(user=self.user))
def onFollowers(self, *args):
"""Open followers timeline for this user"""
pub.sendMessage('execute-action', action='openFollowersTimeline', kwargs=dict(user=self.user))
def _getImages(self):
"""Downloads image from mastodon server
This method should run on a separate thread
"""
log.debug("Downloading user's header and avatar images...")
try:
header = requests.get(self.user.header)
avatar = requests.get(self.user.avatar)
except requests.exceptions.RequestException as mess:
log.exception("An exception was raised while downloading images:", mess)
return
wx.CallAfter(self._drawImages, header.content, avatar.content)
def _drawImages(self, headerImageBytes, avatarImageBytes):
"""Draws images on the bitmap ui"""
# log.debug("Drawing images...")
# Header
headerImage = wx.Image(BytesIO(headerImageBytes), wx.BITMAP_TYPE_ANY)
headerImage.Rescale(300, 100, wx.IMAGE_QUALITY_HIGH)
self.headerImage.SetBitmap(headerImage.ConvertToBitmap())
# Avatar
avatarImage = wx.Image(BytesIO(avatarImageBytes), wx.BITMAP_TYPE_ANY)
avatarImage.Rescale(150, 150, wx.IMAGE_QUALITY_HIGH)
self.avatarImage.SetBitmap(avatarImage.ConvertToBitmap())

View File

@@ -0,0 +1,205 @@
# -*- coding: utf-8 -*-
import os
import requests
from io import BytesIO
import wx
def return_true():
return True
class UpdateProfileDialog(wx.Dialog):
"""
A dialog for user to update his / her profile details.
layout is:
```
header
avatar
name
bio
meta data
```
"""
def __init__(self, display_name: str, note: str, header: str, avatar: str, fields: list, locked: bool, bot: bool, discoverable: bool):
"""Initialize update profile dialog
Parameters:
- display_name: The user's display name to show in the display name field
- note: The users bio to show in the bio field
- header: the users header pic link
- avatar: The users avatar pic link
"""
super().__init__(parent=None)
self.SetTitle(_("Update Profile"))
self.header = header
self.avatar = avatar
panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
# create widgets
display_name_label = wx.StaticText(panel, label=_("&Display Name"))
self.display_name = wx.TextCtrl(panel, value=display_name, style= wx.TE_PROCESS_ENTER, size=(200, 30))
name_sizer = wx.BoxSizer(wx.HORIZONTAL)
name_sizer.Add(display_name_label, wx.SizerFlags().Center())
name_sizer.Add(self.display_name, wx.SizerFlags().Center())
sizer.Add(name_sizer, wx.CENTER)
bio_label = wx.StaticText(panel, label=_("&Bio"))
self.bio = wx.TextCtrl(panel, value=note, style=wx.TE_PROCESS_ENTER | wx.TE_MULTILINE, size=(400, 60))
bio_sizer = wx.BoxSizer(wx.HORIZONTAL)
bio_sizer.Add(bio_label, wx.SizerFlags().Center())
bio_sizer.Add(self.bio, wx.SizerFlags().Center())
sizer.Add(bio_sizer, wx.CENTER)
# header
header_label = wx.StaticText(panel, label=_("Header"))
try:
response = requests.get(self.header)
except requests.exceptions.RequestException:
# Create empty image
self.header_image = wx.StaticBitmap()
else:
image_bytes = BytesIO(response.content)
image = wx.Image(image_bytes, wx.BITMAP_TYPE_ANY)
image.Rescale(300, 100, wx.IMAGE_QUALITY_HIGH)
self.header_image = wx.StaticBitmap(panel, bitmap=image.ConvertToBitmap())
self.header_image.AcceptsFocusFromKeyboard = return_true
self.change_header = wx.Button(panel, label=_("Change &header"))
header_sizer = wx.BoxSizer(wx.HORIZONTAL)
header_sizer.Add(header_label, wx.SizerFlags().Center())
header_sizer.Add(self.header_image, wx.SizerFlags().Center())
header_sizer.Add(self.change_header, wx.SizerFlags().Center())
sizer.Add(header_sizer, wx.CENTER)
# avatar
avatar_label = wx.StaticText(panel, label=_("Avatar"))
try:
response = requests.get(self.avatar)
except requests.exceptions.RequestException:
# Create empty image
self.avatar_image = wx.StaticBitmap()
else:
image_bytes = BytesIO(response.content)
image = wx.Image(image_bytes, wx.BITMAP_TYPE_ANY)
image.Rescale(150, 150, wx.IMAGE_QUALITY_HIGH)
self.avatar_image = wx.StaticBitmap(panel, bitmap=image.ConvertToBitmap())
self.avatar_image.AcceptsFocusFromKeyboard = return_true
self.change_avatar = wx.Button(panel, label=_("Change &avatar"))
avatar_sizer = wx.BoxSizer(wx.HORIZONTAL)
avatar_sizer.Add(avatar_label, wx.SizerFlags().Center())
avatar_sizer.Add(self.avatar_image, wx.SizerFlags().Center())
avatar_sizer.Add(self.change_avatar, wx.SizerFlags().Center())
sizer.Add(avatar_sizer, wx.CENTER)
self.fields = []
for i in range(1, 5):
field_sizer = wx.BoxSizer(wx.HORIZONTAL)
field_label = wx.StaticText(panel, label=_("Field &{}: Label").format(i))
field_sizer.Add(field_label, wx.SizerFlags().Center().Border(wx.ALL, 5))
label_textctrl = wx.TextCtrl(panel, style=wx.TE_PROCESS_ENTER | wx.TE_MULTILINE, size=(200, 30))
if i <= len(fields):
label_textctrl.SetValue(fields[i-1][0])
field_sizer.Add(label_textctrl, wx.SizerFlags().Expand().Border(wx.ALL, 5))
content_label = wx.StaticText(panel, label=_("Content"))
field_sizer.Add(content_label, wx.SizerFlags().Center().Border(wx.ALL, 5))
content_textctrl = wx.TextCtrl(panel, style=wx.TE_PROCESS_ENTER | wx.TE_MULTILINE, size=(400, 60))
if i <= len(fields):
content_textctrl.SetValue(fields[i-1][1])
field_sizer.Add(content_textctrl, wx.SizerFlags().Expand().Border(wx.ALL, 5))
sizer.Add(field_sizer, 0, wx.CENTER)
self.fields.append((label_textctrl, content_textctrl))
self.locked = wx.CheckBox(panel, label=_("&Private account"))
self.locked.SetValue(locked)
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)
sizer.Add(self.locked, wx.SizerFlags().Expand().Border(wx.ALL, 5))
sizer.Add(self.bot, wx.SizerFlags().Expand().Border(wx.ALL, 5))
sizer.Add(self.discoverable, wx.SizerFlags().Expand().Border(wx.ALL, 5))
ok = wx.Button(panel, wx.ID_OK, _(u"&OK"))
ok.SetDefault()
cancel = wx.Button(panel, wx.ID_CANCEL, _("&Close"))
self.SetEscapeId(cancel.GetId())
action_sizer = wx.BoxSizer(wx.HORIZONTAL)
action_sizer.Add(ok, wx.SizerFlags().Center())
action_sizer.Add(cancel, wx.SizerFlags().Center())
sizer.Add(action_sizer, wx.CENTER)
panel.SetSizer(sizer)
sizer.Fit(self)
self.Center()
# manage events
ok.Bind(wx.EVT_BUTTON, self.on_ok)
self.change_header.Bind(wx.EVT_BUTTON, self.on_change_header)
self.change_avatar.Bind(wx.EVT_BUTTON, self.on_change_avatar)
self.AutoLayout = True
def on_ok(self, *args):
"""Method called when user clicks ok in dialog"""
self.data = {
'display_name': self.display_name.GetValue(),
'note': self.bio.GetValue(),
'header': self.header,
'avatar': self.avatar,
'fields': [(label.GetValue(), content.GetValue()) for label, content in self.fields if label.GetValue() and content.GetValue()],
'locked': self.locked.GetValue(),
'bot': self.bot.GetValue(),
'discoverable': self.discoverable.GetValue(),
}
self.EndModal(wx.ID_OK)
def on_change_header(self, *args):
"""Display a dialog for the user to choose a picture and update the
appropriate attribute"""
wildcard = "Images (*.png;*.jpg;*.gif)|*.png;*.jpg;*.gif"
dlg = wx.FileDialog(self, _("Select header image - max 2MB"), wildcard=wildcard)
if dlg.ShowModal() == wx.CLOSE:
return
if os.path.getsize(dlg.GetPath()) > 2097152:
# File size exceeds the limit
message = _("The selected file is larger than 2MB. Do you want to select another file?")
caption = _("File more than 2MB")
style = wx.YES_NO | wx.ICON_WARNING
# Display the message box
result = wx.MessageBox(message, caption, style)
return self.on_change_header() if result == wx.YES else None
self.header = dlg.GetPath()
image = wx.Image(self.header, wx.BITMAP_TYPE_ANY)
image.Rescale(150, 150, wx.IMAGE_QUALITY_HIGH)
self.header_image.SetBitmap(image.ConvertToBitmap())
def on_change_avatar(self, *args):
"""Display a dialog for the user to choose a picture and update the
appropriate attribute"""
wildcard = "Images (*.png;*.jpg;*.gif)|*.png;*.jpg;*.gif"
dlg = wx.FileDialog(self, _("Select avatar image - max 2MB"), wildcard=wildcard)
if dlg.ShowModal() == wx.CLOSE:
return
if os.path.getsize(dlg.GetPath()) > 2097152:
# File size exceeds the limit
message = _("The selected file is larger than 2MB. Do you want to select another file?")
caption = _("File more than 2MB")
style = wx.YES_NO | wx.ICON_WARNING
# Display the message box
result = wx.MessageBox(message, caption, style)
return self.on_change_avatar() if result == wx.YES else None
self.avatar = dlg.GetPath()
image = wx.Image(self.avatar, wx.BITMAP_TYPE_ANY)
image.Rescale(150, 150, wx.IMAGE_QUALITY_HIGH)
self.avatar_image.SetBitmap(image.ConvertToBitmap())

View File

@@ -0,0 +1,79 @@
# -*- coding: utf-8 -*-
import wx
class UserActionsDialog(wx.Dialog):
def __init__(self, users=[], default="follow", *args, **kwargs):
super(UserActionsDialog, self).__init__(parent=None, *args, **kwargs)
panel = wx.Panel(self)
userSizer = wx.BoxSizer()
self.SetTitle(_(u"Action"))
userLabel = wx.StaticText(panel, -1, _(u"&User"))
self.cb = wx.ComboBox(panel, -1, choices=users, value=users[0])
self.cb.SetFocus()
self.autocompletion = wx.Button(panel, -1, _(u"&Autocomplete users"))
userSizer.Add(userLabel, 0, wx.ALL, 5)
userSizer.Add(self.cb, 0, wx.ALL, 5)
userSizer.Add(self.autocompletion, 0, wx.ALL, 5)
actionSizer = wx.BoxSizer(wx.VERTICAL)
label2 = wx.StaticText(panel, -1, _(u"Action"))
self.follow = wx.RadioButton(panel, -1, _(u"&Follow"), name=_(u"Action"), style=wx.RB_GROUP)
self.unfollow = wx.RadioButton(panel, -1, _(u"U&nfollow"))
self.mute = wx.RadioButton(panel, -1, _(u"&Mute"))
self.unmute = wx.RadioButton(panel, -1, _(u"Unmu&te"))
self.block = wx.RadioButton(panel, -1, _(u"&Block"))
self.unblock = wx.RadioButton(panel, -1, _(u"Unbl&ock"))
self.setup_default(default)
hSizer = wx.BoxSizer(wx.HORIZONTAL)
hSizer.Add(label2, 0, wx.ALL, 5)
actionSizer.Add(self.follow, 0, wx.ALL, 5)
actionSizer.Add(self.unfollow, 0, wx.ALL, 5)
actionSizer.Add(self.mute, 0, wx.ALL, 5)
actionSizer.Add(self.unmute, 0, wx.ALL, 5)
actionSizer.Add(self.block, 0, wx.ALL, 5)
actionSizer.Add(self.unblock, 0, wx.ALL, 5)
hSizer.Add(actionSizer, 0, wx.ALL, 5)
sizer = wx.BoxSizer(wx.VERTICAL)
ok = wx.Button(panel, wx.ID_OK, _(u"&OK"))
ok.SetDefault()
cancel = wx.Button(panel, wx.ID_CANCEL, _(u"&Close"))
btnsizer = wx.BoxSizer()
btnsizer.Add(ok)
btnsizer.Add(cancel)
sizer.Add(userSizer)
sizer.Add(hSizer, 0, wx.ALL, 5)
sizer.Add(btnsizer)
panel.SetSizer(sizer)
def get_action(self):
if self.follow.GetValue() == True: return "follow"
elif self.unfollow.GetValue() == True: return "unfollow"
elif self.mute.GetValue() == True: return "mute"
elif self.unmute.GetValue() == True: return "unmute"
elif self.block.GetValue() == True: return "block"
elif self.unblock.GetValue() == True: return "unblock"
def setup_default(self, default):
if default == "follow":
self.follow.SetValue(True)
elif default == "unfollow":
self.unfollow.SetValue(True)
elif default == "mute":
self.mute.SetValue(True)
elif default == "unmute":
self.unmute.SetValue(True)
elif default == "block":
self.block.SetValue(True)
elif default == "unblock":
self.unblock.SetValue(True)
def get_response(self):
return self.ShowModal()
def get_user(self):
return self.cb.GetValue()
def get_position(self):
return self.cb.GetPosition()
def popup_menu(self, menu):
self.PopupMenu(menu, self.cb.GetPosition())

View File

@@ -0,0 +1,57 @@
# -*- coding: utf-8 -*-
import wx
class UserTimeline(wx.Dialog):
def __init__(self, users=[], default="posts", *args, **kwargs):
super(UserTimeline, self).__init__(parent=None, *args, **kwargs)
panel = wx.Panel(self)
userSizer = wx.BoxSizer()
self.SetTitle(_("Timeline for %s") % (users[0]))
userLabel = wx.StaticText(panel, -1, _(u"User"))
self.cb = wx.ComboBox(panel, -1, choices=users, value=users[0])
self.cb.SetFocus()
self.autocompletion = wx.Button(panel, -1, _(u"&Autocomplete users"))
userSizer.Add(userLabel, 0, wx.ALL, 5)
userSizer.Add(self.cb, 0, wx.ALL, 5)
userSizer.Add(self.autocompletion, 0, wx.ALL, 5)
actionSizer = wx.BoxSizer(wx.VERTICAL)
label2 = wx.StaticText(panel, -1, _(u"Buffer type"))
self.posts = wx.RadioButton(panel, -1, _(u"&Posts"), style=wx.RB_GROUP)
self.followers = wx.RadioButton(panel, -1, _(u"&Followers"))
self.following = wx.RadioButton(panel, -1, _("Fo&llowing"))
self.setup_default(default)
hSizer = wx.BoxSizer(wx.HORIZONTAL)
hSizer.Add(label2, 0, wx.ALL, 5)
actionSizer.Add(self.posts, 0, wx.ALL, 5)
actionSizer.Add(self.followers, 0, wx.ALL, 5)
actionSizer.Add(self.following, 0, wx.ALL, 5)
hSizer.Add(actionSizer, 0, wx.ALL, 5)
sizer = wx.BoxSizer(wx.VERTICAL)
ok = wx.Button(panel, wx.ID_OK, _(u"&OK"))
ok.SetDefault()
cancel = wx.Button(panel, wx.ID_CANCEL, _(u"&Close"))
btnsizer = wx.BoxSizer()
btnsizer.Add(ok)
btnsizer.Add(cancel)
sizer.Add(userSizer)
sizer.Add(hSizer, 0, wx.ALL, 5)
sizer.Add(btnsizer)
panel.SetSizer(sizer)
def get_action(self):
if self.posts.GetValue() == True: return "posts"
elif self.followers.GetValue() == True: return "followers"
elif self.following.GetValue() == True: return "following"
def setup_default(self, default):
if default == "posts":
self.posts.SetValue(True)
def get_user(self):
return self.cb.GetValue()
def get_position(self):
return self.cb.GetPosition()
def popup_menu(self, menu):
self.PopupMenu(menu, self.cb.GetPosition())

View File

@@ -0,0 +1,52 @@
# -*- coding: UTF-8 -*-
import wx
import output
from typing import List
class EditTemplateDialog(wx.Dialog):
def __init__(self, template: str, variables: List[str] = [], default_template: str = "", *args, **kwds) -> None:
super(EditTemplateDialog, self).__init__(parent=None, title=_("Edit Template"), *args, **kwds)
self.default_template = default_template
mainSizer = wx.BoxSizer(wx.VERTICAL)
sizer_1 = wx.BoxSizer(wx.HORIZONTAL)
mainSizer.Add(sizer_1, 1, wx.EXPAND, 0)
label_1 = wx.StaticText(self, wx.ID_ANY, _("Edit template"))
sizer_1.Add(label_1, 0, 0, 0)
self.template = wx.TextCtrl(self, wx.ID_ANY, template)
sizer_1.Add(self.template, 0, 0, 0)
sizer_2 = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, _("Available variables")), wx.HORIZONTAL)
mainSizer.Add(sizer_2, 1, wx.EXPAND, 0)
self.variables = wx.ListBox(self, wx.ID_ANY, choices=["$"+v for v in variables])
self.variables.Bind(wx.EVT_CHAR_HOOK, self.on_keypress)
sizer_2.Add(self.variables, 0, 0, 0)
sizer_3 = wx.StdDialogButtonSizer()
mainSizer.Add(sizer_3, 0, wx.ALIGN_RIGHT | wx.ALL, 4)
self.button_SAVE = wx.Button(self, wx.ID_SAVE)
self.button_SAVE.SetDefault()
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.Bind(wx.EVT_BUTTON, self.on_restore)
sizer_3.AddButton(self.button_CANCEL)
sizer_3.Realize()
self.SetSizer(mainSizer)
mainSizer.Fit(self)
self.SetAffirmativeId(self.button_SAVE.GetId())
self.SetEscapeId(self.button_CANCEL.GetId())
self.Layout()
def on_keypress(self, event, *args, **kwargs):
if event.GetKeyCode() == wx.WXK_RETURN:
self.template.ChangeValue(self.template.GetValue()+self.variables.GetStringSelection()+", ")
output.speak(self.template.GetValue()+self.variables.GetStringSelection()+", ")
return
event.Skip()
def on_restore(self, *args, **kwargs) -> None:
self.template.ChangeValue(self.default_template)
output.speak(_("Restored template to {}.").format(self.default_template))
self.template.SetFocus()
def invalid_template() -> None:
wx.MessageDialog(None, _("the template you have specified include variables that do not exists for the object. Please fix the template and try again. For your reference, you can see a list of all available variables in the variables list while editing your template."), _("Invalid template"), wx.ICON_ERROR).ShowModal()

View File

@@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import wx
class urlList(wx.Dialog):
def __init__(self, title=_(u"Select URL")):
super(urlList, self).__init__(parent=None, title=title)
panel = wx.Panel(self)
self.lista = wx.ListBox(panel, -1)
self.lista.SetFocus()
self.lista.SetSize(self.lista.GetBestSize())
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.lista, 0, wx.ALL, 5)
goBtn = wx.Button(panel, wx.ID_OK)
goBtn.SetDefault()
cancelBtn = wx.Button(panel, wx.ID_CANCEL)
btnSizer = wx.BoxSizer()
btnSizer.Add(goBtn, 0, wx.ALL, 5)
btnSizer.Add(cancelBtn, 0, wx.ALL, 5)
sizer.Add(btnSizer, 0, wx.ALL, 5)
panel.SetSizer(sizer)
self.SetClientSize(sizer.CalcMin())
def populate_list(self, urls):
for i in urls:
self.lista.Append(i)
self.lista.SetSelection(0)
def get_string(self):
return self.lista.GetStringSelection()
def get_item(self):
return self.lista.GetSelection()
def get_response(self):
return self.ShowModal()

View File

@@ -0,0 +1,95 @@
# -*- coding: utf-8 -*-
import wx
import gettext
from . import baseDialog
class addAliasDialog(baseDialog.BaseWXDialog):
def __init__(self, title, users):
super(addAliasDialog, self).__init__(parent=None, id=wx.ID_ANY, title=title)
panel = wx.Panel(self)
userSizer = wx.BoxSizer()
self.cb = wx.ComboBox(panel, -1, choices=users, value=users[0], size=wx.DefaultSize)
self.cb.SetFocus()
self.autocompletion = wx.Button(panel, -1, _(u"&Autocomplete users"))
userSizer.Add(wx.StaticText(panel, -1, _(u"User")), 0, wx.ALL, 5)
userSizer.Add(self.cb, 0, wx.ALL, 5)
userSizer.Add(self.autocompletion, 0, wx.ALL, 5)
aliasSizer = wx.BoxSizer(wx.HORIZONTAL)
aliasLabel = wx.StaticText(panel, wx.ID_ANY, _("Alias"))
self.alias = wx.TextCtrl(panel, wx.ID_ANY)
aliasSizer.Add(aliasLabel, 0, wx.ALL, 5)
aliasSizer.Add(self.alias, 0, wx.ALL, 5)
sizer = wx.BoxSizer(wx.VERTICAL)
ok = wx.Button(panel, wx.ID_OK, _(u"OK"))
ok.SetDefault()
cancel = wx.Button(panel, wx.ID_CANCEL, _(u"Close"))
btnsizer = wx.BoxSizer()
btnsizer.Add(ok, 0, wx.ALL, 5)
btnsizer.Add(cancel, 0, wx.ALL, 5)
sizer.Add(userSizer, 0, wx.ALL, 5)
sizer.Add(aliasSizer, 0, wx.ALL, 5)
sizer.Add(btnsizer, 0, wx.ALL, 5)
panel.SetSizer(sizer)
self.SetClientSize(sizer.CalcMin())
def get_user(self):
return (self.cb.GetValue(), self.alias.GetValue())
class userAliasEditorDialog(wx.Dialog):
def __init__(self, *args, **kwds):
super(userAliasEditorDialog, self).__init__(parent=None)
self.SetTitle(_("Edit user aliases"))
main_sizer = wx.BoxSizer(wx.VERTICAL)
userListSizer = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, _("Users")), wx.VERTICAL)
main_sizer.Add(userListSizer, 1, wx.EXPAND, 0)
self.users = wx.ListBox(self, wx.ID_ANY, choices=[])
self.users.Bind(wx.EVT_LISTBOX, self.on_selection_changes)
userListSizer.Add(self.users, 0, 0, 0)
actionsSizer = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, _("Actions")), wx.HORIZONTAL)
main_sizer.Add(actionsSizer, 1, wx.EXPAND, 0)
self.add = wx.Button(self, wx.ID_ANY, _("Add alias"))
self.add.SetToolTip(_("Adds a new user alias"))
actionsSizer.Add(self.add, 0, 0, 0)
self.edit = wx.Button(self, wx.ID_ANY, _("Edit"))
self.edit.SetToolTip(_("Edit the currently focused user Alias."))
self.edit.Enable(False)
actionsSizer.Add(self.edit, 0, 0, 0)
self.remove = wx.Button(self, wx.ID_ANY, _("Remove"))
self.remove.SetToolTip(_("Remove the currently focused user alias."))
self.remove.Enable(False)
actionsSizer.Add(self.remove, 0, 0, 0)
btnSizer = wx.StdDialogButtonSizer()
main_sizer.Add(btnSizer, 0, wx.ALIGN_RIGHT | wx.ALL, 4)
self.button_CLOSE = wx.Button(self, wx.ID_CLOSE, "")
btnSizer.AddButton(self.button_CLOSE)
btnSizer.Realize()
self.SetSizer(main_sizer)
main_sizer.Fit(self)
self.SetEscapeId(self.button_CLOSE.GetId())
self.Layout()
def on_selection_changes(self, *args, **kwargs):
selection = self.users.GetSelection()
if selection == -1:
self.enable_action_buttons(False)
else:
self.enable_action_buttons(True)
def get_selected_user(self):
return self.users.GetStringSelection()
def remove_alias_dialog(self, *args, **kwargs):
dlg = wx.MessageDialog(self, _("Are you sure you want to delete this user alias?"), _("Remove user alias"), wx.YES_NO)
if dlg.ShowModal() == wx.ID_YES:
return True
else:
return False
def enable_action_buttons(self, enabled=True):
self.edit.Enable(enabled)
self.remove.Enable(enabled)
def edit_alias_dialog(self, title):
dlg = wx.TextEntryDialog(self, title, _("User alias"))
if dlg.ShowModal() == wx.ID_OK:
return dlg.GetValue()

View File

@@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
import wx
class UserListDialog(wx.Dialog):
def __init__(self, parent=None, title="", users=[]):
super(UserListDialog, self).__init__(parent=parent, title=title, size=(400, 300))
self.users = users
self.init_ui()
def init_ui(self):
panel = wx.Panel(self)
main_sizer = wx.BoxSizer(wx.VERTICAL)
title_text = wx.StaticText(panel, label=self.GetTitle())
title_font = title_text.GetFont()
title_font.PointSize += 2
title_font = title_font.Bold()
title_text.SetFont(title_font)
main_sizer.Add(title_text, 0, wx.ALIGN_CENTER | wx.TOP, 10)
user_list_box = wx.StaticBox(panel, wx.ID_ANY, "Users")
user_list_sizer = wx.StaticBoxSizer(user_list_box, wx.VERTICAL)
self.user_list = wx.ListBox(panel, wx.ID_ANY, choices=self.users, style=wx.LB_SINGLE)
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")
buttons_sizer.Add(self.actions_button, 0, wx.RIGHT, 10)
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")
buttons_sizer.Add(close_button, 0)
main_sizer.Add(buttons_sizer, 0, wx.ALIGN_CENTER | wx.BOTTOM, 15)
panel.SetSizer(main_sizer)
# self.SetSizerAndFit(main_sizer)