mastodon: Added account settings dialog (except autocompletion settings)

This commit is contained in:
Manuel Cortez 2022-12-08 11:14:14 -06:00
parent d5ed5f12af
commit 35b758ecf1
No known key found for this signature in database
GPG Key ID: 9E0735CA15EFE790
3 changed files with 414 additions and 1 deletions

View File

@ -2,12 +2,13 @@
import wx import wx
import logging import logging
from pubsub import pub from pubsub import pub
from mysc import restart
from wxUI.dialogs.mastodon import dialogs from wxUI.dialogs.mastodon import dialogs
from wxUI.dialogs.mastodon import search as search_dialogs from wxUI.dialogs.mastodon import search as search_dialogs
from wxUI.dialogs.mastodon import dialogs from wxUI.dialogs.mastodon import dialogs
from wxUI import commonMessageDialogs from wxUI import commonMessageDialogs
from sessions.twitter import utils from sessions.twitter import utils
from . import userActions from . import userActions, settings
log = logging.getLogger("controller.mastodon.handler") log = logging.getLogger("controller.mastodon.handler")
@ -177,3 +178,13 @@ class Handler(object):
buffer.session.settings["other_buffers"]["following_timelines"].append(user.id) buffer.session.settings["other_buffers"]["following_timelines"].append(user.id)
buffer.session.sound.play("create_timeline.ogg") buffer.session.sound.play("create_timeline.ogg")
buffer.session.settings.write() buffer.session.settings.write()
def account_settings(self, buffer, controller):
d = settings.accountSettingsController(buffer, controller)
if d.response == wx.ID_OK:
d.save_configuration()
if d.needs_restart == True:
commonMessageDialogs.needs_restart()
buffer.session.settings.write()
buffer.session.save_persistent_data()
restart.restart_program()

View File

@ -0,0 +1,216 @@
# -*- coding: utf-8 -*-
import os
import threading
import logging
import sound_lib
import paths
import widgetUtils
import output
from collections import OrderedDict
from wxUI import commonMessageDialogs
from wxUI.dialogs.mastodon import configuration
from extra.autocompletionUsers import scan, manage
from extra.ocr import OCRSpace
from controller.settings import globalSettingsController
from . templateEditor import EditTemplate
log = logging.getLogger("Settings")
class accountSettingsController(globalSettingsController):
def __init__(self, buffer, window):
self.user = buffer.session.db["user_name"]
self.buffer = buffer
self.window = window
self.config = buffer.session.settings
self.dialog = configuration.configurationDialog()
self.create_config()
self.needs_restart = False
self.is_started = True
def create_config(self):
self.dialog.create_general_account()
# widgetUtils.connect_event(self.dialog.general.userAutocompletionScan, widgetUtils.BUTTON_PRESSED, self.on_autocompletion_scan)
# widgetUtils.connect_event(self.dialog.general.userAutocompletionManage, widgetUtils.BUTTON_PRESSED, self.on_autocompletion_manage)
self.dialog.set_value("general", "relative_time", self.config["general"]["relative_times"])
self.dialog.set_value("general", "show_screen_names", self.config["general"]["show_screen_names"])
self.dialog.set_value("general", "hide_emojis", self.config["general"]["hide_emojis"])
self.dialog.set_value("general", "itemsPerApiCall", self.config["general"]["max_posts_per_call"])
self.dialog.set_value("general", "reverse_timelines", self.config["general"]["reverse_timelines"])
boost_mode = self.config["general"]["boost_mode"]
if boost_mode == "ask":
self.dialog.set_value("general", "ask_before_boost", True)
else:
self.dialog.set_value("general", "ask_before_boost", False)
self.dialog.set_value("general", "persist_size", str(self.config["general"]["persist_size"]))
self.dialog.set_value("general", "load_cache_in_memory", self.config["general"]["load_cache_in_memory"])
self.dialog.create_reporting()
self.dialog.set_value("reporting", "speech_reporting", self.config["reporting"]["speech_reporting"])
self.dialog.set_value("reporting", "braille_reporting", self.config["reporting"]["braille_reporting"])
post_template = self.config["templates"]["post"]
conversation_template = self.config["templates"]["conversation"]
person_template = self.config["templates"]["person"]
self.dialog.create_templates(post_template=post_template, conversation_template=conversation_template, person_template=person_template)
widgetUtils.connect_event(self.dialog.templates.post, widgetUtils.BUTTON_PRESSED, self.edit_post_template)
widgetUtils.connect_event(self.dialog.templates.conversation, widgetUtils.BUTTON_PRESSED, self.edit_conversation_template)
widgetUtils.connect_event(self.dialog.templates.person, widgetUtils.BUTTON_PRESSED, self.edit_person_template)
self.dialog.create_other_buffers()
buffer_values = self.get_buffers_list()
self.dialog.buffers.insert_buffers(buffer_values)
self.dialog.buffers.connect_hook_func(self.toggle_buffer_active)
widgetUtils.connect_event(self.dialog.buffers.toggle_state, widgetUtils.BUTTON_PRESSED, self.toggle_state)
widgetUtils.connect_event(self.dialog.buffers.up, widgetUtils.BUTTON_PRESSED, self.dialog.buffers.move_up)
widgetUtils.connect_event(self.dialog.buffers.down, widgetUtils.BUTTON_PRESSED, self.dialog.buffers.move_down)
self.input_devices = sound_lib.input.Input.get_device_names()
self.output_devices = sound_lib.output.Output.get_device_names()
self.soundpacks = []
[self.soundpacks.append(i) for i in os.listdir(paths.sound_path()) if os.path.isdir(os.path.join(paths.sound_path(), i)) == True ]
self.dialog.create_sound(self.input_devices, self.output_devices, self.soundpacks)
self.dialog.set_value("sound", "volumeCtrl", int(self.config["sound"]["volume"]*100))
self.dialog.set_value("sound", "input", self.config["sound"]["input_device"])
self.dialog.set_value("sound", "output", self.config["sound"]["output_device"])
self.dialog.set_value("sound", "session_mute", self.config["sound"]["session_mute"])
self.dialog.set_value("sound", "soundpack", self.config["sound"]["current_soundpack"])
self.dialog.set_value("sound", "indicate_audio", self.config["sound"]["indicate_audio"])
self.dialog.set_value("sound", "indicate_img", self.config["sound"]["indicate_img"])
self.dialog.create_extras(OCRSpace.translatable_langs)
language_index = OCRSpace.OcrLangs.index(self.config["mysc"]["ocr_language"])
self.dialog.extras.ocr_lang.SetSelection(language_index)
self.dialog.realize()
self.dialog.set_title(_("Account settings for %s") % (self.user,))
self.response = self.dialog.get_response()
def edit_post_template(self, *args, **kwargs):
template = self.config["templates"]["post"]
control = EditTemplate(template=template, type="post")
result = control.run_dialog()
if result != "": # Template has been saved.
self.config["templates"]["post"] = result
self.config.write()
self.dialog.templates.post.SetLabel(_("Edit template for posts. Current template: {}").format(result))
def edit_conversation_template(self, *args, **kwargs):
template = self.config["templates"]["conversation"]
control = EditTemplate(template=template, type="conversation")
result = control.run_dialog()
if result != "": # Template has been saved.
self.config["templates"]["conversation"] = result
self.config.write()
self.dialog.templates.conversation.SetLabel(_("Edit template for conversations. Current template: {}").format(result))
def edit_person_template(self, *args, **kwargs):
template = self.config["templates"]["person"]
control = EditTemplate(template=template, type="person")
result = control.run_dialog()
if result != "": # Template has been saved.
self.config["templates"]["person"] = result
self.config.write()
self.dialog.templates.person.SetLabel(_("Edit template for persons. Current template: {}").format(result))
def save_configuration(self):
if self.config["general"]["relative_times"] != self.dialog.get_value("general", "relative_time"):
self.needs_restart = True
log.debug("Triggered app restart due to change in relative times.")
self.config["general"]["relative_times"] = self.dialog.get_value("general", "relative_time")
self.config["general"]["show_screen_names"] = self.dialog.get_value("general", "show_screen_names")
self.config["general"]["hide_emojis"] = self.dialog.get_value("general", "hide_emojis")
self.config["general"]["max_posts_per_call"] = self.dialog.get_value("general", "itemsPerApiCall")
if self.config["general"]["load_cache_in_memory"] != self.dialog.get_value("general", "load_cache_in_memory"):
self.config["general"]["load_cache_in_memory"] = self.dialog.get_value("general", "load_cache_in_memory")
self.needs_restart = True
log.debug("Triggered app restart due to change in database strategy management.")
if self.config["general"]["persist_size"] != self.dialog.get_value("general", "persist_size"):
if self.dialog.get_value("general", "persist_size") == '':
self.config["general"]["persist_size"] =-1
else:
try:
self.config["general"]["persist_size"] = int(self.dialog.get_value("general", "persist_size"))
except ValueError:
output.speak("Invalid cache size, setting to default.",True)
self.config["general"]["persist_size"] =1764
if self.config["general"]["reverse_timelines"] != self.dialog.get_value("general", "reverse_timelines"):
self.needs_restart = True
log.debug("Triggered app restart due to change in timeline order.")
self.config["general"]["reverse_timelines"] = self.dialog.get_value("general", "reverse_timelines")
ask_before_boost = self.dialog.get_value("general", "ask_before_boost")
if ask_before_boost == True:
self.config["general"]["boost_mode"] = "ask"
else:
self.config["general"]["boost_mode"] = "direct"
buffers_list = self.dialog.buffers.get_list()
if buffers_list != self.config["general"]["buffer_order"]:
self.needs_restart = True
log.debug("Triggered app restart due to change in buffer ordering.")
self.config["general"]["buffer_order"] = buffers_list
self.config["reporting"]["speech_reporting"] = self.dialog.get_value("reporting", "speech_reporting")
self.config["reporting"]["braille_reporting"] = self.dialog.get_value("reporting", "braille_reporting")
self.config["mysc"]["ocr_language"] = OCRSpace.OcrLangs[self.dialog.extras.ocr_lang.GetSelection()]
if self.config["sound"]["input_device"] != self.dialog.sound.get("input"):
self.config["sound"]["input_device"] = self.dialog.sound.get("input")
try:
self.buffer.session.sound.input.set_device(self.buffer.session.sound.input.find_device_by_name(self.config["sound"]["input_device"]))
except:
self.config["sound"]["input_device"] = "default"
if self.config["sound"]["output_device"] != self.dialog.sound.get("output"):
self.config["sound"]["output_device"] = self.dialog.sound.get("output")
try:
self.buffer.session.sound.output.set_device(self.buffer.session.sound.output.find_device_by_name(self.config["sound"]["output_device"]))
except:
self.config["sound"]["output_device"] = "default"
self.config["sound"]["volume"] = self.dialog.get_value("sound", "volumeCtrl")/100.0
self.config["sound"]["session_mute"] = self.dialog.get_value("sound", "session_mute")
self.config["sound"]["current_soundpack"] = self.dialog.sound.get("soundpack")
self.config["sound"]["indicate_audio"] = self.dialog.get_value("sound", "indicate_audio")
self.config["sound"]["indicate_img"] = self.dialog.get_value("sound", "indicate_img")
self.buffer.session.sound.config = self.config["sound"]
self.buffer.session.sound.check_soundpack()
self.config.write()
def toggle_state(self,*args,**kwargs):
return self.dialog.buffers.change_selected_item()
def on_autocompletion_scan(self, *args, **kwargs):
configuration = scan.autocompletionScan(self.buffer.session.settings, self.buffer, self.window)
to_scan = configuration.show_dialog()
if to_scan == True:
configuration.prepare_progress_dialog()
t = threading.Thread(target=configuration.scan)
t.start()
def on_autocompletion_manage(self, *args, **kwargs):
configuration = manage.autocompletionManage(self.buffer.session)
configuration.show_settings()
def get_buffers_list(self):
all_buffers=OrderedDict()
all_buffers['home']=_("Home")
all_buffers['local'] = _("Local")
all_buffers['federated'] = _("Federated")
all_buffers['mentions']=_("Mentions")
all_buffers['direct_messages']=_("Direct Messages")
all_buffers['sent']=_("Sent")
all_buffers['favorites']=_("Favorites")
all_buffers['bookmarks']=_("Bookmarks")
all_buffers['followers']=_("Followers")
all_buffers['following']=_("Following")
all_buffers['blocked']=_("Blocked users")
all_buffers['muted']=_("Muted users")
all_buffers['notifications']=_("Notifications")
list_buffers = []
hidden_buffers=[]
all_buffers_keys = list(all_buffers.keys())
# Check buffers shown first.
for i in self.config["general"]["buffer_order"]:
if i in all_buffers_keys:
list_buffers.append((i, all_buffers[i], True))
# This second pass will retrieve all hidden buffers.
for i in all_buffers_keys:
if i not in self.config["general"]["buffer_order"]:
hidden_buffers.append((i, all_buffers[i], False))
list_buffers.extend(hidden_buffers)
return list_buffers
def toggle_buffer_active(self, ev):
change = self.dialog.buffers.get_event(ev)
if change == True:
self.dialog.buffers.change_selected_item()

View File

@ -0,0 +1,186 @@
# -*- 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 account and add followers and following users to the user autocompletion database"))
self.userAutocompletionScan.Enable(False)
self.userAutocompletionManage = wx.Button(self, wx.ID_ANY, _("Manage autocompletion database"))
self.userAutocompletionManage.Enable(False)
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.relative_time = wx.CheckBox(self, wx.ID_ANY, _("Relative timestamps"))
sizer.Add(self.relative_time, 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, _("Inverted 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, _("Show 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 emojis 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 conversations. Current template: {}").format(conversation_template))
sizer.Add(self.conversation, 0, wx.ALL, 5)
self.person = wx.Button(self, wx.ID_ANY, _("Edit template for persons. 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"Session 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 images 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)