Merge pull request #486 from MCV-Software/autocomplete_redesign

Changes in user autocompletion feature. Closes #466. Closes #368
This commit is contained in:
Manuel Cortez 2022-08-03 11:56:13 -05:00 committed by GitHub
commit 1e686cffba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 408 additions and 120 deletions

View File

@ -2,6 +2,9 @@ TWBlue Changelog
## changes in this version ## changes in this version
* the user autocompletion feature has been completely rewritten to be easier to use, particularly for people with many followers/following users:
* In the account settings dialog, there's a button that opens up a new dialog that allows you to "scan" your account in order to add all users from your followers/following list. This process will read your data directly from Twitter and depending in the amount of people you have in your account it might take too many API calls. Please use it with caution. You can, for example, do the process separately for your followers/following people so it will be easier to handle, in case you have a massive amount of people. If TWBlue is unable to complete the scan, you will see an error and will be prompted to try again in 15 minutes, once your API calls have refreshed.
* It is possible to use the user autocompletion functionality in dialogs where you can select an user, for example when adding or removing someone from a list, or displaying lists for someone.
* Implemented a new setting, available in the account settings dialog, that allows to hide emojis in twitter usernames. * Implemented a new setting, available in the account settings dialog, that allows to hide emojis in twitter usernames.
* Fixed error when attempting to mention an user by using the "mention" button in any people buffer. Now tweets should be posted normally. * Fixed error when attempting to mention an user by using the "mention" button in any people buffer. Now tweets should be posted normally.
* Fixed error when loading other user lists. ([#465](https://github.com/MCV-Software/TWBlue/issues/465)) * Fixed error when loading other user lists. ([#465](https://github.com/MCV-Software/TWBlue/issues/465))

View File

@ -0,0 +1,2 @@
# -*- coding: utf-8 -*-
from .base import BaseBuffer

View File

@ -0,0 +1,141 @@
# -*- coding: utf-8 -*-
""" Common logic to all buffers in TWBlue."""
import logging
import wx
import output
import sound
import widgetUtils
log = logging.getLogger("controller.buffers.base.base")
class Buffer(object):
""" A basic buffer object. This should be the base class for all other derived buffers."""
def __init__(self, parent=None, function=None, session=None, *args, **kwargs):
"""Inits the main controller for this buffer:
@ parent wx.Treebook object: Container where we will put this buffer.
@ function str or None: function to be called periodically and update items on this buffer.
@ session sessionmanager.session object or None: Session handler for settings, database and data access.
"""
super(Buffer, self).__init__()
self.function = function
# Compose_function will be used to render an object on this buffer. Normally, signature is as follows:
# compose_function(item, db, relative_times, show_screen_names=False, session=None)
# Read more about compose functions in sessions/twitter/compose.py.
self.compose_function = None
self.args = args
self.kwargs = kwargs
# This will be used as a reference to the wx.Panel object wich stores the buffer GUI.
self.buffer = None
# This should countains the account associated to this buffer.
self.account = ""
# This controls whether the start_stream function should be called when starting the program.
self.needs_init = True
# if this is set to False, the buffer will be ignored on the invisible interface.
self.invisible = False
# Control variable, used to track time of execution for calls to start_stream.
self.execution_time = 0
def clear_list(self):
pass
def get_event(self, ev):
""" Catch key presses in the WX interface and generate the corresponding event names."""
if ev.GetKeyCode() == wx.WXK_RETURN and ev.ControlDown(): event = "audio"
elif ev.GetKeyCode() == wx.WXK_RETURN: event = "url"
elif ev.GetKeyCode() == wx.WXK_F5: event = "volume_down"
elif ev.GetKeyCode() == wx.WXK_F6: event = "volume_up"
elif ev.GetKeyCode() == wx.WXK_DELETE and ev.ShiftDown(): event = "clear_list"
elif ev.GetKeyCode() == wx.WXK_DELETE: event = "destroy_status"
# Raise a Special event when pressed Shift+F10 because Wx==4.1.x does not seems to trigger this by itself.
# See https://github.com/manuelcortez/TWBlue/issues/353
elif ev.GetKeyCode() == wx.WXK_F10 and ev.ShiftDown(): event = "show_menu"
else:
event = None
ev.Skip()
if event != None:
try:
### ToDo: Remove after WX fixes issue #353 in the widgets.
if event == "show_menu":
return self.show_menu(widgetUtils.MENU, pos=self.buffer.list.list.GetPosition())
getattr(self, event)()
except AttributeError:
pass
def volume_down(self):
""" Decreases volume by 5%"""
if self.session.settings["sound"]["volume"] > 0.0:
if self.session.settings["sound"]["volume"] <= 0.05:
self.session.settings["sound"]["volume"] = 0.0
else:
self.session.settings["sound"]["volume"] -=0.05
sound.URLPlayer.player.audio_set_volume(int(self.session.settings["sound"]["volume"]*100.0))
self.session.sound.play("volume_changed.ogg")
self.session.settings.write()
def volume_up(self):
""" Increases volume by 5%."""
if self.session.settings["sound"]["volume"] < 1.0:
if self.session.settings["sound"]["volume"] >= 0.95:
self.session.settings["sound"]["volume"] = 1.0
else:
self.session.settings["sound"]["volume"] +=0.05
sound.URLPlayer.player.audio_set_volume(int(self.session.settings["sound"]["volume"]*100))
self.session.sound.play("volume_changed.ogg")
self.session.settings.write()
def start_stream(self, mandatory=False, play_sound=True):
pass
def get_more_items(self):
output.speak(_(u"This action is not supported for this buffer"), True)
def put_items_on_list(self, items):
pass
def remove_buffer(self):
return False
def remove_item(self, item):
f = self.buffer.list.get_selected()
self.buffer.list.remove_item(item)
self.buffer.list.select_item(f)
def bind_events(self):
pass
def get_object(self):
return self.buffer
def get_message(self):
pass
def set_list_position(self, reversed=False):
if reversed == False:
self.buffer.list.select_item(-1)
else:
self.buffer.list.select_item(0)
def reply(self):
pass
def send_message(self):
pass
def share_item(self):
pass
def can_share(self):
pass
def destroy_status(self):
pass
def post_status(self, *args, **kwargs):
pass
def save_positions(self):
try:
self.session.db[self.name+"_pos"]=self.buffer.list.get_selected()
except AttributeError:
pass

View File

@ -18,6 +18,7 @@ if system == "Windows":
from . import user from . import user
from . import listsController from . import listsController
from . import filterController from . import filterController
from . import userSelector
elif system == "Linux": elif system == "Linux":
from gtkUI import (view, commonMessageDialogs) from gtkUI import (view, commonMessageDialogs)
from sessions.twitter import utils, compose from sessions.twitter import utils, compose
@ -518,10 +519,9 @@ class Controller(object):
users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name]
else: else:
users = utils.get_all_users(tweet, buff.session) users = utils.get_all_users(tweet, buff.session)
dlg = dialogs.utils.selectUserDialog(_(u"Select the user"), users) selector = userSelector.userSelector(users=users, session_id=buff.session.session_id)
if dlg.get_response() == widgetUtils.OK: user = selector.get_user()
user = dlg.get_user() if user == None:
else:
return return
l = listsController.listsController(buff.session, user=user) l = listsController.listsController(buff.session, user=user)
@ -535,10 +535,9 @@ class Controller(object):
users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name]
else: else:
users = utils.get_all_users(tweet, buff.session) users = utils.get_all_users(tweet, buff.session)
dlg = dialogs.utils.selectUserDialog(_(u"Select the user"), users) selector = userSelector.userSelector(users=users, session_id=buff.session.session_id)
if dlg.get_response() == widgetUtils.OK: user = selector.get_user()
user = dlg.get_user() if user == None:
else:
return return
dlg = dialogs.lists.addUserListDialog() dlg = dialogs.lists.addUserListDialog()
dlg.populate_list([compose.compose_list(item) for item in buff.session.db["lists"]]) dlg.populate_list([compose.compose_list(item) for item in buff.session.db["lists"]])
@ -564,10 +563,9 @@ class Controller(object):
users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name]
else: else:
users = utils.get_all_users(tweet, buff.session) users = utils.get_all_users(tweet, buff.session)
dlg = dialogs.utils.selectUserDialog(_(u"Select the user"), users) selector = userSelector.userSelector(users=users, session_id=buff.session.session_id)
if dlg.get_response() == widgetUtils.OK: user = selector.get_user()
user = dlg.get_user() if user == None:
else:
return return
dlg = dialogs.lists.removeUserListDialog() dlg = dialogs.lists.removeUserListDialog()
dlg.populate_list([compose.compose_list(item) for item in buff.session.db["lists"]]) dlg.populate_list([compose.compose_list(item) for item in buff.session.db["lists"]])

View File

@ -11,8 +11,9 @@ from pubsub import pub
from twitter_text import parse_tweet from twitter_text import parse_tweet
from wxUI.dialogs import twitterDialogs, urlList from wxUI.dialogs import twitterDialogs, urlList
from wxUI import commonMessageDialogs from wxUI import commonMessageDialogs
from extra import translator, SpellChecker, autocompletionUsers from extra import translator, SpellChecker
from extra.AudioUploader import audioUploader from extra.AudioUploader import audioUploader
from extra.autocompletionUsers import completion
from sessions.twitter import utils from sessions.twitter import utils
class basicTweet(object): class basicTweet(object):
@ -160,7 +161,7 @@ class tweet(basicTweet):
self.text_processor() self.text_processor()
def autocomplete_users(self, *args, **kwargs): def autocomplete_users(self, *args, **kwargs):
c = autocompletionUsers.completion.autocompletionUsers(self.message, self.session.session_id) c = completion.autocompletionUsers(self.message, self.session.session_id)
c.show_menu() c.show_menu()
def add_tweet(self, event, update_gui=True, *args, **kwargs): def add_tweet(self, event, update_gui=True, *args, **kwargs):
@ -269,7 +270,7 @@ class dm(basicTweet):
self.text_processor() self.text_processor()
def autocomplete_users(self, *args, **kwargs): def autocomplete_users(self, *args, **kwargs):
c = autocompletionUsers.completion.autocompletionUsers(self.message, self.session.session_id) c = completion.autocompletionUsers(self.message, self.session.session_id)
c.show_menu("dm") c.show_menu("dm")
def text_processor(self, *args, **kwargs): def text_processor(self, *args, **kwargs):

View File

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import os import os
import webbrowser import webbrowser
import threading
import logging import logging
import sound_lib import sound_lib
import paths import paths
@ -16,7 +17,7 @@ from pubsub import pub
from mysc import autostart as autostart_windows from mysc import autostart as autostart_windows
from wxUI.dialogs import configuration from wxUI.dialogs import configuration
from wxUI import commonMessageDialogs from wxUI import commonMessageDialogs
from extra.autocompletionUsers import settings from extra.autocompletionUsers import scan, manage
from extra.ocr import OCRSpace from extra.ocr import OCRSpace
from .editTemplateController import EditTemplate from .editTemplateController import EditTemplate
@ -142,7 +143,8 @@ class accountSettingsController(globalSettingsController):
def create_config(self): def create_config(self):
self.dialog.create_general_account() self.dialog.create_general_account()
widgetUtils.connect_event(self.dialog.general.au, widgetUtils.BUTTON_PRESSED, self.manage_autocomplete) 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", "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", "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", "hide_emojis", self.config["general"]["hide_emojis"])
@ -304,8 +306,19 @@ class accountSettingsController(globalSettingsController):
def toggle_state(self,*args,**kwargs): def toggle_state(self,*args,**kwargs):
return self.dialog.buffers.change_selected_item() return self.dialog.buffers.change_selected_item()
def manage_autocomplete(self, *args, **kwargs): def on_autocompletion_scan(self, *args, **kwargs):
configuration = settings.autocompletionSettings(self.buffer.session.settings, self.buffer, self.window) 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 add_ignored_client(self, *args, **kwargs): def add_ignored_client(self, *args, **kwargs):
client = commonMessageDialogs.get_ignored_client() client = commonMessageDialogs.get_ignored_client()

View File

@ -4,7 +4,7 @@ import output
from wxUI.dialogs import userActions from wxUI.dialogs import userActions
from pubsub import pub from pubsub import pub
from tweepy.errors import TweepyException from tweepy.errors import TweepyException
from extra import autocompletionUsers from extra.autocompletionUsers import completion
class userActionsController(object): class userActionsController(object):
def __init__(self, buffer, users=[], default="follow"): def __init__(self, buffer, users=[], default="follow"):
@ -17,7 +17,7 @@ class userActionsController(object):
self.process_action() self.process_action()
def autocomplete_users(self, *args, **kwargs): def autocomplete_users(self, *args, **kwargs):
c = autocompletionUsers.completion.autocompletionUsers(self.dialog, self.session.session_id) c = completion.autocompletionUsers(self.dialog, self.session.session_id)
c.show_menu("dm") c.show_menu("dm")
def process_action(self): def process_action(self):

View File

@ -2,7 +2,6 @@
import widgetUtils import widgetUtils
from pubsub import pub from pubsub import pub
from wxUI.dialogs import userAliasDialogs from wxUI.dialogs import userAliasDialogs
from extra import autocompletionUsers
class userAliasController(object): class userAliasController(object):
def __init__(self, settings): def __init__(self, settings):

View File

@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
""" Small utility dessigned to select users from the currently focused item or the autocomplete database. """
import wx
import widgetUtils
from wxUI.dialogs import utils
from extra.autocompletionUsers import completion
class userSelector(object):
def __init__(self, users, session_id, title=_("Select user")):
""" Creates a dialog that chooses an user selector, from where users who have the autocomplete database already filled can also use that feature.
:param users: lists of users extracted from the currently focused item.
:type users: list
:param session_id: ID of the session to instantiate autocomplete database.
:type session_id: str
:param title: Title of the user selector dialog.
:type title: str
"""
self.session_id = session_id
self.dlg = utils.selectUserDialog(users=users, title=title)
widgetUtils.connect_event(self.dlg.autocompletion, widgetUtils.BUTTON_PRESSED, self.on_autocomplete_users)
def on_autocomplete_users(self, *args, **kwargs):
""" performs user autocompletion, if configured properly. """
c = completion.autocompletionUsers(self.dlg, self.session_id)
c.show_menu("dm")
def get_user(self):
""" Actually shows the dialog and returns an user if the dialog was accepted, None otherwise.
:rtype: str or None
"""
if self.dlg.ShowModal() == wx.ID_OK:
user = self.dlg.get_user()
else:
user = None
self.dlg.Destroy()
return user

View File

@ -1,4 +1,2 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# -*- coding: utf-8 -*- """ Autocompletion users for TWBlue. This package contains all needed code to support this feature, including automatic addition of users, management and code to show the autocompletion menu when an user is composing a tweet. """
""" Autocompletion users feature for TWBlue. This package contains all needed code to support this feature, including automatic addition of users, management and code to show the autocompletion menu when an user is composing a tweet. """
from . import completion, settings

View File

@ -8,7 +8,7 @@ class autocompletionUsers(object):
def __init__(self, window, session_id): def __init__(self, window, session_id):
""" Class constructor. Displays a menu with users matching the specified pattern for autocompletion. """ Class constructor. Displays a menu with users matching the specified pattern for autocompletion.
:param window: A wx control where the menu should be displayed. :param window: A wx control where the menu should be displayed. Normally this is going to be the wx.TextCtrl indicating the tweet's text or direct message recipient.
:type window: wx.Dialog :type window: wx.Dialog
:param session_id: Session ID which calls this class. We will load the users database from this session. :param session_id: Session ID which calls this class. We will load the users database from this session.
:type session_id: str. :type session_id: str.
@ -29,8 +29,8 @@ class autocompletionUsers(object):
:param mode: this controls how the dialog will behave. Possible values are 'tweet' and 'dm'. In tweet mode, the matching pattern will be @user (@ is required), while in 'dm' mode the matching pattern will be anything written in the text control. :param mode: this controls how the dialog will behave. Possible values are 'tweet' and 'dm'. In tweet mode, the matching pattern will be @user (@ is required), while in 'dm' mode the matching pattern will be anything written in the text control.
:type mode: str :type mode: str
""" """
position = self.window.text.GetInsertionPoint()
if mode == "tweet": if mode == "tweet":
position = self.window.text.GetInsertionPoint()
text = self.window.text.GetValue() text = self.window.text.GetValue()
text = text[:position] text = text[:position]
try: try:
@ -60,7 +60,7 @@ class autocompletionUsers(object):
users = self.db.get_users(pattern) users = self.db.get_users(pattern)
if len(users) > 0: if len(users) > 0:
menu.append_options(users) menu.append_options(users)
self.window.PopupMenu(menu, self.window.text.GetPosition()) self.window.PopupMenu(menu, self.window.cb.GetPosition())
menu.destroy() menu.destroy()
else: else:
output.speak(_(u"There are no results in your users database")) output.speak(_(u"There are no results in your users database"))

View File

@ -1,15 +1,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" Management of users in the local database for autocompletion. """
import time
import widgetUtils import widgetUtils
from tweepy.cursor import Cursor
from tweepy.errors import TweepyException from tweepy.errors import TweepyException
from . import storage, wx_manage
from wxUI import commonMessageDialogs from wxUI import commonMessageDialogs
from . import storage, wx_manage
class autocompletionManage(object): class autocompletionManage(object):
def __init__(self, session): def __init__(self, session):
""" class constructor. Manages everything related to user autocompletion.
:param session: Sessiom where the autocompletion management has been requested.
:type session: sessions.base.Session.
"""
super(autocompletionManage, self).__init__() super(autocompletionManage, self).__init__()
self.session = session self.session = session
self.dialog = wx_manage.autocompletionManageDialog() # Instantiate database so we can perform modifications on it.
self.database = storage.storage(self.session.session_id) self.database = storage.storage(self.session.session_id)
def show_settings(self):
""" display user management dialog and connect events associated to it. """
self.dialog = wx_manage.autocompletionManageDialog()
self.users = self.database.get_all_users() self.users = self.database.get_all_users()
self.dialog.put_users(self.users) self.dialog.put_users(self.users)
widgetUtils.connect_event(self.dialog.add, widgetUtils.BUTTON_PRESSED, self.add_user) widgetUtils.connect_event(self.dialog.add, widgetUtils.BUTTON_PRESSED, self.add_user)
@ -17,6 +29,7 @@ class autocompletionManage(object):
self.dialog.get_response() self.dialog.get_response()
def update_list(self): def update_list(self):
""" update users list in management dialog. This function is normallhy used after we modify the database in any way, so we can reload all users in the autocompletion user management list. """
item = self.dialog.users.get_selected() item = self.dialog.users.get_selected()
self.dialog.users.clear() self.dialog.users.clear()
self.users = self.database.get_all_users() self.users = self.database.get_all_users()
@ -24,9 +37,12 @@ class autocompletionManage(object):
self.dialog.users.select_item(item) self.dialog.users.select_item(item)
def add_user(self, *args, **kwargs): def add_user(self, *args, **kwargs):
""" Add a new Twitter username to the autocompletion database. """
usr = self.dialog.get_user() usr = self.dialog.get_user()
if usr == False: if usr == False:
return return
# check if user exists.
# ToDo: in case we want to adapt this for other networks we'd need to refactor this check.
try: try:
data = self.session.twitter.get_user(screen_name=usr) data = self.session.twitter.get_user(screen_name=usr)
except TweepyException as e: except TweepyException as e:
@ -36,7 +52,8 @@ class autocompletionManage(object):
self.database.set_user(data.screen_name, data.name, 0) self.database.set_user(data.screen_name, data.name, 0)
self.update_list() self.update_list()
def remove_user(self, ev): def remove_user(self, *args, **kwargs):
""" Remove focused user from the autocompletion database. """
if commonMessageDialogs.delete_user_from_db() == widgetUtils.YES: if commonMessageDialogs.delete_user_from_db() == widgetUtils.YES:
item = self.dialog.users.get_selected() item = self.dialog.users.get_selected()
user = self.users[item] user = self.users[item]

View File

@ -0,0 +1,110 @@
# -*- coding: utf-8 -*-
""" Scanning code for autocompletion feature on TWBlue. This module can retrieve user objects from the selected Twitter account automatically. """
import time
import wx
import widgetUtils
import output
from tweepy.cursor import Cursor
from tweepy.errors import TweepyException
from pubsub import pub
from . import wx_scan
from . import manage
from . import storage
class autocompletionScan(object):
def __init__(self, config, buffer, window):
""" Class constructor. This class will take care of scanning the selected Twitter account to populate the database with users automatically upon request.
:param config: Config for the session that will be scanned in search for users.
:type config: dict
:param buffer: home buffer for the focused session.
:type buffer: controller.buffers.twitter.base.baseBuffer
:param window: Main Window of TWBlue.
:type window:wx.Frame
"""
super(autocompletionScan, self).__init__()
self.config = config
self.buffer = buffer
self.window = window
def show_dialog(self):
self.dialog = wx_scan.autocompletionScanDialog()
self.dialog.set("friends", self.config["mysc"]["save_friends_in_autocompletion_db"])
self.dialog.set("followers", self.config["mysc"]["save_followers_in_autocompletion_db"])
if self.dialog.get_response() == widgetUtils.OK:
confirmation = wx_scan.confirm()
return confirmation
def prepare_progress_dialog(self):
self.progress_dialog = wx_scan.autocompletionScanProgressDialog()
# connect method to update progress dialog
pub.subscribe(self.on_update_progress, "on-update-progress")
self.progress_dialog.Show()
def on_update_progress(self, percent):
if percent > 100:
percent = 100
wx.CallAfter(self.progress_dialog.update, percent)
def scan(self):
""" Attempts to add all users selected by current user to the autocomplete database. """
ids = []
self.config["mysc"]["save_friends_in_autocompletion_db"] = self.dialog.get("friends")
self.config["mysc"]["save_followers_in_autocompletion_db"] = self.dialog.get("followers")
output.speak(_("Updating database... You can close this window now. A message will tell you when the process finishes."))
database = storage.storage(self.buffer.session.session_id)
percent = 0
# Retrieve ids of all following users
if self.dialog.get("friends") == True:
for i in Cursor(self.buffer.session.twitter.get_friend_ids, count=5000).items():
if str(i) not in ids:
ids.append(str(i))
# same step, but for followers.
if self.dialog.get("followers") == True:
try:
for i in Cursor(self.buffer.session.twitter.get_follower_ids, count=5000).items():
if str(i) not in ids:
ids.append(str(i))
except TweepyException:
wx.CallAfter(wx_scan.show_error)
return self.done()
# As next step requires batches of 100s users, let's split our user Ids so we won't break the param rules.
split_users = [ids[i:i + 100] for i in range(0, len(ids), 100)]
# store returned users in this list.
users = []
for z in split_users:
if len(z) == 0:
continue
try:
results = self.buffer.session.twitter.lookup_users(user_id=z)
except TweepyException:
wx.CallAfter(wx_scan.show_error)
return self.done()
users.extend(results)
time.sleep(1)
percent = percent + (100/len(split_users))
pub.sendMessage("on-update-progress", percent=percent)
for user in users:
database.set_user(user.screen_name, user.name, 1)
wx.CallAfter(wx_scan.show_success, len(users))
self.done()
def done(self):
wx.CallAfter(self.progress_dialog.Destroy)
wx.CallAfter(self.dialog.Destroy)
pub.unsubscribe(self.on_update_progress, "on-update-progress")
def execute_at_startup(window, buffer, config):
database = storage.storage(buffer.session.session_id)
if config["mysc"]["save_followers_in_autocompletion_db"] == True and config["other_buffers"]["show_followers"] == True:
buffer = window.search_buffer("followers", config["twitter"]["user_name"])
for i in buffer.session.db[buffer.name]:
database.set_user(i.screen_name, i.name, 1)
else:
database.remove_by_buffer(1)
if config["mysc"]["save_friends_in_autocompletion_db"] == True and config["other_buffers"]["show_friends"] == True:
buffer = window.search_buffer("friends", config["twitter"]["user_name"])
for i in buffer.session.db[buffer.name]:
database.set_user(i.screen_name, i.name, 2)
else:
database.remove_by_buffer(2)

View File

@ -1,59 +0,0 @@
# -*- coding: utf-8 -*-
import widgetUtils
import output
from . import wx_settings
from . import manage
from . import storage
from mysc.thread_utils import call_threaded
class autocompletionSettings(object):
def __init__(self, config, buffer, window):
super(autocompletionSettings, self).__init__()
self.config = config
self.buffer = buffer
self.window = window
self.dialog = wx_settings.autocompletionSettingsDialog()
self.dialog.set("friends_buffer", self.config["mysc"]["save_friends_in_autocompletion_db"])
self.dialog.set("followers_buffer", self.config["mysc"]["save_followers_in_autocompletion_db"])
widgetUtils.connect_event(self.dialog.viewList, widgetUtils.BUTTON_PRESSED, self.view_list)
if self.dialog.get_response() == widgetUtils.OK:
call_threaded(self.add_users_to_database)
def add_users_to_database(self):
self.config["mysc"]["save_friends_in_autocompletion_db"] = self.dialog.get("friends_buffer")
self.config["mysc"]["save_followers_in_autocompletion_db"] = self.dialog.get("followers_buffer")
output.speak(_(u"Updating database... You can close this window now. A message will tell you when the process finishes."))
database = storage.storage(self.buffer.session.session_id)
if self.dialog.get("followers_buffer") == True:
buffer = self.window.search_buffer("followers", self.config["twitter"]["user_name"])
for i in buffer.session.db[buffer.name]:
database.set_user(i.screen_name, i.name, 1)
else:
database.remove_by_buffer(1)
if self.dialog.get("friends_buffer") == True:
buffer = self.window.search_buffer("friends", self.config["twitter"]["user_name"])
for i in buffer.session.db[buffer.name]:
database.set_user(i.screen_name, i.name, 2)
else:
database.remove_by_buffer(2)
wx_settings.show_success_dialog()
self.dialog.destroy()
def view_list(self, ev):
q = manage.autocompletionManage(self.buffer.session)
def execute_at_startup(window, buffer, config):
database = storage.storage(buffer.session.session_id)
if config["mysc"]["save_followers_in_autocompletion_db"] == True and config["other_buffers"]["show_followers"] == True:
buffer = window.search_buffer("followers", config["twitter"]["user_name"])
for i in buffer.session.db[buffer.name]:
database.set_user(i.screen_name, i.name, 1)
else:
database.remove_by_buffer(1)
if config["mysc"]["save_friends_in_autocompletion_db"] == True and config["other_buffers"]["show_friends"] == True:
buffer = window.search_buffer("friends", config["twitter"]["user_name"])
for i in buffer.session.db[buffer.name]:
database.set_user(i.screen_name, i.name, 2)
else:
database.remove_by_buffer(2)

View File

@ -11,7 +11,7 @@ class menu(wx.Menu):
def append_options(self, options): def append_options(self, options):
for i in options: for i in options:
item = wx.MenuItem(self, wx.ID_ANY, "%s (@%s)" % (i[1], i[0])) item = wx.MenuItem(self, wx.ID_ANY, "%s (@%s)" % (i[1], i[0]))
self.AppendItem(item) self.Append(item)
self.Bind(wx.EVT_MENU, lambda evt, temp=i[0]: self.select_text(evt, temp), item) self.Bind(wx.EVT_MENU, lambda evt, temp=i[0]: self.select_text(evt, temp), item)
def select_text(self, ev, text): def select_text(self, ev, text):

View File

@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
import wx
import widgetUtils
import application
class autocompletionScanDialog(widgetUtils.BaseDialog):
def __init__(self):
super(autocompletionScanDialog, self).__init__(parent=None, id=-1, title=_(u"Autocomplete users' settings"))
panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
self.followers = wx.CheckBox(panel, -1, _("Add followers to database"))
self.friends = wx.CheckBox(panel, -1, _("Add friends to database"))
sizer.Add(self.followers, 0, wx.ALL, 5)
sizer.Add(self.friends, 0, wx.ALL, 5)
ok = wx.Button(panel, wx.ID_OK)
cancel = wx.Button(panel, wx.ID_CANCEL)
sizerBtn = wx.BoxSizer(wx.HORIZONTAL)
sizerBtn.Add(ok, 0, wx.ALL, 5)
sizer.Add(cancel, 0, wx.ALL, 5)
sizer.Add(sizerBtn, 0, wx.ALL, 5)
panel.SetSizer(sizer)
self.SetClientSize(sizer.CalcMin())
class autocompletionScanProgressDialog(widgetUtils.BaseDialog):
def __init__(self, *args, **kwargs):
super(autocompletionScanProgressDialog, self).__init__(parent=None, id=wx.ID_ANY, title=_("Updating autocompletion database"), *args, **kwargs)
panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
self.progress_bar = wx.Gauge(parent=panel)
sizer.Add(self.progress_bar)
panel.SetSizerAndFit(sizer)
def update(self, percent):
self.progress_bar.SetValue(percent)
def confirm():
with wx.MessageDialog(None, _("This process will retrieve the users you selected from Twitter, and add them to the user autocomplete database. Please note that if there are many users or you have tried to perform this action less than 15 minutes ago, TWBlue may reach a limit in Twitter API calls when trying to load the users into the database. If this happens, we will show you an error, in which case you will have to try this process again in a few minutes. If this process ends with no error, you will be redirected back to the account settings dialog. Do you want to continue?"), _("Attention"), style=wx.ICON_QUESTION|wx.YES_NO) as result:
if result.ShowModal() == wx.ID_YES:
return True
return False
def show_success(users):
with wx.MessageDialog(None, _("TWBlue has imported {} users successfully.").format(users), _("Done")) as dlg:
dlg.ShowModal()
def show_error():
with wx.MessageDialog(None, _("Error adding users from Twitter. Please try again in about 15 minutes."), _("Error"), style=wx.ICON_ERROR) as dlg:
dlg.ShowModal()

View File

@ -1,27 +0,0 @@
# -*- coding: utf-8 -*-
import wx
import widgetUtils
import application
class autocompletionSettingsDialog(widgetUtils.BaseDialog):
def __init__(self):
super(autocompletionSettingsDialog, self).__init__(parent=None, id=-1, title=_(u"Autocomplete users' settings"))
panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
self.followers_buffer = wx.CheckBox(panel, -1, _(u"Add users from followers buffer"))
self.friends_buffer = wx.CheckBox(panel, -1, _(u"Add users from friends buffer"))
sizer.Add(self.followers_buffer, 0, wx.ALL, 5)
sizer.Add(self.friends_buffer, 0, wx.ALL, 5)
self.viewList = wx.Button(panel, -1, _(u"Manage database..."))
sizer.Add(self.viewList, 0, wx.ALL, 5)
ok = wx.Button(panel, wx.ID_OK)
cancel = wx.Button(panel, wx.ID_CANCEL)
sizerBtn = wx.BoxSizer(wx.HORIZONTAL)
sizerBtn.Add(ok, 0, wx.ALL, 5)
sizer.Add(cancel, 0, wx.ALL, 5)
sizer.Add(sizerBtn, 0, wx.ALL, 5)
panel.SetSizer(sizer)
self.SetClientSize(sizer.CalcMin())
def show_success_dialog():
wx.MessageDialog(None, _(u"{0}'s database of users has been updated.").format(application.name,), _(u"Done"), wx.OK).ShowModal()

View File

@ -99,8 +99,13 @@ class generalAccount(wx.Panel, baseDialog.BaseWXDialog):
def __init__(self, parent): def __init__(self, parent):
super(generalAccount, self).__init__(parent) super(generalAccount, self).__init__(parent)
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
self.au = wx.Button(self, wx.ID_ANY, _(u"Autocompletion settings...")) userAutocompletionBox = wx.StaticBox(self, label=_("User autocompletion settings"))
sizer.Add(self.au, 0, wx.ALL, 5) self.userAutocompletionScan = wx.Button(self, wx.ID_ANY, _("Scan account and add friends and followers 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.relative_time = wx.CheckBox(self, wx.ID_ANY, _(U"Relative timestamps")) self.relative_time = wx.CheckBox(self, wx.ID_ANY, _(U"Relative timestamps"))
sizer.Add(self.relative_time, 0, wx.ALL, 5) sizer.Add(self.relative_time, 0, wx.ALL, 5)
tweetsPerCallBox = wx.BoxSizer(wx.HORIZONTAL) tweetsPerCallBox = wx.BoxSizer(wx.HORIZONTAL)