changed indentation from tabs to spaces

This commit is contained in:
Manuel Cortez 2021-09-22 09:17:12 -05:00
parent 5c02a67ac7
commit 4bdba42eab
129 changed files with 9224 additions and 9230 deletions

View File

@ -8,24 +8,24 @@ log = logging.getLogger("authenticator.official")
class AuthenticationError(Exception): pass class AuthenticationError(Exception): pass
def login(user, password): def login(user, password):
""" Generates authentication workflow at VK servers. """ """ Generates authentication workflow at VK servers. """
log.info("Authenticating user account.") log.info("Authenticating user account.")
access_token = None access_token = None
try: try:
params = CommonParams(supported_clients.VK_OFFICIAL.user_agent) params = CommonParams(supported_clients.VK_OFFICIAL.user_agent)
receiver = TokenReceiverOfficial(user, password, params, "GET_CODE") receiver = TokenReceiverOfficial(user, password, params, "GET_CODE")
access_token = receiver.get_token()["access_token"] access_token = receiver.get_token()["access_token"]
log.debug("got a valid access token for {}".format(user)) log.debug("got a valid access token for {}".format(user))
except TokenException as err: except TokenException as err:
if err.code == TokenException.TWOFA_REQ and 'validation_sid' in err.extra: if err.code == TokenException.TWOFA_REQ and 'validation_sid' in err.extra:
log.debug("User requires two factor verification. Calling methods to send an SMS...") log.debug("User requires two factor verification. Calling methods to send an SMS...")
try: try:
TwoFAHelper(params).validate_phone(err.extra['validation_sid']) TwoFAHelper(params).validate_phone(err.extra['validation_sid'])
except TokenException as err: except TokenException as err:
if err.code == TokenException.TWOFA_ERR: if err.code == TokenException.TWOFA_ERR:
wxUI.two_auth_limit() wxUI.two_auth_limit()
raise AuthenticationError("Error authentication two factor auth.") raise AuthenticationError("Error authentication two factor auth.")
code, remember = wxUI.two_factor_auth() code, remember = wxUI.two_factor_auth()
receiver = TokenReceiverOfficial(user, password, params, code) receiver = TokenReceiverOfficial(user, password, params, code)
access_token = receiver.get_token()["access_token"] access_token = receiver.get_token()["access_token"]
return access_token return access_token

View File

@ -5,16 +5,16 @@ import wx
import widgetUtils import widgetUtils
def two_factor_auth(): def two_factor_auth():
code = None code = None
dlg = wx.TextEntryDialog(None, _("Please provide the authentication code you have received from VK."), _("Two factor authentication code")) dlg = wx.TextEntryDialog(None, _("Please provide the authentication code you have received from VK."), _("Two factor authentication code"))
response = dlg.ShowModal() response = dlg.ShowModal()
if response == widgetUtils.OK: if response == widgetUtils.OK:
code = dlg.GetValue() code = dlg.GetValue()
dlg.Destroy() dlg.Destroy()
return (code, True) return (code, True)
def bad_password(): def bad_password():
return wx.MessageDialog(None, _("Your password or email address are incorrect. Please fix the mistakes and try it again."), _("Wrong data"), wx.ICON_ERROR).ShowModal() return wx.MessageDialog(None, _("Your password or email address are incorrect. Please fix the mistakes and try it again."), _("Wrong data"), wx.ICON_ERROR).ShowModal()
def two_auth_limit(): def two_auth_limit():
return wx.MessageDialog(None, _("It seems you have reached the limits to request authorization via SMS. Please try it again in a couple of hours."), _("Error requiring sms verification"), wx.ICON_ERROR).ShowModal() return wx.MessageDialog(None, _("It seems you have reached the limits to request authorization via SMS. Please try it again in a couple of hours."), _("Error requiring sms verification"), wx.ICON_ERROR).ShowModal()

View File

@ -11,7 +11,6 @@ MAINSPEC = "app-configuration.defaults"
app = None app = None
def setup (): def setup ():
global app global app
log.debug("Loading global app settings...") log.debug("Loading global app settings...")
app = config_utils.load_config(os.path.join(paths.config_path(), MAINFILE), os.path.join(paths.app_path(), MAINSPEC)) app = config_utils.load_config(os.path.join(paths.config_path(), MAINFILE), os.path.join(paths.app_path(), MAINSPEC))

View File

@ -6,68 +6,68 @@ import string
class ConfigLoadError(Exception): pass class ConfigLoadError(Exception): pass
def load_config(config_path, configspec_path=None, *args, **kwargs): def load_config(config_path, configspec_path=None, *args, **kwargs):
if os.path.exists(config_path): if os.path.exists(config_path):
clean_config(config_path) clean_config(config_path)
spec = ConfigObj(configspec_path, encoding='UTF8', list_values=False, _inspec=True) spec = ConfigObj(configspec_path, encoding='UTF8', list_values=False, _inspec=True)
try: try:
config = ConfigObj(infile=config_path, configspec=spec, create_empty=True, encoding='UTF8', *args, **kwargs) config = ConfigObj(infile=config_path, configspec=spec, create_empty=True, encoding='UTF8', *args, **kwargs)
except ParseError: except ParseError:
raise ConfigLoadError("Unable to load %r" % config_path) raise ConfigLoadError("Unable to load %r" % config_path)
validator = Validator() validator = Validator()
validated = config.validate(validator, copy=True) validated = config.validate(validator, copy=True)
if validated == True: if validated == True:
config.write() config.write()
return config return config
def is_blank(arg): def is_blank(arg):
"Check if a line is blank." "Check if a line is blank."
for c in arg: for c in arg:
if c not in string.whitespace: if c not in string.whitespace:
return False return False
return True return True
def get_keys(path): def get_keys(path):
"Gets the keys of a configobj config file." "Gets the keys of a configobj config file."
res=[] res=[]
fin=open(path) fin=open(path)
for line in fin: for line in fin:
if not is_blank(line): if not is_blank(line):
res.append(line[0:line.find('=')].strip()) res.append(line[0:line.find('=')].strip())
fin.close() fin.close()
return res return res
def hist(keys): def hist(keys):
"Generates a histogram of an iterable." "Generates a histogram of an iterable."
res={} res={}
for k in keys: for k in keys:
res[k]=res.setdefault(k,0)+1 res[k]=res.setdefault(k,0)+1
return res return res
def find_problems(hist): def find_problems(hist):
"Takes a histogram and returns a list of items occurring more than once." "Takes a histogram and returns a list of items occurring more than once."
res=[] res=[]
for k,v in list(hist.items()): for k,v in list(hist.items()):
if v>1: if v>1:
res.append(k) res.append(k)
return res return res
def clean_config(path): def clean_config(path):
"Cleans a config file. If duplicate values are found, delete all of them and just use the default." "Cleans a config file. If duplicate values are found, delete all of them and just use the default."
orig=[] orig=[]
cleaned=[] cleaned=[]
fin=open(path) fin=open(path)
for line in fin: for line in fin:
orig.append(line) orig.append(line)
fin.close() fin.close()
for p in find_problems(hist(get_keys(path))): for p in find_problems(hist(get_keys(path))):
for o in orig: for o in orig:
o.strip() o.strip()
if p not in o: if p not in o:
cleaned.append(o) cleaned.append(o)
if len(cleaned) != 0: if len(cleaned) != 0:
cam=open(path,'w') cam=open(path,'w')
for c in cleaned: for c in cleaned:
cam.write(c) cam.write(c)
cam.close() cam.close()
return True return True
else: else:
return False return False

View File

@ -21,289 +21,289 @@ from .wall import wallBuffer
log = logging.getLogger("controller.buffers.audio") log = logging.getLogger("controller.buffers.audio")
class audioBuffer(wallBuffer): class audioBuffer(wallBuffer):
def create_tab(self, parent): def create_tab(self, parent):
self.tab = audio.audioTab(parent) self.tab = audio.audioTab(parent)
self.tab.name = self.name self.tab.name = self.name
self.connect_events() self.connect_events()
if self.name == "me_audio": if self.name == "me_audio":
self.tab.post.Enable(True) self.tab.post.Enable(True)
def get_event(self, ev): def get_event(self, ev):
if ev.GetKeyCode() == wx.WXK_RETURN: if ev.GetKeyCode() == wx.WXK_RETURN:
if len(self.tab.list.get_multiple_selection()) < 2: if len(self.tab.list.get_multiple_selection()) < 2:
event = "play_all" event = "play_all"
else: else:
event = "play_audio" event = "play_audio"
else: else:
event = None event = None
ev.Skip() ev.Skip()
if event != None: if event != None:
try: try:
getattr(self, event)(skip_pause=True) getattr(self, event)(skip_pause=True)
except AttributeError: except AttributeError:
pass pass
def connect_events(self): def connect_events(self):
widgetUtils.connect_event(self.tab.play, widgetUtils.BUTTON_PRESSED, self.play_audio) widgetUtils.connect_event(self.tab.play, widgetUtils.BUTTON_PRESSED, self.play_audio)
widgetUtils.connect_event(self.tab.play_all, widgetUtils.BUTTON_PRESSED, self.play_all) widgetUtils.connect_event(self.tab.play_all, widgetUtils.BUTTON_PRESSED, self.play_all)
pub.subscribe(self.change_label, "playback-changed") pub.subscribe(self.change_label, "playback-changed")
super(audioBuffer, self).connect_events() super(audioBuffer, self).connect_events()
def play_audio(self, *args, **kwargs): def play_audio(self, *args, **kwargs):
if player.player.check_is_playing() and not "skip_pause" in kwargs: if player.player.check_is_playing() and not "skip_pause" in kwargs:
return pub.sendMessage("pause") return pub.sendMessage("pause")
selected = self.tab.list.get_multiple_selection() selected = self.tab.list.get_multiple_selection()
if len(selected) == 0: if len(selected) == 0:
return return
elif len(selected) == 1: elif len(selected) == 1:
pub.sendMessage("play", object=self.session.db[self.name]["items"][selected[0]]) pub.sendMessage("play", object=self.session.db[self.name]["items"][selected[0]])
else: else:
selected_audios = [self.session.db[self.name]["items"][item] for item in selected] selected_audios = [self.session.db[self.name]["items"][item] for item in selected]
pub.sendMessage("play-all", list_of_songs=selected_audios) pub.sendMessage("play-all", list_of_songs=selected_audios)
return True return True
def play_next(self, *args, **kwargs): def play_next(self, *args, **kwargs):
selected = self.tab.list.get_selected() selected = self.tab.list.get_selected()
if selected < 0: if selected < 0:
selected = 0 selected = 0
if self.tab.list.get_count() <= selected+1: if self.tab.list.get_count() <= selected+1:
newpos = 0 newpos = 0
else: else:
newpos = selected+1 newpos = selected+1
self.tab.list.select_item(newpos) self.tab.list.select_item(newpos)
self.play_audio() self.play_audio()
def play_previous(self, *args, **kwargs): def play_previous(self, *args, **kwargs):
selected = self.tab.list.get_selected() selected = self.tab.list.get_selected()
if selected <= 0: if selected <= 0:
selected = self.tab.list.get_count() selected = self.tab.list.get_count()
newpos = selected-1 newpos = selected-1
self.tab.list.select_item(newpos) self.tab.list.select_item(newpos)
self.play_audio() self.play_audio()
def open_post(self, *args, **kwargs): def open_post(self, *args, **kwargs):
selected = self.tab.list.get_multiple_selection() selected = self.tab.list.get_multiple_selection()
if len(selected) < 1: if len(selected) < 1:
return return
audios = [self.session.db[self.name]["items"][audio] for audio in selected] audios = [self.session.db[self.name]["items"][audio] for audio in selected]
a = presenters.displayAudioPresenter(session=self.session, postObject=audios, interactor=interactors.displayAudioInteractor(), view=views.displayAudio()) a = presenters.displayAudioPresenter(session=self.session, postObject=audios, interactor=interactors.displayAudioInteractor(), view=views.displayAudio())
def play_all(self, *args, **kwargs): def play_all(self, *args, **kwargs):
selected = self.tab.list.get_selected() selected = self.tab.list.get_selected()
if selected == -1: if selected == -1:
selected = 0 selected = 0
if self.name not in self.session.db: if self.name not in self.session.db:
return return
audios = [i for i in self.session.db[self.name]["items"][selected:]] audios = [i for i in self.session.db[self.name]["items"][selected:]]
pub.sendMessage("play-all", list_of_songs=audios) pub.sendMessage("play-all", list_of_songs=audios)
return True return True
def remove_buffer(self, mandatory=False): def remove_buffer(self, mandatory=False):
if "me_audio" == self.name or "popular_audio" == self.name or "recommended_audio" == self.name: if "me_audio" == self.name or "popular_audio" == self.name or "recommended_audio" == self.name:
output.speak(_("This buffer can't be deleted")) output.speak(_("This buffer can't be deleted"))
return False return False
else: else:
if mandatory == False: if mandatory == False:
dlg = commonMessages.remove_buffer() dlg = commonMessages.remove_buffer()
else: else:
dlg = widgetUtils.YES dlg = widgetUtils.YES
if dlg == widgetUtils.YES: if dlg == widgetUtils.YES:
self.session.db.pop(self.name) self.session.db.pop(self.name)
return True return True
else: else:
return False return False
def get_more_items(self, *args, **kwargs): def get_more_items(self, *args, **kwargs):
# Translators: Some buffers can't use the get previous item feature due to API limitations. # Translators: Some buffers can't use the get previous item feature due to API limitations.
output.speak(_("This buffer doesn't support getting more items.")) output.speak(_("This buffer doesn't support getting more items."))
def onFocus(self, event, *args, **kwargs): def onFocus(self, event, *args, **kwargs):
event.Skip() event.Skip()
def add_to_library(self, *args, **kwargs): def add_to_library(self, *args, **kwargs):
call_threaded(self._add_to_library, *args, **kwargs) call_threaded(self._add_to_library, *args, **kwargs)
def _add_to_library(self, *args, **kwargs): def _add_to_library(self, *args, **kwargs):
selected = self.tab.list.get_multiple_selection() selected = self.tab.list.get_multiple_selection()
if len(selected) < 1: if len(selected) < 1:
return return
audios = [self.session.db[self.name]["items"][audio] for audio in selected] audios = [self.session.db[self.name]["items"][audio] for audio in selected]
errors_detected = 0 errors_detected = 0
for i in audios: for i in audios:
args = {} args = {}
args["audio_id"] = i["id"] args["audio_id"] = i["id"]
if "album_id" in i: if "album_id" in i:
args["album_id"] = i["album_id"] args["album_id"] = i["album_id"]
args["owner_id"] = i["owner_id"] args["owner_id"] = i["owner_id"]
try: try:
audio = self.session.vk.client.audio.add(**args) audio = self.session.vk.client.audio.add(**args)
except VkApiError: except VkApiError:
errors_detected = errors_detected + 1 errors_detected = errors_detected + 1
continue continue
if audio != None and int(audio) < 21: if audio != None and int(audio) < 21:
errors_detected = errors_detected + 1 errors_detected = errors_detected + 1
if errors_detected == 0: if errors_detected == 0:
if len(selected) == 1: if len(selected) == 1:
msg = _("Audio added to your library") msg = _("Audio added to your library")
elif len(selected) > 1 and len(selected) < 5: elif len(selected) > 1 and len(selected) < 5:
msg = _("{0} audios were added to your library.").format(len(selected),) msg = _("{0} audios were added to your library.").format(len(selected),)
else: else:
msg = _("{audios} audios were added to your library.").format(audios=len(selected),) msg = _("{audios} audios were added to your library.").format(audios=len(selected),)
output.speak(msg) output.speak(msg)
else: else:
output.speak(_("{0} errors occurred while attempting to add {1} audios to your library.").format(errors_detected, len(selected))) output.speak(_("{0} errors occurred while attempting to add {1} audios to your library.").format(errors_detected, len(selected)))
def remove_from_library(self, *args, **kwargs): def remove_from_library(self, *args, **kwargs):
call_threaded(self._remove_from_library, *args, **kwargs) call_threaded(self._remove_from_library, *args, **kwargs)
def _remove_from_library(self, *args, **kwargs): def _remove_from_library(self, *args, **kwargs):
selected = self.tab.list.get_multiple_selection() selected = self.tab.list.get_multiple_selection()
if len(selected) < 1: if len(selected) < 1:
return return
audios = [self.session.db[self.name]["items"][audio] for audio in selected] audios = [self.session.db[self.name]["items"][audio] for audio in selected]
errors_detected = 0 errors_detected = 0
audios_removed = 0 audios_removed = 0
for i in range(0, len(selected)): for i in range(0, len(selected)):
args = {} args = {}
args["audio_id"] = audios[i]["id"] args["audio_id"] = audios[i]["id"]
args["owner_id"] = self.session.user_id args["owner_id"] = self.session.user_id
result = self.session.vk.client.audio.delete(**args) result = self.session.vk.client.audio.delete(**args)
if int(result) != 1: if int(result) != 1:
errors_dtected = errors_detected + 1 errors_dtected = errors_detected + 1
else: else:
self.session.db[self.name]["items"].pop(selected[i]-audios_removed) self.session.db[self.name]["items"].pop(selected[i]-audios_removed)
self.tab.list.remove_item(selected[i]-audios_removed) self.tab.list.remove_item(selected[i]-audios_removed)
audios_removed = audios_removed + 1 audios_removed = audios_removed + 1
if errors_detected == 0: if errors_detected == 0:
if len(selected) == 1: if len(selected) == 1:
msg = _("Audio removed.") msg = _("Audio removed.")
elif len(selected) > 1 and len(selected) < 5: elif len(selected) > 1 and len(selected) < 5:
msg = _("{0} audios were removed.").format(len(selected),) msg = _("{0} audios were removed.").format(len(selected),)
else: else:
msg = _("{audios} audios were removed.").format(audios=len(selected),) msg = _("{audios} audios were removed.").format(audios=len(selected),)
output.speak(msg) output.speak(msg)
else: else:
output.speak(_("{0} errors occurred while attempting to remove {1} audios.").format(errors_detected, len(selected))) output.speak(_("{0} errors occurred while attempting to remove {1} audios.").format(errors_detected, len(selected)))
def move_to_album(self, *args, **kwargs): def move_to_album(self, *args, **kwargs):
if len(self.session.audio_albums) == 0: if len(self.session.audio_albums) == 0:
return commonMessages.no_audio_albums() return commonMessages.no_audio_albums()
album = selector.album(_("Select the album where you want to move this song"), self.session) album = selector.album(_("Select the album where you want to move this song"), self.session)
if album.item == None: if album.item == None:
return return
call_threaded(self._move_to_album, album.item, *args, **kwargs) call_threaded(self._move_to_album, album.item, *args, **kwargs)
def _move_to_album(self, album, *args, **kwargs): def _move_to_album(self, album, *args, **kwargs):
selected = self.tab.list.get_multiple_selection() selected = self.tab.list.get_multiple_selection()
if len(selected) < 1: if len(selected) < 1:
return return
audios = [self.session.db[self.name]["items"][audio] for audio in selected] audios = [self.session.db[self.name]["items"][audio] for audio in selected]
errors_detected = 0 errors_detected = 0
for i in audios: for i in audios:
id = i["id"] id = i["id"]
try: try:
response = self.session.vk.client.audio.add(playlist_id=album, audio_id=id, owner_id=i["owner_id"]) response = self.session.vk.client.audio.add(playlist_id=album, audio_id=id, owner_id=i["owner_id"])
except VkApiError: except VkApiError:
errors_detected = errors_detected + 1 errors_detected = errors_detected + 1
if errors_detected == 0: if errors_detected == 0:
if len(selected) == 1: if len(selected) == 1:
msg = _("Audio added to playlist.") msg = _("Audio added to playlist.")
elif len(selected) > 1 and len(selected) < 5: elif len(selected) > 1 and len(selected) < 5:
msg = _("{0} audios were added to playlist.").format(len(selected),) msg = _("{0} audios were added to playlist.").format(len(selected),)
else: else:
msg = _("{audios} audios were added to playlist.").format(audios=len(selected),) msg = _("{audios} audios were added to playlist.").format(audios=len(selected),)
output.speak(msg) output.speak(msg)
else: else:
output.speak(_("{0} errors occurred while attempting to add {1} audios to your playlist.").format(errors_detected, len(selected))) output.speak(_("{0} errors occurred while attempting to add {1} audios to your playlist.").format(errors_detected, len(selected)))
def get_menu(self): def get_menu(self):
p = self.get_post() p = self.get_post()
if p == None: if p == None:
return return
m = menus.audioMenu() m = menus.audioMenu()
widgetUtils.connect_event(m, widgetUtils.MENU, self.open_post, menuitem=m.open) widgetUtils.connect_event(m, widgetUtils.MENU, self.open_post, menuitem=m.open)
widgetUtils.connect_event(m, widgetUtils.MENU, self.play_audio, menuitem=m.play) widgetUtils.connect_event(m, widgetUtils.MENU, self.play_audio, menuitem=m.play)
widgetUtils.connect_event(m, widgetUtils.MENU, self.move_to_album, menuitem=m.move) widgetUtils.connect_event(m, widgetUtils.MENU, self.move_to_album, menuitem=m.move)
widgetUtils.connect_event(m, widgetUtils.MENU, self.download, menuitem=m.download) widgetUtils.connect_event(m, widgetUtils.MENU, self.download, menuitem=m.download)
widgetUtils.connect_event(m, widgetUtils.MENU, self.select_all, menuitem=m.select) widgetUtils.connect_event(m, widgetUtils.MENU, self.select_all, menuitem=m.select)
widgetUtils.connect_event(m, widgetUtils.MENU, self.deselect_all, menuitem=m.deselect) widgetUtils.connect_event(m, widgetUtils.MENU, self.deselect_all, menuitem=m.deselect)
# if owner_id is the current user, the audio is added to the user's audios. # if owner_id is the current user, the audio is added to the user's audios.
if p["owner_id"] == self.session.user_id: if p["owner_id"] == self.session.user_id:
m.library.SetItemLabel(_("&Remove")) m.library.SetItemLabel(_("&Remove"))
widgetUtils.connect_event(m, widgetUtils.MENU, self.remove_from_library, menuitem=m.library) widgetUtils.connect_event(m, widgetUtils.MENU, self.remove_from_library, menuitem=m.library)
else: else:
widgetUtils.connect_event(m, widgetUtils.MENU, self.add_to_library, menuitem=m.library) widgetUtils.connect_event(m, widgetUtils.MENU, self.add_to_library, menuitem=m.library)
return m return m
def post(self, *args, **kwargs): def post(self, *args, **kwargs):
""" Uploads an audio to the current user's library from the computer. """ """ Uploads an audio to the current user's library from the computer. """
file = self.tab.get_file_to_upload() file = self.tab.get_file_to_upload()
if file == None: if file == None:
return return
audio_tags = ID3(file) audio_tags = ID3(file)
if "TIT2" in audio_tags: if "TIT2" in audio_tags:
title = audio_tags["TIT2"].text[0] title = audio_tags["TIT2"].text[0]
else: else:
title = _("Untitled") title = _("Untitled")
if "TPE1" in audio_tags: if "TPE1" in audio_tags:
artist = audio_tags["TPE1"].text[0] artist = audio_tags["TPE1"].text[0]
else: else:
artist = _("Unknown artist") artist = _("Unknown artist")
uploader = upload.VkUpload(self.session.vk.session_object) uploader = upload.VkUpload(self.session.vk.session_object)
call_threaded(uploader.audio, file, title=title, artist=artist) call_threaded(uploader.audio, file, title=title, artist=artist)
def open_in_browser(self, *args, **kwargs): def open_in_browser(self, *args, **kwargs):
post = self.get_post() post = self.get_post()
if post == None: if post == None:
return return
url = "https://vk.com/audio{user_id}_{post_id}".format(user_id=post["owner_id"], post_id=post["id"]) url = "https://vk.com/audio{user_id}_{post_id}".format(user_id=post["owner_id"], post_id=post["id"])
webbrowser.open_new_tab(url) webbrowser.open_new_tab(url)
def change_label(self, stopped): def change_label(self, stopped):
if hasattr(self.tab, "play"): if hasattr(self.tab, "play"):
if stopped == False: if stopped == False:
self.tab.play.SetLabel(_("P&ause")) self.tab.play.SetLabel(_("P&ause"))
else: else:
self.tab.play.SetLabel(_("P&lay")) self.tab.play.SetLabel(_("P&lay"))
def __del__(self): def __del__(self):
pub.unsubscribe(self.change_label, "playback-changed") pub.unsubscribe(self.change_label, "playback-changed")
def download(self, *args, **kwargs): def download(self, *args, **kwargs):
selected = self.tab.list.get_multiple_selection() selected = self.tab.list.get_multiple_selection()
if len(selected) < 1: if len(selected) < 1:
return return
audios = [self.session.db[self.name]["items"][audio] for audio in selected] audios = [self.session.db[self.name]["items"][audio] for audio in selected]
if len(audios) == 0: if len(audios) == 0:
return return
elif len(audios) == 1: elif len(audios) == 1:
multiple = False multiple = False
filename = utils.safe_filename("{0} - {1}.mp3".format(audios[0]["title"], audios[0]["artist"])) filename = utils.safe_filename("{0} - {1}.mp3".format(audios[0]["title"], audios[0]["artist"]))
else: else:
multiple = True multiple = True
filename = "" # No default filename for multiple files. filename = "" # No default filename for multiple files.
path = self.tab.get_download_path(filename=filename, multiple=multiple) path = self.tab.get_download_path(filename=filename, multiple=multiple)
self.download_threaded(path, multiple, audios) self.download_threaded(path, multiple, audios)
def download_threaded(self, path, multiple, audios): def download_threaded(self, path, multiple, audios):
if multiple == False: if multiple == False:
url = audios[0]["url"] url = audios[0]["url"]
pub.sendMessage("download-file", url=url, filename=path) pub.sendMessage("download-file", url=url, filename=path)
return return
else: else:
downloads = [] downloads = []
for i in audios: for i in audios:
filename = utils.safe_filename("{0} - {1}.mp3".format(i["title"], i["artist"])) filename = utils.safe_filename("{0} - {1}.mp3".format(i["title"], i["artist"]))
filepath = os.path.join(path, filename) filepath = os.path.join(path, filename)
downloads.append((utils.transform_audio_url(i["url"]), filepath)) downloads.append((utils.transform_audio_url(i["url"]), filepath))
pub.sendMessage("download-files", downloads=downloads) pub.sendMessage("download-files", downloads=downloads)
def select_all(self, *args, **kwargs): def select_all(self, *args, **kwargs):
items = self.tab.list.list.GetItemCount() items = self.tab.list.list.GetItemCount()
for i in range(0, items): for i in range(0, items):
self.tab.list.list.SetItemImage(i, 1) self.tab.list.list.SetItemImage(i, 1)
def deselect_all(self, *args, **kwargs): def deselect_all(self, *args, **kwargs):
items = self.tab.list.list.GetItemCount() items = self.tab.list.list.GetItemCount()
for i in range(0, items): for i in range(0, items):
self.tab.list.list.SetItemImage(i, 0) self.tab.list.list.SetItemImage(i, 0)

View File

@ -9,26 +9,26 @@ from .audio import audioBuffer
log = logging.getLogger("controller.buffers.audioPlaylist") log = logging.getLogger("controller.buffers.audioPlaylist")
class audioAlbumBuffer(audioBuffer): class audioAlbumBuffer(audioBuffer):
""" this buffer was supposed to be used with audio albums """ this buffer was supposed to be used with audio albums
but is deprecated as VK removed its audio support for third party apps.""" but is deprecated as VK removed its audio support for third party apps."""
def create_tab(self, parent): def create_tab(self, parent):
self.tab = audioAlbum.audioAlbumTab(parent) self.tab = audioAlbum.audioAlbumTab(parent)
self.tab.play.Enable(False) self.tab.play.Enable(False)
self.tab.play_all.Enable(False) self.tab.play_all.Enable(False)
self.connect_events() self.connect_events()
self.tab.name = self.name self.tab.name = self.name
if hasattr(self, "can_post") and self.can_post == False and hasattr(self.tab, "post"): if hasattr(self, "can_post") and self.can_post == False and hasattr(self.tab, "post"):
self.tab.post.Enable(False) self.tab.post.Enable(False)
def connect_events(self): def connect_events(self):
super(audioAlbumBuffer, self).connect_events() super(audioAlbumBuffer, self).connect_events()
widgetUtils.connect_event(self.tab.load, widgetUtils.BUTTON_PRESSED, self.load_album) widgetUtils.connect_event(self.tab.load, widgetUtils.BUTTON_PRESSED, self.load_album)
def load_album(self, *args, **kwargs): def load_album(self, *args, **kwargs):
output.speak(_("Loading album...")) output.speak(_("Loading album..."))
self.can_get_items = True self.can_get_items = True
self.tab.load.Enable(False) self.tab.load.Enable(False)
wx.CallAfter(self.get_items) wx.CallAfter(self.get_items)
self.tab.play.Enable(True) self.tab.play.Enable(True)
self.tab.play_all.Enable(True) self.tab.play_all.Enable(True)

View File

@ -22,286 +22,286 @@ log = logging.getLogger("controller.buffers.chat")
class chatBuffer(homeBuffer): class chatBuffer(homeBuffer):
def insert(self, item, reversed=False): def insert(self, item, reversed=False):
""" Add a new item to the list. Uses session.composefunc for parsing the dictionary and create a valid result for putting it in the list.""" """ Add a new item to the list. Uses session.composefunc for parsing the dictionary and create a valid result for putting it in the list."""
# as this tab is based in a text control, we have to overwrite the defaults. # as this tab is based in a text control, we have to overwrite the defaults.
item_ = getattr(renderers, self.compose_function)(item, self.session) item_ = getattr(renderers, self.compose_function)(item, self.session)
# the self.chat dictionary will have (first_line, last_line) as keys and message ID as a value for looking into it when needed. # the self.chat dictionary will have (first_line, last_line) as keys and message ID as a value for looking into it when needed.
# Here we will get first and last line of a chat message appended to the history. # Here we will get first and last line of a chat message appended to the history.
values = self.tab.add_message(item_[0], reverse=reversed) values = self.tab.add_message(item_[0], reverse=reversed)
self.chats[values] = item["id"] self.chats[values] = item["id"]
def get_focused_post(self): def get_focused_post(self):
""" Gets chat message currently in focus""" """ Gets chat message currently in focus"""
# this function replaces self.get_post for this buffer, as we rely in a TextCtrl control for getting chats. # this function replaces self.get_post for this buffer, as we rely in a TextCtrl control for getting chats.
# Instead of the traditional method to do the trick. # Instead of the traditional method to do the trick.
# Get text position here. # Get text position here.
position = self.tab.history.PositionToXY(self.tab.history.GetInsertionPoint()) position = self.tab.history.PositionToXY(self.tab.history.GetInsertionPoint())
id_ = None id_ = None
# The dictionary keys should be looked in reverse order as we are interested in the last result only. # The dictionary keys should be looked in reverse order as we are interested in the last result only.
for i in reversed(list(self.chats.keys())): for i in reversed(list(self.chats.keys())):
# Check if position[2] (line position) matches with something in self.chats # Check if position[2] (line position) matches with something in self.chats
# (All messages, except the last one, should be able to be matched here). # (All messages, except the last one, should be able to be matched here).
# position[2]+1 is added because line may start with 0, while in wx.TextCtrl.GetNumberOfLines() it returns a value counting from 1. # position[2]+1 is added because line may start with 0, while in wx.TextCtrl.GetNumberOfLines() it returns a value counting from 1.
if position[2]+1 >= i[0]: if position[2]+1 >= i[0]:
id_ = self.chats[i] id_ = self.chats[i]
# If we find our chat message, let's skip the rest of the loop. # If we find our chat message, let's skip the rest of the loop.
break break
# Retrieve here the object based in id_ # Retrieve here the object based in id_
if id_ != None: if id_ != None:
for i in self.session.db[self.name]["items"]: for i in self.session.db[self.name]["items"]:
if i["id"] == id_: if i["id"] == id_:
return i return i
return False return False
get_post = get_focused_post get_post = get_focused_post
def onFocus(self, event, *args, **kwargs): def onFocus(self, event, *args, **kwargs):
if event.GetKeyCode() == wx.WXK_UP or event.GetKeyCode() == wx.WXK_DOWN or event.GetKeyCode() == wx.WXK_START or event.GetKeyCode() == wx.WXK_PAGEUP or event.GetKeyCode() == wx.WXK_PAGEDOWN or event.GetKeyCode() == wx.WXK_END: if event.GetKeyCode() == wx.WXK_UP or event.GetKeyCode() == wx.WXK_DOWN or event.GetKeyCode() == wx.WXK_START or event.GetKeyCode() == wx.WXK_PAGEUP or event.GetKeyCode() == wx.WXK_PAGEDOWN or event.GetKeyCode() == wx.WXK_END:
msg = self.get_focused_post() msg = self.get_focused_post()
if msg == False: # Handle the case where the last line of the control cannot be matched to anything. if msg == False: # Handle the case where the last line of the control cannot be matched to anything.
return return
# Mark unread conversations as read. # Mark unread conversations as read.
if "read_state" in msg and msg["read_state"] == 0 and "out" in msg and msg["out"] == 0: if "read_state" in msg and msg["read_state"] == 0 and "out" in msg and msg["out"] == 0:
self.session.soundplayer.play("message_unread.ogg") self.session.soundplayer.play("message_unread.ogg")
call_threaded(self.session.vk.client.messages.markAsRead, peer_id=self.kwargs["peer_id"]) call_threaded(self.session.vk.client.messages.markAsRead, peer_id=self.kwargs["peer_id"])
[i.update(read_state=1) for i in self.session.db[self.name]["items"]] [i.update(read_state=1) for i in self.session.db[self.name]["items"]]
if "attachments" in msg and len(msg["attachments"]) > 0: if "attachments" in msg and len(msg["attachments"]) > 0:
self.tab.attachments.list.Enable(True) self.tab.attachments.list.Enable(True)
self.attachments = list() self.attachments = list()
self.tab.attachments.clear() self.tab.attachments.clear()
self.parse_attachments(msg) self.parse_attachments(msg)
else: else:
self.tab.attachments.list.Enable(False) self.tab.attachments.list.Enable(False)
self.tab.attachments.clear() self.tab.attachments.clear()
event.Skip() event.Skip()
def create_tab(self, parent): def create_tab(self, parent):
self.tab = chat.chatTab(parent) self.tab = chat.chatTab(parent)
self.attachments = list() self.attachments = list()
self.connect_events() self.connect_events()
self.tab.name = self.name self.tab.name = self.name
if hasattr(self, "can_post") and self.can_post == False and hasattr(self.tab, "post"): if hasattr(self, "can_post") and self.can_post == False and hasattr(self.tab, "post"):
self.tab.post.Enable(False) self.tab.post.Enable(False)
def connect_events(self): def connect_events(self):
widgetUtils.connect_event(self.tab.send, widgetUtils.BUTTON_PRESSED, self.send_chat_to_user) widgetUtils.connect_event(self.tab.send, widgetUtils.BUTTON_PRESSED, self.send_chat_to_user)
widgetUtils.connect_event(self.tab.attachment, widgetUtils.BUTTON_PRESSED, self.add_attachment) widgetUtils.connect_event(self.tab.attachment, widgetUtils.BUTTON_PRESSED, self.add_attachment)
widgetUtils.connect_event(self.tab.text, widgetUtils.KEYPRESS, self.catch_enter) widgetUtils.connect_event(self.tab.text, widgetUtils.KEYPRESS, self.catch_enter)
widgetUtils.connect_event(self.tab.actions, widgetUtils.BUTTON_PRESSED, self.actions) widgetUtils.connect_event(self.tab.actions, widgetUtils.BUTTON_PRESSED, self.actions)
self.tab.set_focus_function(self.onFocus) self.tab.set_focus_function(self.onFocus)
def catch_enter(self, event, *args, **kwargs): def catch_enter(self, event, *args, **kwargs):
shift=event.ShiftDown() shift=event.ShiftDown()
if event.GetKeyCode() == wx.WXK_RETURN and shift == False: if event.GetKeyCode() == wx.WXK_RETURN and shift == False:
return self.send_chat_to_user() return self.send_chat_to_user()
t = time.time() t = time.time()
if event.GetUnicodeKey() != wx.WXK_NONE and t-self.last_keypress > 5: if event.GetUnicodeKey() != wx.WXK_NONE and t-self.last_keypress > 5:
self.last_keypress = t self.last_keypress = t
call_threaded(self.session.vk.client.messages.setActivity, peer_id=self.kwargs["peer_id"], type="typing") call_threaded(self.session.vk.client.messages.setActivity, peer_id=self.kwargs["peer_id"], type="typing")
event.Skip() event.Skip()
def get_items(self, show_nextpage=False): def get_items(self, show_nextpage=False):
""" Update buffer with newest items or get older items in the buffer.""" """ Update buffer with newest items or get older items in the buffer."""
if self.can_get_items == False: return if self.can_get_items == False: return
retrieved = True retrieved = True
try: try:
num = getattr(self.session, "get_page")(show_nextpage=show_nextpage, name=self.name, *self.args, **self.kwargs) num = getattr(self.session, "get_page")(show_nextpage=show_nextpage, name=self.name, *self.args, **self.kwargs)
except VkApiError as err: except VkApiError as err:
log.error("Error {0}: {1}".format(err.code, err.error)) log.error("Error {0}: {1}".format(err.code, err.error))
retrieved = err.code retrieved = err.code
return retrieved return retrieved
except: except:
log.exception("Connection error when updating buffer %s. Will try again in 2 minutes" % (self.name,)) log.exception("Connection error when updating buffer %s. Will try again in 2 minutes" % (self.name,))
return False return False
if not hasattr(self, "tab"): if not hasattr(self, "tab"):
# Create GUI associated to this buffer. # Create GUI associated to this buffer.
self.create_tab(self.parent) self.create_tab(self.parent)
# Add name to the new control so we could look for it when needed. # Add name to the new control so we could look for it when needed.
self.tab.name = self.name self.tab.name = self.name
if show_nextpage == False: if show_nextpage == False:
if self.tab.history.GetValue() != "" and num > 0: if self.tab.history.GetValue() != "" and num > 0:
v = [i for i in self.session.db[self.name]["items"][:num]] v = [i for i in self.session.db[self.name]["items"][:num]]
[self.insert(i, False) for i in v] [self.insert(i, False) for i in v]
else: else:
[self.insert(i) for i in self.session.db[self.name]["items"][:num]] [self.insert(i) for i in self.session.db[self.name]["items"][:num]]
else: else:
if num > 0: if num > 0:
# At this point we save more CPU and mathematical work if we just delete everything in the chat history and readd all messages. # At this point we save more CPU and mathematical work if we just delete everything in the chat history and readd all messages.
# Otherwise we'd have to insert new lines at the top and recalculate positions everywhere else. # Otherwise we'd have to insert new lines at the top and recalculate positions everywhere else.
# Firstly, we'd have to save the current focused object so we will place the user in the right part of the text after loading everything again. # Firstly, we'd have to save the current focused object so we will place the user in the right part of the text after loading everything again.
focused_post = self.get_post() focused_post = self.get_post()
self.chats = dict() self.chats = dict()
wx.CallAfter(self.tab.history.SetValue, "") wx.CallAfter(self.tab.history.SetValue, "")
v = [i for i in self.session.db[self.name]["items"]] v = [i for i in self.session.db[self.name]["items"]]
[self.insert(i) for i in v] [self.insert(i) for i in v]
# Now it's time to set back the focus in the post. # Now it's time to set back the focus in the post.
for i in self.chats.keys(): for i in self.chats.keys():
if self.chats[i] == focused_post["id"]: if self.chats[i] == focused_post["id"]:
line = i[0] line = i[0]
wx.CallAfter(self.tab.history.SetInsertionPoint, self.tab.history.XYToPosition(0, line)) wx.CallAfter(self.tab.history.SetInsertionPoint, self.tab.history.XYToPosition(0, line))
output.speak(_("Items loaded")) output.speak(_("Items loaded"))
break break
if self.unread == True and num > 0: if self.unread == True and num > 0:
self.session.db[self.name]["items"][-1].update(read_state=0) self.session.db[self.name]["items"][-1].update(read_state=0)
return retrieved return retrieved
def get_more_items(self): def get_more_items(self):
output.speak(_("Getting more items...")) output.speak(_("Getting more items..."))
call_threaded(self.get_items, show_nextpage=True) call_threaded(self.get_items, show_nextpage=True)
def add_attachment(self, *args, **kwargs): def add_attachment(self, *args, **kwargs):
a = presenters.attachPresenter(session=self.session, view=views.attachDialog(voice_messages=True), interactor=interactors.attachInteractor()) a = presenters.attachPresenter(session=self.session, view=views.attachDialog(voice_messages=True), interactor=interactors.attachInteractor())
if len(a.attachments) != 0: if len(a.attachments) != 0:
self.attachments_to_be_sent = a.attachments self.attachments_to_be_sent = a.attachments
def send_chat_to_user(self, *args, **kwargs): def send_chat_to_user(self, *args, **kwargs):
text = self.tab.text.GetValue() text = self.tab.text.GetValue()
if text == "" and not hasattr(self, "attachments_to_be_sent"): if text == "" and not hasattr(self, "attachments_to_be_sent"):
wx.Bell() wx.Bell()
return return
self.tab.text.SetValue("") self.tab.text.SetValue("")
post_arguments = dict(random_id = random.randint(0, 100000), peer_id=self.kwargs["peer_id"]) post_arguments = dict(random_id = random.randint(0, 100000), peer_id=self.kwargs["peer_id"])
if len(text) > 0: if len(text) > 0:
post_arguments.update(message=text) post_arguments.update(message=text)
if hasattr(self, "attachments_to_be_sent") and len(self.attachments_to_be_sent) > 0: if hasattr(self, "attachments_to_be_sent") and len(self.attachments_to_be_sent) > 0:
attachments = self.attachments_to_be_sent[::] attachments = self.attachments_to_be_sent[::]
else: else:
attachments = [] attachments = []
call_threaded(pub.sendMessage, "post", parent_endpoint="messages", child_endpoint="send", from_buffer=self.name, attachments_list=attachments, post_arguments=post_arguments) call_threaded(pub.sendMessage, "post", parent_endpoint="messages", child_endpoint="send", from_buffer=self.name, attachments_list=attachments, post_arguments=post_arguments)
if hasattr(self, "attachments_to_be_sent"): if hasattr(self, "attachments_to_be_sent"):
del self.attachments_to_be_sent del self.attachments_to_be_sent
def __init__(self, unread=False, *args, **kwargs): def __init__(self, unread=False, *args, **kwargs):
super(chatBuffer, self).__init__(*args, **kwargs) super(chatBuffer, self).__init__(*args, **kwargs)
self.unread = unread self.unread = unread
self.chats = dict() self.chats = dict()
self.peer_typing = 0 self.peer_typing = 0
self.last_keypress = time.time() self.last_keypress = time.time()
def parse_attachments(self, post): def parse_attachments(self, post):
attachments = [] attachments = []
if "attachments" in post: if "attachments" in post:
for i in post["attachments"]: for i in post["attachments"]:
# We don't need the photos_list attachment, so skip it. # We don't need the photos_list attachment, so skip it.
if i["type"] == "photos_list": if i["type"] == "photos_list":
continue continue
try: try:
rendered_object = renderers.add_attachment(i) rendered_object = renderers.add_attachment(i)
except: except:
log.exception("Error parsing the following attachment on chat: %r" % (i,)) log.exception("Error parsing the following attachment on chat: %r" % (i,))
attachments.append(rendered_object) attachments.append(rendered_object)
self.attachments.append(i) self.attachments.append(i)
self.tab.attachments.list.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.open_attachment) self.tab.attachments.list.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.open_attachment)
self.tab.insert_attachments(attachments) self.tab.insert_attachments(attachments)
def open_attachment(self, *args, **kwargs): def open_attachment(self, *args, **kwargs):
index = self.tab.attachments.get_selected() index = self.tab.attachments.get_selected()
attachment = self.attachments[index] attachment = self.attachments[index]
if attachment["type"] == "audio": if attachment["type"] == "audio":
a = presenters.displayAudioPresenter(session=self.session, postObject=[attachment["audio"]], interactor=interactors.displayAudioInteractor(), view=views.displayAudio()) a = presenters.displayAudioPresenter(session=self.session, postObject=[attachment["audio"]], interactor=interactors.displayAudioInteractor(), view=views.displayAudio())
elif attachment["type"] == "audio_message": elif attachment["type"] == "audio_message":
link = attachment["audio_message"]["link_mp3"] link = attachment["audio_message"]["link_mp3"]
pub.sendMessage("play-message", message_url=link) pub.sendMessage("play-message", message_url=link)
elif attachment["type"] == "link": elif attachment["type"] == "link":
output.speak(_("Opening URL..."), True) output.speak(_("Opening URL..."), True)
webbrowser.open_new_tab(attachment["link"]["url"]) webbrowser.open_new_tab(attachment["link"]["url"])
elif attachment["type"] == "doc": elif attachment["type"] == "doc":
output.speak(_("Opening document in web browser...")) output.speak(_("Opening document in web browser..."))
webbrowser.open(attachment["doc"]["url"]) webbrowser.open(attachment["doc"]["url"])
elif attachment["type"] == "video": elif attachment["type"] == "video":
# it seems VK doesn't like to attach video links as normal URLS, so we'll have to # it seems VK doesn't like to attach video links as normal URLS, so we'll have to
# get the full video object and use its "player" key which will open a webbrowser in their site with a player for the video. # get the full video object and use its "player" key which will open a webbrowser in their site with a player for the video.
# see https://vk.com/dev/attachments_w and and https://vk.com/dev/video.get # see https://vk.com/dev/attachments_w and and https://vk.com/dev/video.get
# However, the flash player isn't good for visually impaired people (when you press play you won't be able to close the window with alt+f4), so it could be good to use the HTML5 player. # However, the flash player isn't good for visually impaired people (when you press play you won't be able to close the window with alt+f4), so it could be good to use the HTML5 player.
# For firefox, see https://addons.mozilla.org/ru/firefox/addon/force-html5-video-player-at-vk/ # For firefox, see https://addons.mozilla.org/ru/firefox/addon/force-html5-video-player-at-vk/
# May be I could use a dialogue here for inviting people to use this addon in firefox. It seems it isn't possible to use this html5 player from the player URL. # May be I could use a dialogue here for inviting people to use this addon in firefox. It seems it isn't possible to use this html5 player from the player URL.
object_id = "{0}_{1}".format(attachment["video"]["owner_id"], attachment["video"]["id"]) object_id = "{0}_{1}".format(attachment["video"]["owner_id"], attachment["video"]["id"])
video_object = self.session.vk.client.video.get(owner_id=attachment["video"]["owner_id"], videos=object_id) video_object = self.session.vk.client.video.get(owner_id=attachment["video"]["owner_id"], videos=object_id)
video_object = video_object["items"][0] video_object = video_object["items"][0]
output.speak(_("Opening video in web browser..."), True) output.speak(_("Opening video in web browser..."), True)
webbrowser.open_new_tab(video_object["player"]) webbrowser.open_new_tab(video_object["player"])
elif attachment["type"] == "photo": elif attachment["type"] == "photo":
output.speak(_("Opening photo in web browser..."), True) output.speak(_("Opening photo in web browser..."), True)
# Possible photo sizes for looking in the attachment information. Try to use the biggest photo available. # Possible photo sizes for looking in the attachment information. Try to use the biggest photo available.
possible_sizes = [1280, 604, 130, 75] possible_sizes = [1280, 604, 130, 75]
url = "" url = ""
for i in possible_sizes: for i in possible_sizes:
if "photo_{0}".format(i,) in attachment["photo"]: if "photo_{0}".format(i,) in attachment["photo"]:
url = attachment["photo"]["photo_{0}".format(i,)] url = attachment["photo"]["photo_{0}".format(i,)]
break break
if url != "": if url != "":
webbrowser.open_new_tab(url) webbrowser.open_new_tab(url)
if attachment["type"] == "wall": if attachment["type"] == "wall":
pub.sendMessage("open-post", post_object=attachment["wall"], controller_="displayPost") pub.sendMessage("open-post", post_object=attachment["wall"], controller_="displayPost")
else: else:
log.debug("Unhandled attachment: %r" % (attachment,)) log.debug("Unhandled attachment: %r" % (attachment,))
def clear_reads(self): def clear_reads(self):
for i in self.session.db[self.name]["items"]: for i in self.session.db[self.name]["items"]:
if "read_state" in i and i["read_state"] == 0: if "read_state" in i and i["read_state"] == 0:
i["read_state"] = 1 i["read_state"] = 1
def remove_buffer(self, mandatory=False): def remove_buffer(self, mandatory=False):
""" Remove buffer if the current buffer is not the logged user's wall.""" """ Remove buffer if the current buffer is not the logged user's wall."""
if mandatory == False: if mandatory == False:
dlg = commonMessages.remove_buffer() dlg = commonMessages.remove_buffer()
else: else:
dlg = widgetUtils.YES dlg = widgetUtils.YES
if dlg == widgetUtils.YES: if dlg == widgetUtils.YES:
self.session.db.pop(self.name) self.session.db.pop(self.name)
return True return True
else: else:
return False return False
def open_in_browser(self, *args, **kwargs): def open_in_browser(self, *args, **kwargs):
peer_id = self.kwargs["peer_id"] peer_id = self.kwargs["peer_id"]
url = "https://vk.com/im?sel={peer_id}".format(peer_id=peer_id) url = "https://vk.com/im?sel={peer_id}".format(peer_id=peer_id)
webbrowser.open_new_tab(url) webbrowser.open_new_tab(url)
def actions(self, *args, **kwargs): def actions(self, *args, **kwargs):
menu = menus.toolsMenu() menu = menus.toolsMenu()
widgetUtils.connect_event(menu, widgetUtils.MENU, self.translate_action, menuitem=menu.translate) widgetUtils.connect_event(menu, widgetUtils.MENU, self.translate_action, menuitem=menu.translate)
widgetUtils.connect_event(menu, widgetUtils.MENU, self.spellcheck_action, menuitem=menu.spellcheck) widgetUtils.connect_event(menu, widgetUtils.MENU, self.spellcheck_action, menuitem=menu.spellcheck)
self.tab.PopupMenu(menu, self.tab.actions.GetPosition()) self.tab.PopupMenu(menu, self.tab.actions.GetPosition())
def translate(self, text): def translate(self, text):
dlg = translator.gui.translateDialog() dlg = translator.gui.translateDialog()
if dlg.get_response() == widgetUtils.OK: if dlg.get_response() == widgetUtils.OK:
language_dict = translator.translator.available_languages() language_dict = translator.translator.available_languages()
for k in language_dict: for k in language_dict:
if language_dict[k] == dlg.dest_lang.GetStringSelection(): if language_dict[k] == dlg.dest_lang.GetStringSelection():
dst = k dst = k
msg = translator.translator.translate(text, dst) msg = translator.translator.translate(text, dst)
dlg.Destroy() dlg.Destroy()
return msg return msg
def spellcheck(self, text): def spellcheck(self, text):
checker = SpellChecker.spellchecker.spellChecker(text) checker = SpellChecker.spellchecker.spellChecker(text)
if hasattr(checker, "fixed_text"): if hasattr(checker, "fixed_text"):
final_text = checker.fixed_text final_text = checker.fixed_text
return final_text return final_text
def translate_action(self, *args, **kwargs): def translate_action(self, *args, **kwargs):
text = self.tab.text.GetValue() text = self.tab.text.GetValue()
if text == "": if text == "":
wx.Bell() wx.Bell()
return return
translated = self.translate(text) translated = self.translate(text)
if translated != None: if translated != None:
self.tab.text.ChangeValue(translated) self.tab.text.ChangeValue(translated)
self.tab.text.SetFocus() self.tab.text.SetFocus()
def spellcheck_action(self, *args, **kwargs): def spellcheck_action(self, *args, **kwargs):
text = self.tab.text.GetValue() text = self.tab.text.GetValue()
fixed = self.spellcheck(text) fixed = self.spellcheck(text)
if fixed != None: if fixed != None:
self.tab.text.ChangeValue(fixed) self.tab.text.ChangeValue(fixed)
self.tab.text.SetFocus() self.tab.text.SetFocus()
def translate_message(self, *args, **kwargs): def translate_message(self, *args, **kwargs):
pass pass
def spellcheck_message(self, *args, **kwargs): def spellcheck_message(self, *args, **kwargs):
pass pass

View File

@ -16,53 +16,53 @@ log = logging.getLogger("controller.buffers.communityBoard")
class communityBoardBuffer(wallBuffer): class communityBoardBuffer(wallBuffer):
def create_tab(self, parent): def create_tab(self, parent):
self.tab = communityBoard.communityBoardTab(parent) self.tab = communityBoard.communityBoardTab(parent)
self.connect_events() self.connect_events()
self.tab.name = self.name self.tab.name = self.name
if "can_create_topic" not in self.session.db["group_info"][self.kwargs["group_id"]*-1] or ("can_create_topic" in self.session.db["group_info"][self.kwargs["group_id"]*-1] and self.session.db["group_info"][self.kwargs["group_id"]*-1]["can_create_topic"] != True): if "can_create_topic" not in self.session.db["group_info"][self.kwargs["group_id"]*-1] or ("can_create_topic" in self.session.db["group_info"][self.kwargs["group_id"]*-1] and self.session.db["group_info"][self.kwargs["group_id"]*-1]["can_create_topic"] != True):
self.tab.post.Enable(False) self.tab.post.Enable(False)
def onFocus(self, event, *args, **kwargs): def onFocus(self, event, *args, **kwargs):
event.Skip() event.Skip()
def open_post(self, *args, **kwargs): def open_post(self, *args, **kwargs):
""" Opens the currently focused post.""" """ Opens the currently focused post."""
post = self.get_post() post = self.get_post()
if post == None: if post == None:
return return
a = presenters.displayTopicPresenter(session=self.session, postObject=post, group_id=self.kwargs["group_id"], interactor=interactors.displayPostInteractor(), view=views.displayTopic()) a = presenters.displayTopicPresenter(session=self.session, postObject=post, group_id=self.kwargs["group_id"], interactor=interactors.displayPostInteractor(), view=views.displayTopic())
def open_in_browser(self, *args, **kwargs): def open_in_browser(self, *args, **kwargs):
post = self.get_post() post = self.get_post()
if post == None: if post == None:
return return
# In order to load the selected topic we firstly have to catch the group_id, which is present in self.kwargs # In order to load the selected topic we firstly have to catch the group_id, which is present in self.kwargs
# After getting the group_id we should make it negative # After getting the group_id we should make it negative
group_id = self.kwargs["group_id"]*-1 group_id = self.kwargs["group_id"]*-1
url = "https://vk.com/topic{group_id}_{topic_id}".format(group_id=group_id, topic_id=post["id"]) url = "https://vk.com/topic{group_id}_{topic_id}".format(group_id=group_id, topic_id=post["id"])
webbrowser.open_new_tab(url) webbrowser.open_new_tab(url)
def post(self, *args, **kwargs): def post(self, *args, **kwargs):
menu = wx.Menu() menu = wx.Menu()
user1 = self.session.get_user(self.session.user_id) user1 = self.session.get_user(self.session.user_id)
user2 = self.session.get_user(-1*self.kwargs["group_id"]) user2 = self.session.get_user(-1*self.kwargs["group_id"])
user = menu.Append(wx.NewId(), _("Post as {user1_nom}").format(**user1)) user = menu.Append(wx.NewId(), _("Post as {user1_nom}").format(**user1))
group = menu.Append(wx.NewId(), _("Post as {user1_nom}").format(**user2)) group = menu.Append(wx.NewId(), _("Post as {user1_nom}").format(**user2))
menu.Bind(widgetUtils.MENU, lambda evt: self._post(evt, 1), group) menu.Bind(widgetUtils.MENU, lambda evt: self._post(evt, 1), group)
menu.Bind(widgetUtils.MENU, lambda evt: self._post(evt, 0), user) menu.Bind(widgetUtils.MENU, lambda evt: self._post(evt, 0), user)
self.tab.post.PopupMenu(menu, self.tab.post.GetPosition()) self.tab.post.PopupMenu(menu, self.tab.post.GetPosition())
def _post(self, event, from_group): def _post(self, event, from_group):
owner_id = self.kwargs["group_id"] owner_id = self.kwargs["group_id"]
user = self.session.get_user(-1*owner_id, key="user1") user = self.session.get_user(-1*owner_id, key="user1")
title = _("Create topic in {user1_nom}").format(**user) title = _("Create topic in {user1_nom}").format(**user)
p = presenters.createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createTopicDialog(title=title, message="", text="", topic_title="")) p = presenters.createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createTopicDialog(title=title, message="", text="", topic_title=""))
if hasattr(p, "text") or hasattr(p, "privacy"): if hasattr(p, "text") or hasattr(p, "privacy"):
title = p.view.title.GetValue() title = p.view.title.GetValue()
msg = p.text msg = p.text
post_arguments = dict(title=title, text=msg, group_id=owner_id, from_group=from_group) post_arguments = dict(title=title, text=msg, group_id=owner_id, from_group=from_group)
attachments = [] attachments = []
if hasattr(p, "attachments"): if hasattr(p, "attachments"):
attachments = p.attachments attachments = p.attachments
call_threaded(pub.sendMessage, "post", parent_endpoint="board", child_endpoint="addTopic", from_buffer=self.name, attachments_list=attachments, post_arguments=post_arguments) call_threaded(pub.sendMessage, "post", parent_endpoint="board", child_endpoint="addTopic", from_buffer=self.name, attachments_list=attachments, post_arguments=post_arguments)

View File

@ -6,11 +6,11 @@ from .documents import documentsBuffer
log = logging.getLogger("controller.buffers.communityDocuments") log = logging.getLogger("controller.buffers.communityDocuments")
class communityDocumentsBuffer(documentsBuffer): class communityDocumentsBuffer(documentsBuffer):
can_get_items = True can_get_items = True
def create_tab(self, parent): def create_tab(self, parent):
self.tab = communityDocuments.communityDocumentsTab(parent) self.tab = communityDocuments.communityDocumentsTab(parent)
self.connect_events() self.connect_events()
self.tab.name = self.name self.tab.name = self.name
if hasattr(self, "can_post") and self.can_post == False and hasattr(self.tab, "post"): if hasattr(self, "can_post") and self.can_post == False and hasattr(self.tab, "post"):
self.tab.post.Enable(False) self.tab.post.Enable(False)

View File

@ -8,19 +8,19 @@ log = logging.getLogger("controller.buffers.communityPeople")
class communityPeopleBuffer(peopleBuffer): class communityPeopleBuffer(peopleBuffer):
def get_menu(self, *args, **kwargs): def get_menu(self, *args, **kwargs):
user = self.get_post() user = self.get_post()
m = wx.Menu() m = wx.Menu()
if user.get("can_post") == True: if user.get("can_post") == True:
can_post = m.Append(wx.NewId(), _("&Post on user's wall")) can_post = m.Append(wx.NewId(), _("&Post on user's wall"))
widgetUtils.connect_event(m, widgetUtils.MENU, self.post, menuitem=can_post) widgetUtils.connect_event(m, widgetUtils.MENU, self.post, menuitem=can_post)
if user.get("can_write_private_message") == True: if user.get("can_write_private_message") == True:
can_write_message = m.Append(wx.Id(), _("Send message")) can_write_message = m.Append(wx.Id(), _("Send message"))
widgetUtils.connect_event(m, widgetUtils.MENU, self.new_chat, menuitem=can_write_message) widgetUtils.connect_event(m, widgetUtils.MENU, self.new_chat, menuitem=can_write_message)
profile = m.Append(wx.NewId(), _("View profile")) profile = m.Append(wx.NewId(), _("View profile"))
widgetUtils.connect_event(m, widgetUtils.MENU, self.open_person_profile, menuitem=profile) widgetUtils.connect_event(m, widgetUtils.MENU, self.open_person_profile, menuitem=profile)
timeline = m.Append(wx.NewId(), _("Open timeline")) timeline = m.Append(wx.NewId(), _("Open timeline"))
widgetUtils.connect_event(m, widgetUtils.MENU, self.open_timeline, menuitem=timeline) widgetUtils.connect_event(m, widgetUtils.MENU, self.open_timeline, menuitem=timeline)
open_in_browser = m.Append(wx.NewId(), _("Open in vk.com")) open_in_browser = m.Append(wx.NewId(), _("Open in vk.com"))
widgetUtils.connect_event(m, widgetUtils.MENU, self.open_in_browser, menuitem=open_in_browser) widgetUtils.connect_event(m, widgetUtils.MENU, self.open_in_browser, menuitem=open_in_browser)
return m return m

View File

@ -16,54 +16,54 @@ log = logging.getLogger("controller.buffers.communityWall")
class communityWallBuffer(wallBuffer): class communityWallBuffer(wallBuffer):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(communityWallBuffer, self).__init__(*args, **kwargs) super(communityWallBuffer, self).__init__(*args, **kwargs)
self.group_id = self.kwargs["owner_id"] self.group_id = self.kwargs["owner_id"]
def create_tab(self, parent): def create_tab(self, parent):
self.tab = communityWall.communityWallTab(parent) self.tab = communityWall.communityWallTab(parent)
self.connect_events() self.connect_events()
self.tab.name = self.name self.tab.name = self.name
self.tab.post.Enable(False) self.tab.post.Enable(False)
def connect_events(self): def connect_events(self):
super(communityWallBuffer, self).connect_events() super(communityWallBuffer, self).connect_events()
widgetUtils.connect_event(self.tab.load, widgetUtils.BUTTON_PRESSED, self.load_community) widgetUtils.connect_event(self.tab.load, widgetUtils.BUTTON_PRESSED, self.load_community)
def load_community(self, *args, **kwargs): def load_community(self, *args, **kwargs):
output.speak(_("Loading community...")) output.speak(_("Loading community..."))
self.can_get_items = True self.can_get_items = True
self.tab.load.Enable(False) self.tab.load.Enable(False)
wx.CallAfter(self.get_items) wx.CallAfter(self.get_items)
def get_items(self, *args, **kwargs): def get_items(self, *args, **kwargs):
""" This method retrieves community information, useful to show different parts of the community itself.""" """ This method retrieves community information, useful to show different parts of the community itself."""
if self.can_get_items: if self.can_get_items:
# Strangely, groups.get does not return counters so we need those to show options for loading specific posts for communities. # Strangely, groups.get does not return counters so we need those to show options for loading specific posts for communities.
group_info = self.session.vk.client.groups.getById(group_ids=-1*self.kwargs["owner_id"], fields="counters")[0] group_info = self.session.vk.client.groups.getById(group_ids=-1*self.kwargs["owner_id"], fields="counters")[0]
self.session.db["group_info"][self.group_id].update(group_info) self.session.db["group_info"][self.group_id].update(group_info)
if "can_post" in self.session.db["group_info"][self.group_id] and self.session.db["group_info"][self.group_id]["can_post"] == True: if "can_post" in self.session.db["group_info"][self.group_id] and self.session.db["group_info"][self.group_id]["can_post"] == True:
self.tab.post.Enable(True) self.tab.post.Enable(True)
super(communityWallBuffer, self).get_items(*args, **kwargs) super(communityWallBuffer, self).get_items(*args, **kwargs)
def post(self, *args, **kwargs): def post(self, *args, **kwargs):
menu = wx.Menu() menu = wx.Menu()
user1 = self.session.get_user(self.session.user_id) user1 = self.session.get_user(self.session.user_id)
user2 = self.session.get_user(self.kwargs["owner_id"]) user2 = self.session.get_user(self.kwargs["owner_id"])
user = menu.Append(wx.NewId(), _("Post as {user1_nom}").format(**user1)) user = menu.Append(wx.NewId(), _("Post as {user1_nom}").format(**user1))
group = menu.Append(wx.NewId(), _("Post as {user1_nom}").format(**user2)) group = menu.Append(wx.NewId(), _("Post as {user1_nom}").format(**user2))
menu.Bind(widgetUtils.MENU, lambda evt: self._post(evt, 1), group) menu.Bind(widgetUtils.MENU, lambda evt: self._post(evt, 1), group)
menu.Bind(widgetUtils.MENU, lambda evt: self._post(evt, 0), user) menu.Bind(widgetUtils.MENU, lambda evt: self._post(evt, 0), user)
self.tab.post.PopupMenu(menu, self.tab.post.GetPosition()) self.tab.post.PopupMenu(menu, self.tab.post.GetPosition())
def _post(self, event, from_group): def _post(self, event, from_group):
owner_id = self.kwargs["owner_id"] owner_id = self.kwargs["owner_id"]
user = self.session.get_user(owner_id, key="user1") user = self.session.get_user(owner_id, key="user1")
title = _("Post to {user1_nom}'s wall").format(**user) title = _("Post to {user1_nom}'s wall").format(**user)
p = presenters.createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createPostDialog(title=title, message="", text="")) p = presenters.createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createPostDialog(title=title, message="", text=""))
if hasattr(p, "text") or hasattr(p, "privacy"): if hasattr(p, "text") or hasattr(p, "privacy"):
post_arguments=dict(privacy=p.privacy, message=p.text, owner_id=owner_id, from_group=from_group) post_arguments=dict(privacy=p.privacy, message=p.text, owner_id=owner_id, from_group=from_group)
attachments = [] attachments = []
if hasattr(p, "attachments"): if hasattr(p, "attachments"):
attachments = p.attachments attachments = p.attachments
call_threaded(pub.sendMessage, "post", parent_endpoint="wall", child_endpoint="post", from_buffer=self.name, attachments_list=attachments, post_arguments=post_arguments) call_threaded(pub.sendMessage, "post", parent_endpoint="wall", child_endpoint="post", from_buffer=self.name, attachments_list=attachments, post_arguments=post_arguments)

View File

@ -17,77 +17,77 @@ from .wall import wallBuffer
log = logging.getLogger("controller.buffers.documents") log = logging.getLogger("controller.buffers.documents")
class documentsBuffer(wallBuffer): class documentsBuffer(wallBuffer):
can_get_items = False can_get_items = False
def create_tab(self, parent): def create_tab(self, parent):
self.tab = documents.documentsTab(parent) self.tab = documents.documentsTab(parent)
self.connect_events() self.connect_events()
self.tab.name = self.name self.tab.name = self.name
if hasattr(self, "can_post") and self.can_post == False and hasattr(self.tab, "post"): if hasattr(self, "can_post") and self.can_post == False and hasattr(self.tab, "post"):
self.tab.post.Enable(False) self.tab.post.Enable(False)
def onFocus(self, event, *args,**kwargs): def onFocus(self, event, *args,**kwargs):
post = self.get_post() post = self.get_post()
if post == None: if post == None:
return return
original_date = arrow.get(post["date"]) original_date = arrow.get(post["date"])
created_at = original_date.humanize(locale=languageHandler.curLang[:2]) created_at = original_date.humanize(locale=languageHandler.curLang[:2])
self.tab.list.list.SetItem(self.tab.list.get_selected(), 4, created_at) self.tab.list.list.SetItem(self.tab.list.get_selected(), 4, created_at)
event.Skip() event.Skip()
def connect_events(self): def connect_events(self):
super(documentsBuffer, self).connect_events() super(documentsBuffer, self).connect_events()
# Check if we have a load button in the tab, because documents community buffers don't include it. # Check if we have a load button in the tab, because documents community buffers don't include it.
if hasattr(self.tab, "load"): if hasattr(self.tab, "load"):
widgetUtils.connect_event(self.tab.load, widgetUtils.BUTTON_PRESSED, self.load_documents) widgetUtils.connect_event(self.tab.load, widgetUtils.BUTTON_PRESSED, self.load_documents)
def load_documents(self, *args, **kwargs): def load_documents(self, *args, **kwargs):
output.speak(_("Loading documents...")) output.speak(_("Loading documents..."))
self.can_get_items = True self.can_get_items = True
self.tab.load.Enable(False) self.tab.load.Enable(False)
wx.CallAfter(self.get_items) wx.CallAfter(self.get_items)
def get_menu(self): def get_menu(self):
p = self.get_post() p = self.get_post()
if p == None: if p == None:
return return
if p["owner_id"] == self.session.user_id: if p["owner_id"] == self.session.user_id:
added = True added = True
else: else:
added = False added = False
m = menus.documentMenu(added) m = menus.documentMenu(added)
widgetUtils.connect_event(m, widgetUtils.MENU, self.add_remove_document, menuitem=m.action) widgetUtils.connect_event(m, widgetUtils.MENU, self.add_remove_document, menuitem=m.action)
widgetUtils.connect_event(m, widgetUtils.MENU, self.download, menuitem=m.download) widgetUtils.connect_event(m, widgetUtils.MENU, self.download, menuitem=m.download)
widgetUtils.connect_event(m, widgetUtils.MENU, self.open_in_browser, menuitem=m.open_in_browser) widgetUtils.connect_event(m, widgetUtils.MENU, self.open_in_browser, menuitem=m.open_in_browser)
return m return m
def add_remove_document(self, *args, **kwargs): def add_remove_document(self, *args, **kwargs):
p = self.get_post() p = self.get_post()
if p == None: if p == None:
return return
if p["owner_id"] == self.session.user_id: if p["owner_id"] == self.session.user_id:
result = self.session.vk.client.docs.delete(owner_id=p["owner_id"], doc_id=p["id"]) result = self.session.vk.client.docs.delete(owner_id=p["owner_id"], doc_id=p["id"])
if result == 1: if result == 1:
output.speak(_("The document has been successfully deleted.")) output.speak(_("The document has been successfully deleted."))
self.session.db[self.name]["items"].pop(self.tab.list.get_selected()) self.session.db[self.name]["items"].pop(self.tab.list.get_selected())
self.tab.list.remove_item(self.tab.list.get_selected()) self.tab.list.remove_item(self.tab.list.get_selected())
else: else:
result = self.session.vk.client.docs.add(owner_id=p["owner_id"], doc_id=p["id"]) result = self.session.vk.client.docs.add(owner_id=p["owner_id"], doc_id=p["id"])
output.speak(_("The document has been successfully added.")) output.speak(_("The document has been successfully added."))
def download(self, *args, **kwargs): def download(self, *args, **kwargs):
post = self.get_post() post = self.get_post()
filename = utils.safe_filename(post["title"]) filename = utils.safe_filename(post["title"])
# If document does not end in .extension we must fix it so the file dialog will save it properly later. # If document does not end in .extension we must fix it so the file dialog will save it properly later.
if filename.endswith(post["ext"]) == False: if filename.endswith(post["ext"]) == False:
filename = filename+ "."+post["ext"] filename = filename+ "."+post["ext"]
filepath = self.tab.get_download_path(filename) filepath = self.tab.get_download_path(filename)
if filepath != None: if filepath != None:
pub.sendMessage("download-file", url=post["url"], filename=filepath) pub.sendMessage("download-file", url=post["url"], filename=filepath)
def open_in_browser(self, *args, **kwargs): def open_in_browser(self, *args, **kwargs):
post = self.get_post() post = self.get_post()
if post == None: if post == None:
return return
url = "https://vk.com/doc{user_id}_{post_id}".format(user_id=post["owner_id"], post_id=post["id"]) url = "https://vk.com/doc{user_id}_{post_id}".format(user_id=post["owner_id"], post_id=post["id"])
webbrowser.open_new_tab(url) webbrowser.open_new_tab(url)

View File

@ -8,20 +8,20 @@ log = logging.getLogger("controller.buffers.empty")
class emptyBuffer(object): class emptyBuffer(object):
def __init__(self, name=None, parent=None, *args, **kwargs): def __init__(self, name=None, parent=None, *args, **kwargs):
self.tab = empty.emptyTab(parent=parent, name=name) self.tab = empty.emptyTab(parent=parent, name=name)
self.name = name self.name = name
def get_items(self, *args, **kwargs): def get_items(self, *args, **kwargs):
if not hasattr(self, "tab"): if not hasattr(self, "tab"):
# Create GUI associated to this buffer. # Create GUI associated to this buffer.
self.create_tab(self.parent) self.create_tab(self.parent)
# Add name to the new control so we could look for it when needed. # Add name to the new control so we could look for it when needed.
self.tab.name = self.name self.tab.name = self.name
pass pass
def get_more_items(self, *args, **kwargs): def get_more_items(self, *args, **kwargs):
output.speak(_("This buffer doesn't support getting more items.")) output.speak(_("This buffer doesn't support getting more items."))
def remove_buffer(self, mandatory=False): def remove_buffer(self, mandatory=False):
return False return False

View File

@ -9,73 +9,73 @@ log = logging.getLogger("controller.buffers.friendRequests")
class friendRequestsBuffer(peopleBuffer): class friendRequestsBuffer(peopleBuffer):
def get_items(self, show_nextpage=False): def get_items(self, show_nextpage=False):
if self.can_get_items == False: return if self.can_get_items == False: return
retrieved = True retrieved = True
try: try:
ids = self.session.vk.client.friends.getRequests(*self.args, **self.kwargs) ids = self.session.vk.client.friends.getRequests(*self.args, **self.kwargs)
except VkApiError as err: except VkApiError as err:
log.error("Error {0}: {1}".format(err.code, err.error)) log.error("Error {0}: {1}".format(err.code, err.error))
retrieved = err.code retrieved = err.code
return retrieved return retrieved
except: except:
log.exception("Connection error when updating buffer %s. Will try again in 2 minutes" % (self.name,)) log.exception("Connection error when updating buffer %s. Will try again in 2 minutes" % (self.name,))
return False return False
num = self.session.get_page(name=self.name, show_nextpage=show_nextpage, endpoint="get", parent_endpoint="users", count=1000, user_ids=", ".join([str(i) for i in ids["items"]]), fields="uid, first_name, last_name, last_seen") num = self.session.get_page(name=self.name, show_nextpage=show_nextpage, endpoint="get", parent_endpoint="users", count=1000, user_ids=", ".join([str(i) for i in ids["items"]]), fields="uid, first_name, last_name, last_seen")
if not hasattr(self, "tab"): if not hasattr(self, "tab"):
# Create GUI associated to this buffer. # Create GUI associated to this buffer.
self.create_tab(self.parent) self.create_tab(self.parent)
# Add name to the new control so we could look for it when needed. # Add name to the new control so we could look for it when needed.
self.tab.name = self.name self.tab.name = self.name
if show_nextpage == False: if show_nextpage == False:
if self.tab.list.get_count() > 0 and num > 0: if self.tab.list.get_count() > 0 and num > 0:
v = [i for i in self.session.db[self.name]["items"][:num]] v = [i for i in self.session.db[self.name]["items"][:num]]
v.reverse() v.reverse()
[wx.CallAfter(self.insert, i, True) for i in v] [wx.CallAfter(self.insert, i, True) for i in v]
else: else:
[wx.CallAfter(self.insert, i) for i in self.session.db[self.name]["items"][:num]] [wx.CallAfter(self.insert, i) for i in self.session.db[self.name]["items"][:num]]
return retrieved return retrieved
def accept_friendship(self, *args, **kwargs): def accept_friendship(self, *args, **kwargs):
""" Adds a person to a list of friends. This method is done for accepting someone else's friend request. """ Adds a person to a list of friends. This method is done for accepting someone else's friend request.
https://vk.com/dev/friends.add https://vk.com/dev/friends.add
""" """
person = self.get_post() person = self.get_post()
if person == None: if person == None:
return return
result = self.session.vk.client.friends.add(user_id=person["id"]) result = self.session.vk.client.friends.add(user_id=person["id"])
if result == 2: if result == 2:
msg = _("{0} {1} now is your friend.").format(person["first_name"], person["last_name"]) msg = _("{0} {1} now is your friend.").format(person["first_name"], person["last_name"])
pub.sendMessage("notify", message=msg) pub.sendMessage("notify", message=msg)
self.session.db[self.name]["items"].pop(self.tab.list.get_selected()) self.session.db[self.name]["items"].pop(self.tab.list.get_selected())
self.tab.list.remove_item(self.tab.list.get_selected()) self.tab.list.remove_item(self.tab.list.get_selected())
def decline_friendship(self, *args, **kwargs): def decline_friendship(self, *args, **kwargs):
""" Declines a freind request. """ Declines a freind request.
https://vk.com/dev/friends.delete https://vk.com/dev/friends.delete
""" """
person = self.get_post() person = self.get_post()
if person == None: if person == None:
return return
result = self.session.vk.client.friends.delete(user_id=person["id"]) result = self.session.vk.client.friends.delete(user_id=person["id"])
if "out_request_deleted" in result: if "out_request_deleted" in result:
msg = _("You've deleted the friends request to {0} {1}.").format(person["first_name"], person["last_name"]) msg = _("You've deleted the friends request to {0} {1}.").format(person["first_name"], person["last_name"])
elif "in_request_deleted" in result: elif "in_request_deleted" in result:
msg = _("You've declined the friend request of {0} {1}.").format(person["first_name"], person["last_name"]) msg = _("You've declined the friend request of {0} {1}.").format(person["first_name"], person["last_name"])
pub.sendMessage("notify", message=msg) pub.sendMessage("notify", message=msg)
self.session.db[self.name]["items"].pop(self.tab.list.get_selected()) self.session.db[self.name]["items"].pop(self.tab.list.get_selected())
self.tab.list.remove_item(self.tab.list.get_selected()) self.tab.list.remove_item(self.tab.list.get_selected())
def keep_as_follower(self, *args, **kwargs): def keep_as_follower(self, *args, **kwargs):
""" Adds a person to The followers list of the current user. """ Adds a person to The followers list of the current user.
https://vk.com/dev/friends.add https://vk.com/dev/friends.add
""" """
person = self.get_post() person = self.get_post()
if person == None: if person == None:
return return
result = self.session.vk.client.friends.add(user_id=person["id"], follow=1) result = self.session.vk.client.friends.add(user_id=person["id"], follow=1)
if result == 2: if result == 2:
msg = _("{0} {1} is following you.").format(person["first_name"], person["last_name"]) msg = _("{0} {1} is following you.").format(person["first_name"], person["last_name"])
pub.sendMessage("notify", message=msg) pub.sendMessage("notify", message=msg)
self.session.db[self.name]["items"].pop(self.tab.list.get_selected()) self.session.db[self.name]["items"].pop(self.tab.list.get_selected())
self.tab.list.remove_item(self.tab.list.get_selected()) self.tab.list.remove_item(self.tab.list.get_selected())

View File

@ -20,313 +20,313 @@ from wxUI import commonMessages, menus
log = logging.getLogger("controller.buffers.home") log = logging.getLogger("controller.buffers.home")
class homeBuffer(object): class homeBuffer(object):
""" a basic representation of a buffer. Other buffers should be derived from this class. This buffer represents the "news feed" """ """ a basic representation of a buffer. Other buffers should be derived from this class. This buffer represents the "news feed" """
def get_post(self): def get_post(self):
""" Return the currently focused post.""" """ Return the currently focused post."""
# Handle case where there are no items in the buffer. # Handle case where there are no items in the buffer.
if self.tab.list.get_count() == 0: if self.tab.list.get_count() == 0:
wx.Bell() wx.Bell()
return None return None
return self.session.db[self.name]["items"][self.tab.list.get_selected()] return self.session.db[self.name]["items"][self.tab.list.get_selected()]
def __init__(self, parent=None, name="", session=None, composefunc=None, create_tab=True, *args, **kwargs): def __init__(self, parent=None, name="", session=None, composefunc=None, create_tab=True, *args, **kwargs):
""" Constructor: """ Constructor:
@parent wx.Treebook: parent for the buffer panel, @parent wx.Treebook: parent for the buffer panel,
@name str: Name for saving this buffer's data in the local storage variable, @name str: Name for saving this buffer's data in the local storage variable,
@session sessionmanager.session.vkSession: Session for performing operations in the Vk API. This session should be logged in when this class is instanciated. @session sessionmanager.session.vkSession: Session for performing operations in the Vk API. This session should be logged in when this class is instanciated.
@composefunc str: This function will be called for composing the result which will be put in the listCtrl. Composefunc should exist in the sessionmanager.renderers module. @composefunc str: This function will be called for composing the result which will be put in the listCtrl. Composefunc should exist in the sessionmanager.renderers module.
args and kwargs will be passed to get_items() without any filtering. Be careful there. args and kwargs will be passed to get_items() without any filtering. Be careful there.
""" """
super(homeBuffer, self).__init__() super(homeBuffer, self).__init__()
self.parent = parent self.parent = parent
self.args = args self.args = args
self.kwargs = kwargs self.kwargs = kwargs
self.session = session self.session = session
self.compose_function = composefunc self.compose_function = composefunc
self.name = name self.name = name
if create_tab: if create_tab:
self.create_tab(self.parent) self.create_tab(self.parent)
#Update_function will be called every 3 minutes and it should be able to #Update_function will be called every 3 minutes and it should be able to
# Get all new items in the buffer and sort them properly in the CtrlList. # Get all new items in the buffer and sort them properly in the CtrlList.
# ToDo: Shall we allow dinamically set for update_function? # ToDo: Shall we allow dinamically set for update_function?
self.update_function = "get_page" self.update_function = "get_page"
self.name = name self.name = name
# source_key and post_key will point to the keys for sender and posts in VK API objects. # source_key and post_key will point to the keys for sender and posts in VK API objects.
# They can be changed in the future for other item types in different buffers. # They can be changed in the future for other item types in different buffers.
self.user_key = "source_id" self.user_key = "source_id"
self.post_key = "post_id" self.post_key = "post_id"
# When set to False, update_function won't be executed here. # When set to False, update_function won't be executed here.
self.can_get_items = True self.can_get_items = True
def create_tab(self, parent): def create_tab(self, parent):
""" Create the Wx panel.""" """ Create the Wx panel."""
self.tab = home.homeTab(parent) self.tab = home.homeTab(parent)
# Bind local events (they will respond to events happened in the buffer). # Bind local events (they will respond to events happened in the buffer).
self.connect_events() self.connect_events()
self.tab.name = self.name self.tab.name = self.name
if hasattr(self, "can_post") and self.can_post == False and hasattr(self.tab, "post"): if hasattr(self, "can_post") and self.can_post == False and hasattr(self.tab, "post"):
self.tab.post.Enable(False) self.tab.post.Enable(False)
def insert(self, item, reversed=False): def insert(self, item, reversed=False):
""" Add a new item to the list. Uses renderers.composefunc for parsing the dictionary and create a valid result for putting it in the list.""" """ Add a new item to the list. Uses renderers.composefunc for parsing the dictionary and create a valid result for putting it in the list."""
try: try:
item_ = getattr(renderers, self.compose_function)(item, self.session) item_ = getattr(renderers, self.compose_function)(item, self.session)
wx.CallAfter(self.tab.list.insert_item, reversed, *item_) wx.CallAfter(self.tab.list.insert_item, reversed, *item_)
except: except:
log.exception(item) log.exception(item)
def get_items(self, show_nextpage=False): def get_items(self, show_nextpage=False):
""" Retrieve items from the VK API. This function is called repeatedly by the main controller and users could call it implicitly as well with the update buffer option. """ Retrieve items from the VK API. This function is called repeatedly by the main controller and users could call it implicitly as well with the update buffer option.
@show_nextpage boolean: If it's true, it will try to load previous results. @show_nextpage boolean: If it's true, it will try to load previous results.
""" """
if self.can_get_items == False: return if self.can_get_items == False: return
retrieved = True # Control variable for handling unauthorised/connection errors. retrieved = True # Control variable for handling unauthorised/connection errors.
try: try:
num = getattr(self.session, "get_newsfeed")(show_nextpage=show_nextpage, name=self.name, *self.args, **self.kwargs) num = getattr(self.session, "get_newsfeed")(show_nextpage=show_nextpage, name=self.name, *self.args, **self.kwargs)
except VkApiError as err: except VkApiError as err:
log.error("Error {0}: {1}".format(err.code, err.error)) log.error("Error {0}: {1}".format(err.code, err.error))
retrieved = err.code retrieved = err.code
return retrieved return retrieved
except: except:
log.exception("Connection error when updating buffer %s. Will try again in 2 minutes" % (self.name,)) log.exception("Connection error when updating buffer %s. Will try again in 2 minutes" % (self.name,))
return False return False
if not hasattr(self, "tab"): if not hasattr(self, "tab"):
# Create GUI associated to this buffer. # Create GUI associated to this buffer.
self.create_tab(self.parent) self.create_tab(self.parent)
# Add name to the new control so we could look for it when needed. # Add name to the new control so we could look for it when needed.
if show_nextpage == False: if show_nextpage == False:
if self.tab.list.get_count() > 0 and num > 0: if self.tab.list.get_count() > 0 and num > 0:
v = [i for i in self.session.db[self.name]["items"][:num]] v = [i for i in self.session.db[self.name]["items"][:num]]
v.reverse() v.reverse()
[wx.CallAfter(self.insert, i, True) for i in v] [wx.CallAfter(self.insert, i, True) for i in v]
else: else:
[wx.CallAfter(self.insert, i) for i in self.session.db[self.name]["items"][:num]] [wx.CallAfter(self.insert, i) for i in self.session.db[self.name]["items"][:num]]
else: else:
if num > 0: if num > 0:
[wx.CallAfter(self.insert, i, False) for i in self.session.db[self.name]["items"][-num:]] [wx.CallAfter(self.insert, i, False) for i in self.session.db[self.name]["items"][-num:]]
return retrieved return retrieved
def get_more_items(self): def get_more_items(self):
""" Returns previous items in the buffer.""" """ Returns previous items in the buffer."""
self.get_items(show_nextpage=True) self.get_items(show_nextpage=True)
def post(self, *args, **kwargs): def post(self, *args, **kwargs):
""" Create a post in the current user's wall. """ Create a post in the current user's wall.
This process is handled in two parts. This is the first part, where the GUI is created and user can send the post. This process is handled in two parts. This is the first part, where the GUI is created and user can send the post.
During the second part (threaded), the post will be sent to the API.""" During the second part (threaded), the post will be sent to the API."""
p = presenters.createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createPostDialog(title=_("Write your post"), message="", text="")) p = presenters.createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createPostDialog(title=_("Write your post"), message="", text=""))
if hasattr(p, "text") or hasattr(p, "privacy"): if hasattr(p, "text") or hasattr(p, "privacy"):
post_arguments=dict(privacy=p.privacy, message=p.text) post_arguments=dict(privacy=p.privacy, message=p.text)
attachments = [] attachments = []
if hasattr(p, "attachments"): if hasattr(p, "attachments"):
attachments = p.attachments attachments = p.attachments
call_threaded(pub.sendMessage, "post", parent_endpoint="wall", child_endpoint="post", from_buffer=self.name, attachments_list=attachments, post_arguments=post_arguments) call_threaded(pub.sendMessage, "post", parent_endpoint="wall", child_endpoint="post", from_buffer=self.name, attachments_list=attachments, post_arguments=post_arguments)
def connect_events(self): def connect_events(self):
""" Bind all events to this buffer""" """ Bind all events to this buffer"""
widgetUtils.connect_event(self.tab.post, widgetUtils.BUTTON_PRESSED, self.post) widgetUtils.connect_event(self.tab.post, widgetUtils.BUTTON_PRESSED, self.post)
widgetUtils.connect_event(self.tab.list.list, widgetUtils.KEYPRESS, self.get_event) widgetUtils.connect_event(self.tab.list.list, widgetUtils.KEYPRESS, self.get_event)
widgetUtils.connect_event(self.tab.list.list, wx.EVT_CONTEXT_MENU, self.show_menu) widgetUtils.connect_event(self.tab.list.list, wx.EVT_CONTEXT_MENU, self.show_menu)
self.tab.set_focus_function(self.onFocus) self.tab.set_focus_function(self.onFocus)
def show_menu(self, ev, pos=0, *args, **kwargs): def show_menu(self, ev, pos=0, *args, **kwargs):
""" Show contextual menu when pressing menu key or right mouse click in a list item.""" """ Show contextual menu when pressing menu key or right mouse click in a list item."""
if self.tab.list.get_count() == 0: return if self.tab.list.get_count() == 0: return
menu = self.get_menu() menu = self.get_menu()
if pos != 0: if pos != 0:
self.tab.PopupMenu(menu, pos) self.tab.PopupMenu(menu, pos)
else: else:
self.tab.PopupMenu(menu, self.tab.list.list.GetPosition()) self.tab.PopupMenu(menu, self.tab.list.list.GetPosition())
def show_menu_by_key(self, ev): def show_menu_by_key(self, ev):
""" Show contextual menu when menu key is pressed""" """ Show contextual menu when menu key is pressed"""
if self.tab.list.get_count() == 0: if self.tab.list.get_count() == 0:
return return
if ev.GetKeyCode() == wx.WXK_WINDOWS_MENU: if ev.GetKeyCode() == wx.WXK_WINDOWS_MENU:
self.show_menu(widgetUtils.MENU, pos=self.tab.list.list.GetPosition()) self.show_menu(widgetUtils.MENU, pos=self.tab.list.list.GetPosition())
def get_menu(self): def get_menu(self):
""" Returns contextual menu options. They will change according to the focused item""" """ Returns contextual menu options. They will change according to the focused item"""
p = self.get_post() p = self.get_post()
if p == None: if p == None:
return return
# determine if the current user is able to delete the object. # determine if the current user is able to delete the object.
if "can_delete" in p: if "can_delete" in p:
can_delete = True==p["can_delete"] can_delete = True==p["can_delete"]
else: else:
can_delete = False can_delete = False
m = menus.postMenu(can_delete=can_delete) m = menus.postMenu(can_delete=can_delete)
if ("likes" in p) == False: if ("likes" in p) == False:
m.like.Enable(False) m.like.Enable(False)
elif p["likes"]["user_likes"] == 1: elif p["likes"]["user_likes"] == 1:
m.like.Enable(False) m.like.Enable(False)
m.dislike.Enable(True) m.dislike.Enable(True)
if ("comments" in p) == False: if ("comments" in p) == False:
m.comment.Enable(False) m.comment.Enable(False)
m.open_in_browser.Enable(False) m.open_in_browser.Enable(False)
if "type" in p and p["type"] != "friend" and p["type"] != "audio" and p["type"] != "video" and p["type"] != "playlist" or self.name != "home_timeline": if "type" in p and p["type"] != "friend" and p["type"] != "audio" and p["type"] != "video" and p["type"] != "playlist" or self.name != "home_timeline":
m.open_in_browser.Enable(True) m.open_in_browser.Enable(True)
widgetUtils.connect_event(m, widgetUtils.MENU, self.open_post, menuitem=m.open) widgetUtils.connect_event(m, widgetUtils.MENU, self.open_post, menuitem=m.open)
widgetUtils.connect_event(m, widgetUtils.MENU, self.do_like, menuitem=m.like) widgetUtils.connect_event(m, widgetUtils.MENU, self.do_like, menuitem=m.like)
widgetUtils.connect_event(m, widgetUtils.MENU, self.do_dislike, menuitem=m.dislike) widgetUtils.connect_event(m, widgetUtils.MENU, self.do_dislike, menuitem=m.dislike)
widgetUtils.connect_event(m, widgetUtils.MENU, self.do_comment, menuitem=m.comment) widgetUtils.connect_event(m, widgetUtils.MENU, self.do_comment, menuitem=m.comment)
widgetUtils.connect_event(m, widgetUtils.MENU, self.open_in_browser, menuitem=m.open_in_browser) widgetUtils.connect_event(m, widgetUtils.MENU, self.open_in_browser, menuitem=m.open_in_browser)
if hasattr(m, "view_profile"): if hasattr(m, "view_profile"):
widgetUtils.connect_event(m, widgetUtils.MENU, self.open_person_profile, menuitem=m.view_profile) widgetUtils.connect_event(m, widgetUtils.MENU, self.open_person_profile, menuitem=m.view_profile)
if hasattr(m, "delete"): if hasattr(m, "delete"):
widgetUtils.connect_event(m, widgetUtils.MENU, self.delete, menuitem=m.delete) widgetUtils.connect_event(m, widgetUtils.MENU, self.delete, menuitem=m.delete)
return m return m
def do_like(self, *args, **kwargs): def do_like(self, *args, **kwargs):
""" Set like in the currently focused post.""" """ Set like in the currently focused post."""
post = self.get_post() post = self.get_post()
if post == None: if post == None:
return return
user = post[self.user_key] user = post[self.user_key]
id = post[self.post_key] id = post[self.post_key]
if "type" in post: if "type" in post:
type_ = post["type"] type_ = post["type"]
else: else:
type_ = "post" type_ = "post"
l = self.session.vk.client.likes.add(owner_id=user, item_id=id, type=type_) l = self.session.vk.client.likes.add(owner_id=user, item_id=id, type=type_)
self.session.db[self.name]["items"][self.tab.list.get_selected()]["likes"]["count"] = l["likes"] self.session.db[self.name]["items"][self.tab.list.get_selected()]["likes"]["count"] = l["likes"]
self.session.db[self.name]["items"][self.tab.list.get_selected()]["likes"]["user_likes"] = 1 self.session.db[self.name]["items"][self.tab.list.get_selected()]["likes"]["user_likes"] = 1
# Translators: This will be used when user presses like. # Translators: This will be used when user presses like.
output.speak(_("You liked this")) output.speak(_("You liked this"))
def do_dislike(self, *args, **kwargs): def do_dislike(self, *args, **kwargs):
""" Set dislike (undo like) in the currently focused post.""" """ Set dislike (undo like) in the currently focused post."""
post = self.get_post() post = self.get_post()
if post == None: if post == None:
return return
user = post[self.user_key] user = post[self.user_key]
id = post[self.post_key] id = post[self.post_key]
if "type" in post: if "type" in post:
type_ = post["type"] type_ = post["type"]
else: else:
type_ = "post" type_ = "post"
l = self.session.vk.client.likes.delete(owner_id=user, item_id=id, type=type_) l = self.session.vk.client.likes.delete(owner_id=user, item_id=id, type=type_)
self.session.db[self.name]["items"][self.tab.list.get_selected()]["likes"]["count"] = l["likes"] self.session.db[self.name]["items"][self.tab.list.get_selected()]["likes"]["count"] = l["likes"]
self.session.db[self.name]["items"][self.tab.list.get_selected()]["likes"]["user_likes"] = 2 self.session.db[self.name]["items"][self.tab.list.get_selected()]["likes"]["user_likes"] = 2
# Translators: This will be user in 'dislike' # Translators: This will be user in 'dislike'
output.speak(_("You don't like this")) output.speak(_("You don't like this"))
def do_comment(self, *args, **kwargs): def do_comment(self, *args, **kwargs):
""" Make a comment into the currently focused post.""" """ Make a comment into the currently focused post."""
post = self.get_post() post = self.get_post()
if post == None: if post == None:
return return
comment = presenters.createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createPostDialog(title=_("Add a comment"), message="", text="", mode="comment")) comment = presenters.createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createPostDialog(title=_("Add a comment"), message="", text="", mode="comment"))
if hasattr(comment, "text") or hasattr(comment, "privacy"): if hasattr(comment, "text") or hasattr(comment, "privacy"):
msg = comment.text msg = comment.text
try: try:
user = post[self.user_key] user = post[self.user_key]
id = post[self.post_key] id = post[self.post_key]
self.session.vk.client.wall.addComment(owner_id=user, post_id=id, text=msg) self.session.vk.client.wall.addComment(owner_id=user, post_id=id, text=msg)
output.speak(_("You've posted a comment")) output.speak(_("You've posted a comment"))
except Exception as msg: except Exception as msg:
log.error(msg) log.error(msg)
def delete(self, *args, **kwargs): def delete(self, *args, **kwargs):
post = self.get_post() post = self.get_post()
if ("type" in post and post["type"] == "post") or self.name != "newsfeed": if ("type" in post and post["type"] == "post") or self.name != "newsfeed":
question = commonMessages.remove_post() question = commonMessages.remove_post()
if question == widgetUtils.NO: if question == widgetUtils.NO:
return return
if "owner_id" in self.kwargs: if "owner_id" in self.kwargs:
result = self.session.vk.client.wall.delete(owner_id=self.kwargs["owner_id"], post_id=post[self.post_key]) result = self.session.vk.client.wall.delete(owner_id=self.kwargs["owner_id"], post_id=post[self.post_key])
else: else:
result = self.session.vk.client.wall.delete(post_id=post[self.post_key]) result = self.session.vk.client.wall.delete(post_id=post[self.post_key])
pub.sendMessage("post_deleted", post_id=post[self.post_key]) pub.sendMessage("post_deleted", post_id=post[self.post_key])
self.session.db[self.name]["items"].pop(self.tab.list.get_selected()) self.session.db[self.name]["items"].pop(self.tab.list.get_selected())
self.tab.list.remove_item(self.tab.list.get_selected()) self.tab.list.remove_item(self.tab.list.get_selected())
def get_event(self, ev): def get_event(self, ev):
""" Parses keyboard input in the ListCtrl and executes the event associated with user keypresses.""" """ Parses keyboard input in the ListCtrl and executes the event associated with user keypresses."""
if ev.GetKeyCode() == wx.WXK_RETURN: event = "open_post" if ev.GetKeyCode() == wx.WXK_RETURN: event = "open_post"
else: else:
event = None event = None
ev.Skip() ev.Skip()
if event != None: if event != None:
try: try:
getattr(self, event)() getattr(self, event)()
except AttributeError: except AttributeError:
pass pass
def volume_down(self): def volume_down(self):
""" Decreases player volume by 2%""" """ Decreases player volume by 2%"""
player.player.volume = player.player.volume-2 player.player.volume = player.player.volume-2
def volume_up(self): def volume_up(self):
""" Increases player volume by 2%""" """ Increases player volume by 2%"""
player.player.volume = player.player.volume+2 player.player.volume = player.player.volume+2
def play_audio(self, *args, **kwargs): def play_audio(self, *args, **kwargs):
""" Play audio in currently focused buffer, if possible.""" """ Play audio in currently focused buffer, if possible."""
post = self.get_post() post = self.get_post()
if post == None: if post == None:
return return
if "type" in post and post["type"] == "audio": if "type" in post and post["type"] == "audio":
pub.sendMessage("play", object=post["audio"]["items"][0]) pub.sendMessage("play", object=post["audio"]["items"][0])
return True return True
def open_person_profile(self, *args, **kwargs): def open_person_profile(self, *args, **kwargs):
""" Views someone's profile.""" """ Views someone's profile."""
selected = self.get_post() selected = self.get_post()
if selected == None: if selected == None:
return return
# Check all possible keys for an user object in VK API. # Check all possible keys for an user object in VK API.
keys = ["from_id", "source_id", "id"] keys = ["from_id", "source_id", "id"]
for i in keys: for i in keys:
if i in selected: if i in selected:
pub.sendMessage("user-profile", person=selected[i]) pub.sendMessage("user-profile", person=selected[i])
break break
def open_post(self, *args, **kwargs): def open_post(self, *args, **kwargs):
""" Opens the currently focused post.""" """ Opens the currently focused post."""
post = self.get_post() post = self.get_post()
if post == None: if post == None:
return return
if "type" in post and post["type"] == "audio": if "type" in post and post["type"] == "audio":
a = presenters.displayAudioPresenter(session=self.session, postObject=post["audio"]["items"], interactor=interactors.displayAudioInteractor(), view=views.displayAudio()) a = presenters.displayAudioPresenter(session=self.session, postObject=post["audio"]["items"], interactor=interactors.displayAudioInteractor(), view=views.displayAudio())
elif "type" in post and post["type"] == "friend": elif "type" in post and post["type"] == "friend":
pub.sendMessage("open-post", post_object=post, controller_="displayFriendship", vars=dict(caption=_("{user1_nom} added the following friends"))) pub.sendMessage("open-post", post_object=post, controller_="displayFriendship", vars=dict(caption=_("{user1_nom} added the following friends")))
else: else:
pub.sendMessage("open-post", post_object=post, controller_="displayPost") pub.sendMessage("open-post", post_object=post, controller_="displayPost")
def pause_audio(self, *args, **kwargs): def pause_audio(self, *args, **kwargs):
""" pauses audio playback.""" """ pauses audio playback."""
pub.sendMessage("pause") pub.sendMessage("pause")
def remove_buffer(self, mandatory): def remove_buffer(self, mandatory):
""" Function for removing a buffer. Returns True if removal is successful, False otherwise""" """ Function for removing a buffer. Returns True if removal is successful, False otherwise"""
return False return False
def get_users(self): def get_users(self):
""" Returns source user in the post.""" """ Returns source user in the post."""
post = self.get_post() post = self.get_post()
if post == None: if post == None:
return return
if ("type" in post) == False: if ("type" in post) == False:
return [post["from_id"]] return [post["from_id"]]
else: else:
return [post["source_id"]] return [post["source_id"]]
def onFocus(self, event, *args,**kwargs): def onFocus(self, event, *args,**kwargs):
""" Function executed when the item in a list is selected. """ Function executed when the item in a list is selected.
For this buffer it updates the date of posts in the list.""" For this buffer it updates the date of posts in the list."""
post = self.get_post() post = self.get_post()
if post == None: if post == None:
return return
original_date = arrow.get(post["date"]) original_date = arrow.get(post["date"])
created_at = original_date.humanize(locale=languageHandler.curLang[:2]) created_at = original_date.humanize(locale=languageHandler.curLang[:2])
self.tab.list.list.SetItem(self.tab.list.get_selected(), 2, created_at) self.tab.list.list.SetItem(self.tab.list.get_selected(), 2, created_at)
event.Skip() event.Skip()
def open_in_browser(self, *args, **kwargs): def open_in_browser(self, *args, **kwargs):
post = self.get_post() post = self.get_post()
if post == None: if post == None:
return return
url = "https://vk.com/wall{user_id}_{post_id}".format(user_id=post["source_id"], post_id=post["post_id"]) url = "https://vk.com/wall{user_id}_{post_id}".format(user_id=post["source_id"], post_id=post["post_id"])
webbrowser.open_new_tab(url) webbrowser.open_new_tab(url)

View File

@ -7,10 +7,10 @@ log = logging.getLogger("controller.buffers")
class notificationBuffer(wallBuffer): class notificationBuffer(wallBuffer):
def create_tab(self, parent): def create_tab(self, parent):
self.tab = notification.notificationTab(parent) self.tab = notification.notificationTab(parent)
self.connect_events() self.connect_events()
self.tab.name = self.name self.tab.name = self.name
def onFocus(self, event, *args, **kwargs): def onFocus(self, event, *args, **kwargs):
event.Skip() event.Skip()

View File

@ -21,205 +21,205 @@ log = logging.getLogger("controller.buffers.friends")
class peopleBuffer(wallBuffer): class peopleBuffer(wallBuffer):
def post(self, *args, **kwargs): def post(self, *args, **kwargs):
user = self.get_post() user = self.get_post()
if "can_post" not in user: # retrieve data if not present in the object. if "can_post" not in user: # retrieve data if not present in the object.
user = self.session.vk.client.users.get(user_ids=user["id"], fields="can_post")[0] user = self.session.vk.client.users.get(user_ids=user["id"], fields="can_post")[0]
if user.get("can_post") == True: if user.get("can_post") == True:
user_str = self.session.get_user(user["id"], key="user1") user_str = self.session.get_user(user["id"], key="user1")
title = _("Post to {user1_nom}'s wall").format(**user_str) title = _("Post to {user1_nom}'s wall").format(**user_str)
p = presenters.createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createPostDialog(title=title, message="", text="")) p = presenters.createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createPostDialog(title=title, message="", text=""))
if hasattr(p, "text") or hasattr(p, "privacy"): if hasattr(p, "text") or hasattr(p, "privacy"):
post_arguments=dict(privacy=p.privacy, message=p.text, owner_id=user["id"]) post_arguments=dict(privacy=p.privacy, message=p.text, owner_id=user["id"])
attachments = [] attachments = []
if hasattr(p, "attachments"): if hasattr(p, "attachments"):
attachments = p.attachments attachments = p.attachments
call_threaded(pub.sendMessage, "post", parent_endpoint="wall", child_endpoint="post", from_buffer=self.name, attachments_list=attachments, post_arguments=post_arguments) call_threaded(pub.sendMessage, "post", parent_endpoint="wall", child_endpoint="post", from_buffer=self.name, attachments_list=attachments, post_arguments=post_arguments)
def create_tab(self, parent): def create_tab(self, parent):
self.tab = people.peopleTab(parent) self.tab = people.peopleTab(parent)
self.connect_events() self.connect_events()
self.tab.name = self.name self.tab.name = self.name
if hasattr(self, "can_post") and self.can_post == False and hasattr(self.tab, "post"): if hasattr(self, "can_post") and self.can_post == False and hasattr(self.tab, "post"):
self.tab.post.Enable(False) self.tab.post.Enable(False)
def connect_events(self): def connect_events(self):
super(peopleBuffer, self).connect_events() super(peopleBuffer, self).connect_events()
widgetUtils.connect_event(self.tab.new_chat, widgetUtils.BUTTON_PRESSED, self.new_chat) widgetUtils.connect_event(self.tab.new_chat, widgetUtils.BUTTON_PRESSED, self.new_chat)
def new_chat(self, *args, **kwargs): def new_chat(self, *args, **kwargs):
user = self.get_post() user = self.get_post()
if user == None: if user == None:
return return
user_id = user["id"] user_id = user["id"]
pub.sendMessage("new-chat", user_id=user_id) pub.sendMessage("new-chat", user_id=user_id)
def onFocus(self, *args, **kwargs): def onFocus(self, *args, **kwargs):
post = self.get_post() post = self.get_post()
if post == None: if post == None:
return return
if post.get("can_post") == True: if post.get("can_post") == True:
self.tab.post.Enable(True) self.tab.post.Enable(True)
else: else:
self.tab.post.Enable(False) self.tab.post.Enable(False)
# Check if we are allowed to contact people. this might be false for communitiy members. # Check if we are allowed to contact people. this might be false for communitiy members.
if post.get("can_write_private_message") == True: if post.get("can_write_private_message") == True:
self.tab.new_chat.Enable(True) self.tab.new_chat.Enable(True)
else: else:
self.tab.new_chat.Enable(False) self.tab.new_chat.Enable(False)
if ("last_seen" in post) == False: return if ("last_seen" in post) == False: return
original_date = arrow.get(post["last_seen"]["time"]) original_date = arrow.get(post["last_seen"]["time"])
now = arrow.now() now = arrow.now()
original_date.to(now.tzinfo) original_date.to(now.tzinfo)
diffdate = now-original_date diffdate = now-original_date
if diffdate.days == 0 and diffdate.seconds <= 360: if diffdate.days == 0 and diffdate.seconds <= 360:
online_status = _("Online") online_status = _("Online")
else: else:
# Translators: This is the date of last seen # Translators: This is the date of last seen
online_status = _("Last seen {0}").format(original_date.humanize(locale=languageHandler.curLang[:2]),) online_status = _("Last seen {0}").format(original_date.humanize(locale=languageHandler.curLang[:2]),)
self.tab.list.list.SetItem(self.tab.list.get_selected(), 1, online_status) self.tab.list.list.SetItem(self.tab.list.get_selected(), 1, online_status)
def open_timeline(self, *args, **kwargs): def open_timeline(self, *args, **kwargs):
user = self.get_post() user = self.get_post()
if user == None: if user == None:
return return
a = timeline.timelineDialog([self.session.get_user(user["id"])["user1_gen"]], show_selector=False) a = timeline.timelineDialog([self.session.get_user(user["id"])["user1_gen"]], show_selector=False)
if a.get_response() == widgetUtils.OK: if a.get_response() == widgetUtils.OK:
buffer_type = a.get_buffer_type() buffer_type = a.get_buffer_type()
user_id = user["id"] user_id = user["id"]
pub.sendMessage("create-timeline", user_id=user_id, buffer_type=buffer_type) pub.sendMessage("create-timeline", user_id=user_id, buffer_type=buffer_type)
def get_menu(self, *args, **kwargs): def get_menu(self, *args, **kwargs):
""" display menu for people buffers (friends and requests)""" """ display menu for people buffers (friends and requests)"""
# If this is an incoming requests buffer, there is a flag in the peopleMenu that shows a few new options. # If this is an incoming requests buffer, there is a flag in the peopleMenu that shows a few new options.
# So let's make sure we call it accordingly. # So let's make sure we call it accordingly.
if self.name == "friend_requests": if self.name == "friend_requests":
m = menus.peopleMenu(is_request=True) m = menus.peopleMenu(is_request=True)
# Connect the accept and decline methods from here. # Connect the accept and decline methods from here.
widgetUtils.connect_event(m, widgetUtils.MENU, self.accept_friendship, menuitem=m.accept) widgetUtils.connect_event(m, widgetUtils.MENU, self.accept_friendship, menuitem=m.accept)
widgetUtils.connect_event(m, widgetUtils.MENU, self.decline_friendship, menuitem=m.decline) widgetUtils.connect_event(m, widgetUtils.MENU, self.decline_friendship, menuitem=m.decline)
widgetUtils.connect_event(m, widgetUtils.MENU, self.keep_as_follower, menuitem=m.keep_as_follower) widgetUtils.connect_event(m, widgetUtils.MENU, self.keep_as_follower, menuitem=m.keep_as_follower)
elif self.name == "subscribers": elif self.name == "subscribers":
m = menus.peopleMenu(is_subscriber=True) m = menus.peopleMenu(is_subscriber=True)
widgetUtils.connect_event(m, widgetUtils.MENU, self.accept_friendship, menuitem=m.add) widgetUtils.connect_event(m, widgetUtils.MENU, self.accept_friendship, menuitem=m.add)
else: else:
m = menus.peopleMenu(is_request=False) m = menus.peopleMenu(is_request=False)
widgetUtils.connect_event(m, widgetUtils.MENU, self.decline_friendship, menuitem=m.decline) widgetUtils.connect_event(m, widgetUtils.MENU, self.decline_friendship, menuitem=m.decline)
widgetUtils.connect_event(m, widgetUtils.MENU, self.block_person, menuitem=m.block) widgetUtils.connect_event(m, widgetUtils.MENU, self.block_person, menuitem=m.block)
# It is not allowed to send messages to people who is not your friends, so let's disable it if we're in a pending or outgoing requests buffer. # It is not allowed to send messages to people who is not your friends, so let's disable it if we're in a pending or outgoing requests buffer.
if "friend_requests" in self.name: if "friend_requests" in self.name:
m.message.Enable(False) m.message.Enable(False)
widgetUtils.connect_event(m, widgetUtils.MENU, self.new_chat, menuitem=m.message) widgetUtils.connect_event(m, widgetUtils.MENU, self.new_chat, menuitem=m.message)
widgetUtils.connect_event(m, widgetUtils.MENU, self.open_timeline, menuitem=m.timeline) widgetUtils.connect_event(m, widgetUtils.MENU, self.open_timeline, menuitem=m.timeline)
widgetUtils.connect_event(m, widgetUtils.MENU, self.open_person_profile, menuitem=m.view_profile) widgetUtils.connect_event(m, widgetUtils.MENU, self.open_person_profile, menuitem=m.view_profile)
widgetUtils.connect_event(m, widgetUtils.MENU, self.open_in_browser, menuitem=m.open_in_browser) widgetUtils.connect_event(m, widgetUtils.MENU, self.open_in_browser, menuitem=m.open_in_browser)
return m return m
def open_post(self, *args, **kwargs): pass def open_post(self, *args, **kwargs): pass
def play_audio(self, *args, **kwargs): return False def play_audio(self, *args, **kwargs): return False
def pause_audio(self, *args, **kwargs): pass def pause_audio(self, *args, **kwargs): pass
def accept_friendship(self, *args, **kwargs): def accept_friendship(self, *args, **kwargs):
pass pass
def decline_friendship(self, *args, **kwargs): def decline_friendship(self, *args, **kwargs):
person = self.get_post() person = self.get_post()
if person == None: if person == None:
return return
user = self.session.get_user(person["id"]) user = self.session.get_user(person["id"])
question = commonMessages.remove_friend(user) question = commonMessages.remove_friend(user)
if question == widgetUtils.NO: if question == widgetUtils.NO:
return return
result = self.session.vk.client.friends.delete(user_id=person["id"]) result = self.session.vk.client.friends.delete(user_id=person["id"])
if "friend_deleted" in result: if "friend_deleted" in result:
msg = _("You've removed {user1_nom} from your friends.").format(**user,) msg = _("You've removed {user1_nom} from your friends.").format(**user,)
pub.sendMessage("notify", message=msg) pub.sendMessage("notify", message=msg)
self.session.db[self.name]["items"].pop(self.tab.list.get_selected()) self.session.db[self.name]["items"].pop(self.tab.list.get_selected())
self.tab.list.remove_item(self.tab.list.get_selected()) self.tab.list.remove_item(self.tab.list.get_selected())
def block_person(self, *args, **kwargs): def block_person(self, *args, **kwargs):
person = self.get_post() person = self.get_post()
if person == None: if person == None:
return return
user = self.session.get_user(person["id"]) user = self.session.get_user(person["id"])
question = commonMessages.block_person(user) question = commonMessages.block_person(user)
if question == widgetUtils.NO: if question == widgetUtils.NO:
return return
result = self.session.vk.client.account.ban(owner_id=person["id"]) result = self.session.vk.client.account.ban(owner_id=person["id"])
if result == 1: if result == 1:
msg = _("You've blocked {user1_nom} from your friends.").format(**user,) msg = _("You've blocked {user1_nom} from your friends.").format(**user,)
pub.sendMessage("notify", message=msg) pub.sendMessage("notify", message=msg)
self.session.db[self.name]["items"].pop(self.tab.list.get_selected()) self.session.db[self.name]["items"].pop(self.tab.list.get_selected())
self.tab.list.remove_item(self.tab.list.get_selected()) self.tab.list.remove_item(self.tab.list.get_selected())
def keep_as_follower(self, *args, **kwargs): def keep_as_follower(self, *args, **kwargs):
pass pass
def add_person(self, person): def add_person(self, person):
# This tracks if the user already exists here, in such case we just will update the last_seen variable # This tracks if the user already exists here, in such case we just will update the last_seen variable
existing = False existing = False
for i in self.session.db[self.name]["items"]: for i in self.session.db[self.name]["items"]:
if person["id"] == i["id"]: if person["id"] == i["id"]:
existing = True existing = True
i["last_seen"]["time"] = person["last_seen"]["time"] i["last_seen"]["time"] = person["last_seen"]["time"]
break break
# Add the new user to the buffer just if it does not exists previously. # Add the new user to the buffer just if it does not exists previously.
if existing == False: if existing == False:
# Ensure the user won't loose the focus after the new item is added. # Ensure the user won't loose the focus after the new item is added.
focused_item = self.tab.list.get_selected()+1 focused_item = self.tab.list.get_selected()+1
self.session.db[self.name]["items"].insert(0, person) self.session.db[self.name]["items"].insert(0, person)
self.insert(person, True) self.insert(person, True)
# Selects back the previously focused item. # Selects back the previously focused item.
self.tab.list.select_item(focused_item) self.tab.list.select_item(focused_item)
def remove_person(self, user_id): def remove_person(self, user_id):
# Make sure the user is present in the buffer, otherwise don't attempt to remove a None Value from the list. # Make sure the user is present in the buffer, otherwise don't attempt to remove a None Value from the list.
user = None user = None
focused_user = self.get_post() focused_user = self.get_post()
for i in self.session.db[self.name]["items"]: for i in self.session.db[self.name]["items"]:
if i["id"] == user_id: if i["id"] == user_id:
user = i user = i
break break
if user != None: if user != None:
person_index = self.session.db[self.name]["items"].index(user) person_index = self.session.db[self.name]["items"].index(user)
focused_item = self.tab.list.get_selected() focused_item = self.tab.list.get_selected()
self.session.db[self.name]["items"].pop(person_index) self.session.db[self.name]["items"].pop(person_index)
self.tab.list.remove_item(person_index) self.tab.list.remove_item(person_index)
if user != focused_user: if user != focused_user:
# Let's find the position of the previously focused user. # Let's find the position of the previously focused user.
focus = None focus = None
for i in range(0, len(self.session.db[self.name]["items"])): for i in range(0, len(self.session.db[self.name]["items"])):
if focused_user["id"] == self.session.db[self.name]["items"][i]["id"]: if focused_user["id"] == self.session.db[self.name]["items"][i]["id"]:
self.tab.list.select_item(i) self.tab.list.select_item(i)
return return
elif user == focused_user and person_index < self.tab.list.get_count(): elif user == focused_user and person_index < self.tab.list.get_count():
self.tab.list.select_item(person_index) self.tab.list.select_item(person_index)
else: else:
self.tab.list.select_item(self.tab.list.get_count()-1) self.tab.list.select_item(self.tab.list.get_count()-1)
def get_friend(self, user_id): def get_friend(self, user_id):
for i in self.session.db["friends_"]["items"]: for i in self.session.db["friends_"]["items"]:
if i["id"] == user_id: if i["id"] == user_id:
return i return i
log.exception("Getting user manually...") log.exception("Getting user manually...")
user = self.session.vk.client.users.get(user_ids=event.user_id, fields="last_seen")[0] user = self.session.vk.client.users.get(user_ids=event.user_id, fields="last_seen")[0]
return user return user
def update_online(self): def update_online(self):
online_users = self.session.vk.client.friends.getOnline() online_users = self.session.vk.client.friends.getOnline()
now = time.time() now = time.time()
for i in self.session.db[self.name]["items"]: for i in self.session.db[self.name]["items"]:
if i["id"] in online_users: if i["id"] in online_users:
i["last_seen"]["time"] = now i["last_seen"]["time"] = now
else: else:
log.exception("Removing an user from online status manually... %r" % (i)) log.exception("Removing an user from online status manually... %r" % (i))
self.remove_person(i["id"]) self.remove_person(i["id"])
def open_in_browser(self, *args, **kwargs): def open_in_browser(self, *args, **kwargs):
post = self.get_post() post = self.get_post()
if post == None: if post == None:
return return
url = "https://vk.com/id{user_id}".format(user_id=post["id"]) url = "https://vk.com/id{user_id}".format(user_id=post["id"])
webbrowser.open_new_tab(url) webbrowser.open_new_tab(url)

View File

@ -12,114 +12,114 @@ from .wall import wallBuffer
log = logging.getLogger("controller.buffers.video") log = logging.getLogger("controller.buffers.video")
class videoBuffer(wallBuffer): class videoBuffer(wallBuffer):
""" This buffer represents video elements, and it can be used for showing videos for the logged user or someone else.""" """ This buffer represents video elements, and it can be used for showing videos for the logged user or someone else."""
def create_tab(self, parent): def create_tab(self, parent):
self.tab = video.videoTab(parent) self.tab = video.videoTab(parent)
self.connect_events() self.connect_events()
self.tab.name = self.name self.tab.name = self.name
if hasattr(self, "can_post") and self.can_post == False and hasattr(self.tab, "post"): if hasattr(self, "can_post") and self.can_post == False and hasattr(self.tab, "post"):
self.tab.post.Enable(False) self.tab.post.Enable(False)
def connect_events(self): def connect_events(self):
widgetUtils.connect_event(self.tab.play, widgetUtils.BUTTON_PRESSED, self.play_audio) widgetUtils.connect_event(self.tab.play, widgetUtils.BUTTON_PRESSED, self.play_audio)
super(videoBuffer, self).connect_events() super(videoBuffer, self).connect_events()
def play_audio(self, *args, **kwargs): def play_audio(self, *args, **kwargs):
""" Due to inheritance this method should be called play_audio, but play the currently focused video. """ Due to inheritance this method should be called play_audio, but play the currently focused video.
Opens a webbrowser pointing to the video's URL.""" Opens a webbrowser pointing to the video's URL."""
selected = self.tab.list.get_selected() selected = self.tab.list.get_selected()
if self.tab.list.get_count() == 0: if self.tab.list.get_count() == 0:
return return
if selected == -1: if selected == -1:
selected = 0 selected = 0
output.speak(_("Opening video in webbrowser...")) output.speak(_("Opening video in webbrowser..."))
webbrowser.open_new_tab(self.session.db[self.name]["items"][selected]["player"]) webbrowser.open_new_tab(self.session.db[self.name]["items"][selected]["player"])
# print self.session.db[self.name]["items"][selected] # print self.session.db[self.name]["items"][selected]
return True return True
def open_post(self, *args, **kwargs): def open_post(self, *args, **kwargs):
pass pass
def remove_buffer(self, mandatory=False): def remove_buffer(self, mandatory=False):
if "me_video" == self.name: if "me_video" == self.name:
output.speak(_("This buffer can't be deleted")) output.speak(_("This buffer can't be deleted"))
return False return False
else: else:
if mandatory == False: if mandatory == False:
dlg = commonMessages.remove_buffer() dlg = commonMessages.remove_buffer()
else: else:
dlg = widgetUtils.YES dlg = widgetUtils.YES
if dlg == widgetUtils.YES: if dlg == widgetUtils.YES:
self.session.db.pop(self.name) self.session.db.pop(self.name)
return True return True
else: else:
return False return False
def get_more_items(self, *args, **kwargs): def get_more_items(self, *args, **kwargs):
# Translators: Some buffers can't use the get previous item feature due to API limitations. # Translators: Some buffers can't use the get previous item feature due to API limitations.
output.speak(_("This buffer doesn't support getting more items.")) output.speak(_("This buffer doesn't support getting more items."))
def onFocus(self, event, *args, **kwargs): def onFocus(self, event, *args, **kwargs):
event.Skip() event.Skip()
def add_to_library(self, *args, **kwargs): def add_to_library(self, *args, **kwargs):
post = self.get_post() post = self.get_post()
if post == None: if post == None:
return return
args = {} args = {}
args["video_id"] = post["id"] args["video_id"] = post["id"]
if "album_id" in post: if "album_id" in post:
args["album_id"] = post["album_id"] args["album_id"] = post["album_id"]
args["owner_id"] = post["owner_id"] args["owner_id"] = post["owner_id"]
video = self.session.vk.client.video.add(**args) video = self.session.vk.client.video.add(**args)
if video != None and int(video) > 21: if video != None and int(video) > 21:
output.speak(_("Video added to your library")) output.speak(_("Video added to your library"))
def remove_from_library(self, *args, **kwargs): def remove_from_library(self, *args, **kwargs):
post = self.get_post() post = self.get_post()
if post == None: if post == None:
return return
args = {} args = {}
args["video_id"] = post["id"] args["video_id"] = post["id"]
args["owner_id"] = self.session.user_id args["owner_id"] = self.session.user_id
result = self.session.vk.client.video.delete(**args) result = self.session.vk.client.video.delete(**args)
if int(result) == 1: if int(result) == 1:
output.speak(_("Removed video from library")) output.speak(_("Removed video from library"))
self.tab.list.remove_item(self.tab.list.get_selected()) self.tab.list.remove_item(self.tab.list.get_selected())
def move_to_album(self, *args, **kwargs): def move_to_album(self, *args, **kwargs):
if len(self.session.video_albums) == 0: if len(self.session.video_albums) == 0:
return commonMessages.no_video_albums() return commonMessages.no_video_albums()
post= self.get_post() post= self.get_post()
if post == None: if post == None:
return return
album = selector.album(_("Select the album where you want to move this video"), self.session, "video_albums") album = selector.album(_("Select the album where you want to move this video"), self.session, "video_albums")
if album.item == None: return if album.item == None: return
id = post["id"] id = post["id"]
response = self.session.vk.client.video.addToAlbum(album_ids=album.item, video_id=id, target_id=self.session.user_id, owner_id=self.get_post()["owner_id"]) response = self.session.vk.client.video.addToAlbum(album_ids=album.item, video_id=id, target_id=self.session.user_id, owner_id=self.get_post()["owner_id"])
if response == 1: if response == 1:
# Translators: Used when the user has moved an video to an album. # Translators: Used when the user has moved an video to an album.
output.speak(_("Moved")) output.speak(_("Moved"))
def get_menu(self): def get_menu(self):
""" We'll use the same menu that is used for audio items, as the options are exactly the same""" """ We'll use the same menu that is used for audio items, as the options are exactly the same"""
p = self.get_post() p = self.get_post()
if p == None: if p == None:
return return
m = menus.audioMenu() m = menus.audioMenu()
widgetUtils.connect_event(m, widgetUtils.MENU, self.move_to_album, menuitem=m.move) widgetUtils.connect_event(m, widgetUtils.MENU, self.move_to_album, menuitem=m.move)
# if owner_id is the current user, the audio is added to the user's audios. # if owner_id is the current user, the audio is added to the user's audios.
if p["owner_id"] == self.session.user_id: if p["owner_id"] == self.session.user_id:
m.library.SetItemLabel(_("&Remove")) m.library.SetItemLabel(_("&Remove"))
widgetUtils.connect_event(m, widgetUtils.MENU, self.remove_from_library, menuitem=m.library) widgetUtils.connect_event(m, widgetUtils.MENU, self.remove_from_library, menuitem=m.library)
else: else:
widgetUtils.connect_event(m, widgetUtils.MENU, self.add_to_library, menuitem=m.library) widgetUtils.connect_event(m, widgetUtils.MENU, self.add_to_library, menuitem=m.library)
return m return m
def open_in_browser(self, *args, **kwargs): def open_in_browser(self, *args, **kwargs):
post = self.get_post() post = self.get_post()
if post == None: if post == None:
return return
url = "https://vk.com/video{user_id}_{video_id}".format(user_id=post["owner_id"], video_id=post["id"]) url = "https://vk.com/video{user_id}_{video_id}".format(user_id=post["owner_id"], video_id=post["id"])
webbrowser.open_new_tab(url) webbrowser.open_new_tab(url)

View File

@ -10,21 +10,21 @@ log = logging.getLogger("controller.buffers")
class videoAlbumBuffer(videoBuffer): class videoAlbumBuffer(videoBuffer):
def create_tab(self, parent): def create_tab(self, parent):
self.tab = video.videoAlbumTab(parent) self.tab = video.videoAlbumTab(parent)
self.tab.play.Enable(False) self.tab.play.Enable(False)
self.connect_events() self.connect_events()
self.tab.name = self.name self.tab.name = self.name
if hasattr(self, "can_post") and self.can_post == False and hasattr(self.tab, "post"): if hasattr(self, "can_post") and self.can_post == False and hasattr(self.tab, "post"):
self.tab.post.Enable(False) self.tab.post.Enable(False)
def connect_events(self): def connect_events(self):
super(videoAlbumBuffer, self).connect_events() super(videoAlbumBuffer, self).connect_events()
widgetUtils.connect_event(self.tab.load, widgetUtils.BUTTON_PRESSED, self.load_album) widgetUtils.connect_event(self.tab.load, widgetUtils.BUTTON_PRESSED, self.load_album)
def load_album(self, *args, **kwargs): def load_album(self, *args, **kwargs):
output.speak(_("Loading album...")) output.speak(_("Loading album..."))
self.can_get_items = True self.can_get_items = True
self.tab.load.Enable(False) self.tab.load.Enable(False)
wx.CallAfter(self.get_items) wx.CallAfter(self.get_items)
self.tab.play.Enable(True) self.tab.play.Enable(True)

View File

@ -17,88 +17,88 @@ from .home import homeBuffer
log = logging.getLogger("controller.buffers.wall") log = logging.getLogger("controller.buffers.wall")
class wallBuffer(homeBuffer): class wallBuffer(homeBuffer):
""" This buffer represents an user's wall. It may be used either for the current user or someone else.""" """ This buffer represents an user's wall. It may be used either for the current user or someone else."""
def get_items(self, show_nextpage=False): def get_items(self, show_nextpage=False):
""" Update buffer with newest items or get older items in the buffer.""" """ Update buffer with newest items or get older items in the buffer."""
if self.can_get_items == False: return if self.can_get_items == False: return
retrieved = True retrieved = True
try: try:
num = getattr(self.session, "get_page")(show_nextpage=show_nextpage, name=self.name, *self.args, **self.kwargs) num = getattr(self.session, "get_page")(show_nextpage=show_nextpage, name=self.name, *self.args, **self.kwargs)
except VkApiError as err: except VkApiError as err:
log.error("Error {0}: {1}".format(err.code, err.error)) log.error("Error {0}: {1}".format(err.code, err.error))
retrieved = err.code retrieved = err.code
return retrieved return retrieved
except: except:
log.exception("Connection error when updating buffer %s. Will try again in 2 minutes" % (self.name,)) log.exception("Connection error when updating buffer %s. Will try again in 2 minutes" % (self.name,))
return False return False
if not hasattr(self, "tab"): if not hasattr(self, "tab"):
# Create GUI associated to this buffer. # Create GUI associated to this buffer.
self.create_tab(self.parent) self.create_tab(self.parent)
# Add name to the new control so we could look for it when needed. # Add name to the new control so we could look for it when needed.
self.tab.name = self.name self.tab.name = self.name
if show_nextpage == False: if show_nextpage == False:
if self.tab.list.get_count() > 0 and num > 0: if self.tab.list.get_count() > 0 and num > 0:
v = [i for i in self.session.db[self.name]["items"][:num]] v = [i for i in self.session.db[self.name]["items"][:num]]
v.reverse() v.reverse()
[wx.CallAfter(self.insert, i, True) for i in v] [wx.CallAfter(self.insert, i, True) for i in v]
else: else:
[wx.CallAfter(self.insert, i) for i in self.session.db[self.name]["items"][:num]] [wx.CallAfter(self.insert, i) for i in self.session.db[self.name]["items"][:num]]
else: else:
if num > 0: if num > 0:
[wx.CallAfter(self.insert, i, False) for i in self.session.db[self.name]["items"][-num:]] [wx.CallAfter(self.insert, i, False) for i in self.session.db[self.name]["items"][-num:]]
return retrieved return retrieved
def remove_buffer(self, mandatory=False): def remove_buffer(self, mandatory=False):
""" Remove buffer if the current buffer is not the logged user's wall.""" """ Remove buffer if the current buffer is not the logged user's wall."""
if "me_feed" == self.name: if "me_feed" == self.name:
output.speak(_("This buffer can't be deleted")) output.speak(_("This buffer can't be deleted"))
return False return False
else: else:
if mandatory == False: if mandatory == False:
dlg = commonMessages.remove_buffer() dlg = commonMessages.remove_buffer()
else: else:
dlg = widgetUtils.YES dlg = widgetUtils.YES
if dlg == widgetUtils.YES: if dlg == widgetUtils.YES:
self.session.db.pop(self.name) self.session.db.pop(self.name)
return True return True
else: else:
return False return False
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(wallBuffer, self).__init__(*args, **kwargs) super(wallBuffer, self).__init__(*args, **kwargs)
self.user_key = "from_id" self.user_key = "from_id"
self.post_key = "id" self.post_key = "id"
self.can_post = True self.can_post = True
self.can_write_private_message = True self.can_write_private_message = True
# if this is an user timeline we must check permissions to hide buttons when needed. # if this is an user timeline we must check permissions to hide buttons when needed.
if "owner_id" in self.kwargs and self.kwargs["owner_id"] > 0 and "feed" in self.name: if "owner_id" in self.kwargs and self.kwargs["owner_id"] > 0 and "feed" in self.name:
permissions = self.session.vk.client.users.get(user_ids=self.kwargs["owner_id"], fields="can_post, can_see_all_posts, can_write_private_message") permissions = self.session.vk.client.users.get(user_ids=self.kwargs["owner_id"], fields="can_post, can_see_all_posts, can_write_private_message")
self.can_post = permissions[0]["can_post"] self.can_post = permissions[0]["can_post"]
self.can_see_all_posts = permissions[0]["can_see_all_posts"] self.can_see_all_posts = permissions[0]["can_see_all_posts"]
self.can_write_private_message = permissions[0]["can_write_private_message"] self.can_write_private_message = permissions[0]["can_write_private_message"]
log.debug("Checked permissions on buffer {0}, permissions were {1}".format(self.name, permissions)) log.debug("Checked permissions on buffer {0}, permissions were {1}".format(self.name, permissions))
def post(self, *args, **kwargs): def post(self, *args, **kwargs):
""" Create a post in the wall for the specified user """ Create a post in the wall for the specified user
This process is handled in two parts. This is the first part, where the GUI is created and user can send the post. This process is handled in two parts. This is the first part, where the GUI is created and user can send the post.
During the second part (threaded), the post will be sent to the API.""" During the second part (threaded), the post will be sent to the API."""
if "owner_id" not in self.kwargs: if "owner_id" not in self.kwargs:
return super(wallBuffer, self).post() return super(wallBuffer, self).post()
owner_id = self.kwargs["owner_id"] owner_id = self.kwargs["owner_id"]
user = self.session.get_user(owner_id, key="user1") user = self.session.get_user(owner_id, key="user1")
title = _("Post to {user1_nom}'s wall").format(**user) title = _("Post to {user1_nom}'s wall").format(**user)
p = presenters.createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createPostDialog(title=title, message="", text="")) p = presenters.createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createPostDialog(title=title, message="", text=""))
if hasattr(p, "text") or hasattr(p, "privacy"): if hasattr(p, "text") or hasattr(p, "privacy"):
post_arguments=dict(privacy=p.privacy, message=p.text, owner_id=owner_id) post_arguments=dict(privacy=p.privacy, message=p.text, owner_id=owner_id)
attachments = [] attachments = []
if hasattr(p, "attachments"): if hasattr(p, "attachments"):
attachments = p.attachments attachments = p.attachments
call_threaded(pub.sendMessage, "post", parent_endpoint="wall", child_endpoint="post", from_buffer=self.name, attachments_list=attachments, post_arguments=post_arguments) call_threaded(pub.sendMessage, "post", parent_endpoint="wall", child_endpoint="post", from_buffer=self.name, attachments_list=attachments, post_arguments=post_arguments)
def open_in_browser(self, *args, **kwargs): def open_in_browser(self, *args, **kwargs):
post = self.get_post() post = self.get_post()
if post == None: if post == None:
return return
url = "https://vk.com/wall{user_id}_{post_id}".format(user_id=post["from_id"], post_id=post["id"]) url = "https://vk.com/wall{user_id}_{post_id}".format(user_id=post["from_id"], post_id=post["id"])
webbrowser.open_new_tab(url) webbrowser.open_new_tab(url)

File diff suppressed because it is too large Load Diff

View File

@ -4,24 +4,23 @@ from wxUI.dialogs import selector as gui
class album(object): class album(object):
def __init__(self, title, session, album_type="audio_albums"): def __init__(self, title, session, album_type="audio_albums"):
super(album, self).__init__() super(album, self).__init__()
self.item = None self.item = None
self.session = session self.session = session
if not hasattr(self.session, album_type): if not hasattr(self.session, album_type):
return return
self.albums = getattr(self.session, album_type) self.albums = getattr(self.session, album_type)
self.dialog = gui.selectAlbum(title=title, albums=self.get_albums_as_string()) self.dialog = gui.selectAlbum(title=title, albums=self.get_albums_as_string())
response = self.dialog.get_response() response = self.dialog.get_response()
if response == widgetUtils.OK: if response == widgetUtils.OK:
self.item = self.search_item(self.dialog.get_string()) self.item = self.search_item(self.dialog.get_string())
def get_albums_as_string(self): def get_albums_as_string(self):
return [i["title"] for i in self.albums] return [i["title"] for i in self.albums]
def search_item(self, item):
for i in self.albums:
if i["title"] == item:
return i["id"]
return None
def search_item(self, item):
for i in self.albums:
if i["title"] == item:
return i["id"]
return None

View File

@ -3,4 +3,4 @@ from __future__ import unicode_literals
from . import spellchecker from . import spellchecker
import platform import platform
if platform.system() == "Windows": if platform.system() == "Windows":
from .wx_ui import * from .wx_ui import *

View File

@ -15,62 +15,62 @@ from enchant import tokenize
log = logging.getLogger("extra.SpellChecker.spellChecker") log = logging.getLogger("extra.SpellChecker.spellChecker")
class spellChecker(object): class spellChecker(object):
def __init__(self, text): def __init__(self, text):
super(spellChecker, self).__init__() super(spellChecker, self).__init__()
self.active = True self.active = True
try: try:
if config.app["app-settings"]["language"] == "system": if config.app["app-settings"]["language"] == "system":
log.debug("Using the system language") log.debug("Using the system language")
self.dict = enchant.DictWithPWL(languageHandler.curLang[:2], os.path.join(paths.config_path(), "wordlist.dict")) self.dict = enchant.DictWithPWL(languageHandler.curLang[:2], os.path.join(paths.config_path(), "wordlist.dict"))
else: else:
log.debug("Using language: %s" % (languageHandler.getLanguage(),)) log.debug("Using language: %s" % (languageHandler.getLanguage(),))
self.dict = enchant.DictWithPWL(languageHandler.getLanguage()[:2], os.path.join(paths.config_path(), "wordlist.dict")) self.dict = enchant.DictWithPWL(languageHandler.getLanguage()[:2], os.path.join(paths.config_path(), "wordlist.dict"))
except DictNotFoundError: except DictNotFoundError:
log.exception("Dictionary for language %s not found." % (languageHandler.getLanguage(),)) log.exception("Dictionary for language %s not found." % (languageHandler.getLanguage(),))
wx_ui.dict_not_found_error() wx_ui.dict_not_found_error()
self.active = False self.active = False
self.checker = SpellChecker(self.dict, filters=[twitterFilter.TwitterFilter, tokenize.EmailFilter, tokenize.URLFilter]) self.checker = SpellChecker(self.dict, filters=[twitterFilter.TwitterFilter, tokenize.EmailFilter, tokenize.URLFilter])
self.checker.set_text(text) self.checker.set_text(text)
if self.active == True: if self.active == True:
log.debug("Creating dialog...") log.debug("Creating dialog...")
self.dialog = wx_ui.spellCheckerDialog() self.dialog = wx_ui.spellCheckerDialog()
widgetUtils.connect_event(self.dialog.ignore, widgetUtils.BUTTON_PRESSED, self.ignore) widgetUtils.connect_event(self.dialog.ignore, widgetUtils.BUTTON_PRESSED, self.ignore)
widgetUtils.connect_event(self.dialog.ignoreAll, widgetUtils.BUTTON_PRESSED, self.ignoreAll) widgetUtils.connect_event(self.dialog.ignoreAll, widgetUtils.BUTTON_PRESSED, self.ignoreAll)
widgetUtils.connect_event(self.dialog.replace, widgetUtils.BUTTON_PRESSED, self.replace) widgetUtils.connect_event(self.dialog.replace, widgetUtils.BUTTON_PRESSED, self.replace)
widgetUtils.connect_event(self.dialog.replaceAll, widgetUtils.BUTTON_PRESSED, self.replaceAll) widgetUtils.connect_event(self.dialog.replaceAll, widgetUtils.BUTTON_PRESSED, self.replaceAll)
widgetUtils.connect_event(self.dialog.add, widgetUtils.BUTTON_PRESSED, self.add) widgetUtils.connect_event(self.dialog.add, widgetUtils.BUTTON_PRESSED, self.add)
self.check() self.check()
self.dialog.get_response() self.dialog.get_response()
self.fixed_text = self.checker.get_text() self.fixed_text = self.checker.get_text()
def check(self): def check(self):
try: try:
next(self.checker) next(self.checker)
textToSay = _(u"Misspelled word: %s") % (self.checker.word,) textToSay = _(u"Misspelled word: %s") % (self.checker.word,)
context = u"... %s %s %s" % (self.checker.leading_context(10), self.checker.word, self.checker.trailing_context(10)) context = u"... %s %s %s" % (self.checker.leading_context(10), self.checker.word, self.checker.trailing_context(10))
self.dialog.set_title(textToSay) self.dialog.set_title(textToSay)
output.speak(textToSay) output.speak(textToSay)
self.dialog.set_word_and_suggestions(word=self.checker.word, context=context, suggestions=self.checker.suggest()) self.dialog.set_word_and_suggestions(word=self.checker.word, context=context, suggestions=self.checker.suggest())
except StopIteration: except StopIteration:
log.debug("Process finished.") log.debug("Process finished.")
wx_ui.finished() wx_ui.finished()
self.dialog.Destroy() self.dialog.Destroy()
def ignore(self, ev): def ignore(self, ev):
self.check() self.check()
def ignoreAll(self, ev): def ignoreAll(self, ev):
self.checker.ignore_always(word=self.checker.word) self.checker.ignore_always(word=self.checker.word)
self.check() self.check()
def replace(self, ev): def replace(self, ev):
self.checker.replace(self.dialog.get_selected_suggestion()) self.checker.replace(self.dialog.get_selected_suggestion())
self.check() self.check()
def replaceAll(self, ev): def replaceAll(self, ev):
self.checker.replace_always(self.dialog.get_selected_suggestion()) self.checker.replace_always(self.dialog.get_selected_suggestion())
self.check() self.check()
def add(self, ev): def add(self, ev):
self.checker.add() self.checker.add()
self.check() self.check()

View File

@ -21,63 +21,63 @@ import wx
import application import application
class spellCheckerDialog(wx.Dialog): class spellCheckerDialog(wx.Dialog):
def __init__(self): def __init__(self):
super(spellCheckerDialog, self).__init__(None, 1) super(spellCheckerDialog, self).__init__(None, 1)
panel = wx.Panel(self) panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
word = wx.StaticText(panel, -1, _(u"Misspelled word")) word = wx.StaticText(panel, -1, _(u"Misspelled word"))
self.word = wx.TextCtrl(panel, -1) self.word = wx.TextCtrl(panel, -1)
wordBox = wx.BoxSizer(wx.HORIZONTAL) wordBox = wx.BoxSizer(wx.HORIZONTAL)
wordBox.Add(word, 0, wx.ALL, 5) wordBox.Add(word, 0, wx.ALL, 5)
wordBox.Add(self.word, 0, wx.ALL, 5) wordBox.Add(self.word, 0, wx.ALL, 5)
context = wx.StaticText(panel, -1, _(u"Context")) context = wx.StaticText(panel, -1, _(u"Context"))
self.context = wx.TextCtrl(panel, -1) self.context = wx.TextCtrl(panel, -1)
contextBox = wx.BoxSizer(wx.HORIZONTAL) contextBox = wx.BoxSizer(wx.HORIZONTAL)
contextBox.Add(context, 0, wx.ALL, 5) contextBox.Add(context, 0, wx.ALL, 5)
contextBox.Add(self.context, 0, wx.ALL, 5) contextBox.Add(self.context, 0, wx.ALL, 5)
suggest = wx.StaticText(panel, -1, _(u"Suggestions")) suggest = wx.StaticText(panel, -1, _(u"Suggestions"))
self.suggestions = wx.ListBox(panel, -1, choices=[], style=wx.LB_SINGLE) self.suggestions = wx.ListBox(panel, -1, choices=[], style=wx.LB_SINGLE)
suggestionsBox = wx.BoxSizer(wx.HORIZONTAL) suggestionsBox = wx.BoxSizer(wx.HORIZONTAL)
suggestionsBox.Add(suggest, 0, wx.ALL, 5) suggestionsBox.Add(suggest, 0, wx.ALL, 5)
suggestionsBox.Add(self.suggestions, 0, wx.ALL, 5) suggestionsBox.Add(self.suggestions, 0, wx.ALL, 5)
self.ignore = wx.Button(panel, -1, _(u"&Ignore")) self.ignore = wx.Button(panel, -1, _(u"&Ignore"))
self.ignoreAll = wx.Button(panel, -1, _(u"I&gnore all")) self.ignoreAll = wx.Button(panel, -1, _(u"I&gnore all"))
self.replace = wx.Button(panel, -1, _(u"&Replace")) self.replace = wx.Button(panel, -1, _(u"&Replace"))
self.replaceAll = wx.Button(panel, -1, _(u"R&eplace all")) self.replaceAll = wx.Button(panel, -1, _(u"R&eplace all"))
self.add = wx.Button(panel, -1, _(u"&Add to personal dictionary")) self.add = wx.Button(panel, -1, _(u"&Add to personal dictionary"))
close = wx.Button(panel, wx.ID_CANCEL) close = wx.Button(panel, wx.ID_CANCEL)
btnBox = wx.BoxSizer(wx.HORIZONTAL) btnBox = wx.BoxSizer(wx.HORIZONTAL)
btnBox.Add(self.ignore, 0, wx.ALL, 5) btnBox.Add(self.ignore, 0, wx.ALL, 5)
btnBox.Add(self.ignoreAll, 0, wx.ALL, 5) btnBox.Add(self.ignoreAll, 0, wx.ALL, 5)
btnBox.Add(self.replace, 0, wx.ALL, 5) btnBox.Add(self.replace, 0, wx.ALL, 5)
btnBox.Add(self.replaceAll, 0, wx.ALL, 5) btnBox.Add(self.replaceAll, 0, wx.ALL, 5)
btnBox.Add(self.add, 0, wx.ALL, 5) btnBox.Add(self.add, 0, wx.ALL, 5)
btnBox.Add(close, 0, wx.ALL, 5) btnBox.Add(close, 0, wx.ALL, 5)
sizer.Add(wordBox, 0, wx.ALL, 5) sizer.Add(wordBox, 0, wx.ALL, 5)
sizer.Add(contextBox, 0, wx.ALL, 5) sizer.Add(contextBox, 0, wx.ALL, 5)
sizer.Add(suggestionsBox, 0, wx.ALL, 5) sizer.Add(suggestionsBox, 0, wx.ALL, 5)
sizer.Add(btnBox, 0, wx.ALL, 5) sizer.Add(btnBox, 0, wx.ALL, 5)
panel.SetSizer(sizer) panel.SetSizer(sizer)
self.SetClientSize(sizer.CalcMin()) self.SetClientSize(sizer.CalcMin())
def get_response(self): def get_response(self):
return self.ShowModal() return self.ShowModal()
def set_title(self, title): def set_title(self, title):
return self.SetTitle(title) return self.SetTitle(title)
def set_word_and_suggestions(self, word, context, suggestions): def set_word_and_suggestions(self, word, context, suggestions):
self.word.SetValue(word) self.word.SetValue(word)
self.context.ChangeValue(context) self.context.ChangeValue(context)
self.suggestions.Set(suggestions) self.suggestions.Set(suggestions)
self.suggestions.SetFocus() self.suggestions.SetFocus()
def get_selected_suggestion(self): def get_selected_suggestion(self):
return self.suggestions.GetStringSelection() return self.suggestions.GetStringSelection()
def dict_not_found_error(): def dict_not_found_error():
wx.MessageDialog(None, _(u"An error has occurred. There are no dictionaries available for the selected language in {0}").format(application.name,), _(u"Error"), wx.ICON_ERROR).ShowModal() wx.MessageDialog(None, _(u"An error has occurred. There are no dictionaries available for the selected language in {0}").format(application.name,), _(u"Error"), wx.ICON_ERROR).ShowModal()
def finished(): def finished():
wx.MessageDialog(None, _(u"Spell check complete."), application.name, style=wx.OK).ShowModal() wx.MessageDialog(None, _(u"Spell check complete."), application.name, style=wx.OK).ShowModal()

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import platform import platform
if platform.system() == "Windows": if platform.system() == "Windows":
from . import wx_ui as gui from . import wx_ui as gui
from . import translator from . import translator

View File

@ -9,12 +9,12 @@ log = logging.getLogger("extras.translator")
t = None t = None
def translate(text="", target="en"): def translate(text="", target="en"):
global t global t
log.debug("Received translation request for language %s, text=%s" % (target, text)) log.debug("Received translation request for language %s, text=%s" % (target, text))
if t == None: if t == None:
t = Translator() t = Translator()
vars = dict(text=text, dest=target) vars = dict(text=text, dest=target)
return t.translate(**vars).text return t.translate(**vars).text
supported_langs = None supported_langs = None
@ -113,4 +113,4 @@ languages = {
} }
def available_languages(): def available_languages():
return dict(sorted(languages.items(), key=lambda x: x[1])) return dict(sorted(languages.items(), key=lambda x: x[1]))

View File

@ -21,25 +21,25 @@ import wx
from widgetUtils import BaseDialog from widgetUtils import BaseDialog
class translateDialog(BaseDialog): class translateDialog(BaseDialog):
def __init__(self): def __init__(self):
languages = [] languages = []
language_dict = translator.available_languages() language_dict = translator.available_languages()
for k in language_dict: for k in language_dict:
languages.append(language_dict[k]) languages.append(language_dict[k])
super(translateDialog, self).__init__(None, -1, title=_(u"Translate message")) super(translateDialog, self).__init__(None, -1, title=_(u"Translate message"))
panel = wx.Panel(self) panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
staticDest = wx.StaticText(panel, -1, _(u"Target language")) staticDest = wx.StaticText(panel, -1, _(u"Target language"))
self.dest_lang = wx.ComboBox(panel, -1, choices=languages, style = wx.CB_READONLY) self.dest_lang = wx.ComboBox(panel, -1, choices=languages, style = wx.CB_READONLY)
self.dest_lang.SetFocus() self.dest_lang.SetFocus()
self.dest_lang.SetSelection(0) self.dest_lang.SetSelection(0)
listSizer = wx.BoxSizer(wx.HORIZONTAL) listSizer = wx.BoxSizer(wx.HORIZONTAL)
listSizer.Add(staticDest) listSizer.Add(staticDest)
listSizer.Add(self.dest_lang) listSizer.Add(self.dest_lang)
ok = wx.Button(panel, wx.ID_OK) ok = wx.Button(panel, wx.ID_OK)
ok.SetDefault() ok.SetDefault()
cancel = wx.Button(panel, wx.ID_CANCEL) cancel = wx.Button(panel, wx.ID_CANCEL)
self.SetEscapeId(wx.ID_CANCEL) self.SetEscapeId(wx.ID_CANCEL)
def get(self, control): def get(self, control):
return getattr(self, control).GetSelection() return getattr(self, control).GetSelection()

View File

@ -8,7 +8,7 @@ from . import fix_win32com
from . import fix_libloader from . import fix_libloader
def setup(): def setup():
fix_requests.fix() fix_requests.fix()
# if hasattr(sys, "frozen"): # if hasattr(sys, "frozen"):
fix_libloader.fix() fix_libloader.fix()
fix_win32com.fix() fix_win32com.fix()

View File

@ -12,25 +12,25 @@ from libloader import com
fixed=False fixed=False
def patched_getmodule(modname): def patched_getmodule(modname):
mod=__import__(modname) mod=__import__(modname)
return sys.modules[modname] return sys.modules[modname]
def load_com(*names): def load_com(*names):
global fixed global fixed
if fixed==False: if fixed==False:
gencache._GetModule=patched_getmodule gencache._GetModule=patched_getmodule
com.prepare_gencache() com.prepare_gencache()
fixed=True fixed=True
result = None result = None
for name in names: for name in names:
try: try:
result = gencache.EnsureDispatch(name) result = gencache.EnsureDispatch(name)
break break
except com_error: except com_error:
continue continue
if result is None: if result is None:
raise com_error("Unable to load any of the provided com objects.") raise com_error("Unable to load any of the provided com objects.")
return result return result
def fix(): def fix():
com.load_com = load_com com.load_com = load_com

View File

@ -7,6 +7,6 @@ import logging
log = logging.getLogger("fixes.fix_requests") log = logging.getLogger("fixes.fix_requests")
def fix(): def fix():
log.debug("Applying fix for requests...") log.debug("Applying fix for requests...")
os.environ["REQUESTS_CA_BUNDLE"] = os.path.join(paths.app_path(), "cacert.pem")#.encode(paths.fsencoding) os.environ["REQUESTS_CA_BUNDLE"] = os.path.join(paths.app_path(), "cacert.pem")#.encode(paths.fsencoding)
# log.debug("Changed CA path to %s" % (os.environ["REQUESTS_CA_BUNDLE"]))#.decode(paths.fsencoding))) # log.debug("Changed CA path to %s" % (os.environ["REQUESTS_CA_BUNDLE"]))#.decode(paths.fsencoding)))

View File

@ -1,6 +1,6 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import win32com.client import win32com.client
def fix(): def fix():
if win32com.client.gencache.is_readonly == True: if win32com.client.gencache.is_readonly == True:
win32com.client.gencache.is_readonly = False win32com.client.gencache.is_readonly = False
win32com.client.gencache.Rebuild() win32com.client.gencache.Rebuild()

View File

@ -8,86 +8,86 @@ from . import base
class attachInteractor(base.baseInteractor): class attachInteractor(base.baseInteractor):
def insert_attachment(self, attachment): def insert_attachment(self, attachment):
self.view.attachments.insert_item(False, *attachment) self.view.attachments.insert_item(False, *attachment)
def remove_attachment(self, attachment): def remove_attachment(self, attachment):
self.view.attachments.remove_item(attachment) self.view.attachments.remove_item(attachment)
def install(self, *args, **kwargs): def install(self, *args, **kwargs):
super(attachInteractor, self).install(*args, **kwargs) super(attachInteractor, self).install(*args, **kwargs)
widgetUtils.connect_event(self.view.photo, widgetUtils.BUTTON_PRESSED, self.on_image) widgetUtils.connect_event(self.view.photo, widgetUtils.BUTTON_PRESSED, self.on_image)
widgetUtils.connect_event(self.view.audio, widgetUtils.BUTTON_PRESSED, self.on_audio) widgetUtils.connect_event(self.view.audio, widgetUtils.BUTTON_PRESSED, self.on_audio)
widgetUtils.connect_event(self.view.document, widgetUtils.BUTTON_PRESSED, self.on_document) widgetUtils.connect_event(self.view.document, widgetUtils.BUTTON_PRESSED, self.on_document)
if hasattr(self.view, "voice_message"): if hasattr(self.view, "voice_message"):
widgetUtils.connect_event(self.view.voice_message, widgetUtils.BUTTON_PRESSED, self.on_upload_voice_message) widgetUtils.connect_event(self.view.voice_message, widgetUtils.BUTTON_PRESSED, self.on_upload_voice_message)
widgetUtils.connect_event(self.view.remove, widgetUtils.BUTTON_PRESSED, self.on_remove_attachment) widgetUtils.connect_event(self.view.remove, widgetUtils.BUTTON_PRESSED, self.on_remove_attachment)
pub.subscribe(self.insert_attachment, self.modulename+"_insert_attachment") pub.subscribe(self.insert_attachment, self.modulename+"_insert_attachment")
pub.subscribe(self.remove_attachment, self.modulename+"_remove_attachment") pub.subscribe(self.remove_attachment, self.modulename+"_remove_attachment")
def uninstall(self): def uninstall(self):
super(attachInteractor, self).uninstall() super(attachInteractor, self).uninstall()
pub.unsubscribe(self.insert_attachment, self.modulename+"_insert_attachment") pub.unsubscribe(self.insert_attachment, self.modulename+"_insert_attachment")
pub.unsubscribe(self.remove_attachment, self.modulename+"_remove_attachment") pub.unsubscribe(self.remove_attachment, self.modulename+"_remove_attachment")
def on_image(self, *args, **kwargs): def on_image(self, *args, **kwargs):
""" display menu for adding image attachments. """ """ display menu for adding image attachments. """
m = attachMenu() m = attachMenu()
# disable add from VK as it is not supported in images, yet. # disable add from VK as it is not supported in images, yet.
m.add.Enable(False) m.add.Enable(False)
widgetUtils.connect_event(m, widgetUtils.MENU, self.on_upload_image, menuitem=m.upload) widgetUtils.connect_event(m, widgetUtils.MENU, self.on_upload_image, menuitem=m.upload)
self.view.PopupMenu(m, self.view.photo.GetPosition()) self.view.PopupMenu(m, self.view.photo.GetPosition())
def on_audio(self, *args, **kwargs): def on_audio(self, *args, **kwargs):
""" display menu to add audio attachments.""" """ display menu to add audio attachments."""
m = attachMenu() m = attachMenu()
widgetUtils.connect_event(m, widgetUtils.MENU, self.on_upload_audio, menuitem=m.upload) widgetUtils.connect_event(m, widgetUtils.MENU, self.on_upload_audio, menuitem=m.upload)
widgetUtils.connect_event(m, widgetUtils.MENU, self.on_add_audio, menuitem=m.add) widgetUtils.connect_event(m, widgetUtils.MENU, self.on_add_audio, menuitem=m.add)
self.view.PopupMenu(m, self.view.audio.GetPosition()) self.view.PopupMenu(m, self.view.audio.GetPosition())
def on_document(self, *args, **kwargs): def on_document(self, *args, **kwargs):
""" display menu for adding document attachments. """ """ display menu for adding document attachments. """
m = attachMenu() m = attachMenu()
# disable add from VK as it is not supported in documents, yet. # disable add from VK as it is not supported in documents, yet.
m.add.Enable(False) m.add.Enable(False)
widgetUtils.connect_event(m, widgetUtils.MENU, self.on_upload_document, menuitem=m.upload) widgetUtils.connect_event(m, widgetUtils.MENU, self.on_upload_document, menuitem=m.upload)
self.view.PopupMenu(m, self.view.photo.GetPosition()) self.view.PopupMenu(m, self.view.photo.GetPosition())
def on_upload_image(self, *args, **kwargs): def on_upload_image(self, *args, **kwargs):
""" allows uploading an image from the computer. """ allows uploading an image from the computer.
""" """
image, description = self.view.get_image() image, description = self.view.get_image()
if image != None: if image != None:
self.presenter.upload_image(image, description) self.presenter.upload_image(image, description)
def on_upload_audio(self, *args, **kwargs): def on_upload_audio(self, *args, **kwargs):
""" Allows uploading an audio file from the computer. Only mp3 files are supported. """ """ Allows uploading an audio file from the computer. Only mp3 files are supported. """
audio = self.view.get_audio() audio = self.view.get_audio()
if audio != None: if audio != None:
self.presenter.upload_audio(audio) self.presenter.upload_audio(audio)
def on_upload_document(self, *args, **kwargs): def on_upload_document(self, *args, **kwargs):
""" allows uploading a document from the computer. """ allows uploading a document from the computer.
""" """
document = self.view.get_document() document = self.view.get_document()
if document != None: if document != None:
if document.endswith(".mp3") or document.endswith(".exe"): if document.endswith(".mp3") or document.endswith(".exe"):
self.view.invalid_attachment() self.view.invalid_attachment()
return return
self.presenter.upload_document(document) self.presenter.upload_document(document)
def on_upload_voice_message(self, *args, **kwargs): def on_upload_voice_message(self, *args, **kwargs):
self.presenter.upload_voice_message() self.presenter.upload_voice_message()
def on_add_audio(self, *args, **kwargs): def on_add_audio(self, *args, **kwargs):
""" Allow adding an audio directly from the user's audio library.""" """ Allow adding an audio directly from the user's audio library."""
audios = self.presenter.get_available_audios() audios = self.presenter.get_available_audios()
select = selector.selectAttachment(_("Select the audio files you want to send"), audios) select = selector.selectAttachment(_("Select the audio files you want to send"), audios)
if select.get_response() == widgetUtils.OK and select.attachments.GetCount() > 0: if select.get_response() == widgetUtils.OK and select.attachments.GetCount() > 0:
attachments = select.get_all_attachments() attachments = select.get_all_attachments()
self.presenter.take_audios(attachments) self.presenter.take_audios(attachments)
def on_remove_attachment(self, *args, **kwargs): def on_remove_attachment(self, *args, **kwargs):
""" Remove the currently focused item from the attachments list.""" """ Remove the currently focused item from the attachments list."""
current_item = self.view.attachments.get_selected() current_item = self.view.attachments.get_selected()
self.presenter.remove_attachment(current_item) self.presenter.remove_attachment(current_item)

View File

@ -5,25 +5,25 @@ from pubsub import pub
from . import base from . import base
class audioRecorderInteractor(base.baseInteractor): class audioRecorderInteractor(base.baseInteractor):
def install(self, presenter, view, modulename="audiorecorder"): def install(self, presenter, view, modulename="audiorecorder"):
super(audioRecorderInteractor, self).install(view=view, presenter=presenter, modulename=modulename) super(audioRecorderInteractor, self).install(view=view, presenter=presenter, modulename=modulename)
widgetUtils.connect_event(view.play, widgetUtils.BUTTON_PRESSED, self.on_play) widgetUtils.connect_event(view.play, widgetUtils.BUTTON_PRESSED, self.on_play)
widgetUtils.connect_event(view.record, widgetUtils.BUTTON_PRESSED, self.on_record) widgetUtils.connect_event(view.record, widgetUtils.BUTTON_PRESSED, self.on_record)
widgetUtils.connect_event(view.discard, widgetUtils.BUTTON_PRESSED, self.on_discard) widgetUtils.connect_event(view.discard, widgetUtils.BUTTON_PRESSED, self.on_discard)
def start(self): def start(self):
result = self.view.get_response() result = self.view.get_response()
if result == widgetUtils.OK: if result == widgetUtils.OK:
self.on_postprocess() self.on_postprocess()
def on_record(self, *args, **kwargs): def on_record(self, *args, **kwargs):
self.presenter.toggle_recording() self.presenter.toggle_recording()
def on_discard(self, *args, **kwargs): def on_discard(self, *args, **kwargs):
self.presenter.discard_recording() self.presenter.discard_recording()
def on_play(self, *args, **kwargs): def on_play(self, *args, **kwargs):
self.presenter.play() self.presenter.play()
def on_postprocess(self): def on_postprocess(self):
self.presenter.postprocess() self.presenter.postprocess()

View File

@ -3,38 +3,38 @@ from pubsub import pub
class baseInteractor(object): class baseInteractor(object):
def install(self, view, presenter, modulename): def install(self, view, presenter, modulename):
self.modulename = modulename self.modulename = modulename
self.view = view self.view = view
self.presenter = presenter self.presenter = presenter
pub.subscribe(self.disable_control, "{modulename}_disable_control".format(modulename=modulename)) pub.subscribe(self.disable_control, "{modulename}_disable_control".format(modulename=modulename))
pub.subscribe(self.enable_control, "{modulename}_enable_control".format(modulename=modulename)) pub.subscribe(self.enable_control, "{modulename}_enable_control".format(modulename=modulename))
pub.subscribe(self.set_label, "{modulename}_set_label".format(modulename=modulename)) pub.subscribe(self.set_label, "{modulename}_set_label".format(modulename=modulename))
pub.subscribe(self.focus_control, "{modulename}_focus_control".format(modulename=modulename)) pub.subscribe(self.focus_control, "{modulename}_focus_control".format(modulename=modulename))
pub.subscribe(self.set_title, "{modulename}_set_title".format(modulename=modulename)) pub.subscribe(self.set_title, "{modulename}_set_title".format(modulename=modulename))
def uninstall(self): def uninstall(self):
pub.unsubscribe(self.disable_control, "{modulename}_disable_control".format(modulename=self.modulename)) pub.unsubscribe(self.disable_control, "{modulename}_disable_control".format(modulename=self.modulename))
pub.unsubscribe(self.enable_control, "{modulename}_enable_control".format(modulename=self.modulename)) pub.unsubscribe(self.enable_control, "{modulename}_enable_control".format(modulename=self.modulename))
pub.unsubscribe(self.set_label, "{modulename}_set_label".format(modulename=self.modulename)) pub.unsubscribe(self.set_label, "{modulename}_set_label".format(modulename=self.modulename))
pub.unsubscribe(self.focus_control, "{modulename}_focus_control".format(modulename=self.modulename)) pub.unsubscribe(self.focus_control, "{modulename}_focus_control".format(modulename=self.modulename))
pub.unsubscribe(self.set_title, "{modulename}_set_title".format(modulename=self.modulename)) pub.unsubscribe(self.set_title, "{modulename}_set_title".format(modulename=self.modulename))
self.view.Destroy() self.view.Destroy()
def start(self): def start(self):
self.result = self.view.get_response() self.result = self.view.get_response()
def disable_control(self, control): def disable_control(self, control):
self.view.disable(control) self.view.disable(control)
def enable_control(self, control): def enable_control(self, control):
self.view.enable(control) self.view.enable(control)
def focus_control(self, control): def focus_control(self, control):
getattr(self.view, control).SetFocus() getattr(self.view, control).SetFocus()
def set_label(self, control, label): def set_label(self, control, label):
self.view.set(control, label) self.view.set(control, label)
def set_title(self, value): def set_title(self, value):
self.view.SetTitle(value) self.view.SetTitle(value)

View File

@ -6,26 +6,26 @@ from . import base
class blacklistInteractor(base.baseInteractor): class blacklistInteractor(base.baseInteractor):
def add_items(self, control, items): def add_items(self, control, items):
if not hasattr(self.view, control): if not hasattr(self.view, control):
raise AttributeError("The control is not present in the view.") raise AttributeError("The control is not present in the view.")
for i in items: for i in items:
getattr(self.view, control).insert_item(False, *i) getattr(self.view, control).insert_item(False, *i)
def install(self, *args, **kwargs): def install(self, *args, **kwargs):
super(blacklistInteractor, self).install(*args, **kwargs) super(blacklistInteractor, self).install(*args, **kwargs)
widgetUtils.connect_event(self.view.unblock, widgetUtils.BUTTON_PRESSED, self.on_unblock) widgetUtils.connect_event(self.view.unblock, widgetUtils.BUTTON_PRESSED, self.on_unblock)
pub.subscribe(self.add_items, self.modulename+"_add_items") pub.subscribe(self.add_items, self.modulename+"_add_items")
def uninstall(self): def uninstall(self):
super(blacklistInteractor, self).uninstall() super(blacklistInteractor, self).uninstall()
pub.unsubscribe(self.add_items, self.modulename+"_add_items") pub.unsubscribe(self.add_items, self.modulename+"_add_items")
def on_unblock(self, *args, **kwargs): def on_unblock(self, *args, **kwargs):
question = commonMessages.unblock_person() question = commonMessages.unblock_person()
if question == widgetUtils.NO: if question == widgetUtils.NO:
return return
item = self.view.persons.get_selected() item = self.view.persons.get_selected()
if self.presenter.unblock_person(item) == 1: if self.presenter.unblock_person(item) == 1:
self.view.persons.remove_item(item) self.view.persons.remove_item(item)

View File

@ -6,67 +6,67 @@ from . import base
class configurationInteractor(base.baseInteractor): class configurationInteractor(base.baseInteractor):
def create_tab(self, tab, arglist=dict()): def create_tab(self, tab, arglist=dict()):
getattr(self.view, "create_"+tab)(**arglist) getattr(self.view, "create_"+tab)(**arglist)
def set_setting(self, tab, setting, value): def set_setting(self, tab, setting, value):
self.view.set_value(tab, setting, value) self.view.set_value(tab, setting, value)
def restart(self): def restart(self):
dlg = restart_program_dialog() dlg = restart_program_dialog()
if dlg == widgetUtils.YES: if dlg == widgetUtils.YES:
self.presenter.restart_application() self.presenter.restart_application()
def set_language(self, language): def set_language(self, language):
self.view.general.language.SetSelection(language) self.view.general.language.SetSelection(language)
def install(self, *args, **kwargs): def install(self, *args, **kwargs):
super(configurationInteractor, self).install(*args, **kwargs) super(configurationInteractor, self).install(*args, **kwargs)
pub.subscribe(self.create_tab, self.modulename+"_create_tab") pub.subscribe(self.create_tab, self.modulename+"_create_tab")
pub.subscribe(self.set_setting, self.modulename+"_set") pub.subscribe(self.set_setting, self.modulename+"_set")
pub.subscribe(self.restart, self.modulename+"_restart_program") pub.subscribe(self.restart, self.modulename+"_restart_program")
pub.subscribe(self.set_language, self.modulename+"_set_language") pub.subscribe(self.set_language, self.modulename+"_set_language")
def uninstall(self): def uninstall(self):
super(configurationInteractor, self).uninstall() super(configurationInteractor, self).uninstall()
pub.unsubscribe(self.create_tab, self.modulename+"_create_tab") pub.unsubscribe(self.create_tab, self.modulename+"_create_tab")
pub.unsubscribe(self.set_setting, self.modulename+"_set") pub.unsubscribe(self.set_setting, self.modulename+"_set")
pub.unsubscribe(self.restart, self.modulename+"_restart_program") pub.unsubscribe(self.restart, self.modulename+"_restart_program")
pub.unsubscribe(self.set_language, self.modulename+"_set_language") pub.unsubscribe(self.set_language, self.modulename+"_set_language")
def start(self): def start(self):
self.view.realize() self.view.realize()
result = self.view.get_response() result = self.view.get_response()
if result == widgetUtils.OK: if result == widgetUtils.OK:
self.on_save_settings() self.on_save_settings()
def on_save_settings(self, *args, **kwargs): def on_save_settings(self, *args, **kwargs):
self.presenter.update_setting(section="buffers", setting="count_for_wall_buffers", value=self.view.get_value("buffers", "wall_buffer_count")) self.presenter.update_setting(section="buffers", setting="count_for_wall_buffers", value=self.view.get_value("buffers", "wall_buffer_count"))
self.presenter.update_setting(section="buffers", setting="count_for_video_buffers", value=self.view.get_value("buffers", "video_buffers_count")) self.presenter.update_setting(section="buffers", setting="count_for_video_buffers", value=self.view.get_value("buffers", "video_buffers_count"))
self.presenter.update_setting(section="buffers", setting="count_for_chat_buffers", value=self.view.get_value("buffers", "chat_buffers_count")) self.presenter.update_setting(section="buffers", setting="count_for_chat_buffers", value=self.view.get_value("buffers", "chat_buffers_count"))
self.presenter.update_setting(section="general", setting="load_images", value=self.view.get_value("general", "load_images")) self.presenter.update_setting(section="general", setting="load_images", value=self.view.get_value("general", "load_images"))
update_channel = self.presenter.get_update_channel_type(self.view.get_value("general", "update_channel")) update_channel = self.presenter.get_update_channel_type(self.view.get_value("general", "update_channel"))
if update_channel != self.presenter.session.settings["general"]["update_channel"]: if update_channel != self.presenter.session.settings["general"]["update_channel"]:
if update_channel == "stable": if update_channel == "stable":
self.presenter.update_setting(section="general", setting="update_channel", value=update_channel) self.presenter.update_setting(section="general", setting="update_channel", value=update_channel)
elif update_channel == "weekly": elif update_channel == "weekly":
dialog = self.view.weekly_channel() dialog = self.view.weekly_channel()
if dialog == widgetUtils.YES: if dialog == widgetUtils.YES:
self.presenter.update_setting(section="general", setting="update_channel", value=update_channel) self.presenter.update_setting(section="general", setting="update_channel", value=update_channel)
elif update_channel == "alpha": elif update_channel == "alpha":
dialog = self.view.alpha_channel() dialog = self.view.alpha_channel()
if dialog == widgetUtils.YES: if dialog == widgetUtils.YES:
self.presenter.update_setting(section="general", setting="update_channel", value=update_channel) self.presenter.update_setting(section="general", setting="update_channel", value=update_channel)
self.presenter.update_setting(section="chat", setting="notify_online", value=self.view.get_value("chat", "notify_online")) self.presenter.update_setting(section="chat", setting="notify_online", value=self.view.get_value("chat", "notify_online"))
self.presenter.update_setting(section="chat", setting="notify_offline", value=self.view.get_value("chat", "notify_offline")) self.presenter.update_setting(section="chat", setting="notify_offline", value=self.view.get_value("chat", "notify_offline"))
self.presenter.update_setting(section="chat", setting="notifications", value=self.presenter.get_notification_type(self.view.get_value("chat", "notifications"))) self.presenter.update_setting(section="chat", setting="notifications", value=self.presenter.get_notification_type(self.view.get_value("chat", "notifications")))
self.presenter.update_setting(section="load_at_startup", setting="audio_albums", value=self.view.get_value("startup", "audio_albums")) self.presenter.update_setting(section="load_at_startup", setting="audio_albums", value=self.view.get_value("startup", "audio_albums"))
self.presenter.update_setting(section="load_at_startup", setting="video_albums", value=self.view.get_value("startup", "video_albums")) self.presenter.update_setting(section="load_at_startup", setting="video_albums", value=self.view.get_value("startup", "video_albums"))
self.presenter.update_setting(section="load_at_startup", setting="communities", value=self.view.get_value("startup", "communities")) self.presenter.update_setting(section="load_at_startup", setting="communities", value=self.view.get_value("startup", "communities"))
self.presenter.update_app_setting(section="app-settings", setting="language", value=self.presenter.codes[self.view.general.language.GetSelection()]) self.presenter.update_app_setting(section="app-settings", setting="language", value=self.presenter.codes[self.view.general.language.GetSelection()])
self.presenter.update_app_setting(section="sound", setting="input_device", value=self.view.get_value("sound", "input")) self.presenter.update_app_setting(section="sound", setting="input_device", value=self.view.get_value("sound", "input"))
self.presenter.update_app_setting(section="sound", setting="output_device", value=self.view.get_value("sound", "output")) self.presenter.update_app_setting(section="sound", setting="output_device", value=self.view.get_value("sound", "output"))
self.presenter.update_app_setting(section="app-settings", setting="use_proxy", value=self.view.get_value("general", "use_proxy")) self.presenter.update_app_setting(section="app-settings", setting="use_proxy", value=self.view.get_value("general", "use_proxy"))
self.presenter.update_app_setting(section="app-settings", setting="debug_logging", value=self.view.get_value("general", "debug_logging")) self.presenter.update_app_setting(section="app-settings", setting="debug_logging", value=self.view.get_value("general", "debug_logging"))
self.presenter.save_app_settings_file() self.presenter.save_app_settings_file()
self.presenter.save_settings_file() self.presenter.save_settings_file()

View File

@ -7,67 +7,67 @@ from .import base
class createPostInteractor(base.baseInteractor): class createPostInteractor(base.baseInteractor):
def set(self, control, value): def set(self, control, value):
if not hasattr(self.view, control): if not hasattr(self.view, control):
raise AttributeError("The control is not present in the view.") raise AttributeError("The control is not present in the view.")
getattr(self.view, control).SetValue(value) getattr(self.view, control).SetValue(value)
def add_tagged_users(self, users): def add_tagged_users(self, users):
self.view.text.SetValue(self.view.text.GetValue()+", ".join(users)) self.view.text.SetValue(self.view.text.GetValue()+", ".join(users))
def install(self, *args, **kwargs): def install(self, *args, **kwargs):
super(createPostInteractor, self).install(*args, **kwargs) super(createPostInteractor, self).install(*args, **kwargs)
widgetUtils.connect_event(self.view.spellcheck, widgetUtils.BUTTON_PRESSED, self.on_spellcheck) widgetUtils.connect_event(self.view.spellcheck, widgetUtils.BUTTON_PRESSED, self.on_spellcheck)
widgetUtils.connect_event(self.view.translateButton, widgetUtils.BUTTON_PRESSED, self.on_translate) widgetUtils.connect_event(self.view.translateButton, widgetUtils.BUTTON_PRESSED, self.on_translate)
widgetUtils.connect_event(self.view.mention, widgetUtils.BUTTON_PRESSED, self.on_mention) widgetUtils.connect_event(self.view.mention, widgetUtils.BUTTON_PRESSED, self.on_mention)
if hasattr(self.view, "attach"): if hasattr(self.view, "attach"):
widgetUtils.connect_event(self.view.attach, widgetUtils.BUTTON_PRESSED, self.on_add_attachments) widgetUtils.connect_event(self.view.attach, widgetUtils.BUTTON_PRESSED, self.on_add_attachments)
pub.subscribe(self.set, self.modulename+"_set") pub.subscribe(self.set, self.modulename+"_set")
pub.subscribe(self.add_tagged_users, self.modulename+"_add_tagged_users") pub.subscribe(self.add_tagged_users, self.modulename+"_add_tagged_users")
def uninstall(self): def uninstall(self):
super(createPostInteractor, self).uninstall() super(createPostInteractor, self).uninstall()
pub.unsubscribe(self.set, self.modulename+"_set") pub.unsubscribe(self.set, self.modulename+"_set")
pub.unsubscribe(self.add_tagged_users, self.modulename+"_add_tagged_users") pub.unsubscribe(self.add_tagged_users, self.modulename+"_add_tagged_users")
def start(self): def start(self):
self.result = self.view.get_response() self.result = self.view.get_response()
if self.result == widgetUtils.OK: if self.result == widgetUtils.OK:
self.presenter.text = self.view.get_text() self.presenter.text = self.view.get_text()
if hasattr(self.view, "privacy"): if hasattr(self.view, "privacy"):
self.presenter.privacy = self.get_privacy_options() self.presenter.privacy = self.get_privacy_options()
else: else:
self.presenter.privacy = 0 self.presenter.privacy = 0
def get_privacy_options(self): def get_privacy_options(self):
p = self.view.get("privacy") p = self.view.get("privacy")
if p == _("Friends of friends"): if p == _("Friends of friends"):
privacy = 0 privacy = 0
elif p == _("All users"): elif p == _("All users"):
privacy = 1 privacy = 1
return privacy return privacy
def on_mention(self, *args, **kwargs): def on_mention(self, *args, **kwargs):
users = self.presenter.get_friends() users = self.presenter.get_friends()
select = selector.selectPeople(users) select = selector.selectPeople(users)
if select.get_response() == widgetUtils.OK and select.users.GetCount() > 0: if select.get_response() == widgetUtils.OK and select.users.GetCount() > 0:
tagged_users = select.get_all_users() tagged_users = select.get_all_users()
self.presenter.add_tagged_users(tagged_users) self.presenter.add_tagged_users(tagged_users)
def on_translate(self, *args, **kwargs): def on_translate(self, *args, **kwargs):
dlg = translator.gui.translateDialog() dlg = translator.gui.translateDialog()
if dlg.get_response() == widgetUtils.OK: if dlg.get_response() == widgetUtils.OK:
text_to_translate = self.view.get_text() text_to_translate = self.view.get_text()
language_dict = translator.translator.available_languages() language_dict = translator.translator.available_languages()
for k in language_dict: for k in language_dict:
if language_dict[k] == dlg.dest_lang.GetStringSelection(): if language_dict[k] == dlg.dest_lang.GetStringSelection():
dst = k dst = k
self.presenter.translate(text_to_translate, dst) self.presenter.translate(text_to_translate, dst)
dlg.Destroy() dlg.Destroy()
def on_spellcheck(self, event=None): def on_spellcheck(self, event=None):
text = self.view.get_text() text = self.view.get_text()
self.presenter.spellcheck(text) self.presenter.spellcheck(text)
def on_add_attachments(self, *args, **kwargs): def on_add_attachments(self, *args, **kwargs):
self.presenter.add_attachments() self.presenter.add_attachments()

View File

@ -10,295 +10,295 @@ from .import base
class displayPostInteractor(base.baseInteractor): class displayPostInteractor(base.baseInteractor):
def set(self, control, value): def set(self, control, value):
if not hasattr(self.view, control): if not hasattr(self.view, control):
raise AttributeError("The control is not present in the view.") raise AttributeError("The control is not present in the view.")
getattr(self.view, control).SetValue(value) getattr(self.view, control).SetValue(value)
def load_image(self, image): def load_image(self, image):
image = wx.Image(stream=six.BytesIO(image.content)) image = wx.Image(stream=six.BytesIO(image.content))
try: try:
self.view.image.SetBitmap(wx.Bitmap(image)) self.view.image.SetBitmap(wx.Bitmap(image))
except ValueError: except ValueError:
return return
self.view.panel.Layout() self.view.panel.Layout()
def add_items(self, control, items): def add_items(self, control, items):
if not hasattr(self.view, control): if not hasattr(self.view, control):
raise AttributeError("The control is not present in the view.") raise AttributeError("The control is not present in the view.")
for i in items: for i in items:
getattr(self.view, control).insert_item(False, *i) getattr(self.view, control).insert_item(False, *i)
def add_item(self, control, item, reversed=False): def add_item(self, control, item, reversed=False):
if not hasattr(self.view, control): if not hasattr(self.view, control):
raise AttributeError("The control is not present in the view.") raise AttributeError("The control is not present in the view.")
getattr(self.view, control).insert_item(reversed, *item) getattr(self.view, control).insert_item(reversed, *item)
def enable_attachments(self): def enable_attachments(self):
self.view.attachments.list.Enable(True) self.view.attachments.list.Enable(True)
def enable_photo_controls(self, navigation): def enable_photo_controls(self, navigation):
self.view.enable_photo_controls(navigation) self.view.enable_photo_controls(navigation)
def clean_list(self, list): def clean_list(self, list):
if not hasattr(self.view, list): if not hasattr(self.view, list):
raise AttributeError("The control is not present in the view.") raise AttributeError("The control is not present in the view.")
getattr(self.view, list).clear() getattr(self.view, list).clear()
def post_deleted(self): def post_deleted(self):
msg = commonMessages.post_deleted() msg = commonMessages.post_deleted()
def install(self, *args, **kwargs): def install(self, *args, **kwargs):
super(displayPostInteractor, self).install(*args, **kwargs) super(displayPostInteractor, self).install(*args, **kwargs)
if hasattr(self.view, "comments"): if hasattr(self.view, "comments"):
self.view.comments.list.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.on_show_comment) self.view.comments.list.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.on_show_comment)
self.view.comments.list.Bind(wx.EVT_LIST_ITEM_FOCUSED, self.on_comment_changed) self.view.comments.list.Bind(wx.EVT_LIST_ITEM_FOCUSED, self.on_comment_changed)
self.view.attachments.list.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.on_open_attachment) self.view.attachments.list.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.on_open_attachment)
widgetUtils.connect_event(self.view.like, widgetUtils.BUTTON_PRESSED, self.on_like) widgetUtils.connect_event(self.view.like, widgetUtils.BUTTON_PRESSED, self.on_like)
widgetUtils.connect_event(self.view.comment, widgetUtils.BUTTON_PRESSED, self.on_add_comment) widgetUtils.connect_event(self.view.comment, widgetUtils.BUTTON_PRESSED, self.on_add_comment)
widgetUtils.connect_event(self.view.tools, widgetUtils.BUTTON_PRESSED, self.on_show_tools_menu) widgetUtils.connect_event(self.view.tools, widgetUtils.BUTTON_PRESSED, self.on_show_tools_menu)
if hasattr(self.view, "likes"): if hasattr(self.view, "likes"):
widgetUtils.connect_event(self.view.likes, widgetUtils.BUTTON_PRESSED, self.on_show_likes_menu) widgetUtils.connect_event(self.view.likes, widgetUtils.BUTTON_PRESSED, self.on_show_likes_menu)
if hasattr(self.view, "shares"): if hasattr(self.view, "shares"):
widgetUtils.connect_event(self.view.shares, widgetUtils.BUTTON_PRESSED, self.on_show_shares_menu) widgetUtils.connect_event(self.view.shares, widgetUtils.BUTTON_PRESSED, self.on_show_shares_menu)
if hasattr(self.view, "repost"): if hasattr(self.view, "repost"):
widgetUtils.connect_event(self.view.repost, widgetUtils.BUTTON_PRESSED, self.on_repost) widgetUtils.connect_event(self.view.repost, widgetUtils.BUTTON_PRESSED, self.on_repost)
self.view.comments.list.Bind(wx.EVT_LIST_ITEM_FOCUSED, self.on_focus) self.view.comments.list.Bind(wx.EVT_LIST_ITEM_FOCUSED, self.on_focus)
if hasattr(self.view, "reply"): if hasattr(self.view, "reply"):
widgetUtils.connect_event(self.view.reply, widgetUtils.BUTTON_PRESSED, self.on_reply) widgetUtils.connect_event(self.view.reply, widgetUtils.BUTTON_PRESSED, self.on_reply)
if hasattr(self.view, "load_more_comments"): if hasattr(self.view, "load_more_comments"):
widgetUtils.connect_event(self.view.load_more_comments, widgetUtils.BUTTON_PRESSED, self.on_load_more_comments) widgetUtils.connect_event(self.view.load_more_comments, widgetUtils.BUTTON_PRESSED, self.on_load_more_comments)
# self.view.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.on_show_menu, self.view.comments.list) # self.view.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.on_show_menu, self.view.comments.list)
# self.view.Bind(wx.EVT_LIST_KEY_DOWN, self.on_show_menu_by_key, self.view.comments.list) # self.view.Bind(wx.EVT_LIST_KEY_DOWN, self.on_show_menu_by_key, self.view.comments.list)
pub.subscribe(self.set, self.modulename+"_set") pub.subscribe(self.set, self.modulename+"_set")
pub.subscribe(self.load_image, self.modulename+"_load_image") pub.subscribe(self.load_image, self.modulename+"_load_image")
pub.subscribe(self.add_items, self.modulename+"_add_items") pub.subscribe(self.add_items, self.modulename+"_add_items")
pub.subscribe(self.add_item, self.modulename+"_add_item") pub.subscribe(self.add_item, self.modulename+"_add_item")
pub.subscribe(self.enable_attachments, self.modulename+"_enable_attachments") pub.subscribe(self.enable_attachments, self.modulename+"_enable_attachments")
pub.subscribe(self.enable_photo_controls, self.modulename+"_enable_photo_controls") pub.subscribe(self.enable_photo_controls, self.modulename+"_enable_photo_controls")
pub.subscribe(self.post_deleted, self.modulename+"_post_deleted") pub.subscribe(self.post_deleted, self.modulename+"_post_deleted")
pub.subscribe(self.clean_list, self.modulename+"_clean_list") pub.subscribe(self.clean_list, self.modulename+"_clean_list")
def uninstall(self): def uninstall(self):
super(displayPostInteractor, self).uninstall() super(displayPostInteractor, self).uninstall()
pub.unsubscribe(self.set, self.modulename+"_set") pub.unsubscribe(self.set, self.modulename+"_set")
pub.unsubscribe(self.load_image, self.modulename+"_load_image") pub.unsubscribe(self.load_image, self.modulename+"_load_image")
pub.unsubscribe(self.add_items, self.modulename+"_add_items") pub.unsubscribe(self.add_items, self.modulename+"_add_items")
pub.unsubscribe(self.add_item, self.modulename+"_add_item") pub.unsubscribe(self.add_item, self.modulename+"_add_item")
pub.unsubscribe(self.enable_attachments, self.modulename+"_enable_attachments") pub.unsubscribe(self.enable_attachments, self.modulename+"_enable_attachments")
pub.unsubscribe(self.enable_photo_controls, self.modulename+"_enable_photo_controls") pub.unsubscribe(self.enable_photo_controls, self.modulename+"_enable_photo_controls")
pub.unsubscribe(self.post_deleted, self.modulename+"_post_deleted") pub.unsubscribe(self.post_deleted, self.modulename+"_post_deleted")
pub.unsubscribe(self.clean_list, self.modulename+"_clean_list") pub.unsubscribe(self.clean_list, self.modulename+"_clean_list")
def on_focus(self, *args, **kwargs): def on_focus(self, *args, **kwargs):
item = self.view.comments.get_selected() item = self.view.comments.get_selected()
if item == -1: if item == -1:
self.view.reply.Enable(False) self.view.reply.Enable(False)
else: else:
self.view.reply.Enable(True) self.view.reply.Enable(True)
def on_like(self, *args, **kwargs): def on_like(self, *args, **kwargs):
self.presenter.post_like() self.presenter.post_like()
def on_repost(self, *args, **kwargs): def on_repost(self, *args, **kwargs):
self.presenter.post_repost() self.presenter.post_repost()
def on_reply(self, *args, **kwargs): def on_reply(self, *args, **kwargs):
if hasattr(self.view, "comments") and (hasattr(self.view, "repost") or not hasattr(self, "post_view")): if hasattr(self.view, "comments") and (hasattr(self.view, "repost") or not hasattr(self, "post_view")):
comment = self.view.comments.get_selected() comment = self.view.comments.get_selected()
self.presenter.reply(comment) self.presenter.reply(comment)
else: else:
self.presenter.reply() self.presenter.reply()
def on_add_comment(self, *args, **kwargs): def on_add_comment(self, *args, **kwargs):
self.presenter.add_comment() self.presenter.add_comment()
def on_load_more_comments(self, *args, **kwargs): def on_load_more_comments(self, *args, **kwargs):
if hasattr(self.presenter, "load_more_comments"): if hasattr(self.presenter, "load_more_comments"):
self.presenter.load_more_comments() self.presenter.load_more_comments()
def on_show_tools_menu(self, *args, **kwargs): def on_show_tools_menu(self, *args, **kwargs):
menu = menus.toolsMenu() menu = menus.toolsMenu()
# widgetUtils.connect_event(self.view, widgetUtils.MENU, self.on_open_url, menuitem=menu.url) # widgetUtils.connect_event(self.view, widgetUtils.MENU, self.on_open_url, menuitem=menu.url)
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.on_translate, menuitem=menu.translate) widgetUtils.connect_event(self.view, widgetUtils.MENU, self.on_translate, menuitem=menu.translate)
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.on_spellcheck, menuitem=menu.spellcheck) widgetUtils.connect_event(self.view, widgetUtils.MENU, self.on_spellcheck, menuitem=menu.spellcheck)
self.view.PopupMenu(menu, self.view.tools.GetPosition()) self.view.PopupMenu(menu, self.view.tools.GetPosition())
def on_open_url(self, *args, **kwargs): def on_open_url(self, *args, **kwargs):
pass pass
def on_open_attachment(self, *args, **kwargs): def on_open_attachment(self, *args, **kwargs):
attachment = self.view.attachments.get_selected() attachment = self.view.attachments.get_selected()
self.presenter.open_attachment(attachment) self.presenter.open_attachment(attachment)
def on_translate(self, *args, **kwargs): def on_translate(self, *args, **kwargs):
dlg = translator.gui.translateDialog() dlg = translator.gui.translateDialog()
if dlg.get_response() == widgetUtils.OK: if dlg.get_response() == widgetUtils.OK:
text_to_translate = self.view.get("post_view") text_to_translate = self.view.get("post_view")
language_dict = translator.translator.available_languages() language_dict = translator.translator.available_languages()
for k in language_dict: for k in language_dict:
if language_dict[k] == dlg.dest_lang.GetStringSelection(): if language_dict[k] == dlg.dest_lang.GetStringSelection():
dst = k dst = k
self.presenter.translate(text_to_translate, dst) self.presenter.translate(text_to_translate, dst)
dlg.Destroy() dlg.Destroy()
def on_spellcheck(self, event=None): def on_spellcheck(self, event=None):
text = self.view.get("post_view") text = self.view.get("post_view")
self.presenter.spellcheck(text) self.presenter.spellcheck(text)
def on_show_comment(self, *args, **kwargs): def on_show_comment(self, *args, **kwargs):
comment = self.view.comments.get_selected() comment = self.view.comments.get_selected()
self.presenter.show_comment(comment) self.presenter.show_comment(comment)
def on_comment_changed(self, *args, **kwargs): def on_comment_changed(self, *args, **kwargs):
if hasattr(self.presenter, "change_comment"): if hasattr(self.presenter, "change_comment"):
comment = self.view.comments.get_selected() comment = self.view.comments.get_selected()
self.presenter.change_comment(comment) self.presenter.change_comment(comment)
def on_show_likes_menu(self, *args, **kwargs): def on_show_likes_menu(self, *args, **kwargs):
self.presenter.show_likes() self.presenter.show_likes()
def on_show_shares_menu(self, *args, **kwargs): def on_show_shares_menu(self, *args, **kwargs):
self.presenter.show_shares() self.presenter.show_shares()
class displayAudioInteractor(base.baseInteractor): class displayAudioInteractor(base.baseInteractor):
def set(self, control, value): def set(self, control, value):
if not hasattr(self.view, control): if not hasattr(self.view, control):
raise AttributeError("The control is not present in the view.") raise AttributeError("The control is not present in the view.")
getattr(self.view, control).SetValue(value) getattr(self.view, control).SetValue(value)
def add_items(self, control, items): def add_items(self, control, items):
if not hasattr(self.view, control): if not hasattr(self.view, control):
raise AttributeError("The control is not present in the view.") raise AttributeError("The control is not present in the view.")
for i in items: for i in items:
getattr(self.view, control).Append(i) getattr(self.view, control).Append(i)
getattr(self.view, control).SetSelection(0) getattr(self.view, control).SetSelection(0)
def change_label(self, stopped): def change_label(self, stopped):
if stopped == False: if stopped == False:
self.view.play.SetLabel(_("P&ause")) self.view.play.SetLabel(_("P&ause"))
else: else:
self.view.play.SetLabel(_("P&lay")) self.view.play.SetLabel(_("P&lay"))
def install(self, *args, **kwargs): def install(self, *args, **kwargs):
super(displayAudioInteractor, self).install(*args, **kwargs) super(displayAudioInteractor, self).install(*args, **kwargs)
widgetUtils.connect_event(self.view.list, widgetUtils.LISTBOX_CHANGED, self.on_change) widgetUtils.connect_event(self.view.list, widgetUtils.LISTBOX_CHANGED, self.on_change)
widgetUtils.connect_event(self.view.download, widgetUtils.BUTTON_PRESSED, self.on_download) widgetUtils.connect_event(self.view.download, widgetUtils.BUTTON_PRESSED, self.on_download)
widgetUtils.connect_event(self.view.play, widgetUtils.BUTTON_PRESSED, self.on_play) widgetUtils.connect_event(self.view.play, widgetUtils.BUTTON_PRESSED, self.on_play)
widgetUtils.connect_event(self.view.add, widgetUtils.BUTTON_PRESSED, self.on_add_to_library) widgetUtils.connect_event(self.view.add, widgetUtils.BUTTON_PRESSED, self.on_add_to_library)
widgetUtils.connect_event(self.view.remove, widgetUtils.BUTTON_PRESSED, self.on_remove_from_library) widgetUtils.connect_event(self.view.remove, widgetUtils.BUTTON_PRESSED, self.on_remove_from_library)
pub.subscribe(self.set, self.modulename+"_set") pub.subscribe(self.set, self.modulename+"_set")
pub.subscribe(self.add_items, self.modulename+"_add_items") pub.subscribe(self.add_items, self.modulename+"_add_items")
pub.subscribe(self.change_label, "playback-changed") pub.subscribe(self.change_label, "playback-changed")
def uninstall(self): def uninstall(self):
super(displayAudioInteractor, self).uninstall() super(displayAudioInteractor, self).uninstall()
pub.unsubscribe(self.set, self.modulename+"_set") pub.unsubscribe(self.set, self.modulename+"_set")
pub.unsubscribe(self.add_items, self.modulename+"_add_items") pub.unsubscribe(self.add_items, self.modulename+"_add_items")
pub.unsubscribe(self.change_label, "playback-changed") pub.unsubscribe(self.change_label, "playback-changed")
def on_change(self, *args, **kwargs): def on_change(self, *args, **kwargs):
post = self.view.get_audio() post = self.view.get_audio()
self.presenter.handle_changes(post) self.presenter.handle_changes(post)
def on_download(self, *args, **kwargs): def on_download(self, *args, **kwargs):
post = self.view.get_audio() post = self.view.get_audio()
suggested_filename = self.presenter.get_suggested_filename(post) suggested_filename = self.presenter.get_suggested_filename(post)
path = self.view.get_destination_path(suggested_filename) path = self.view.get_destination_path(suggested_filename)
self.presenter.download(post, path) self.presenter.download(post, path)
def on_play(self, *args, **kwargs): def on_play(self, *args, **kwargs):
post = self.view.get_audio() post = self.view.get_audio()
self.presenter.play(post) self.presenter.play(post)
def on_add_to_library(self, *args, **kwargs): def on_add_to_library(self, *args, **kwargs):
post = self.view.get_audio() post = self.view.get_audio()
self.presenter.add_to_library(post) self.presenter.add_to_library(post)
def on_remove_from_library(self, *args, **kwargs): def on_remove_from_library(self, *args, **kwargs):
post = self.view.get_audio() post = self.view.get_audio()
self.presenter.remove_from_library(post) self.presenter.remove_from_library(post)
class displayArticleInteractor(base.baseInteractor): class displayArticleInteractor(base.baseInteractor):
def set(self, control, value): def set(self, control, value):
if not hasattr(self.view, control): if not hasattr(self.view, control):
raise AttributeError("The control is not present in the view.") raise AttributeError("The control is not present in the view.")
getattr(self.view, control).SetValue(value) getattr(self.view, control).SetValue(value)
def install(self, *args, **kwargs): def install(self, *args, **kwargs):
super(displayArticleInteractor, self).install(*args, **kwargs) super(displayArticleInteractor, self).install(*args, **kwargs)
pub.subscribe(self.set, self.modulename+"_set") pub.subscribe(self.set, self.modulename+"_set")
def uninstall(self): def uninstall(self):
super(displayArticleInteractor, self).uninstall() super(displayArticleInteractor, self).uninstall()
pub.unsubscribe(self.set, self.modulename+"_set") pub.unsubscribe(self.set, self.modulename+"_set")
class displayPollInteractor(base.baseInteractor): class displayPollInteractor(base.baseInteractor):
def set(self, control, value): def set(self, control, value):
if not hasattr(self.view, control): if not hasattr(self.view, control):
raise AttributeError("The control is not present in the view.") raise AttributeError("The control is not present in the view.")
getattr(self.view, control).SetValue(value) getattr(self.view, control).SetValue(value)
def done(self): def done(self):
self.view.done() self.view.done()
def add_options(self, options, multiple): def add_options(self, options, multiple):
self.view.add_options(options, multiple) self.view.add_options(options, multiple)
def install(self, *args, **kwargs): def install(self, *args, **kwargs):
super(displayPollInteractor, self).install(*args, **kwargs) super(displayPollInteractor, self).install(*args, **kwargs)
pub.subscribe(self.set, self.modulename+"_set") pub.subscribe(self.set, self.modulename+"_set")
pub.subscribe(self.done, self.modulename+"_done") pub.subscribe(self.done, self.modulename+"_done")
pub.subscribe(self.add_options, self.modulename+"_add_options") pub.subscribe(self.add_options, self.modulename+"_add_options")
def uninstall(self): def uninstall(self):
super(displayPollInteractor, self).uninstall() super(displayPollInteractor, self).uninstall()
pub.unsubscribe(self.set, self.modulename+"_set") pub.unsubscribe(self.set, self.modulename+"_set")
pub.unsubscribe(self.done, self.modulename+"_done") pub.unsubscribe(self.done, self.modulename+"_done")
pub.unsubscribe(self.add_options, self.modulename+"_add_options") pub.unsubscribe(self.add_options, self.modulename+"_add_options")
def start(self, *args, **kwargs): def start(self, *args, **kwargs):
super(displayPollInteractor, self).start(*args, **kwargs) super(displayPollInteractor, self).start(*args, **kwargs)
if self.result == widgetUtils.OK: # USer votd. if self.result == widgetUtils.OK: # USer votd.
answers = self.view.get_answers() answers = self.view.get_answers()
self.presenter.vote(answers) self.presenter.vote(answers)
class displayFriendshipInteractor(base.baseInteractor): class displayFriendshipInteractor(base.baseInteractor):
def add_items(self, control, items): def add_items(self, control, items):
if not hasattr(self.view, control): if not hasattr(self.view, control):
raise AttributeError("The control is not present in the view.") raise AttributeError("The control is not present in the view.")
for i in items: for i in items:
getattr(self.view, control).insert_item(False, *[i]) getattr(self.view, control).insert_item(False, *[i])
def install(self, *args, **kwargs): def install(self, *args, **kwargs):
super(displayFriendshipInteractor, self).install(*args, **kwargs) super(displayFriendshipInteractor, self).install(*args, **kwargs)
pub.subscribe(self.add_items, self.modulename+"_add_items") pub.subscribe(self.add_items, self.modulename+"_add_items")
self.view.friends.list.Bind(wx.EVT_CONTEXT_MENU, self.on_context_menu) self.view.friends.list.Bind(wx.EVT_CONTEXT_MENU, self.on_context_menu)
def uninstall(self): def uninstall(self):
super(displayFriendshipInteractor, self).uninstall() super(displayFriendshipInteractor, self).uninstall()
pub.unsubscribe(self.add_items, self.modulename+"_add_items") pub.unsubscribe(self.add_items, self.modulename+"_add_items")
def on_context_menu(self, *args, **kwargs): def on_context_menu(self, *args, **kwargs):
item = self.view.friends.get_selected() item = self.view.friends.get_selected()
if item < 0: if item < 0:
return return
menu = menus.peopleMenu(False, False, True) menu = menus.peopleMenu(False, False, True)
widgetUtils.connect_event(menu, widgetUtils.MENU, self.on_view_profile, menuitem=menu.view_profile) widgetUtils.connect_event(menu, widgetUtils.MENU, self.on_view_profile, menuitem=menu.view_profile)
widgetUtils.connect_event(menu, widgetUtils.MENU, self.on_open_in_browser, menuitem=menu.open_in_browser) widgetUtils.connect_event(menu, widgetUtils.MENU, self.on_open_in_browser, menuitem=menu.open_in_browser)
# Generally message sending is blocked. # Generally message sending is blocked.
menu.message.Enable(False) menu.message.Enable(False)
self.view.PopupMenu(menu, self.view.friends.list.GetPosition()) self.view.PopupMenu(menu, self.view.friends.list.GetPosition())
def on_view_profile(self, *args, **kwargs): def on_view_profile(self, *args, **kwargs):
item = self.view.friends.get_selected() item = self.view.friends.get_selected()
self.presenter.view_profile(item) self.presenter.view_profile(item)
def on_open_in_browser(self, *args, **kwargs): def on_open_in_browser(self, *args, **kwargs):
item = self.view.friends.get_selected() item = self.view.friends.get_selected()
self.presenter.open_in_browser(item) self.presenter.open_in_browser(item)

View File

@ -9,62 +9,62 @@ from . import base
class userProfileInteractor(base.baseInteractor): class userProfileInteractor(base.baseInteractor):
def enable_control(self, tab, control): def enable_control(self, tab, control):
if not hasattr(self.view, tab): if not hasattr(self.view, tab):
raise AttributeError("The viw does not contain the specified tab.") raise AttributeError("The viw does not contain the specified tab.")
tab = getattr(self.view, tab) tab = getattr(self.view, tab)
if not hasattr(tab, control): if not hasattr(tab, control):
raise AttributeError("The control is not present in the tab.") raise AttributeError("The control is not present in the tab.")
getattr(tab, control).Enable(True) getattr(tab, control).Enable(True)
def set(self, tab, control, value): def set(self, tab, control, value):
if not hasattr(self.view, tab): if not hasattr(self.view, tab):
raise AttributeError("The view does not contain the specified tab.") raise AttributeError("The view does not contain the specified tab.")
tab = getattr(self.view, tab) tab = getattr(self.view, tab)
if not hasattr(tab, control): if not hasattr(tab, control):
raise AttributeError("The control is not present in the tab.") raise AttributeError("The control is not present in the tab.")
control = getattr(tab, control) control = getattr(tab, control)
control.SetValue(value) control.SetValue(value)
def set_label(self, tab, control, value): def set_label(self, tab, control, value):
if not hasattr(self.view, tab): if not hasattr(self.view, tab):
raise AttributeError("The viw does not contain the specified tab.") raise AttributeError("The viw does not contain the specified tab.")
tab = getattr(self.view, tab) tab = getattr(self.view, tab)
if not hasattr(tab, control): if not hasattr(tab, control):
raise AttributeError("The control is not present in the tab.") raise AttributeError("The control is not present in the tab.")
control = getattr(tab, control) control = getattr(tab, control)
control.SetLabel(value) control.SetLabel(value)
def load_image(self, image): def load_image(self, image):
image = wx.Image(stream=six.BytesIO(image.content)) image = wx.Image(stream=six.BytesIO(image.content))
try: try:
self.view.image.SetBitmap(wx.Bitmap(image)) self.view.image.SetBitmap(wx.Bitmap(image))
except ValueError: except ValueError:
return return
self.view.panel.Layout() self.view.panel.Layout()
def install(self, *args, **kwargs): def install(self, *args, **kwargs):
super(userProfileInteractor, self).install(*args, **kwargs) super(userProfileInteractor, self).install(*args, **kwargs)
pub.subscribe(self.set, self.modulename+"_set") pub.subscribe(self.set, self.modulename+"_set")
pub.subscribe(self.load_image, self.modulename+"_load_image") pub.subscribe(self.load_image, self.modulename+"_load_image")
self.view.create_controls("main_info") self.view.create_controls("main_info")
self.view.realice() self.view.realice()
widgetUtils.connect_event(self.view.main_info.go_site, widgetUtils.BUTTON_PRESSED, self.on_visit_website) widgetUtils.connect_event(self.view.main_info.go_site, widgetUtils.BUTTON_PRESSED, self.on_visit_website)
def uninstall(self): def uninstall(self):
super(userProfileInteractor, self).uninstall() super(userProfileInteractor, self).uninstall()
pub.unsubscribe(self.set, self.modulename+"_set") pub.unsubscribe(self.set, self.modulename+"_set")
pub.unsubscribe(self.load_image, self.modulename+"_load_image") pub.unsubscribe(self.load_image, self.modulename+"_load_image")
def on_visit_website(self, *args, **kwargs): def on_visit_website(self, *args, **kwargs):
urls = self.presenter.get_urls() urls = self.presenter.get_urls()
if len(urls) == 1: if len(urls) == 1:
self.presenter.visit_url(urls[0]) self.presenter.visit_url(urls[0])
else: else:
dialog = urlList.urlList() dialog = urlList.urlList()
dialog.populate_list(urls) dialog.populate_list(urls)
if dialog.get_response() != widgetUtils.OK: if dialog.get_response() != widgetUtils.OK:
return return
selected_url = urls[dialog.get_item()] selected_url = urls[dialog.get_item()]
self.presenter.visit_url(selected_url) self.presenter.visit_url(selected_url)

View File

@ -28,37 +28,37 @@ from mysc.thread_utils import call_threaded
from . import wx_ui from . import wx_ui
class reportBug(object): class reportBug(object):
def __init__(self): def __init__(self):
self.dialog = wx_ui.reportBugDialog() self.dialog = wx_ui.reportBugDialog()
widgetUtils.connect_event(self.dialog.ok, widgetUtils.BUTTON_PRESSED, self.send) widgetUtils.connect_event(self.dialog.ok, widgetUtils.BUTTON_PRESSED, self.send)
self.dialog.get_response() self.dialog.get_response()
def do_report(self, *args, **kwargs): def do_report(self, *args, **kwargs):
r = requests.post(*args, **kwargs) r = requests.post(*args, **kwargs)
if r.status_code > 300: if r.status_code > 300:
wx.CallAfter(self.dialog.error) wx.CallAfter(self.dialog.error)
wx.CallAfter(self.dialog.progress.Destroy) wx.CallAfter(self.dialog.progress.Destroy)
wx.CallAfter(self.dialog.success, r.json()["data"]["issue"]["id"]) wx.CallAfter(self.dialog.success, r.json()["data"]["issue"]["id"])
def send(self, *args, **kwargs): def send(self, *args, **kwargs):
if self.dialog.get("summary") == "" or self.dialog.get("description") == "" or self.dialog.get("first_name") == "" or self.dialog.get("last_name") == "": if self.dialog.get("summary") == "" or self.dialog.get("description") == "" or self.dialog.get("first_name") == "" or self.dialog.get("last_name") == "":
self.dialog.no_filled() self.dialog.no_filled()
return return
if self.dialog.get("agree") == False: if self.dialog.get("agree") == False:
self.dialog.no_checkbox() self.dialog.no_checkbox()
return return
title = self.dialog.get("summary") title = self.dialog.get("summary")
body = self.dialog.get("description") body = self.dialog.get("description")
issue_type = "issue" # for now just have issue issue_type = "issue" # for now just have issue
app_type = paths.mode app_type = paths.mode
app_version = application.version app_version = application.version
reporter_name = "{first_name} {last_name}".format(first_name=self.dialog.get("first_name"), last_name=self.dialog.get("last_name")) reporter_name = "{first_name} {last_name}".format(first_name=self.dialog.get("first_name"), last_name=self.dialog.get("last_name"))
reporter_contact_type = "email" # For now just email is supported in the issue reporter reporter_contact_type = "email" # For now just email is supported in the issue reporter
reporter_contact_handle = self.dialog.get("email") reporter_contact_handle = self.dialog.get("email")
operating_system = platform.platform() operating_system = platform.platform()
json = dict(title=title, issue_type=issue_type, body=body, operating_system=operating_system, app_type=app_type, app_version=app_version, reporter_name=reporter_name, reporter_contact_handle=reporter_contact_handle, reporter_contact_type=reporter_contact_type) json = dict(title=title, issue_type=issue_type, body=body, operating_system=operating_system, app_type=app_type, app_version=app_version, reporter_name=reporter_name, reporter_contact_handle=reporter_contact_handle, reporter_contact_type=reporter_contact_type)
auth=HTTPBasicAuth(application.bts_name, application.bts_access_token) auth=HTTPBasicAuth(application.bts_name, application.bts_access_token)
url = "{bts_url}/issue/new".format(bts_url=application.bts_url) url = "{bts_url}/issue/new".format(bts_url=application.bts_url)
call_threaded(self.do_report, url, json=json, auth=auth) call_threaded(self.do_report, url, json=json, auth=auth)
self.dialog.show_progress() self.dialog.show_progress()
self.dialog.EndModal(wx.ID_OK) self.dialog.EndModal(wx.ID_OK)

View File

@ -22,89 +22,89 @@ import widgetUtils
import application import application
class reportBugDialog(widgetUtils.BaseDialog): class reportBugDialog(widgetUtils.BaseDialog):
def __init__(self): def __init__(self):
super(reportBugDialog, self).__init__(parent=None, id=wx.NewId()) super(reportBugDialog, self).__init__(parent=None, id=wx.NewId())
self.SetTitle(_("Report an error")) self.SetTitle(_("Report an error"))
panel = wx.Panel(self) panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
summaryLabel = wx.StaticText(panel, -1, _("Briefly describe what happened. You will be able to thoroughly explain it later"), size=wx.DefaultSize) summaryLabel = wx.StaticText(panel, -1, _("Briefly describe what happened. You will be able to thoroughly explain it later"), size=wx.DefaultSize)
self.summary = wx.TextCtrl(panel, -1) self.summary = wx.TextCtrl(panel, -1)
dc = wx.WindowDC(self.summary) dc = wx.WindowDC(self.summary)
dc.SetFont(self.summary.GetFont()) dc.SetFont(self.summary.GetFont())
self.summary.SetSize(dc.GetTextExtent("a"*80)) self.summary.SetSize(dc.GetTextExtent("a"*80))
summaryB = wx.BoxSizer(wx.HORIZONTAL) summaryB = wx.BoxSizer(wx.HORIZONTAL)
summaryB.Add(summaryLabel, 0, wx.ALL, 5) summaryB.Add(summaryLabel, 0, wx.ALL, 5)
summaryB.Add(self.summary, 0, wx.ALL, 5) summaryB.Add(self.summary, 0, wx.ALL, 5)
sizer.Add(summaryB, 0, wx.ALL, 5) sizer.Add(summaryB, 0, wx.ALL, 5)
first_nameLabel = wx.StaticText(panel, -1, _("First Name"), size=wx.DefaultSize) first_nameLabel = wx.StaticText(panel, -1, _("First Name"), size=wx.DefaultSize)
self.first_name = wx.TextCtrl(panel, -1) self.first_name = wx.TextCtrl(panel, -1)
dc = wx.WindowDC(self.first_name) dc = wx.WindowDC(self.first_name)
dc.SetFont(self.first_name.GetFont()) dc.SetFont(self.first_name.GetFont())
self.first_name.SetSize(dc.GetTextExtent("a"*40)) self.first_name.SetSize(dc.GetTextExtent("a"*40))
first_nameB = wx.BoxSizer(wx.HORIZONTAL) first_nameB = wx.BoxSizer(wx.HORIZONTAL)
first_nameB.Add(first_nameLabel, 0, wx.ALL, 5) first_nameB.Add(first_nameLabel, 0, wx.ALL, 5)
first_nameB.Add(self.first_name, 0, wx.ALL, 5) first_nameB.Add(self.first_name, 0, wx.ALL, 5)
sizer.Add(first_nameB, 0, wx.ALL, 5) sizer.Add(first_nameB, 0, wx.ALL, 5)
last_nameLabel = wx.StaticText(panel, -1, _("Last Name"), size=wx.DefaultSize) last_nameLabel = wx.StaticText(panel, -1, _("Last Name"), size=wx.DefaultSize)
self.last_name = wx.TextCtrl(panel, -1) self.last_name = wx.TextCtrl(panel, -1)
dc = wx.WindowDC(self.last_name) dc = wx.WindowDC(self.last_name)
dc.SetFont(self.last_name.GetFont()) dc.SetFont(self.last_name.GetFont())
self.last_name.SetSize(dc.GetTextExtent("a"*40)) self.last_name.SetSize(dc.GetTextExtent("a"*40))
last_nameB = wx.BoxSizer(wx.HORIZONTAL) last_nameB = wx.BoxSizer(wx.HORIZONTAL)
last_nameB.Add(last_nameLabel, 0, wx.ALL, 5) last_nameB.Add(last_nameLabel, 0, wx.ALL, 5)
last_nameB.Add(self.last_name, 0, wx.ALL, 5) last_nameB.Add(self.last_name, 0, wx.ALL, 5)
sizer.Add(last_nameB, 0, wx.ALL, 5) sizer.Add(last_nameB, 0, wx.ALL, 5)
emailLabel = wx.StaticText(panel, -1, _("Email address (Will not be public)"), size=wx.DefaultSize) emailLabel = wx.StaticText(panel, -1, _("Email address (Will not be public)"), size=wx.DefaultSize)
self.email = wx.TextCtrl(panel, -1) self.email = wx.TextCtrl(panel, -1)
dc = wx.WindowDC(self.email) dc = wx.WindowDC(self.email)
dc.SetFont(self.email.GetFont()) dc.SetFont(self.email.GetFont())
self.email.SetSize(dc.GetTextExtent("a"*30)) self.email.SetSize(dc.GetTextExtent("a"*30))
emailB = wx.BoxSizer(wx.HORIZONTAL) emailB = wx.BoxSizer(wx.HORIZONTAL)
emailB.Add(emailLabel, 0, wx.ALL, 5) emailB.Add(emailLabel, 0, wx.ALL, 5)
emailB.Add(self.email, 0, wx.ALL, 5) emailB.Add(self.email, 0, wx.ALL, 5)
sizer.Add(emailB, 0, wx.ALL, 5) sizer.Add(emailB, 0, wx.ALL, 5)
descriptionLabel = wx.StaticText(panel, -1, _("Here, you can describe the bug in detail"), size=wx.DefaultSize) descriptionLabel = wx.StaticText(panel, -1, _("Here, you can describe the bug in detail"), size=wx.DefaultSize)
self.description = wx.TextCtrl(panel, -1, style=wx.TE_MULTILINE) self.description = wx.TextCtrl(panel, -1, style=wx.TE_MULTILINE)
dc = wx.WindowDC(self.description) dc = wx.WindowDC(self.description)
dc.SetFont(self.description.GetFont()) dc.SetFont(self.description.GetFont())
(x, y) = dc.GetMultiLineTextExtent("0"*2000) (x, y) = dc.GetMultiLineTextExtent("0"*2000)
self.description.SetSize((x, y)) self.description.SetSize((x, y))
descBox = wx.BoxSizer(wx.HORIZONTAL) descBox = wx.BoxSizer(wx.HORIZONTAL)
descBox.Add(descriptionLabel, 0, wx.ALL, 5) descBox.Add(descriptionLabel, 0, wx.ALL, 5)
descBox.Add(self.description, 0, wx.ALL, 5) descBox.Add(self.description, 0, wx.ALL, 5)
sizer.Add(descBox, 0, wx.ALL, 5) sizer.Add(descBox, 0, wx.ALL, 5)
self.agree = wx.CheckBox(panel, -1, _("I know that the {0} bug system will get my email address to contact me and fix the bug quickly").format(application.name,)) self.agree = wx.CheckBox(panel, -1, _("I know that the {0} bug system will get my email address to contact me and fix the bug quickly").format(application.name,))
self.agree.SetValue(False) self.agree.SetValue(False)
sizer.Add(self.agree, 0, wx.ALL, 5) sizer.Add(self.agree, 0, wx.ALL, 5)
self.ok = wx.Button(panel, wx.ID_OK, _("Send report")) self.ok = wx.Button(panel, wx.ID_OK, _("Send report"))
self.ok.SetDefault() self.ok.SetDefault()
cancel = wx.Button(panel, wx.ID_CANCEL, _("Cancel")) cancel = wx.Button(panel, wx.ID_CANCEL, _("Cancel"))
btnBox = wx.BoxSizer(wx.HORIZONTAL) btnBox = wx.BoxSizer(wx.HORIZONTAL)
btnBox.Add(self.ok, 0, wx.ALL, 5) btnBox.Add(self.ok, 0, wx.ALL, 5)
btnBox.Add(cancel, 0, wx.ALL, 5) btnBox.Add(cancel, 0, wx.ALL, 5)
sizer.Add(btnBox, 0, wx.ALL, 5) sizer.Add(btnBox, 0, wx.ALL, 5)
panel.SetSizer(sizer) panel.SetSizer(sizer)
self.SetClientSize(sizer.CalcMin()) self.SetClientSize(sizer.CalcMin())
def no_filled(self): def no_filled(self):
wx.MessageDialog(self, _("You must fill out the following fields: first name, last name, email address and issue information."), _("Error"), wx.OK|wx.ICON_ERROR).ShowModal() wx.MessageDialog(self, _("You must fill out the following fields: first name, last name, email address and issue information."), _("Error"), wx.OK|wx.ICON_ERROR).ShowModal()
def no_checkbox(self): def no_checkbox(self):
wx.MessageDialog(self, _("You need to mark the checkbox to provide us your email address to contact you if it is necessary."), _("Error"), wx.ICON_ERROR).ShowModal() wx.MessageDialog(self, _("You need to mark the checkbox to provide us your email address to contact you if it is necessary."), _("Error"), wx.ICON_ERROR).ShowModal()
def success(self, id): def success(self, id):
wx.MessageDialog(self, _("Thanks for reporting this bug! In future versions, you may be able to find it in the changes list. You have received an email with more information regarding your report. You've reported the bug number %i") % (id), _("reported"), wx.OK).ShowModal() wx.MessageDialog(self, _("Thanks for reporting this bug! In future versions, you may be able to find it in the changes list. You have received an email with more information regarding your report. You've reported the bug number %i") % (id), _("reported"), wx.OK).ShowModal()
self.Destroy() self.Destroy()
def error(self): def error(self):
wx.MessageDialog(self, _("Something unexpected occurred while trying to report the bug. Please, try again later"), _("Error while reporting"), wx.ICON_ERROR|wx.OK).ShowModal() wx.MessageDialog(self, _("Something unexpected occurred while trying to report the bug. Please, try again later"), _("Error while reporting"), wx.ICON_ERROR|wx.OK).ShowModal()
self.Destroy() self.Destroy()
def show_progress(self): def show_progress(self):
self.progress = wx.ProgressDialog(title=_("Sending report..."), message=_("Please wait while your report is being send."), maximum=100, parent=self) self.progress = wx.ProgressDialog(title=_("Sending report..."), message=_("Please wait while your report is being send."), maximum=100, parent=self)
self.progress.ShowModal() self.progress.ShowModal()

View File

@ -5,12 +5,12 @@ log = logging.getLogger("keyring")
keyring = None keyring = None
def setup(): def setup():
global keyring global keyring
if keyring == None: if keyring == None:
keyring = Keyring() keyring = Keyring()
log.debug("Keyring started") log.debug("Keyring started")
class Keyring(object): class Keyring(object):
def get_api_key(self): def get_api_key(self):
return "5093442" return "5093442"

View File

@ -20,195 +20,195 @@ LOCALE_SLANGDISPLAYNAME=0x6f
curLang="en" curLang="en"
def localeNameToWindowsLCID(localeName): def localeNameToWindowsLCID(localeName):
"""Retreave the Windows locale identifier (LCID) for the given locale name """Retreave the Windows locale identifier (LCID) for the given locale name
@param localeName: a string of 2letterLanguage_2letterCountry or or just 2letterLanguage @param localeName: a string of 2letterLanguage_2letterCountry or or just 2letterLanguage
@type localeName: string @type localeName: string
@returns: a Windows LCID @returns: a Windows LCID
@rtype: integer @rtype: integer
""" """
#Windows Vista is able to convert locale names to LCIDs #Windows Vista is able to convert locale names to LCIDs
func_LocaleNameToLCID=getattr(ctypes.windll.kernel32,'LocaleNameToLCID',None) func_LocaleNameToLCID=getattr(ctypes.windll.kernel32,'LocaleNameToLCID',None)
if func_LocaleNameToLCID is not None: if func_LocaleNameToLCID is not None:
localeName=localeName.replace('_','-') localeName=localeName.replace('_','-')
LCID=func_LocaleNameToLCID(str(localeName),0) LCID=func_LocaleNameToLCID(str(localeName),0)
else: #Windows doesn't have this functionality, manually search Python's windows_locale dictionary for the LCID else: #Windows doesn't have this functionality, manually search Python's windows_locale dictionary for the LCID
localeName=locale.normalize(localeName) localeName=locale.normalize(localeName)
if '.' in localeName: if '.' in localeName:
localeName=localeName.split('.')[0] localeName=localeName.split('.')[0]
LCList=[x[0] for x in locale.windows_locale.items() if x[1]==localeName] LCList=[x[0] for x in locale.windows_locale.items() if x[1]==localeName]
if len(LCList)>0: if len(LCList)>0:
LCID=LCList[0] LCID=LCList[0]
else: else:
LCID=0 LCID=0
return LCID return LCID
def getLanguageDescription(language): def getLanguageDescription(language):
"""Finds out the description (localized full name) of a given local name""" """Finds out the description (localized full name) of a given local name"""
desc=None desc=None
if platform.system() == "Windows": if platform.system() == "Windows":
LCID=localeNameToWindowsLCID(language) LCID=localeNameToWindowsLCID(language)
if LCID!=0: if LCID!=0:
buf=ctypes.create_unicode_buffer(1024) buf=ctypes.create_unicode_buffer(1024)
if '_' not in language: if '_' not in language:
res=ctypes.windll.kernel32.GetLocaleInfoW(LCID,LOCALE_SLANGDISPLAYNAME,buf,1024) res=ctypes.windll.kernel32.GetLocaleInfoW(LCID,LOCALE_SLANGDISPLAYNAME,buf,1024)
else: else:
res=0 res=0
if res==0: if res==0:
res=ctypes.windll.kernel32.GetLocaleInfoW(LCID,LOCALE_SLANGUAGE,buf,1024) res=ctypes.windll.kernel32.GetLocaleInfoW(LCID,LOCALE_SLANGUAGE,buf,1024)
desc=buf.value desc=buf.value
elif platform.system() == "Linux" or not desc: elif platform.system() == "Linux" or not desc:
desc={ desc={
"am":pgettext("languageName","Amharic"), "am":pgettext("languageName","Amharic"),
"an":pgettext("languageName","Aragonese"), "an":pgettext("languageName","Aragonese"),
"es":pgettext("languageName","Spanish"), "es":pgettext("languageName","Spanish"),
"pt":pgettext("languageName","Portuguese"), "pt":pgettext("languageName","Portuguese"),
"ru":pgettext("languageName","Russian"), "ru":pgettext("languageName","Russian"),
"it":pgettext("languageName","italian"), "it":pgettext("languageName","italian"),
"tr":pgettext("languageName","Turkey"), "tr":pgettext("languageName","Turkey"),
"gl":pgettext("languageName","Galician"), "gl":pgettext("languageName","Galician"),
"ca":pgettext("languageName","Catala"), "ca":pgettext("languageName","Catala"),
"eu":pgettext("languageName","Vasque"), "eu":pgettext("languageName","Vasque"),
"pl":pgettext("languageName","polish"), "pl":pgettext("languageName","polish"),
"ar":pgettext("languageName","Arabic"), "ar":pgettext("languageName","Arabic"),
"ne":pgettext("languageName","Nepali"), "ne":pgettext("languageName","Nepali"),
"sr":pgettext("languageName","Serbian (Latin)"), "sr":pgettext("languageName","Serbian (Latin)"),
"ja":pgettext("languageName","Japanese"), "ja":pgettext("languageName","Japanese"),
}.get(language,None) }.get(language,None)
return desc return desc
def getAvailableLanguages(): def getAvailableLanguages():
"""generates a list of locale names, plus their full localized language and country names. """generates a list of locale names, plus their full localized language and country names.
@rtype: list of tuples @rtype: list of tuples
""" """
#Make a list of all the locales found in NVDA's locale dir #Make a list of all the locales found in NVDA's locale dir
l=[x for x in os.listdir(paths.locale_path()) if not x.startswith('.')] l=[x for x in os.listdir(paths.locale_path()) if not x.startswith('.')]
l=[x for x in l if os.path.isfile(os.path.join(paths.locale_path(), '%s/LC_MESSAGES/%s.po' % (x, application.short_name)))] l=[x for x in l if os.path.isfile(os.path.join(paths.locale_path(), '%s/LC_MESSAGES/%s.po' % (x, application.short_name)))]
#Make sure that en (english) is in the list as it may not have any locale files, but is default #Make sure that en (english) is in the list as it may not have any locale files, but is default
if 'en' not in l: if 'en' not in l:
l.append('en') l.append('en')
l.sort() l.sort()
#For each locale, ask Windows for its human readable display name #For each locale, ask Windows for its human readable display name
d=[] d=[]
for i in l: for i in l:
desc=getLanguageDescription(i) desc=getLanguageDescription(i)
label="%s, %s"%(desc,i) if desc else i label="%s, %s"%(desc,i) if desc else i
d.append(label) d.append(label)
#include a 'user default, windows' language, which just represents the default language for this user account #include a 'user default, windows' language, which just represents the default language for this user account
l.append("system") l.append("system")
# Translators: the label for the Windows default NVDA interface language. # Translators: the label for the Windows default NVDA interface language.
d.append(_("User default")) d.append(_("User default"))
#return a zipped up version of both the lists (a list with tuples of locale,label) #return a zipped up version of both the lists (a list with tuples of locale,label)
return list(zip(l,d)) return list(zip(l,d))
def makePgettext(translations): def makePgettext(translations):
"""Obtaina pgettext function for use with a gettext translations instance. """Obtaina pgettext function for use with a gettext translations instance.
pgettext is used to support message contexts, pgettext is used to support message contexts,
but Python 2.7's gettext module doesn't support this, but Python 2.7's gettext module doesn't support this,
so NVDA must provide its own implementation. so NVDA must provide its own implementation.
""" """
if isinstance(translations, gettext.GNUTranslations): if isinstance(translations, gettext.GNUTranslations):
def pgettext(context, message): def pgettext(context, message):
message = str(message) message = str(message)
try: try:
# Look up the message with its context. # Look up the message with its context.
return translations._catalog["%s\x04%s" % (context, message)] return translations._catalog["%s\x04%s" % (context, message)]
except KeyError: except KeyError:
return message return message
else: else:
def pgettext(context, message): def pgettext(context, message):
return str(message) return str(message)
return pgettext return pgettext
def setLanguage(lang): def setLanguage(lang):
system = platform.system() system = platform.system()
global curLang global curLang
try: try:
if lang=="system": if lang=="system":
if system == "Windows": if system == "Windows":
windowsLCID=ctypes.windll.kernel32.GetUserDefaultUILanguage() windowsLCID=ctypes.windll.kernel32.GetUserDefaultUILanguage()
localeName=locale.windows_locale[windowsLCID] localeName=locale.windows_locale[windowsLCID]
elif system == "Darwin": elif system == "Darwin":
import Foundation import Foundation
localeName = Foundation.NSLocale.currentLocale().identifier() localeName = Foundation.NSLocale.currentLocale().identifier()
elif system == "Linux": elif system == "Linux":
localeName = locale.getdefaultlocale()[0] localeName = locale.getdefaultlocale()[0]
trans=gettext.translation(application.short_name, localedir=paths.locale_path(), languages=[localeName]) trans=gettext.translation(application.short_name, localedir=paths.locale_path(), languages=[localeName])
curLang=localeName curLang=localeName
# else: # else:
# localeName=locale.getdefaultlocale()[0] # localeName=locale.getdefaultlocale()[0]
# trans=gettext.translation('twblue', localedir=paths.locale_path(), languages=[localeName]) # trans=gettext.translation('twblue', localedir=paths.locale_path(), languages=[localeName])
# curLang=localeName # curLang=localeName
else: else:
trans=gettext.translation(application.short_name, localedir=paths.locale_path(), languages=[lang]) trans=gettext.translation(application.short_name, localedir=paths.locale_path(), languages=[lang])
curLang=lang curLang=lang
localeChanged=False localeChanged=False
#Try setting Python's locale to lang #Try setting Python's locale to lang
# try: # try:
if system == "Windows": if system == "Windows":
locale.setlocale(locale.LC_ALL, langToWindowsLocale(lang)) locale.setlocale(locale.LC_ALL, langToWindowsLocale(lang))
localeChanged=True localeChanged=True
else: else:
locale.setlocale(locale.LC_ALL, lang) locale.setlocale(locale.LC_ALL, lang)
localeChanged=True localeChanged=True
# except: # except:
# pass # pass
if not localeChanged and '_' in lang: if not localeChanged and '_' in lang:
#Python couldn'tsupport the language_country locale, just try language. #Python couldn'tsupport the language_country locale, just try language.
try: try:
locale.setlocale(locale.LC_ALL, lang.split('_')[0]) locale.setlocale(locale.LC_ALL, lang.split('_')[0])
except: except:
pass pass
#Set the windows locale for this thread (NVDA core) to this locale. #Set the windows locale for this thread (NVDA core) to this locale.
if system == "Windows": if system == "Windows":
LCID=localeNameToWindowsLCID(lang) LCID=localeNameToWindowsLCID(lang)
ctypes.windll.kernel32.SetThreadLocale(LCID) ctypes.windll.kernel32.SetThreadLocale(LCID)
except IOError: except IOError:
trans=gettext.translation(application.short_name, fallback=True) trans=gettext.translation(application.short_name, fallback=True)
curLang="en" curLang="en"
if sys.version[0] == "3": if sys.version[0] == "3":
trans.install() trans.install()
else: else:
trans.install(unicode=True) trans.install(unicode=True)
# Install our pgettext function. # Install our pgettext function.
# __builtin__.__dict__["pgettext"] = makePgettext(trans) # __builtin__.__dict__["pgettext"] = makePgettext(trans)
def getLanguage(): def getLanguage():
return curLang return curLang
def normalizeLanguage(lang): def normalizeLanguage(lang):
""" """
Normalizes a language-dialect string in to a standard form we can deal with. Normalizes a language-dialect string in to a standard form we can deal with.
Converts any dash to underline, and makes sure that language is lowercase and dialect is upercase. Converts any dash to underline, and makes sure that language is lowercase and dialect is upercase.
""" """
lang=lang.replace('-','_') lang=lang.replace('-','_')
ld=lang.split('_') ld=lang.split('_')
ld[0]=ld[0].lower() ld[0]=ld[0].lower()
#Filter out meta languages such as x-western #Filter out meta languages such as x-western
if ld[0]=='x': if ld[0]=='x':
return None return None
if len(ld)>=2: if len(ld)>=2:
ld[1]=ld[1].upper() ld[1]=ld[1].upper()
return "_".join(ld) return "_".join(ld)
def langToWindowsLocale(lang): def langToWindowsLocale(lang):
languages = {"en": "eng", languages = {"en": "eng",
"ar": "ara", "ar": "ara",
"ca": "cat", "ca": "cat",
"de": "deu", "de": "deu",
"es": "esp", "es": "esp",
"fi": "fin", "fi": "fin",
"fr": "fre_FRA", "fr": "fre_FRA",
"gl": "glc", "gl": "glc",
"eu": "euq", "eu": "euq",
"hu": "hun", "hu": "hun",
"hr": "hrv", "hr": "hrv",
"it": "ita", "it": "ita",
"ja": "jpn", "ja": "jpn",
"pl": "plk", "pl": "plk",
"pt": "ptb", "pt": "ptb",
"ru": "rus", "ru": "rus",
"tr": "trk", "tr": "trk",
"sr": "eng", "sr": "eng",
} }
return languages[lang] return languages[lang]

View File

@ -15,7 +15,7 @@ import logging
import keys import keys
import application import application
if hasattr(sys, "frozen"): if hasattr(sys, "frozen"):
sys.excepthook = lambda x, y, z: logging.critical(''.join(traceback.format_exception(x, y, z))) sys.excepthook = lambda x, y, z: logging.critical(''.join(traceback.format_exception(x, y, z)))
from mysc.thread_utils import call_threaded from mysc.thread_utils import call_threaded
from wxUI import commonMessages from wxUI import commonMessages
@ -24,48 +24,48 @@ log = logging.getLogger("main")
orig_session_init = None orig_session_init = None
def setup(): def setup():
global orig_session_init global orig_session_init
log.debug("Starting Socializer %s" % (application.version,)) log.debug("Starting Socializer %s" % (application.version,))
config.setup() config.setup()
if config.app["app-settings"]["debug_logging"] == True: if config.app["app-settings"]["debug_logging"] == True:
logger.app_handler.setLevel(logging.DEBUG) logger.app_handler.setLevel(logging.DEBUG)
log.info("Using %s %s" % (platform.system(), platform.architecture()[0])) log.info("Using %s %s" % (platform.system(), platform.architecture()[0]))
log.debug("Application path is %s" % (paths.app_path(),)) log.debug("Application path is %s" % (paths.app_path(),))
log.debug("config path is %s" % (paths.config_path(),)) log.debug("config path is %s" % (paths.config_path(),))
output.setup() output.setup()
languageHandler.setLanguage(config.app["app-settings"]["language"]) languageHandler.setLanguage(config.app["app-settings"]["language"])
log.debug("Language set to %s" % (languageHandler.getLanguage())) log.debug("Language set to %s" % (languageHandler.getLanguage()))
keys.setup() keys.setup()
app = widgetUtils.mainLoopObject() app = widgetUtils.mainLoopObject()
if config.app["app-settings"]["first_start"]: if config.app["app-settings"]["first_start"]:
log.debug("Detected first time execution.") log.debug("Detected first time execution.")
proxy_option = commonMessages.proxy_question() proxy_option = commonMessages.proxy_question()
if proxy_option == widgetUtils.YES: if proxy_option == widgetUtils.YES:
config.app["app-settings"]["use_proxy"] = True config.app["app-settings"]["use_proxy"] = True
log.debug("User has requested to use proxy for connecting to VK.") log.debug("User has requested to use proxy for connecting to VK.")
config.app["app-settings"]["first_start"] = False config.app["app-settings"]["first_start"] = False
config.app.write() config.app.write()
if config.app["app-settings"]["use_proxy"]: if config.app["app-settings"]["use_proxy"]:
log.debug("Enabling proxy support... ") log.debug("Enabling proxy support... ")
import requests import requests
orig_session_init=requests.sessions.Session.__init__ orig_session_init=requests.sessions.Session.__init__
requests.sessions.Session.__init__=patched_session_init requests.sessions.Session.__init__=patched_session_init
requests.Session.__init__=patched_session_init requests.Session.__init__=patched_session_init
from controller import mainController from controller import mainController
from sessionmanager import sessionManager from sessionmanager import sessionManager
log.debug("Created Application mainloop object") log.debug("Created Application mainloop object")
sm = sessionManager.sessionManagerController() sm = sessionManager.sessionManagerController()
sm.show() sm.show()
del sm del sm
r = mainController.Controller() r = mainController.Controller()
call_threaded(r.login) call_threaded(r.login)
app.run() app.run()
def patched_session_init(self): def patched_session_init(self):
global orig_session_init global orig_session_init
orig_session_init(self) orig_session_init(self)
self.proxies={"http": "http://socializer:socializer@socializer.su:3128", self.proxies={"http": "http://socializer:socializer@socializer.su:3128",
"https": "http://socializer:socializer@socializer.su:3128"} "https": "http://socializer:socializer@socializer.su:3128"}
setup() setup()

View File

@ -5,14 +5,13 @@ import logging
log = logging.getLogger("mysc.localization") log = logging.getLogger("mysc.localization")
def get(rootFolder): def get(rootFolder):
log.debug("Getting documentation folder. RootFolder: %s" % (rootFolder,)) log.debug("Getting documentation folder. RootFolder: %s" % (rootFolder,))
defaultLocale = languageHandler.curLang defaultLocale = languageHandler.curLang
if len(defaultLocale) > 2: if len(defaultLocale) > 2:
defaultLocale = defaultLocale[:2] defaultLocale = defaultLocale[:2]
log.debug("Locale: %s" % (defaultLocale,)) log.debug("Locale: %s" % (defaultLocale,))
if os.path.exists(rootFolder+"/"+defaultLocale): if os.path.exists(rootFolder+"/"+defaultLocale):
return defaultLocale return defaultLocale
else: else:
log.debug("The folder does not exist, using the English folder...") log.debug("The folder does not exist, using the English folder...")
return "en" return "en"

View File

@ -4,34 +4,34 @@ import logging
log = logging.getLogger("mysc.repeating_timer") log = logging.getLogger("mysc.repeating_timer")
class RepeatingTimer(threading.Thread): class RepeatingTimer(threading.Thread):
"""Call a function after a specified number of seconds, it will then repeat again after the specified number of seconds """Call a function after a specified number of seconds, it will then repeat again after the specified number of seconds
Note: If the function provided takes time to execute, this time is NOT taken from the next wait period Note: If the function provided takes time to execute, this time is NOT taken from the next wait period
t = RepeatingTimer(30.0, f, args=[], kwargs={}) t = RepeatingTimer(30.0, f, args=[], kwargs={})
t.start() t.start()
t.cancel() # stop the timer's actions t.cancel() # stop the timer's actions
""" """
def __init__(self, interval, function, daemon=True, *args, **kwargs): def __init__(self, interval, function, daemon=True, *args, **kwargs):
threading.Thread.__init__(self) threading.Thread.__init__(self)
self.daemon = daemon self.daemon = daemon
self.interval = float(interval) self.interval = float(interval)
self.function = function self.function = function
self.args = args self.args = args
self.kwargs = kwargs self.kwargs = kwargs
self.finished = threading.Event() self.finished = threading.Event()
def cancel(self): def cancel(self):
"""Stop the timer if it hasn't finished yet""" """Stop the timer if it hasn't finished yet"""
log.debug("Stopping repeater for %s" % (self.function,)) log.debug("Stopping repeater for %s" % (self.function,))
self.finished.set() self.finished.set()
stop = cancel stop = cancel
def run(self): def run(self):
while not self.finished.is_set(): while not self.finished.is_set():
self.finished.wait(self.interval) self.finished.wait(self.interval)
if not self.finished.is_set(): #In case someone has canceled while waiting if not self.finished.is_set(): #In case someone has canceled while waiting
try: try:
self.function(*self.args, **self.kwargs) self.function(*self.args, **self.kwargs)
except: except:
log.exception("Execution failed. Function: %r args: %r and kwargs: %r" % (self.function, self.args, self.kwargs)) log.exception("Execution failed. Function: %r args: %r and kwargs: %r" % (self.function, self.args, self.kwargs))

View File

@ -3,10 +3,10 @@ from __future__ import unicode_literals
import sys, os import sys, os
def restart_program(): def restart_program():
""" Function that restarts the application if is executed.""" """ Function that restarts the application if is executed."""
args = sys.argv[:] args = sys.argv[:]
if not hasattr(sys, "frozen"): if not hasattr(sys, "frozen"):
args.insert(0, sys.executable) args.insert(0, sys.executable)
if sys.platform == 'win32': if sys.platform == 'win32':
args = ['"%s"' % arg for arg in args] args = ['"%s"' % arg for arg in args]
os.execv(sys.executable, args) os.execv(sys.executable, args)

View File

@ -5,13 +5,13 @@ standard_library.install_aliases()
import threading import threading
def call_threaded(func, *args, **kwargs): def call_threaded(func, *args, **kwargs):
#Call the given function in a daemonized thread and return the thread. #Call the given function in a daemonized thread and return the thread.
def new_func(*a, **k): def new_func(*a, **k):
# try: # try:
func(*a, **k) func(*a, **k)
# except: # except:
# pass # pass
thread = threading.Thread(target=new_func, args=args, kwargs=kwargs) thread = threading.Thread(target=new_func, args=args, kwargs=kwargs)
thread.daemon = True thread.daemon = True
thread.start() thread.start()
return thread return thread

View File

@ -9,34 +9,34 @@ speaker = None
retries = 0 retries = 0
def speak(text, interrupt=0): def speak(text, interrupt=0):
global speaker, retries global speaker, retries
if not speaker: if not speaker:
setup() setup()
try: try:
speaker.speak(text, interrupt) speaker.speak(text, interrupt)
except: except:
if retries < 5: if retries < 5:
retries = retries + 1 retries = retries + 1
speak(text) speak(text)
# speaker.braille(text) # speaker.braille(text)
def setup (): def setup ():
global speaker global speaker
logger.debug("Initializing output subsystem.") logger.debug("Initializing output subsystem.")
try: try:
# speaker = speech.Speaker(speech.outputs.Sapi5()) # speaker = speech.Speaker(speech.outputs.Sapi5())
# else: # else:
speaker = outputs.auto.Auto() speaker = outputs.auto.Auto()
except: except:
logger.exception("Output: Error during initialization.") logger.exception("Output: Error during initialization.")
def enable_sapi(): def enable_sapi():
speaker = outputs.sapi.SAPI5() speaker = outputs.sapi.SAPI5()
def copy(text): def copy(text):
import win32clipboard import win32clipboard
#Copies text to the clipboard. #Copies text to the clipboard.
win32clipboard.OpenClipboard() win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard() win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardText(text) win32clipboard.SetClipboardText(text)
win32clipboard.CloseClipboard() win32clipboard.CloseClipboard()

View File

@ -15,58 +15,58 @@ fsencoding = sys.getfilesystemencoding()
#log = logging.getLogger("paths") #log = logging.getLogger("paths")
if len(glob.glob("Uninstall.exe")) > 0: # installed copy if len(glob.glob("Uninstall.exe")) > 0: # installed copy
mode= "installed" mode= "installed"
def app_path(): def app_path():
return paths_.app_path() return paths_.app_path()
def config_path(): def config_path():
global mode, directory global mode, directory
if mode == "portable": if mode == "portable":
if directory != None: path = os.path.join(directory, "config") if directory != None: path = os.path.join(directory, "config")
elif directory == None: path = os.path.join(app_path(), "config") elif directory == None: path = os.path.join(app_path(), "config")
elif mode == "installed": elif mode == "installed":
path = os.path.join(data_path(), "config") path = os.path.join(data_path(), "config")
if not os.path.exists(path): if not os.path.exists(path):
# log.debug("%s path does not exist, creating..." % (path,)) # log.debug("%s path does not exist, creating..." % (path,))
os.mkdir(path) os.mkdir(path)
return path return path
def logs_path(): def logs_path():
global mode, directory global mode, directory
if mode == "portable": if mode == "portable":
if directory != None: path = os.path.join(directory, "logs") if directory != None: path = os.path.join(directory, "logs")
elif directory == None: path = os.path.join(app_path(), "logs") elif directory == None: path = os.path.join(app_path(), "logs")
elif mode == "installed": elif mode == "installed":
path = os.path.join(data_path(), "logs") path = os.path.join(data_path(), "logs")
if not os.path.exists(path): if not os.path.exists(path):
# log.debug("%s path does not exist, creating..." % (path,)) # log.debug("%s path does not exist, creating..." % (path,))
os.mkdir(path) os.mkdir(path)
return path return path
def data_path(app_name='socializer'): def data_path(app_name='socializer'):
if platform.system() == "Windows": if platform.system() == "Windows":
data_path = os.path.join(os.getenv("AppData"), app_name) data_path = os.path.join(os.getenv("AppData"), app_name)
else: else:
data_path = os.path.join(os.environ['HOME'], ".%s" % app_name) data_path = os.path.join(os.environ['HOME'], ".%s" % app_name)
if not os.path.exists(data_path): if not os.path.exists(data_path):
os.mkdir(data_path) os.mkdir(data_path)
return data_path return data_path
def locale_path(): def locale_path():
return os.path.join(app_path(), "locales") return os.path.join(app_path(), "locales")
def sound_path(): def sound_path():
return os.path.join(app_path(), "sounds") return os.path.join(app_path(), "sounds")
def com_path(): def com_path():
global mode, directory global mode, directory
if mode == "portable": if mode == "portable":
if directory != None: path = os.path.join(directory, "com_cache") if directory != None: path = os.path.join(directory, "com_cache")
elif directory == None: path = os.path.join(app_path(), "com_cache") elif directory == None: path = os.path.join(app_path(), "com_cache")
elif mode == "installed": elif mode == "installed":
path = os.path.join(data_path(), "com_cache") path = os.path.join(data_path(), "com_cache")
if not os.path.exists(path): if not os.path.exists(path):
# log.debug("%s path does not exist, creating..." % (path,)) # log.debug("%s path does not exist, creating..." % (path,))
os.mkdir(path) os.mkdir(path)
return path return path

View File

@ -1,15 +1,15 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" A "presenter" in the socializer's terminology is a module that handles business logic in the application's workflow. """ A "presenter" in the socializer's terminology is a module that handles business logic in the application's workflow.
All presenter classes should derive from base.basePresenter and will be completely abstracted from views (the GUI elements). It means presenters and views don't know anything about the each other. All presenter classes should derive from base.basePresenter and will be completely abstracted from views (the GUI elements). It means presenters and views don't know anything about the each other.
Both Presenters and views can communicate through the interactors. Interactors are responsible to receive user input and send requests to the presenters, aswell as receiving presenter requests and render those in the view. Both Presenters and views can communicate through the interactors. Interactors are responsible to receive user input and send requests to the presenters, aswell as receiving presenter requests and render those in the view.
So, in a tipical user interaction made in socializer, the following could happen when someone decides to do something: So, in a tipical user interaction made in socializer, the following could happen when someone decides to do something:
1. A new presenter is created, with two mandatory arguments: The corresponding view and interactor. 1. A new presenter is created, with two mandatory arguments: The corresponding view and interactor.
2. The presenter will call to the install() method in the interactor, to connect all GUI events to their corresponding methods. All of these functions will be present in the interactor only. 2. The presenter will call to the install() method in the interactor, to connect all GUI events to their corresponding methods. All of these functions will be present in the interactor only.
3. After install(), the presenter will run the View, which will display the graphical user interface that users can see and interact with. The view is the only layer directly accessible from the user world and does not handle any kind of logic. 3. After install(), the presenter will run the View, which will display the graphical user interface that users can see and interact with. The view is the only layer directly accessible from the user world and does not handle any kind of logic.
4. If the user presses a button or generates an event connected to a function in the interactor side, the function will be executed in the interactor. The interactor is aware of the View, and holds a reference to the presenter. The interactor should call other GUI elements if necessary and handle some logic (related to GUI, like yes/no dialogs). The interactor can call the presenter to retrieve some information, though the interactor cannot perform any business logic (like altering the cache database, retrieving usernames and so on). 4. If the user presses a button or generates an event connected to a function in the interactor side, the function will be executed in the interactor. The interactor is aware of the View, and holds a reference to the presenter. The interactor should call other GUI elements if necessary and handle some logic (related to GUI, like yes/no dialogs). The interactor can call the presenter to retrieve some information, though the interactor cannot perform any business logic (like altering the cache database, retrieving usernames and so on).
5. If the interactor calls something in the presenter, it will be executed. The presenter knows everything about VK and the session object, so it will fetch data, save it in the cache, call other methods from VK and what not. If the presenter wants to change something in the GUI elements (for example, hiding a control or displaying something else), it will send a pubsub event that the interactor will receive and act on accordingly. 5. If the interactor calls something in the presenter, it will be executed. The presenter knows everything about VK and the session object, so it will fetch data, save it in the cache, call other methods from VK and what not. If the presenter wants to change something in the GUI elements (for example, hiding a control or displaying something else), it will send a pubsub event that the interactor will receive and act on accordingly.
By using this design pattern it allows more decoupled code, easier testing (as we don't need to instantiate the views) and easy to switch (or add) a new graphical user interface by replacing interactors and views. By using this design pattern it allows more decoupled code, easier testing (as we don't need to instantiate the views) and easy to switch (or add) a new graphical user interface by replacing interactors and views.
""" """
from . import player from . import player
from .base import * from .base import *

View File

@ -1,15 +1,15 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" A "presenter" in the socializer's terminology is a module that handles business logic in the application's workflow. """ A "presenter" in the socializer's terminology is a module that handles business logic in the application's workflow.
All presenter classes should derive from base.basePresenter and will be completely abstracted from views (the GUI elements). It means presenters and views don't know anything about the each other. All presenter classes should derive from base.basePresenter and will be completely abstracted from views (the GUI elements). It means presenters and views don't know anything about the each other.
Both Presenters and views can communicate through the interactors. Interactors are responsible to receive user input and send requests to the presenters, aswell as receiving presenter requests and render those in the view. Both Presenters and views can communicate through the interactors. Interactors are responsible to receive user input and send requests to the presenters, aswell as receiving presenter requests and render those in the view.
So, in a tipical user interaction made in socializer, the following could happen when someone decides to do something: So, in a tipical user interaction made in socializer, the following could happen when someone decides to do something:
1. A new presenter is created, with two mandatory arguments: The corresponding view and interactor. 1. A new presenter is created, with two mandatory arguments: The corresponding view and interactor.
2. The presenter will call to the install() method in the interactor, to connect all GUI events to their corresponding methods. All of these functions will be present in the interactor only. 2. The presenter will call to the install() method in the interactor, to connect all GUI events to their corresponding methods. All of these functions will be present in the interactor only.
3. After install(), the presenter will run the View, which will display the graphical user interface that users can see and interact with. The view is the only layer directly accessible from the user world and does not handle any kind of logic. 3. After install(), the presenter will run the View, which will display the graphical user interface that users can see and interact with. The view is the only layer directly accessible from the user world and does not handle any kind of logic.
4. If the user presses a button or generates an event connected to a function in the interactor side, the function will be executed in the interactor. The interactor is aware of the View, and holds a reference to the presenter. The interactor should call other GUI elements if necessary and handle some logic (related to GUI, like yes/no dialogs). The interactor can call the presenter to retrieve some information, though the interactor cannot perform any business logic (like altering the cache database, retrieving usernames and so on). 4. If the user presses a button or generates an event connected to a function in the interactor side, the function will be executed in the interactor. The interactor is aware of the View, and holds a reference to the presenter. The interactor should call other GUI elements if necessary and handle some logic (related to GUI, like yes/no dialogs). The interactor can call the presenter to retrieve some information, though the interactor cannot perform any business logic (like altering the cache database, retrieving usernames and so on).
5. If the interactor calls something in the presenter, it will be executed. The presenter knows everything about VK and the session object, so it will fetch data, save it in the cache, call other methods from VK and what not. If the presenter wants to change something in the GUI elements (for example, hiding a control or displaying something else), it will send a pubsub event that the interactor will receive and act on accordingly. 5. If the interactor calls something in the presenter, it will be executed. The presenter knows everything about VK and the session object, so it will fetch data, save it in the cache, call other methods from VK and what not. If the presenter wants to change something in the GUI elements (for example, hiding a control or displaying something else), it will send a pubsub event that the interactor will receive and act on accordingly.
By using this design pattern it allows more decoupled code, easier testing (as we don't need to instantiate the views) and easy to switch (or add) a new graphical user interface by replacing interactors and views. By using this design pattern it allows more decoupled code, easier testing (as we don't need to instantiate the views) and easy to switch (or add) a new graphical user interface by replacing interactors and views.
""" """
from .attach import * from .attach import *
from .audioRecorder import * from .audioRecorder import *

View File

@ -15,109 +15,109 @@ from . import audioRecorder, base
log = logging.getLogger(__file__) log = logging.getLogger(__file__)
class attachPresenter(base.basePresenter): class attachPresenter(base.basePresenter):
""" Controller used in some sections of the application, it can do the following: """ Controller used in some sections of the application, it can do the following:
* Handle all user input related to adding local or online files (online files are those already uploaded in vk). * Handle all user input related to adding local or online files (online files are those already uploaded in vk).
* Prepare local files to be uploaded once a post will be sent (no uploading work is done here, but structured dicts will be generated). * Prepare local files to be uploaded once a post will be sent (no uploading work is done here, but structured dicts will be generated).
* Parse online files and allow addition of them as attachments, so this controller will add both local and online files in the same dialog. * Parse online files and allow addition of them as attachments, so this controller will add both local and online files in the same dialog.
""" """
def __init__(self, session, view, interactor, voice_messages=False): def __init__(self, session, view, interactor, voice_messages=False):
""" Constructor. """ Constructor.
@ session sessionmanager.session object: an object capable of calling all VK methods and accessing the session database. @ session sessionmanager.session object: an object capable of calling all VK methods and accessing the session database.
@voice_messages bool: If True, will add a button for sending voice messages. @voice_messages bool: If True, will add a button for sending voice messages.
""" """
super(attachPresenter, self).__init__(view=view, interactor=interactor, modulename="attach") super(attachPresenter, self).__init__(view=view, interactor=interactor, modulename="attach")
self.session = session self.session = session
# Self.attachments will hold a reference to all attachments added to the dialog. # Self.attachments will hold a reference to all attachments added to the dialog.
self.attachments = list() self.attachments = list()
self.run() self.run()
def upload_image(self, image, description): def upload_image(self, image, description):
""" allows uploading an image from the computer. Description will be used when posting to VK. """ allows uploading an image from the computer. Description will be used when posting to VK.
""" """
imageInfo = {"type": "photo", "file": image, "description": description, "from": "local"} imageInfo = {"type": "photo", "file": image, "description": description, "from": "local"}
self.attachments.append(imageInfo) self.attachments.append(imageInfo)
# Translators: This is the text displayed in the attachments dialog, when the user adds a photo. # Translators: This is the text displayed in the attachments dialog, when the user adds a photo.
info = [_("Photo"), description] info = [_("Photo"), description]
self.send_message("insert_attachment", attachment=info) self.send_message("insert_attachment", attachment=info)
self.send_message("enable_control", control="remove") self.send_message("enable_control", control="remove")
def upload_audio(self, audio): def upload_audio(self, audio):
""" Allows uploading an audio file from the computer. Only mp3 files are supported. """ """ Allows uploading an audio file from the computer. Only mp3 files are supported. """
if audio != None: if audio != None:
# Define data structure for this attachment, as will be required by VK API later. # Define data structure for this attachment, as will be required by VK API later.
# Let's extract the ID3 tags to show them in the list and send them to VK, too. # Let's extract the ID3 tags to show them in the list and send them to VK, too.
try: try:
audio_tags = ID3(audio) audio_tags = ID3(audio)
if "TIT2" in audio_tags: if "TIT2" in audio_tags:
title = audio_tags["TIT2"].text[0] title = audio_tags["TIT2"].text[0]
else: else:
title = _("Untitled") title = _("Untitled")
if "TPE1" in audio_tags: if "TPE1" in audio_tags:
artist = audio_tags["TPE1"].text[0] artist = audio_tags["TPE1"].text[0]
else: else:
artist = _("Unknown artist") artist = _("Unknown artist")
except ID3NoHeaderError: # File doesn't include ID3 tags so let's assume unknown artist. except ID3NoHeaderError: # File doesn't include ID3 tags so let's assume unknown artist.
artist = _("Unknown artist") artist = _("Unknown artist")
title = os.path.basename(audio).replace(".mp3", "") title = os.path.basename(audio).replace(".mp3", "")
audioInfo = {"type": "audio", "file": audio, "from": "local", "title": title, "artist": artist} audioInfo = {"type": "audio", "file": audio, "from": "local", "title": title, "artist": artist}
self.attachments.append(audioInfo) self.attachments.append(audioInfo)
# Translators: This is the text displayed in the attachments dialog, when the user adds an audio file. # Translators: This is the text displayed in the attachments dialog, when the user adds an audio file.
info = [_("Audio file"), "{title} - {artist}".format(title=title, artist=artist)] info = [_("Audio file"), "{title} - {artist}".format(title=title, artist=artist)]
self.send_message("insert_attachment", attachment=info) self.send_message("insert_attachment", attachment=info)
self.send_message("enable_control", control="remove") self.send_message("enable_control", control="remove")
def upload_document(self, document): def upload_document(self, document):
""" allows uploading a document from the computer. """ allows uploading a document from the computer.
""" """
doc_info = {"type": "document", "file": document, "from": "local", "title": os.path.basename(os.path.splitext(document)[0])} doc_info = {"type": "document", "file": document, "from": "local", "title": os.path.basename(os.path.splitext(document)[0])}
self.attachments.append(doc_info) self.attachments.append(doc_info)
# Translators: This is the text displayed in the attachments dialog, when the user adds a document. # Translators: This is the text displayed in the attachments dialog, when the user adds a document.
info = [_("Document"), os.path.basename(document)] info = [_("Document"), os.path.basename(document)]
self.send_message("insert_attachment", attachment=info) self.send_message("insert_attachment", attachment=info)
self.send_message("enable_control", control="remove") self.send_message("enable_control", control="remove")
def upload_voice_message(self): def upload_voice_message(self):
a = audioRecorder.audioRecorderPresenter(view=views.audioRecorderDialog(), interactor=interactors.audioRecorderInteractor()) a = audioRecorder.audioRecorderPresenter(view=views.audioRecorderDialog(), interactor=interactors.audioRecorderInteractor())
if a.file != None and a.duration != 0: if a.file != None and a.duration != 0:
audioInfo = {"type": "voice_message", "file": a.file, "from": "local"} audioInfo = {"type": "voice_message", "file": a.file, "from": "local"}
self.attachments.append(audioInfo) self.attachments.append(audioInfo)
# Translators: This is the text displayed in the attachments dialog, when the user adds an audio file. # Translators: This is the text displayed in the attachments dialog, when the user adds an audio file.
info = [_("Voice message"), seconds_to_string(a.duration,)] info = [_("Voice message"), seconds_to_string(a.duration,)]
self.send_message("insert_attachment", attachment=info) self.send_message("insert_attachment", attachment=info)
self.send_message("enable_control", control="remove") self.send_message("enable_control", control="remove")
####### ToDo: replace this with selector presenter when finished. ####### ToDo: replace this with selector presenter when finished.
def get_available_audios(self): def get_available_audios(self):
# Let's reuse the already downloaded audios. # Let's reuse the already downloaded audios.
list_of_audios = self.session.db["me_audio"]["items"] list_of_audios = self.session.db["me_audio"]["items"]
audios = [] audios = []
for i in list_of_audios: for i in list_of_audios:
audios.append("{0}, {1}".format(i["title"], i["artist"])) audios.append("{0}, {1}".format(i["title"], i["artist"]))
return audios return audios
def take_audios(self, audios_list): def take_audios(self, audios_list):
list_of_audios = self.session.db["me_audio"]["items"] list_of_audios = self.session.db["me_audio"]["items"]
for i in audios_list: for i in audios_list:
info = dict(type="audio", id=list_of_audios[i]["id"], owner_id=list_of_audios[i]["owner_id"]) info = dict(type="audio", id=list_of_audios[i]["id"], owner_id=list_of_audios[i]["owner_id"])
info["from"] = "online" info["from"] = "online"
self.attachments.append(info) self.attachments.append(info)
# Translators: This is the text displayed in the attachments dialog, when the user adds an audio file. # Translators: This is the text displayed in the attachments dialog, when the user adds an audio file.
info2 = [_("Audio file"), "{0} - {1}".format(list_of_audios[i]["title"], list_of_audios[i]["artist"])] info2 = [_("Audio file"), "{0} - {1}".format(list_of_audios[i]["title"], list_of_audios[i]["artist"])]
self.send_message("insert_attachment", attachment=info2) self.send_message("insert_attachment", attachment=info2)
self.check_remove_status() self.check_remove_status()
def remove_attachment(self, item_index): def remove_attachment(self, item_index):
""" Remove the currently focused item from the attachments list.""" """ Remove the currently focused item from the attachments list."""
log.debug("Removing item %d" % (item_index,)) log.debug("Removing item %d" % (item_index,))
if item_index == -1: item_index = 0 if item_index == -1: item_index = 0
self.attachments.pop(item_index) self.attachments.pop(item_index)
self.send_message("remove_attachment", attachment=item_index) self.send_message("remove_attachment", attachment=item_index)
self.check_remove_status() self.check_remove_status()
log.debug("Removed") log.debug("Removed")
def check_remove_status(self): def check_remove_status(self):
""" Checks whether the remove button should remain enabled.""" """ Checks whether the remove button should remain enabled."""
if len(self.attachments) == 0: if len(self.attachments) == 0:
self.send_message("disable_control", control="remove") self.send_message("disable_control", control="remove")

View File

@ -10,102 +10,102 @@ from mysc.thread_utils import call_threaded
from . import base from . import base
class audioRecorderPresenter(base.basePresenter): class audioRecorderPresenter(base.basePresenter):
def __init__(self, view, interactor): def __init__(self, view, interactor):
super(audioRecorderPresenter, self).__init__(view=view, interactor=interactor, modulename="audiorecorder") super(audioRecorderPresenter, self).__init__(view=view, interactor=interactor, modulename="audiorecorder")
self.recorded = False self.recorded = False
self.recording = None self.recording = None
self.duration = 0 self.duration = 0
self.playing = None self.playing = None
self.file = None self.file = None
self.run() self.run()
def toggle_recording(self, *args, **kwargs): def toggle_recording(self, *args, **kwargs):
if self.recording != None: if self.recording != None:
self.stop_recording() self.stop_recording()
else: else:
self.start_recording() self.start_recording()
def start_recording(self): def start_recording(self):
self.file = tempfile.mktemp(suffix='.wav') self.file = tempfile.mktemp(suffix='.wav')
self.recording = sound.get_recording(self.file) self.recording = sound.get_recording(self.file)
self.duration = time.time() self.duration = time.time()
self.recording.play() self.recording.play()
self.send_message("set_label", control="record", label=_("&Stop")) self.send_message("set_label", control="record", label=_("&Stop"))
output.speak(_("Recording")) output.speak(_("Recording"))
self.send_message("disable_control", control="ok") self.send_message("disable_control", control="ok")
def stop_recording(self): def stop_recording(self):
self.recording.stop() self.recording.stop()
self.duration = int(time.time()-self.duration) self.duration = int(time.time()-self.duration)
self.recording.free() self.recording.free()
output.speak(_("Stopped")) output.speak(_("Stopped"))
self.recorded = True self.recorded = True
self.send_message("set_label", control="record", label=_("&Record")) self.send_message("set_label", control="record", label=_("&Record"))
self.send_message("disable_control", control="record") self.send_message("disable_control", control="record")
self.send_message("enable_control", control="play") self.send_message("enable_control", control="play")
self.send_message("enable_control", control="discard") self.send_message("enable_control", control="discard")
self.send_message("enable_control", control="ok") self.send_message("enable_control", control="ok")
self.send_message("focus_control", control="play") self.send_message("focus_control", control="play")
def discard_recording(self, *args, **kwargs): def discard_recording(self, *args, **kwargs):
if self.playing: if self.playing:
self._stop() self._stop()
if self.recording != None: if self.recording != None:
self.cleanup() self.cleanup()
self.send_message("disable_control", control="play") self.send_message("disable_control", control="play")
self.send_message("disable_control", control="ok") self.send_message("disable_control", control="ok")
self.file = None self.file = None
self.send_message("enable_control", control="record") self.send_message("enable_control", control="record")
self.send_message("focus_control", control="record") self.send_message("focus_control", control="record")
self.send_message("disable_control", control="discard") self.send_message("disable_control", control="discard")
self.recording = None self.recording = None
output.speak(_("Discarded")) output.speak(_("Discarded"))
def play(self, *args, **kwargs): def play(self, *args, **kwargs):
if not self.playing: if not self.playing:
call_threaded(self._play) call_threaded(self._play)
else: else:
self._stop() self._stop()
def _play(self): def _play(self):
output.speak(_("Playing...")) output.speak(_("Playing..."))
# try: # try:
self.playing = sound_lib.stream.FileStream(file=str(self.file), flags=sound_lib.stream.BASS_UNICODE) self.playing = sound_lib.stream.FileStream(file=str(self.file), flags=sound_lib.stream.BASS_UNICODE)
self.playing.play() self.playing.play()
self.send_message("set_label", control="play", label=_("&Stop")) self.send_message("set_label", control="play", label=_("&Stop"))
try: try:
while self.playing.is_playing: while self.playing.is_playing:
pass pass
self.send_message("set_label", control="play", label=_("&Play")) self.send_message("set_label", control="play", label=_("&Play"))
self.playing.free() self.playing.free()
self.playing = None self.playing = None
except: except:
pass pass
def _stop(self): def _stop(self):
output.speak(_("Stopped")) output.speak(_("Stopped"))
self.playing.stop() self.playing.stop()
self.playing.free() self.playing.free()
self.send_message("set_label", control="play", label=_("&Play")) self.send_message("set_label", control="play", label=_("&Play"))
self.playing = None self.playing = None
def postprocess(self): def postprocess(self):
if self.file.lower().endswith('.wav'): if self.file.lower().endswith('.wav'):
output.speak(_("Recoding audio...")) output.speak(_("Recoding audio..."))
sound.recode_audio(self.file) sound.recode_audio(self.file)
self.wav_file = self.file self.wav_file = self.file
self.file = '%s.ogg' % self.file[:-4] self.file = '%s.ogg' % self.file[:-4]
self.cleanup() self.cleanup()
def cleanup(self): def cleanup(self):
if self.playing and self.playing.is_playing: if self.playing and self.playing.is_playing:
self.playing.stop() self.playing.stop()
if self.recording != None: if self.recording != None:
if self.recording.is_playing: if self.recording.is_playing:
self.recording.stop() self.recording.stop()
try: try:
self.recording.free() self.recording.free()
except: except:
pass pass
if hasattr(self, 'wav_file'): if hasattr(self, 'wav_file'):
os.remove(self.wav_file) os.remove(self.wav_file)

View File

@ -5,15 +5,15 @@ from interactors import configuration as interactor
class basePresenter(object): class basePresenter(object):
def __init__(self, view, interactor, modulename): def __init__(self, view, interactor, modulename):
self.modulename = modulename self.modulename = modulename
self.interactor = interactor self.interactor = interactor
self.view = view self.view = view
self.interactor.install(view=view, presenter=self, modulename=modulename) self.interactor.install(view=view, presenter=self, modulename=modulename)
def run(self): def run(self):
self.interactor.start() self.interactor.start()
self.interactor.uninstall() self.interactor.uninstall()
def send_message(self, msg, *args, **kwargs): def send_message(self, msg, *args, **kwargs):
pub.sendMessage(self.modulename+"_"+msg, *args, **kwargs) pub.sendMessage(self.modulename+"_"+msg, *args, **kwargs)

View File

@ -5,26 +5,26 @@ from . import base
class blacklistPresenter(base.basePresenter): class blacklistPresenter(base.basePresenter):
def __init__(self, session, view, interactor): def __init__(self, session, view, interactor):
self.session = session self.session = session
super(blacklistPresenter, self).__init__(view=view, interactor=interactor, modulename="blacklist") super(blacklistPresenter, self).__init__(view=view, interactor=interactor, modulename="blacklist")
self.worker = threading.Thread(target=self.load_information) self.worker = threading.Thread(target=self.load_information)
self.worker.finished = threading.Event() self.worker.finished = threading.Event()
self.worker.start() self.worker.start()
self.run() self.run()
def load_information(self): def load_information(self):
banned_users = self.session.vk.client.account.getBanned(count=200) banned_users = self.session.vk.client.account.getBanned(count=200)
self.users = banned_users["profiles"] self.users = banned_users["profiles"]
items = [] items = []
for i in self.users: for i in self.users:
str_user = "{first_name} {last_name}".format(first_name=i["first_name"], last_name=i["last_name"]) str_user = "{first_name} {last_name}".format(first_name=i["first_name"], last_name=i["last_name"])
items.append([str_user]) items.append([str_user])
self.send_message("add_items", control="persons", items=items) self.send_message("add_items", control="persons", items=items)
def unblock_person(self, item): def unblock_person(self, item):
result = self.session.vk.client.account.unban(owner_id=self.users[item]["id"]) result = self.session.vk.client.account.unban(owner_id=self.users[item]["id"])
if result == 1: if result == 1:
msg = _("You've unblocked {user1_nom} from your friends.").format(**self.session.get_user(self.users[item]["id"]),) msg = _("You've unblocked {user1_nom} from your friends.").format(**self.session.get_user(self.users[item]["id"]),)
pub.sendMessage("notify", message=msg) pub.sendMessage("notify", message=msg)
return result return result

View File

@ -8,97 +8,97 @@ from . import base
class configurationPresenter(base.basePresenter): class configurationPresenter(base.basePresenter):
def __init__(self, session, view, interactor): def __init__(self, session, view, interactor):
self.session = session self.session = session
super(configurationPresenter, self).__init__(view=view, interactor=interactor, modulename="configuration") super(configurationPresenter, self).__init__(view=view, interactor=interactor, modulename="configuration")
# Control requirement for a restart of the application. # Control requirement for a restart of the application.
self.needs_restart = False self.needs_restart = False
self.create_config() self.create_config()
self.run() self.run()
def get_notification_label(self, value): def get_notification_label(self, value):
if value == "native": if value == "native":
return _("Native") return _("Native")
else: else:
return _("Custom") return _("Custom")
def get_update_channel_label(self, value): def get_update_channel_label(self, value):
if value == "stable": if value == "stable":
return _("Stable") return _("Stable")
elif value == "weekly": elif value == "weekly":
return _("Weekly") return _("Weekly")
else: else:
return _("Alpha") return _("Alpha")
def get_notification_type(self, value): def get_notification_type(self, value):
if value == _("Native"): if value == _("Native"):
return "native" return "native"
else: else:
return "custom" return "custom"
def get_update_channel_type(self, value): def get_update_channel_type(self, value):
if value == _("Stable"): if value == _("Stable"):
return "stable" return "stable"
elif value == _("Weekly"): elif value == _("Weekly"):
return "weekly" return "weekly"
else: else:
return "alpha" return "alpha"
def create_config(self): def create_config(self):
self.langs = languageHandler.getAvailableLanguages() self.langs = languageHandler.getAvailableLanguages()
langs = [i[1] for i in self.langs] langs = [i[1] for i in self.langs]
self.codes = [i[0] for i in self.langs] self.codes = [i[0] for i in self.langs]
id = self.codes.index(config.app["app-settings"]["language"]) id = self.codes.index(config.app["app-settings"]["language"])
self.send_message("create_tab", tab="general", arglist=dict(languages=langs)) self.send_message("create_tab", tab="general", arglist=dict(languages=langs))
self.send_message("set_language", language=id) self.send_message("set_language", language=id)
self.send_message("set", tab="general", setting="load_images", value=self.session.settings["general"]["load_images"]) self.send_message("set", tab="general", setting="load_images", value=self.session.settings["general"]["load_images"])
self.send_message("set", tab="general", setting="use_proxy", value=config.app["app-settings"]["use_proxy"]) self.send_message("set", tab="general", setting="use_proxy", value=config.app["app-settings"]["use_proxy"])
self.send_message("set", tab="general", setting="debug_logging", value=config.app["app-settings"]["debug_logging"]) self.send_message("set", tab="general", setting="debug_logging", value=config.app["app-settings"]["debug_logging"])
self.send_message("set", tab="general", setting="update_channel", value=self.get_update_channel_label(self.session.settings["general"]["update_channel"])) self.send_message("set", tab="general", setting="update_channel", value=self.get_update_channel_label(self.session.settings["general"]["update_channel"]))
self.send_message("create_tab", tab="buffers") self.send_message("create_tab", tab="buffers")
self.send_message("set", tab="buffers", setting="wall_buffer_count", value=self.session.settings["buffers"]["count_for_wall_buffers"]) self.send_message("set", tab="buffers", setting="wall_buffer_count", value=self.session.settings["buffers"]["count_for_wall_buffers"])
self.send_message("set", tab="buffers", setting="video_buffers_count", value=self.session.settings["buffers"]["count_for_video_buffers"]) self.send_message("set", tab="buffers", setting="video_buffers_count", value=self.session.settings["buffers"]["count_for_video_buffers"])
self.send_message("set", tab="buffers", setting="chat_buffers_count", value=self.session.settings["buffers"]["count_for_chat_buffers"]) self.send_message("set", tab="buffers", setting="chat_buffers_count", value=self.session.settings["buffers"]["count_for_chat_buffers"])
self.send_message("create_tab", tab="chat") self.send_message("create_tab", tab="chat")
self.send_message("set", tab="chat", setting="notify_online", value=self.session.settings["chat"]["notify_online"]) self.send_message("set", tab="chat", setting="notify_online", value=self.session.settings["chat"]["notify_online"])
self.send_message("set", tab="chat", setting="notify_offline", value=self.session.settings["chat"]["notify_offline"]) self.send_message("set", tab="chat", setting="notify_offline", value=self.session.settings["chat"]["notify_offline"])
self.send_message("set", tab="chat", setting="notifications", value=self.get_notification_label(self.session.settings["chat"]["notifications"])) self.send_message("set", tab="chat", setting="notifications", value=self.get_notification_label(self.session.settings["chat"]["notifications"]))
self.send_message("create_tab", tab="startup_options") self.send_message("create_tab", tab="startup_options")
self.send_message("set", tab="startup", setting="audio_albums", value=self.session.settings["load_at_startup"]["audio_albums"]) self.send_message("set", tab="startup", setting="audio_albums", value=self.session.settings["load_at_startup"]["audio_albums"])
self.send_message("set", tab="startup", setting="video_albums", value=self.session.settings["load_at_startup"]["video_albums"]) self.send_message("set", tab="startup", setting="video_albums", value=self.session.settings["load_at_startup"]["video_albums"])
self.send_message("set", tab="startup", setting="communities", value=self.session.settings["load_at_startup"]["communities"]) self.send_message("set", tab="startup", setting="communities", value=self.session.settings["load_at_startup"]["communities"])
self.input_devices = sound_lib.input.Input.get_device_names() self.input_devices = sound_lib.input.Input.get_device_names()
self.output_devices = sound_lib.output.Output.get_device_names() self.output_devices = sound_lib.output.Output.get_device_names()
self.send_message("create_tab", tab="sound", arglist=dict(input_devices=self.input_devices, output_devices=self.output_devices, soundpacks=[])) self.send_message("create_tab", tab="sound", arglist=dict(input_devices=self.input_devices, output_devices=self.output_devices, soundpacks=[]))
self.send_message("set", tab="sound", setting="input", value=config.app["sound"]["input_device"]) self.send_message("set", tab="sound", setting="input", value=config.app["sound"]["input_device"])
self.send_message("set", tab="sound", setting="output", value=config.app["sound"]["output_device"]) self.send_message("set", tab="sound", setting="output", value=config.app["sound"]["output_device"])
def update_setting(self, section, setting, value): def update_setting(self, section, setting, value):
if section not in self.session.settings: if section not in self.session.settings:
raise AttributeError("The configuration section is not present in the spec file.") raise AttributeError("The configuration section is not present in the spec file.")
if setting not in self.session.settings[section]: if setting not in self.session.settings[section]:
raise AttributeError("The setting you specified is not present in the config file.") raise AttributeError("The setting you specified is not present in the config file.")
self.session.settings[section][setting] = value self.session.settings[section][setting] = value
def save_settings_file(self): def save_settings_file(self):
self.session.settings.write() self.session.settings.write()
def update_app_setting(self, section, setting, value): def update_app_setting(self, section, setting, value):
if section not in config.app: if section not in config.app:
raise AttributeError("The configuration section is not present in the spec file.") raise AttributeError("The configuration section is not present in the spec file.")
if setting not in config.app[section]: if setting not in config.app[section]:
raise AttributeError("The setting you specified is not present in the config file.") raise AttributeError("The setting you specified is not present in the config file.")
# check if certain settings have been changed so we'd restart the client. # check if certain settings have been changed so we'd restart the client.
# List of app settings that require a restart after being changed. # List of app settings that require a restart after being changed.
settings_needing_restart = ["language", "use_proxy", "input_device", "output_device", "debug_logging"] settings_needing_restart = ["language", "use_proxy", "input_device", "output_device", "debug_logging"]
if value != config.app[section][setting] and setting in settings_needing_restart: if value != config.app[section][setting] and setting in settings_needing_restart:
self.needs_restart = True self.needs_restart = True
config.app[section][setting] = value config.app[section][setting] = value
def save_app_settings_file(self): def save_app_settings_file(self):
config.app.write() config.app.write()
if self.needs_restart: if self.needs_restart:
self.send_message("restart_program") self.send_message("restart_program")
def restart_application(self): def restart_application(self):
restart.restart_program() restart.restart_program()

View File

@ -14,45 +14,45 @@ log = getLogger("controller.message")
class createPostPresenter(base.basePresenter): class createPostPresenter(base.basePresenter):
def __init__(self, session, view, interactor): def __init__(self, session, view, interactor):
super(createPostPresenter, self).__init__(view=view, interactor=interactor, modulename="create_post") super(createPostPresenter, self).__init__(view=view, interactor=interactor, modulename="create_post")
self.session = session self.session = session
self.images = [] self.images = []
self.tagged_people = [] self.tagged_people = []
self.run() self.run()
def get_friends(self): def get_friends(self):
try: try:
fields = "id, first_name, last_name" fields = "id, first_name, last_name"
self.friends = self.session.vk.client.friends.get(count=5000, fields=fields) self.friends = self.session.vk.client.friends.get(count=5000, fields=fields)
except AttributeError: except AttributeError:
time.sleep(2) time.sleep(2)
log.exception("Error retrieving friends...") log.exception("Error retrieving friends...")
return [] return []
self.users = [] self.users = []
for i in self.friends["items"]: for i in self.friends["items"]:
self.users.append("{0} {1}".format(i["first_name"], i["last_name"])) self.users.append("{0} {1}".format(i["first_name"], i["last_name"]))
return self.users return self.users
def add_tagged_users(self, tagged_users): def add_tagged_users(self, tagged_users):
self.tagged_people = [] self.tagged_people = []
for i in tagged_users: for i in tagged_users:
self.tagged_people.append("[id%s|%s]" % (str(self.friends["items"][i]["id"]), self.friends["items"][i]["first_name"])) self.tagged_people.append("[id%s|%s]" % (str(self.friends["items"][i]["id"]), self.friends["items"][i]["first_name"]))
self.send_message("add_tagged_users", users=self.tagged_people) self.send_message("add_tagged_users", users=self.tagged_people)
def translate(self, text, language): def translate(self, text, language):
msg = translator.translator.translate(text, language) msg = translator.translator.translate(text, language)
self.send_message("set", control="text", value=msg) self.send_message("set", control="text", value=msg)
self.send_message("focus_control", control="text") self.send_message("focus_control", control="text")
output.speak(_("Translated")) output.speak(_("Translated"))
def spellcheck(self, text): def spellcheck(self, text):
checker = SpellChecker.spellchecker.spellChecker(text) checker = SpellChecker.spellchecker.spellChecker(text)
if hasattr(checker, "fixed_text"): if hasattr(checker, "fixed_text"):
self.send_message("set", control="text", value=checker.fixed_text) self.send_message("set", control="text", value=checker.fixed_text)
self.send_message("focus_control", control="text") self.send_message("focus_control", control="text")
def add_attachments(self): def add_attachments(self):
a = attach.attachPresenter(session=self.session, view=views.attachDialog(), interactor=interactors.attachInteractor()) a = attach.attachPresenter(session=self.session, view=views.attachDialog(), interactor=interactors.attachInteractor())
if len(a.attachments) != 0: if len(a.attachments) != 0:
self.attachments = a.attachments self.attachments = a.attachments

View File

@ -10,38 +10,38 @@ from presenters import base
log = logging.getLogger(__file__) log = logging.getLogger(__file__)
class displayArticlePresenter(base.basePresenter): class displayArticlePresenter(base.basePresenter):
def __init__(self, session, postObject, view, interactor): def __init__(self, session, postObject, view, interactor):
super(displayArticlePresenter, self).__init__(view=view, interactor=interactor, modulename="display_article") super(displayArticlePresenter, self).__init__(view=view, interactor=interactor, modulename="display_article")
self.session = session self.session = session
self.post = postObject self.post = postObject
self.load_article() self.load_article()
self.run() self.run()
def load_article(self): def load_article(self):
""" Loads the article in the interactor. """ Loads the article in the interactor.
This function retrieves, by using the params defined in the VK API, the web version of the article and extracts some info from it. This function retrieves, by using the params defined in the VK API, the web version of the article and extracts some info from it.
this is needed because there are no public API for articles so far. this is needed because there are no public API for articles so far.
""" """
article = self.post[0] article = self.post[0]
# By using the vk_api's session, proxy settings are applied, thus might work in blocked countries. # By using the vk_api's session, proxy settings are applied, thus might work in blocked countries.
article_body = self.session.vk.session_object.http.get(article["view_url"]) article_body = self.session.vk.session_object.http.get(article["view_url"])
# Parse and extract text from all paragraphs. # Parse and extract text from all paragraphs.
# ToDo: Extract all links and set those as attachments. # ToDo: Extract all links and set those as attachments.
soup = BeautifulSoup(article_body.text, "lxml") soup = BeautifulSoup(article_body.text, "lxml")
# ToDo: Article extraction require testing to see if you can add more tags beside paragraphs. # ToDo: Article extraction require testing to see if you can add more tags beside paragraphs.
msg = [p.get_text() for p in soup.find_all("p")] msg = [p.get_text() for p in soup.find_all("p")]
msg = "\n\n".join(msg) msg = "\n\n".join(msg)
self.send_message("set", control="article_view", value=msg) self.send_message("set", control="article_view", value=msg)
self.send_message("set_title", value=article["title"]) self.send_message("set_title", value=article["title"])
# Retrieve views count # Retrieve views count
views = soup.find("div", class_="articleView__views_info") views = soup.find("div", class_="articleView__views_info")
# This might return None if VK changes anything, so let's avoid errors. # This might return None if VK changes anything, so let's avoid errors.
if views == None: if views == None:
views = str(-1) views = str(-1)
else: else:
views = views.text views = views.text
# Find the integer and remove the words from the string. # Find the integer and remove the words from the string.
numbers = re.findall(r'\d+', views) numbers = re.findall(r'\d+', views)
if len(numbers) != 0: if len(numbers) != 0:
views = numbers[0] views = numbers[0]
self.send_message("set", control="views", value=views) self.send_message("set", control="views", value=views)

View File

@ -8,93 +8,93 @@ from presenters import base, player
log = logging.getLogger(__file__) log = logging.getLogger(__file__)
class displayAudioPresenter(base.basePresenter): class displayAudioPresenter(base.basePresenter):
def __init__(self, session, postObject, view, interactor): def __init__(self, session, postObject, view, interactor):
super(displayAudioPresenter, self).__init__(view=view, interactor=interactor, modulename="display_audio") super(displayAudioPresenter, self).__init__(view=view, interactor=interactor, modulename="display_audio")
self.added_audios = {} self.added_audios = {}
self.session = session self.session = session
self.post = postObject self.post = postObject
self.load_audios() self.load_audios()
self.fill_information(0) self.fill_information(0)
self.run() self.run()
def add_to_library(self, audio_index): def add_to_library(self, audio_index):
post = self.post[audio_index] post = self.post[audio_index]
args = {} args = {}
args["audio_id"] = post["id"] args["audio_id"] = post["id"]
if "album_id" in post: if "album_id" in post:
args["album_id"] = post["album_id"] args["album_id"] = post["album_id"]
args["owner_id"] = post["owner_id"] args["owner_id"] = post["owner_id"]
audio = self.session.vk.client.audio.add(**args) audio = self.session.vk.client.audio.add(**args)
if audio != None and int(audio) > 21: if audio != None and int(audio) > 21:
self.added_audios[post["id"]] = audio self.added_audios[post["id"]] = audio
self.send_message("disable_control", control="add") self.send_message("disable_control", control="add")
self.send_message("enable_control", control="remove") self.send_message("enable_control", control="remove")
def remove_from_library(self, audio_index): def remove_from_library(self, audio_index):
post = self.post[audio_index] post = self.post[audio_index]
args = {} args = {}
if post["id"] in self.added_audios: if post["id"] in self.added_audios:
args["audio_id"] = self.added_audios[post["id"]] args["audio_id"] = self.added_audios[post["id"]]
args["owner_id"] = self.session.user_id args["owner_id"] = self.session.user_id
else: else:
args["audio_id"] = post["id"] args["audio_id"] = post["id"]
args["owner_id"] = post["owner_id"] args["owner_id"] = post["owner_id"]
result = self.session.vk.client.audio.delete(**args) result = self.session.vk.client.audio.delete(**args)
if int(result) == 1: if int(result) == 1:
self.send_message("enable_control", control="add") self.send_message("enable_control", control="add")
self.send_message("disable_control", control="remove") self.send_message("disable_control", control="remove")
if post["id"] in self.added_audios: if post["id"] in self.added_audios:
self.added_audios.pop(post["id"]) self.added_audios.pop(post["id"])
def fill_information(self, index): def fill_information(self, index):
post = self.post[index] post = self.post[index]
if "artist" in post: if "artist" in post:
self.send_message("set", control="artist", value=post["artist"]) self.send_message("set", control="artist", value=post["artist"])
if "title" in post: if "title" in post:
self.send_message("set", control="title", value=post["title"]) self.send_message("set", control="title", value=post["title"])
if "duration" in post: if "duration" in post:
self.send_message("set", control="duration", value=utils.seconds_to_string(post["duration"])) self.send_message("set", control="duration", value=utils.seconds_to_string(post["duration"]))
self.send_message("set_title", value="{0} - {1}".format(post["title"], post["artist"])) self.send_message("set_title", value="{0} - {1}".format(post["title"], post["artist"]))
call_threaded(self.get_lyrics, index) call_threaded(self.get_lyrics, index)
if post["owner_id"] == self.session.user_id or (post["id"] in self.added_audios) == True: if post["owner_id"] == self.session.user_id or (post["id"] in self.added_audios) == True:
self.send_message("enable_control", control="remove") self.send_message("enable_control", control="remove")
self.send_message("disable_control", control="add") self.send_message("disable_control", control="add")
else: else:
self.send_message("enable_control", control="add") self.send_message("enable_control", control="add")
self.send_message("disable_control", control="remove") self.send_message("disable_control", control="remove")
def get_lyrics(self, audio_index): def get_lyrics(self, audio_index):
post = self.post[audio_index] post = self.post[audio_index]
if "lyrics_id" in post: if "lyrics_id" in post:
l = self.session.vk.client.audio.getLyrics(lyrics_id=int(post["lyrics_id"])) l = self.session.vk.client.audio.getLyrics(lyrics_id=int(post["lyrics_id"]))
self.send_message("set", control="lyric", value=l["text"]) self.send_message("set", control="lyric", value=l["text"])
else: else:
self.send_message("disable_control", control="lyric") self.send_message("disable_control", control="lyric")
def get_suggested_filename(self, audio_index): def get_suggested_filename(self, audio_index):
post = self.post[audio_index] post = self.post[audio_index]
return utils.safe_filename("{0} - {1}.mp3".format(post["title"], post["artist"])) return utils.safe_filename("{0} - {1}.mp3".format(post["title"], post["artist"]))
def download(self, audio_index, path): def download(self, audio_index, path):
post = self.post[audio_index] post = self.post[audio_index]
if path != None: if path != None:
pub.sendMessage("download-file", url=post["url"], filename=path) pub.sendMessage("download-file", url=post["url"], filename=path)
def play(self, audio_index): def play(self, audio_index):
post = self.post[audio_index] post = self.post[audio_index]
if player.player.check_is_playing() == True: if player.player.check_is_playing() == True:
return pub.sendMessage("stop") return pub.sendMessage("stop")
pub.sendMessage("play", object=post) pub.sendMessage("play", object=post)
def load_audios(self): def load_audios(self):
audios = [] audios = []
for i in self.post: for i in self.post:
s = "{0} - {1}. {2}".format(i["title"], i["artist"], utils.seconds_to_string(i["duration"])) s = "{0} - {1}. {2}".format(i["title"], i["artist"], utils.seconds_to_string(i["duration"]))
audios.append(s) audios.append(s)
self.send_message("add_items", control="list", items=audios) self.send_message("add_items", control="list", items=audios)
if len(self.post) == 1: if len(self.post) == 1:
self.send_message("disable_control", control="list") self.send_message("disable_control", control="list")
self.send_message("focus_control", control="title") self.send_message("focus_control", control="title")
def handle_changes(self, audio_index): def handle_changes(self, audio_index):
self.fill_information(audio_index) self.fill_information(audio_index)

View File

@ -20,359 +20,359 @@ from . import audio, poll, article
log = logging.getLogger(__file__) log = logging.getLogger(__file__)
def get_message(status): def get_message(status):
message = "" message = ""
if "text" in status: if "text" in status:
message = utils.clean_text(status["text"]) message = utils.clean_text(status["text"])
return message return message
class displayPostPresenter(base.basePresenter): class displayPostPresenter(base.basePresenter):
""" Base class for post representation.""" """ Base class for post representation."""
def __init__(self, session, postObject, view, interactor): def __init__(self, session, postObject, view, interactor):
super(displayPostPresenter, self).__init__(view=view, interactor=interactor, modulename="display_post") super(displayPostPresenter, self).__init__(view=view, interactor=interactor, modulename="display_post")
self.type = "post" self.type = "post"
self.session = session self.session = session
self.post = postObject self.post = postObject
# Posts from newsfeed contains this source_id instead from_id in walls. Also it uses post_id and walls use just id. # Posts from newsfeed contains this source_id instead from_id in walls. Also it uses post_id and walls use just id.
if "source_id" in self.post: if "source_id" in self.post:
self.user_identifier = "source_id" self.user_identifier = "source_id"
self.post_identifier = "post_id" self.post_identifier = "post_id"
else: else:
# In wall's posts, if someone has posted in user's wall, owner_id should be used instead from_id # In wall's posts, if someone has posted in user's wall, owner_id should be used instead from_id
# This will help for retrieving comments, do likes, etc. # This will help for retrieving comments, do likes, etc.
if "owner_id" not in self.post: if "owner_id" not in self.post:
self.user_identifier = "from_id" self.user_identifier = "from_id"
else: else:
self.user_identifier = "owner_id" self.user_identifier = "owner_id"
self.post_identifier = "id" self.post_identifier = "id"
self.attachments = [] self.attachments = []
self.load_images = False self.load_images = False
# We'll put images here, so it will be easier to work with them. # We'll put images here, so it will be easier to work with them.
self.images = [] self.images = []
self.imageIndex = 0 self.imageIndex = 0
result = self.get_post_information() result = self.get_post_information()
# Stop loading everything else if post was deleted. # Stop loading everything else if post was deleted.
if result == False: if result == False:
self.interactor.uninstall() self.interactor.uninstall()
return return
self.worker = threading.Thread(target=self.load_all_components) self.worker = threading.Thread(target=self.load_all_components)
self.worker.finished = threading.Event() self.worker.finished = threading.Event()
self.worker.start() self.worker.start()
# connect here the pubsub event for successful posting of comments. # connect here the pubsub event for successful posting of comments.
pub.subscribe(self.posted, "posted") pub.subscribe(self.posted, "posted")
self.run() self.run()
pub.unsubscribe(self.posted, "posted") pub.unsubscribe(self.posted, "posted")
def posted(self, from_buffer=None): def posted(self, from_buffer=None):
self.clear_comments_list() self.clear_comments_list()
def get_comments(self): def get_comments(self):
""" Get comments and insert them in a list.""" """ Get comments and insert them in a list."""
user = self.post[self.user_identifier] user = self.post[self.user_identifier]
id = self.post[self.post_identifier] id = self.post[self.post_identifier]
comments_data = self.session.vk.client.wall.getComments(owner_id=user, post_id=id, need_likes=1, count=100, extended=1, preview_length=0, thread_items_count=10) comments_data = self.session.vk.client.wall.getComments(owner_id=user, post_id=id, need_likes=1, count=100, extended=1, preview_length=0, thread_items_count=10)
self.comments = dict(items=[], profiles=comments_data["profiles"]) self.comments = dict(items=[], profiles=comments_data["profiles"])
for i in comments_data["items"]: for i in comments_data["items"]:
self.comments["items"].append(i) self.comments["items"].append(i)
if i.get("thread") != None and i["thread"].get("count") > 0: if i.get("thread") != None and i["thread"].get("count") > 0:
for newI in i["thread"]["items"]: for newI in i["thread"]["items"]:
self.comments["items"].append(newI) self.comments["items"].append(newI)
comments_ = [] comments_ = []
# Save profiles in session local storage for a future usage. # Save profiles in session local storage for a future usage.
# Although community objects are returned here, we should not add those because their names are changed. # Although community objects are returned here, we should not add those because their names are changed.
# For example, self reference to a group is marked as "Administrator", which would ruin this profile to be rendered somewhere else. # For example, self reference to a group is marked as "Administrator", which would ruin this profile to be rendered somewhere else.
data = dict(groups=[], profiles=self.comments["profiles"]) data = dict(groups=[], profiles=self.comments["profiles"])
self.session.process_usernames(data) self.session.process_usernames(data)
for i in self.comments["items"]: for i in self.comments["items"]:
# If comment has a "deleted" key it should not be displayed, obviously. # If comment has a "deleted" key it should not be displayed, obviously.
if "deleted" in i: if "deleted" in i:
continue continue
from_ = self.session.get_user(i["from_id"])["user1_nom"] from_ = self.session.get_user(i["from_id"])["user1_nom"]
if "reply_to_user" in i: if "reply_to_user" in i:
extra_info = self.session.get_user(i["reply_to_user"])["user1_nom"] extra_info = self.session.get_user(i["reply_to_user"])["user1_nom"]
from_ = _("{0} > {1}").format(from_, extra_info) from_ = _("{0} > {1}").format(from_, extra_info)
# As we set the comment reply properly in the from_ field, let's remove the first username from here if it exists. # As we set the comment reply properly in the from_ field, let's remove the first username from here if it exists.
fixed_text = utils.clean_text(i["text"]) fixed_text = utils.clean_text(i["text"])
if len(fixed_text) > 140: if len(fixed_text) > 140:
text = fixed_text[:141] text = fixed_text[:141]
else: else:
text = fixed_text text = fixed_text
original_date = arrow.get(i["date"]) original_date = arrow.get(i["date"])
created_at = original_date.humanize(locale=languageHandler.curLang[:2]) created_at = original_date.humanize(locale=languageHandler.curLang[:2])
likes = str(i["likes"]["count"]) likes = str(i["likes"]["count"])
comments_.append((from_, text, created_at, likes)) comments_.append((from_, text, created_at, likes))
self.send_message("add_items", control="comments", items=comments_) self.send_message("add_items", control="comments", items=comments_)
def get_post_information(self): def get_post_information(self):
from_ = self.session.get_user(self.post[self.user_identifier]) from_ = self.session.get_user(self.post[self.user_identifier])
if "copy_history" in self.post: if "copy_history" in self.post:
title = _("repost from {user1_nom}").format(**from_) title = _("repost from {user1_nom}").format(**from_)
else: else:
if ("from_id" in self.post and "owner_id" in self.post) and (self.post["from_id"] != self.post["owner_id"]): if ("from_id" in self.post and "owner_id" in self.post) and (self.post["from_id"] != self.post["owner_id"]):
# Translators: {0} will be replaced with the user who is posting, and {1} with the wall owner. # Translators: {0} will be replaced with the user who is posting, and {1} with the wall owner.
user2 = self.session.get_user(self.post["owner_id"], "user2") user2 = self.session.get_user(self.post["owner_id"], "user2")
user2.update(from_) user2.update(from_)
title = _("Post from {user1_nom} in the {user2_nom}'s wall").format(**user2) title = _("Post from {user1_nom} in the {user2_nom}'s wall").format(**user2)
else: else:
title = _("Post from {user1_nom}").format(**from_) title = _("Post from {user1_nom}").format(**from_)
self.send_message("set_title", value=title) self.send_message("set_title", value=title)
message = "" message = ""
# Retrieve again the post, so we'll make sure to get the most up to date information. # Retrieve again the post, so we'll make sure to get the most up to date information.
# And we add a counter for views. # And we add a counter for views.
post = self.session.vk.client.wall.getById(posts="{owner_id}_{post_id}".format(owner_id=self.post[self.user_identifier], post_id=self.post[self.post_identifier])) post = self.session.vk.client.wall.getById(posts="{owner_id}_{post_id}".format(owner_id=self.post[self.user_identifier], post_id=self.post[self.post_identifier]))
# If this post has been deleted, let's send an event to the interactor so it won't be displayed. # If this post has been deleted, let's send an event to the interactor so it won't be displayed.
if len(post) == 0: if len(post) == 0:
self.send_message("post_deleted") self.send_message("post_deleted")
return False return False
self.post = post[0] self.post = post[0]
if "views" in self.post and self.post["views"]["count"] > 0: if "views" in self.post and self.post["views"]["count"] > 0:
self.send_message("set", control="views", value=str(self.post["views"]["count"])) self.send_message("set", control="views", value=str(self.post["views"]["count"]))
else: else:
self.send_message("disable_control", control="views") self.send_message("disable_control", control="views")
if "owner_id" not in self.post: if "owner_id" not in self.post:
self.user_identifier = "from_id" self.user_identifier = "from_id"
else: else:
self.user_identifier = "owner_id" self.user_identifier = "owner_id"
self.post_identifier = "id" self.post_identifier = "id"
message = get_message(self.post) message = get_message(self.post)
if "copy_history" in self.post: if "copy_history" in self.post:
nm = "\n" nm = "\n"
for i in self.post["copy_history"]: for i in self.post["copy_history"]:
u = self.session.get_user(i["from_id"]) u = self.session.get_user(i["from_id"])
u.update(message=get_message(i)) u.update(message=get_message(i))
nm += "{user1_nom}: {message}\n\n".format(**u) nm += "{user1_nom}: {message}\n\n".format(**u)
self.get_attachments(i, get_message(i)) self.get_attachments(i, get_message(i))
message += nm message += nm
self.send_message("set", control="post_view", value=message) self.send_message("set", control="post_view", value=message)
self.get_attachments(self.post, message) self.get_attachments(self.post, message)
self.check_image_load() self.check_image_load()
def get_attachments(self, post, text): def get_attachments(self, post, text):
attachments = [] attachments = []
self.attachments = [] self.attachments = []
if "attachments" in post: if "attachments" in post:
for i in post["attachments"]: for i in post["attachments"]:
# We don't need the photos_list attachment, so skip it. # We don't need the photos_list attachment, so skip it.
if i["type"] == "photos_list": if i["type"] == "photos_list":
continue continue
if i["type"] == "photo": if i["type"] == "photo":
if self.load_images == False: self.load_images = True if self.load_images == False: self.load_images = True
self.images.append(i) self.images.append(i)
attachments.append(renderers.add_attachment(i)) attachments.append(renderers.add_attachment(i))
self.attachments.append(i) self.attachments.append(i)
# Links in text are not treated like normal attachments, so we'll have to catch and add those to the list without title # Links in text are not treated like normal attachments, so we'll have to catch and add those to the list without title
# We can't get a title because title is provided by the VK API and it will not work for links as simple text. # We can't get a title because title is provided by the VK API and it will not work for links as simple text.
urls = utils.find_urls_in_text(text) urls = utils.find_urls_in_text(text)
if len(urls) > 0: if len(urls) > 0:
links = [] links = []
for i in urls: for i in urls:
links.append({"link": {"title": _("Untitled link"), "url": i}, "type": "link"}) links.append({"link": {"title": _("Untitled link"), "url": i}, "type": "link"})
for i in links: for i in links:
attachments.append(renderers.add_attachment(i)) attachments.append(renderers.add_attachment(i))
self.attachments.append(i) self.attachments.append(i)
if len(self.attachments) > 0: if len(self.attachments) > 0:
self.send_message("enable_attachments") self.send_message("enable_attachments")
self.send_message("add_items", control="attachments", items=attachments) self.send_message("add_items", control="attachments", items=attachments)
else: else:
self.interactor.view.attachments.list.Enable(False) self.interactor.view.attachments.list.Enable(False)
def check_image_load(self): def check_image_load(self):
if self.load_images and len(self.images) > 0 and self.session.settings["general"]["load_images"]: if self.load_images and len(self.images) > 0 and self.session.settings["general"]["load_images"]:
self.send_message("enable_control", control="image") self.send_message("enable_control", control="image")
nav = False # Disable navigation controls in photos nav = False # Disable navigation controls in photos
if len(self.images) > 1: if len(self.images) > 1:
nav = True nav = True
self.send_message("enable_photo_controls", navigation=nav) self.send_message("enable_photo_controls", navigation=nav)
self.set_image(0) self.set_image(0)
def set_next_image(self, *args, **kwargs): def set_next_image(self, *args, **kwargs):
if self.imageIndex < -1 or self.imageIndex == len(self.images)-1: if self.imageIndex < -1 or self.imageIndex == len(self.images)-1:
self.imageIndex = -1 self.imageIndex = -1
if len(self.images) <= self.imageIndex+1: if len(self.images) <= self.imageIndex+1:
self.imageIndex = 0 self.imageIndex = 0
else: else:
self.imageIndex = self.imageIndex + 1 self.imageIndex = self.imageIndex + 1
self.set_image(self.imageIndex) self.set_image(self.imageIndex)
def set_previous_image(self, *args, **kwargs): def set_previous_image(self, *args, **kwargs):
if self.imageIndex <= 0: if self.imageIndex <= 0:
self.imageIndex = len(self.images) self.imageIndex = len(self.images)
self.imageIndex = self.imageIndex - 1 self.imageIndex = self.imageIndex - 1
self.set_image(self.imageIndex) self.set_image(self.imageIndex)
def set_image(self, index): def set_image(self, index):
if len(self.images) < index-1: if len(self.images) < index-1:
return return
# Get's photo URL. # Get's photo URL.
url = self.get_photo_url(self.images[index]["photo"], "x") url = self.get_photo_url(self.images[index]["photo"], "x")
if url != "": if url != "":
img = requests.get(url) img = requests.get(url)
self.send_message("load_image", image=img) self.send_message("load_image", image=img)
# Translators: {0} is the number of the current photo and {1} is the total number of photos. # Translators: {0} is the number of the current photo and {1} is the total number of photos.
output.speak(_("Loaded photo {0} of {1}").format(index+1, len(self.images))) output.speak(_("Loaded photo {0} of {1}").format(index+1, len(self.images)))
return return
def get_photo_url(self, photo, size="x"): def get_photo_url(self, photo, size="x"):
url = "" url = ""
for i in photo["sizes"]: for i in photo["sizes"]:
if i["type"] == size: if i["type"] == size:
url = i["url"] url = i["url"]
break break
return url return url
def load_all_components(self): def load_all_components(self):
self.get_likes() self.get_likes()
self.get_reposts() self.get_reposts()
self.get_comments() self.get_comments()
if self.post["comments"]["can_post"] == 0: if self.post["comments"]["can_post"] == 0:
self.send_message("disable_control", control="comment") self.send_message("disable_control", control="comment")
if self.post["likes"]["can_like"] == 0 and self.post["likes"]["user_likes"] == 0: if self.post["likes"]["can_like"] == 0 and self.post["likes"]["user_likes"] == 0:
self.send_message("disable_control", "like") self.send_message("disable_control", "like")
elif self.post["likes"]["user_likes"] == 1: elif self.post["likes"]["user_likes"] == 1:
self.send_message("set_label", control="like", label=_("&Dislike")) self.send_message("set_label", control="like", label=_("&Dislike"))
if self.post["likes"]["can_publish"] == 0: if self.post["likes"]["can_publish"] == 0:
self.send_message("disable_control", control="repost") self.send_message("disable_control", control="repost")
def post_like(self): def post_like(self):
if ("owner_id" in self.post) == False: if ("owner_id" in self.post) == False:
user = int(self.post[self.user_identifier]) user = int(self.post[self.user_identifier])
else: else:
user = int(self.post["owner_id"]) user = int(self.post["owner_id"])
id = int(self.post[self.post_identifier]) id = int(self.post[self.post_identifier])
if "type" in self.post: if "type" in self.post:
type_ = self.post["type"] type_ = self.post["type"]
else: else:
type_ = self.type type_ = self.type
if self.post["likes"]["user_likes"] == 1: if self.post["likes"]["user_likes"] == 1:
l = self.session.vk.client.likes.delete(owner_id=user, item_id=id, type=type_) l = self.session.vk.client.likes.delete(owner_id=user, item_id=id, type=type_)
output.speak(_("You don't like this")) output.speak(_("You don't like this"))
self.post["likes"]["count"] = l["likes"] self.post["likes"]["count"] = l["likes"]
self.post["likes"]["user_likes"] = 2 self.post["likes"]["user_likes"] = 2
self.get_likes() self.get_likes()
self.send_message("set_label", control="like", label=_("&Like")) self.send_message("set_label", control="like", label=_("&Like"))
else: else:
l = self.session.vk.client.likes.add(owner_id=user, item_id=id, type=type_) l = self.session.vk.client.likes.add(owner_id=user, item_id=id, type=type_)
output.speak(_("You liked this")) output.speak(_("You liked this"))
self.send_message("set_label", control="like", label=_("&Dislike")) self.send_message("set_label", control="like", label=_("&Dislike"))
self.post["likes"]["count"] = l["likes"] self.post["likes"]["count"] = l["likes"]
self.post["likes"]["user_likes"] = 1 self.post["likes"]["user_likes"] = 1
self.get_likes() self.get_likes()
def post_repost(self): def post_repost(self):
object_id = "wall{0}_{1}".format(self.post[self.user_identifier], self.post[self.post_identifier]) object_id = "wall{0}_{1}".format(self.post[self.user_identifier], self.post[self.post_identifier])
p = createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createPostDialog(title=_("Repost"), message=_("Add your comment here"), text="", mode="comment")) p = createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createPostDialog(title=_("Repost"), message=_("Add your comment here"), text="", mode="comment"))
if hasattr(p, "text") or hasattr(p, "privacy"): if hasattr(p, "text") or hasattr(p, "privacy"):
post_arguments = dict(object=object_id, message=p.text) post_arguments = dict(object=object_id, message=p.text)
attachments = [] attachments = []
if hasattr(p, "attachments"): if hasattr(p, "attachments"):
attachments = p.attachments attachments = p.attachments
call_threaded(pub.sendMessage, "post", parent_endpoint="wall", child_endpoint="repost", attachments_list=attachments, post_arguments=post_arguments) call_threaded(pub.sendMessage, "post", parent_endpoint="wall", child_endpoint="repost", attachments_list=attachments, post_arguments=post_arguments)
def get_likes(self): def get_likes(self):
self.send_message("set_label", control="likes", label=_("{0} people like this").format(self.post["likes"]["count"],)) self.send_message("set_label", control="likes", label=_("{0} people like this").format(self.post["likes"]["count"],))
def get_reposts(self): def get_reposts(self):
self.send_message("set_label", control="shares", label=_("Shared {0} times").format(self.post["reposts"]["count"],)) self.send_message("set_label", control="shares", label=_("Shared {0} times").format(self.post["reposts"]["count"],))
def add_comment(self): def add_comment(self):
comment = createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createPostDialog(title=_("Add a comment"), message="", text="", mode="comment")) comment = createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createPostDialog(title=_("Add a comment"), message="", text="", mode="comment"))
if hasattr(comment, "text") or hasattr(comment, "privacy"): if hasattr(comment, "text") or hasattr(comment, "privacy"):
owner_id = self.post[self.user_identifier] owner_id = self.post[self.user_identifier]
post_id = self.post[self.post_identifier] post_id = self.post[self.post_identifier]
post_arguments=dict(message=comment.text, owner_id=owner_id, post_id=post_id) post_arguments=dict(message=comment.text, owner_id=owner_id, post_id=post_id)
attachments = [] attachments = []
if hasattr(comment, "attachments"): if hasattr(comment, "attachments"):
attachments = comment.attachments attachments = comment.attachments
call_threaded(pub.sendMessage, "post", parent_endpoint="wall", child_endpoint="createComment", attachments_list=attachments, post_arguments=post_arguments) call_threaded(pub.sendMessage, "post", parent_endpoint="wall", child_endpoint="createComment", attachments_list=attachments, post_arguments=post_arguments)
def reply(self, comment): def reply(self, comment):
c = self.comments["items"][comment] c = self.comments["items"][comment]
comment = createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createPostDialog(title=_("Reply to {user1_nom}").format(**self.session.get_user(c["from_id"])), message="", text="", mode="comment")) comment = createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createPostDialog(title=_("Reply to {user1_nom}").format(**self.session.get_user(c["from_id"])), message="", text="", mode="comment"))
if hasattr(comment, "text") or hasattr(comment, "privacy"): if hasattr(comment, "text") or hasattr(comment, "privacy"):
post_id = self.post[self.post_identifier] post_id = self.post[self.post_identifier]
post_arguments=dict(message=comment.text, owner_id=c["owner_id"], reply_to_comment=c["id"], post_id=c["post_id"], reply_to_user=c["owner_id"]) post_arguments=dict(message=comment.text, owner_id=c["owner_id"], reply_to_comment=c["id"], post_id=c["post_id"], reply_to_user=c["owner_id"])
attachments = [] attachments = []
if hasattr(comment, "attachments"): if hasattr(comment, "attachments"):
attachments = comment.attachments attachments = comment.attachments
call_threaded(pub.sendMessage, "post", parent_endpoint="wall", child_endpoint="createComment", attachments_list=attachments, post_arguments=post_arguments) call_threaded(pub.sendMessage, "post", parent_endpoint="wall", child_endpoint="createComment", attachments_list=attachments, post_arguments=post_arguments)
def show_comment(self, comment_index): def show_comment(self, comment_index):
from . import comment from . import comment
c = self.comments["items"][comment_index] c = self.comments["items"][comment_index]
c["post_id"] = self.post[self.post_identifier] c["post_id"] = self.post[self.post_identifier]
a = comment.displayCommentPresenter(session=self.session, postObject=c, interactor=interactors.displayPostInteractor(), view=views.displayComment()) a = comment.displayCommentPresenter(session=self.session, postObject=c, interactor=interactors.displayPostInteractor(), view=views.displayComment())
def translate(self, text, language): def translate(self, text, language):
msg = translator.translator.translate(text, language) msg = translator.translator.translate(text, language)
self.send_message("set", control="post_view", value=msg) self.send_message("set", control="post_view", value=msg)
self.send_message("focus_control", control="post_view") self.send_message("focus_control", control="post_view")
output.speak(_("Translated")) output.speak(_("Translated"))
def spellcheck(self, text): def spellcheck(self, text):
checker = SpellChecker.spellchecker.spellChecker(text) checker = SpellChecker.spellchecker.spellChecker(text)
if hasattr(checker, "fixed_text"): if hasattr(checker, "fixed_text"):
self.send_message("set", control="post_view", value=checker.fixed_text) self.send_message("set", control="post_view", value=checker.fixed_text)
self.send_message("focus_control", control="post_view") self.send_message("focus_control", control="post_view")
def open_attachment(self, index): def open_attachment(self, index):
attachment = self.attachments[index] attachment = self.attachments[index]
if attachment["type"] == "audio": if attachment["type"] == "audio":
a = audio.displayAudioPresenter(session=self.session, postObject=[attachment["audio"]], interactor=interactors.displayAudioInteractor(), view=views.displayAudio()) a = audio.displayAudioPresenter(session=self.session, postObject=[attachment["audio"]], interactor=interactors.displayAudioInteractor(), view=views.displayAudio())
elif attachment["type"] == "link": elif attachment["type"] == "link":
output.speak(_("Opening URL..."), True) output.speak(_("Opening URL..."), True)
webbrowser.open_new_tab(attachment["link"]["url"]) webbrowser.open_new_tab(attachment["link"]["url"])
elif attachment["type"] == "doc": elif attachment["type"] == "doc":
output.speak(_("Opening document in web browser...")) output.speak(_("Opening document in web browser..."))
webbrowser.open(attachment["doc"]["url"]) webbrowser.open(attachment["doc"]["url"])
elif attachment["type"] == "video": elif attachment["type"] == "video":
# it seems VK doesn't like to attach video links as normal URLS, so we'll have to # it seems VK doesn't like to attach video links as normal URLS, so we'll have to
# get the full video object and use its "player" key which will open a webbrowser in their site with a player for the video. # get the full video object and use its "player" key which will open a webbrowser in their site with a player for the video.
# see https://vk.com/dev/attachments_w and and https://vk.com/dev/video.get # see https://vk.com/dev/attachments_w and and https://vk.com/dev/video.get
# However, the flash player isn't good for visually impaired people (when you press play you won't be able to close the window with alt+f4), so it could be good to use the HTML5 player. # However, the flash player isn't good for visually impaired people (when you press play you won't be able to close the window with alt+f4), so it could be good to use the HTML5 player.
# For firefox, see https://addons.mozilla.org/ru/firefox/addon/force-html5-video-player-at-vk/ # For firefox, see https://addons.mozilla.org/ru/firefox/addon/force-html5-video-player-at-vk/
# May be I could use a dialogue here for inviting people to use this addon in firefox. It seems it isn't possible to use this html5 player from the player URL. # May be I could use a dialogue here for inviting people to use this addon in firefox. It seems it isn't possible to use this html5 player from the player URL.
object_id = "{0}_{1}".format(attachment["video"]["owner_id"], attachment["video"]["id"]) object_id = "{0}_{1}".format(attachment["video"]["owner_id"], attachment["video"]["id"])
video_object = self.session.vk.client.video.get(owner_id=attachment["video"]["owner_id"], videos=object_id) video_object = self.session.vk.client.video.get(owner_id=attachment["video"]["owner_id"], videos=object_id)
video_object = video_object["items"][0] video_object = video_object["items"][0]
output.speak(_("Opening video in web browser..."), True) output.speak(_("Opening video in web browser..."), True)
webbrowser.open_new_tab(video_object["player"]) webbrowser.open_new_tab(video_object["player"])
elif attachment["type"] == "photo": elif attachment["type"] == "photo":
output.speak(_("Opening photo in web browser..."), True) output.speak(_("Opening photo in web browser..."), True)
# Possible photo sizes for looking in the attachment information. Try to use the biggest photo available. # Possible photo sizes for looking in the attachment information. Try to use the biggest photo available.
possible_sizes = [1280, 604, 130, 75] possible_sizes = [1280, 604, 130, 75]
url = "" url = ""
for i in possible_sizes: for i in possible_sizes:
if "photo_{0}".format(i,) in attachment["photo"]: if "photo_{0}".format(i,) in attachment["photo"]:
url = attachment["photo"]["photo_{0}".format(i,)] url = attachment["photo"]["photo_{0}".format(i,)]
break break
if url != "": if url != "":
webbrowser.open_new_tab(url) webbrowser.open_new_tab(url)
elif attachment["type"] == "poll": elif attachment["type"] == "poll":
a = poll.displayPollPresenter(session=self.session, poll=attachment, interactor=interactors.displayPollInteractor(), view=views.displayPoll()) a = poll.displayPollPresenter(session=self.session, poll=attachment, interactor=interactors.displayPollInteractor(), view=views.displayPoll())
elif attachment["type"] == "article": elif attachment["type"] == "article":
a = article.displayArticlePresenter(session=self.session, postObject=[attachment["article"]], interactor=interactors.displayArticleInteractor(), view=views.displayArticle()) a = article.displayArticlePresenter(session=self.session, postObject=[attachment["article"]], interactor=interactors.displayArticleInteractor(), view=views.displayArticle())
else: else:
log.error("Unhandled attachment: %r" % (attachment,)) log.error("Unhandled attachment: %r" % (attachment,))
def __del__(self): def __del__(self):
if hasattr(self, "worker"): if hasattr(self, "worker"):
self.worker.finished.set() self.worker.finished.set()
def clear_comments_list(self): def clear_comments_list(self):
self.send_message("clean_list", list="comments") self.send_message("clean_list", list="comments")
self.get_comments() self.get_comments()
def show_likes(self): def show_likes(self):
""" show likes for the specified post.""" """ show likes for the specified post."""
data = dict(type="post", owner_id=self.post[self.user_identifier], item_id=self.post["id"], extended=True, count=100, skip_own=True) data = dict(type="post", owner_id=self.post[self.user_identifier], item_id=self.post["id"], extended=True, count=100, skip_own=True)
result = self.session.vk.client.likes.getList(**data) result = self.session.vk.client.likes.getList(**data)
if result["count"] > 0: if result["count"] > 0:
post = {"source_id": self.post[self.user_identifier], "friends": {"items": result["items"]}} post = {"source_id": self.post[self.user_identifier], "friends": {"items": result["items"]}}
pub.sendMessage("open-post", post_object=post, controller_="displayFriendship", vars=dict(caption=_("people who liked this"))) pub.sendMessage("open-post", post_object=post, controller_="displayFriendship", vars=dict(caption=_("people who liked this")))
def show_shares(self): def show_shares(self):
data = dict(type="post", owner_id=self.post[self.user_identifier], item_id=self.post["id"], extended=True, count=1000, skip_own=True, filter="copies") data = dict(type="post", owner_id=self.post[self.user_identifier], item_id=self.post["id"], extended=True, count=1000, skip_own=True, filter="copies")
result = self.session.vk.client.likes.getList(**data) result = self.session.vk.client.likes.getList(**data)
if result["count"] > 0: if result["count"] > 0:
post = {"source_id": self.post[self.user_identifier], "friends": {"items": result["items"]}} post = {"source_id": self.post[self.user_identifier], "friends": {"items": result["items"]}}
pub.sendMessage("open-post", post_object=post, controller_="displayFriendship", vars=dict(caption=_("people who shared this"))) pub.sendMessage("open-post", post_object=post, controller_="displayFriendship", vars=dict(caption=_("people who shared this")))

View File

@ -15,75 +15,75 @@ from . import basePost
log = logging.getLogger(__file__) log = logging.getLogger(__file__)
def get_message(status): def get_message(status):
message = "" message = ""
if "text" in status: if "text" in status:
message = utils.clean_text(status["text"]) message = utils.clean_text(status["text"])
return message return message
class displayCommentPresenter(basePost.displayPostPresenter): class displayCommentPresenter(basePost.displayPostPresenter):
def __init__(self, session, postObject, view, interactor): def __init__(self, session, postObject, view, interactor):
self.type = "comment" self.type = "comment"
self.modulename = "display_comment" self.modulename = "display_comment"
self.interactor = interactor self.interactor = interactor
self.view = view self.view = view
self.interactor.install(view=view, presenter=self, modulename=self.modulename) self.interactor.install(view=view, presenter=self, modulename=self.modulename)
self.session = session self.session = session
self.post = postObject self.post = postObject
self.user_identifier = "from_id" self.user_identifier = "from_id"
self.post_identifier = "id" self.post_identifier = "id"
self.worker = threading.Thread(target=self.load_all_components) self.worker = threading.Thread(target=self.load_all_components)
self.worker.finished = threading.Event() self.worker.finished = threading.Event()
self.worker.start() self.worker.start()
self.attachments = [] self.attachments = []
self.load_images = False self.load_images = False
# We'll put images here, so it will be easier to work with them. # We'll put images here, so it will be easier to work with them.
self.images = [] self.images = []
self.imageIndex = 0 self.imageIndex = 0
# connect here the pubsub event for successful posting of comments. # connect here the pubsub event for successful posting of comments.
pub.subscribe(self.posted, "posted") pub.subscribe(self.posted, "posted")
self.run() self.run()
pub.unsubscribe(self.posted, "posted") pub.unsubscribe(self.posted, "posted")
def load_all_components(self): def load_all_components(self):
self.get_post_information() self.get_post_information()
self.get_likes() self.get_likes()
self.send_message("disable_control", control="comment") self.send_message("disable_control", control="comment")
if self.post["likes"]["can_like"] == 0 and self.post["likes"]["user_likes"] == 0: if self.post["likes"]["can_like"] == 0 and self.post["likes"]["user_likes"] == 0:
self.send_message("disable_control", "like") self.send_message("disable_control", "like")
elif self.post["likes"]["user_likes"] == 1: elif self.post["likes"]["user_likes"] == 1:
self.send_message("set_label", control="like", label=_("&Dislike")) self.send_message("set_label", control="like", label=_("&Dislike"))
def get_post_information(self): def get_post_information(self):
from_ = self.session.get_user(self.post[self.user_identifier]) from_ = self.session.get_user(self.post[self.user_identifier])
if ("from_id" in self.post and "owner_id" in self.post): if ("from_id" in self.post and "owner_id" in self.post):
user2 = self.session.get_user(self.post["owner_id"], "user2") user2 = self.session.get_user(self.post["owner_id"], "user2")
user2.update(from_) user2.update(from_)
title = _("Comment from {user1_nom} in the {user2_nom}'s post").format(**user2) title = _("Comment from {user1_nom} in the {user2_nom}'s post").format(**user2)
self.send_message("set_title", value=title) self.send_message("set_title", value=title)
message = "" message = ""
message = get_message(self.post) message = get_message(self.post)
self.send_message("set", control="post_view", value=message) self.send_message("set", control="post_view", value=message)
self.get_attachments(self.post, message) self.get_attachments(self.post, message)
self.check_image_load() self.check_image_load()
def reply(self, *args, **kwargs): def reply(self, *args, **kwargs):
comment = createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createPostDialog(title=_("Reply to {user1_nom}").format(**self.session.get_user(self.post["from_id"])), message="", text="", mode="comment")) comment = createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createPostDialog(title=_("Reply to {user1_nom}").format(**self.session.get_user(self.post["from_id"])), message="", text="", mode="comment"))
if hasattr(comment, "text") or hasattr(comment, "privacy"): if hasattr(comment, "text") or hasattr(comment, "privacy"):
post_arguments = dict(owner_id=self.post["owner_id"], reply_to_comment=self.post["id"], post_id=self.post["post_id"], reply_to_user=self.post["owner_id"], message=comment.text) post_arguments = dict(owner_id=self.post["owner_id"], reply_to_comment=self.post["id"], post_id=self.post["post_id"], reply_to_user=self.post["owner_id"], message=comment.text)
attachments = [] attachments = []
if hasattr(comment, "attachments"): if hasattr(comment, "attachments"):
attachments = comment.attachments attachments = comment.attachments
call_threaded(pub.sendMessage, "post", parent_endpoint="wall", child_endpoint="createComment", attachments_list=attachments, post_arguments=post_arguments) call_threaded(pub.sendMessage, "post", parent_endpoint="wall", child_endpoint="createComment", attachments_list=attachments, post_arguments=post_arguments)
def show_likes(self): def show_likes(self):
""" show likes for the specified post.""" """ show likes for the specified post."""
data = dict(type="comment", owner_id=self.post["owner_id"], item_id=self.post["id"], extended=True, count=100, skip_own=True) data = dict(type="comment", owner_id=self.post["owner_id"], item_id=self.post["id"], extended=True, count=100, skip_own=True)
result = self.session.vk.client.likes.getList(**data) result = self.session.vk.client.likes.getList(**data)
if result["count"] > 0: if result["count"] > 0:
post = {"source_id": self.post[self.user_identifier], "friends": {"items": result["items"]}} post = {"source_id": self.post[self.user_identifier], "friends": {"items": result["items"]}}
pub.sendMessage("open-post", post_object=post, controller_="displayFriendship", vars=dict(caption=_("people who liked this"))) pub.sendMessage("open-post", post_object=post, controller_="displayFriendship", vars=dict(caption=_("people who liked this")))
def posted(self, from_buffer=None): def posted(self, from_buffer=None):
self.interactor.uninstall() self.interactor.uninstall()
return return

View File

@ -8,43 +8,43 @@ log = logging.getLogger(__file__)
class displayFriendshipPresenter(base.basePresenter): class displayFriendshipPresenter(base.basePresenter):
def __init__(self, session, postObject, view, interactor, caption=""): def __init__(self, session, postObject, view, interactor, caption=""):
self.session = session self.session = session
self.post = postObject self.post = postObject
super(displayFriendshipPresenter, self).__init__(view=view, interactor=interactor, modulename="display_friendship") super(displayFriendshipPresenter, self).__init__(view=view, interactor=interactor, modulename="display_friendship")
list_of_friends = self.get_friend_names() list_of_friends = self.get_friend_names()
from_ = self.session.get_user(self.post["source_id"]) from_ = self.session.get_user(self.post["source_id"])
title = caption.format(**from_) title = caption.format(**from_)
self.send_message("set_title", value=title) self.send_message("set_title", value=title)
self.set_friends_list(list_of_friends) self.set_friends_list(list_of_friends)
self.run() self.run()
def get_friend_names(self): def get_friend_names(self):
self.friends = self.post["friends"]["items"] self.friends = self.post["friends"]["items"]
friends = list() friends = list()
for i in self.friends: for i in self.friends:
if "user_id" in i: if "user_id" in i:
friends.append(self.session.get_user(i["user_id"])["user1_nom"]) friends.append(self.session.get_user(i["user_id"])["user1_nom"])
else: else:
friends.append(self.session.get_user(i["id"])["user1_nom"]) friends.append(self.session.get_user(i["id"])["user1_nom"])
return friends return friends
def set_friends_list(self, friendslist): def set_friends_list(self, friendslist):
self.send_message("add_items", control="friends", items=friendslist) self.send_message("add_items", control="friends", items=friendslist)
def view_profile(self, item): def view_profile(self, item):
user = self.friends[item] user = self.friends[item]
if "user_id" in user: if "user_id" in user:
id = user["user_id"] id = user["user_id"]
else: else:
id = user["id"] id = user["id"]
pub.sendMessage("user-profile", person=id) pub.sendMessage("user-profile", person=id)
def open_in_browser(self, item): def open_in_browser(self, item):
user = self.friends[item] user = self.friends[item]
if "user_id" in user: if "user_id" in user:
id = user["user_id"] id = user["user_id"]
else: else:
id = user["id"] id = user["id"]
url = "https://vk.com/id{user_id}".format(user_id=id) url = "https://vk.com/id{user_id}".format(user_id=id)
webbrowser.open_new_tab(url) webbrowser.open_new_tab(url)

View File

@ -7,49 +7,49 @@ log = logging.getLogger(__file__)
class displayPollPresenter(base.basePresenter): class displayPollPresenter(base.basePresenter):
def __init__(self, session, poll, view, interactor, show_results=False): def __init__(self, session, poll, view, interactor, show_results=False):
super(displayPollPresenter, self).__init__(view=view, interactor=interactor, modulename="display_poll") super(displayPollPresenter, self).__init__(view=view, interactor=interactor, modulename="display_poll")
self.poll = poll["poll"] self.poll = poll["poll"]
self.session = session self.session = session
self.get_poll() self.get_poll()
self.load_poll(show_results) self.load_poll(show_results)
self.run() self.run()
def get_poll(self): def get_poll(self):
# Retrieve the poll again so we will have a fresh and updated object. # Retrieve the poll again so we will have a fresh and updated object.
data = dict(owner_id=self.poll["owner_id"], is_board=int(self.poll["is_board"]), poll_id=self.poll["id"]) data = dict(owner_id=self.poll["owner_id"], is_board=int(self.poll["is_board"]), poll_id=self.poll["id"])
self.poll = self.session.vk.client.polls.getById(**data) self.poll = self.session.vk.client.polls.getById(**data)
def load_poll(self, load_results=False): def load_poll(self, load_results=False):
user = self.session.get_user(self.poll["author_id"]) user = self.session.get_user(self.poll["author_id"])
title = _("Poll from {user1_nom}").format(**user) title = _("Poll from {user1_nom}").format(**user)
self.send_message("set_title", value=title) self.send_message("set_title", value=title)
self.send_message("set", control="question", value=self.poll["question"]) self.send_message("set", control="question", value=self.poll["question"])
if len(self.poll["answer_ids"]) > 0 or ("is_closed" in self.poll and self.poll["is_closed"] == True) or load_results == True or ("can_vote" in self.poll and self.poll["can_vote"] == False): if len(self.poll["answer_ids"]) > 0 or ("is_closed" in self.poll and self.poll["is_closed"] == True) or load_results == True or ("can_vote" in self.poll and self.poll["can_vote"] == False):
options = [] options = []
for i in self.poll["answers"]: for i in self.poll["answers"]:
options.append((i["text"], i["votes"], i["rate"])) options.append((i["text"], i["votes"], i["rate"]))
self.send_message("add_options", options=options, multiple=self.poll["multiple"]) self.send_message("add_options", options=options, multiple=self.poll["multiple"])
self.send_message("done") self.send_message("done")
self.send_message("disable_control", control="ok") self.send_message("disable_control", control="ok")
else: else:
options = [] options = []
for i in self.poll["answers"]: for i in self.poll["answers"]:
options.append(i["text"]) options.append(i["text"])
self.send_message("add_options", options=options, multiple=self.poll["multiple"]) self.send_message("add_options", options=options, multiple=self.poll["multiple"])
self.send_message("done") self.send_message("done")
def vote(self, answers): def vote(self, answers):
ids = "" ids = ""
for i in range(0, len(self.poll["answers"])): for i in range(0, len(self.poll["answers"])):
if answers[i] == True: if answers[i] == True:
ids = ids+"{answer_id},".format(answer_id=self.poll["answers"][i]["id"]) ids = ids+"{answer_id},".format(answer_id=self.poll["answers"][i]["id"])
if self.poll["multiple"] == False: if self.poll["multiple"] == False:
break break
if ids == "": if ids == "":
log.exception("An error occurred when retrieving answer IDS for the following poll: %r. Provided answer list: %r" % (self.poll, answers)) log.exception("An error occurred when retrieving answer IDS for the following poll: %r. Provided answer list: %r" % (self.poll, answers))
return return
data = dict(owner_id=self.poll["owner_id"], poll_id=self.poll["id"], answer_ids=ids, is_board=int(self.poll["is_board"])) data = dict(owner_id=self.poll["owner_id"], poll_id=self.poll["id"], answer_ids=ids, is_board=int(self.poll["is_board"]))
result = self.session.vk.client.polls.addVote(**data) result = self.session.vk.client.polls.addVote(**data)
if result == 1: if result == 1:
output.speak(_("Your vote has been added to this poll.")) output.speak(_("Your vote has been added to this poll."))

View File

@ -18,151 +18,151 @@ log = logging.getLogger(__file__)
class displayTopicPresenter(basePost.displayPostPresenter): class displayTopicPresenter(basePost.displayPostPresenter):
def __init__(self, session, postObject, group_id, view, interactor): def __init__(self, session, postObject, group_id, view, interactor):
self.type = "topic" self.type = "topic"
self.modulename = "display_topic" self.modulename = "display_topic"
self.interactor = interactor self.interactor = interactor
self.view = view self.view = view
self.interactor.install(view=view, presenter=self, modulename=self.modulename) self.interactor.install(view=view, presenter=self, modulename=self.modulename)
self.session = session self.session = session
self.post = postObject self.post = postObject
self.group_id = group_id self.group_id = group_id
self.load_images = False self.load_images = False
# We'll put images here, so it will be easier to work with them. # We'll put images here, so it will be easier to work with them.
self.images = [] self.images = []
self.imageIndex = 0 self.imageIndex = 0
result = self.get_post_information() result = self.get_post_information()
# Stop loading everything else if post was deleted. # Stop loading everything else if post was deleted.
if result == False: if result == False:
self.interactor.uninstall() self.interactor.uninstall()
return return
self.worker = threading.Thread(target=self.load_all_components) self.worker = threading.Thread(target=self.load_all_components)
self.worker.finished = threading.Event() self.worker.finished = threading.Event()
self.worker.start() self.worker.start()
self.attachments = [] self.attachments = []
# connect pubsub event for posted comments. # connect pubsub event for posted comments.
pub.subscribe(self.posted, "posted") pub.subscribe(self.posted, "posted")
self.run() self.run()
pub.unsubscribe(self.posted, "posted") pub.unsubscribe(self.posted, "posted")
def load_all_components(self): def load_all_components(self):
self.get_comments() self.get_comments()
def get_post_information(self): def get_post_information(self):
title = self.post["title"] title = self.post["title"]
self.send_message("set_title", value=title) self.send_message("set_title", value=title)
return True return True
def get_comments(self): def get_comments(self):
""" Get comments and insert them in a list.""" """ Get comments and insert them in a list."""
self.comments = self.session.vk.client.board.getComments(group_id=self.group_id, topic_id=self.post["id"], need_likes=1, count=100, extended=1, sort="desc") self.comments = self.session.vk.client.board.getComments(group_id=self.group_id, topic_id=self.post["id"], need_likes=1, count=100, extended=1, sort="desc")
comments_ = [] comments_ = []
data = dict(profiles=self.comments["profiles"], groups=[]) data = dict(profiles=self.comments["profiles"], groups=[])
self.session.process_usernames(data) self.session.process_usernames(data)
self.comments["items"].reverse() self.comments["items"].reverse()
# If there are less than 100 comments in the topic we should disable the "load previous" button. # If there are less than 100 comments in the topic we should disable the "load previous" button.
if self.comments["count"] <= 100: if self.comments["count"] <= 100:
self.send_message("disable_control", control="load_more_comments") self.send_message("disable_control", control="load_more_comments")
else: else:
left_comments = self.comments["count"]-len(self.comments["items"]) left_comments = self.comments["count"]-len(self.comments["items"])
if left_comments > 100: if left_comments > 100:
left_comments = 100 left_comments = 100
self.send_message("set_label", control="load_more_comments", label=_("Load {comments} previous comments").format(comments=left_comments)) self.send_message("set_label", control="load_more_comments", label=_("Load {comments} previous comments").format(comments=left_comments))
for i in self.comments["items"]: for i in self.comments["items"]:
# If comment has a "deleted" key it should not be displayed, obviously. # If comment has a "deleted" key it should not be displayed, obviously.
if "deleted" in i: if "deleted" in i:
continue continue
from_ = self.session.get_user(i["from_id"])["user1_nom"] from_ = self.session.get_user(i["from_id"])["user1_nom"]
# match user mentions inside text comment. # match user mentions inside text comment.
original_date = arrow.get(i["date"]) original_date = arrow.get(i["date"])
created_at = original_date.humanize(locale=languageHandler.curLang[:2]) created_at = original_date.humanize(locale=languageHandler.curLang[:2])
likes = str(i["likes"]["count"]) likes = str(i["likes"]["count"])
text = utils.clean_text(text=i["text"]) text = utils.clean_text(text=i["text"])
comments_.append((from_, text, created_at, likes)) comments_.append((from_, text, created_at, likes))
self.send_message("add_items", control="comments", items=comments_) self.send_message("add_items", control="comments", items=comments_)
def post_like(self): def post_like(self):
c = self.interactor.view.comments.get_selected() c = self.interactor.view.comments.get_selected()
id = self.comments["items"][c]["id"] id = self.comments["items"][c]["id"]
if self.comments["items"][c]["likes"]["user_likes"] == 1: if self.comments["items"][c]["likes"]["user_likes"] == 1:
l = self.session.vk.client.likes.delete(owner_id=-1*self.group_id, item_id=id, type="topic_comment") l = self.session.vk.client.likes.delete(owner_id=-1*self.group_id, item_id=id, type="topic_comment")
output.speak(_("You don't like this")) output.speak(_("You don't like this"))
self.comments["items"][c]["likes"]["count"] = l["likes"] self.comments["items"][c]["likes"]["count"] = l["likes"]
self.comments["items"][c]["likes"]["user_likes"] = 2 self.comments["items"][c]["likes"]["user_likes"] = 2
self.send_message("set_label", control="like", label=_("&Like")) self.send_message("set_label", control="like", label=_("&Like"))
else: else:
l = self.session.vk.client.likes.add(owner_id=-1*self.group_id, item_id=id, type="topic_comment") l = self.session.vk.client.likes.add(owner_id=-1*self.group_id, item_id=id, type="topic_comment")
output.speak(_("You liked this")) output.speak(_("You liked this"))
self.send_message("set_label", control="like", label=_("&Dislike")) self.send_message("set_label", control="like", label=_("&Dislike"))
self.comments["items"][c]["likes"]["count"] = l["likes"] self.comments["items"][c]["likes"]["count"] = l["likes"]
self.comments["items"][c]["likes"]["user_likes"] = 1 self.comments["items"][c]["likes"]["user_likes"] = 1
self.clear_comments_list() self.clear_comments_list()
def change_comment(self, comment): def change_comment(self, comment):
comment = self.comments["items"][comment] comment = self.comments["items"][comment]
self.send_message("clean_list", list="attachments") self.send_message("clean_list", list="attachments")
self.get_attachments(comment, "") self.get_attachments(comment, "")
if comment["likes"]["user_likes"] == 1: if comment["likes"]["user_likes"] == 1:
self.send_message("set_label", control="like", label=_("&Dislike")) self.send_message("set_label", control="like", label=_("&Dislike"))
else: else:
self.send_message("set_label", control="like", label=_("&Like")) self.send_message("set_label", control="like", label=_("&Like"))
def add_comment(self): def add_comment(self):
comment = createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createPostDialog(title=_("Add a comment"), message="", text="", mode="comment")) comment = createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createPostDialog(title=_("Add a comment"), message="", text="", mode="comment"))
if hasattr(comment, "text") or hasattr(comment, "privacy"): if hasattr(comment, "text") or hasattr(comment, "privacy"):
post_arguments = dict(group_id=self.group_id, topic_id=self.post["id"], message=comment.text) post_arguments = dict(group_id=self.group_id, topic_id=self.post["id"], message=comment.text)
attachments = [] attachments = []
if hasattr(comment, "attachments"): if hasattr(comment, "attachments"):
attachments = comment.attachments attachments = comment.attachments
call_threaded(pub.sendMessage, "post", parent_endpoint="board", child_endpoint="createComment", attachments_list=attachments, post_arguments=post_arguments) call_threaded(pub.sendMessage, "post", parent_endpoint="board", child_endpoint="createComment", attachments_list=attachments, post_arguments=post_arguments)
def reply(self, comment): def reply(self, comment):
c = self.comments["items"][comment] c = self.comments["items"][comment]
comment = createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createPostDialog(title=_("Reply to {user1_nom}").format(**self.session.get_user(c["from_id"])), message="", text="", mode="comment")) comment = createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createPostDialog(title=_("Reply to {user1_nom}").format(**self.session.get_user(c["from_id"])), message="", text="", mode="comment"))
if hasattr(comment, "text") or hasattr(comment, "privacy"): if hasattr(comment, "text") or hasattr(comment, "privacy"):
user = self.session.get_user(c["from_id"]) user = self.session.get_user(c["from_id"])
name = user["user1_nom"].split(" ")[0] name = user["user1_nom"].split(" ")[0]
comment.text = "[post{post_id}|{name}], {text}".format(post_id=c["id"], text=comment.text, name=name) comment.text = "[post{post_id}|{name}], {text}".format(post_id=c["id"], text=comment.text, name=name)
group_id = self.group_id group_id = self.group_id
topic_id = self.post["id"] topic_id = self.post["id"]
post_arguments = dict(group_id=group_id, topic_id=topic_id, reply_to_comment=c["id"], message=comment.text) post_arguments = dict(group_id=group_id, topic_id=topic_id, reply_to_comment=c["id"], message=comment.text)
attachments = [] attachments = []
if hasattr(comment, "attachments"): if hasattr(comment, "attachments"):
attachments = comment.attachments attachments = comment.attachments
call_threaded(pub.sendMessage, "post", parent_endpoint="board", child_endpoint="createComment", attachments_list=attachments, post_arguments=post_arguments) call_threaded(pub.sendMessage, "post", parent_endpoint="board", child_endpoint="createComment", attachments_list=attachments, post_arguments=post_arguments)
def show_comment(self, comment_index): def show_comment(self, comment_index):
c = self.comments["items"][comment_index] c = self.comments["items"][comment_index]
c["post_id"] = self.post["id"] c["post_id"] = self.post["id"]
c["group_id"] = -1*self.group_id c["group_id"] = -1*self.group_id
a = displayTopicCommentPresenter(session=self.session, postObject=c, interactor=interactors.displayPostInteractor(), view=views.displayComment()) a = displayTopicCommentPresenter(session=self.session, postObject=c, interactor=interactors.displayPostInteractor(), view=views.displayComment())
def load_more_comments(self): def load_more_comments(self):
offset = len(self.comments["items"]) offset = len(self.comments["items"])
comments = self.session.vk.client.board.getComments(group_id=self.group_id, topic_id=self.post["id"], need_likes=1, count=100, extended=1, sort="desc", offset=offset) comments = self.session.vk.client.board.getComments(group_id=self.group_id, topic_id=self.post["id"], need_likes=1, count=100, extended=1, sort="desc", offset=offset)
data = dict(profiles=comments["profiles"], groups=[]) data = dict(profiles=comments["profiles"], groups=[])
self.session.process_usernames(data) self.session.process_usernames(data)
# If there are less than 100 comments in the topic we should disable the "load previous" button. # If there are less than 100 comments in the topic we should disable the "load previous" button.
for i in comments["items"]: for i in comments["items"]:
self.comments["items"].insert(0, i) self.comments["items"].insert(0, i)
for i in comments["items"]: for i in comments["items"]:
# If comment has a "deleted" key it should not be displayed, obviously. # If comment has a "deleted" key it should not be displayed, obviously.
if "deleted" in i: if "deleted" in i:
continue continue
from_ = self.session.get_user(i["from_id"])["user1_nom"] from_ = self.session.get_user(i["from_id"])["user1_nom"]
# match user mentions inside text comment. # match user mentions inside text comment.
original_date = arrow.get(i["date"]) original_date = arrow.get(i["date"])
created_at = original_date.humanize(locale=languageHandler.curLang[:2]) created_at = original_date.humanize(locale=languageHandler.curLang[:2])
likes = str(i["likes"]["count"]) likes = str(i["likes"]["count"])
text = utils.clean_text(text=i["text"]) text = utils.clean_text(text=i["text"])
self.send_message("add_item", control="comments", item=(from_, text, created_at, likes), reversed=True) self.send_message("add_item", control="comments", item=(from_, text, created_at, likes), reversed=True)
if len(self.comments["items"]) == self.comments["count"]: if len(self.comments["items"]) == self.comments["count"]:
self.send_message("disable_control", control="load_more_comments") self.send_message("disable_control", control="load_more_comments")
else: else:
left_comments = self.comments["count"]-len(self.comments["items"]) left_comments = self.comments["count"]-len(self.comments["items"])
if left_comments > 100: if left_comments > 100:
left_comments = 100 left_comments = 100
self.send_message("set_label", control="load_more_comments", label=_("Load {comments} previous comments").format(comments=left_comments)) self.send_message("set_label", control="load_more_comments", label=_("Load {comments} previous comments").format(comments=left_comments))
def posted(self, from_buffer=None): def posted(self, from_buffer=None):
self.clear_comments_list() self.clear_comments_list()

View File

@ -10,44 +10,44 @@ from . import comment
log = logging.getLogger(__file__) log = logging.getLogger(__file__)
def get_message(status): def get_message(status):
message = "" message = ""
if "text" in status: if "text" in status:
message = utils.clean_text(status["text"]) message = utils.clean_text(status["text"])
return message return message
class displayTopicCommentPresenter(comment.displayCommentPresenter): class displayTopicCommentPresenter(comment.displayCommentPresenter):
def get_post_information(self): def get_post_information(self):
from_ = self.session.get_user(self.post[self.user_identifier]) from_ = self.session.get_user(self.post[self.user_identifier])
title = from_["user1_nom"] title = from_["user1_nom"]
self.send_message("set_title", value=title) self.send_message("set_title", value=title)
message = "" message = ""
message = get_message(self.post) message = get_message(self.post)
self.send_message("set", control="post_view", value=message) self.send_message("set", control="post_view", value=message)
self.get_attachments(self.post, message) self.get_attachments(self.post, message)
self.check_image_load() self.check_image_load()
self.send_message("disable_control", control="reply") self.send_message("disable_control", control="reply")
def post_like(self): def post_like(self):
id = self.post["id"] id = self.post["id"]
if self.post["likes"]["user_likes"] == 1: if self.post["likes"]["user_likes"] == 1:
l = self.session.vk.client.likes.delete(owner_id=self.post["group_id"], item_id=id, type="topic_comment") l = self.session.vk.client.likes.delete(owner_id=self.post["group_id"], item_id=id, type="topic_comment")
output.speak(_("You don't like this")) output.speak(_("You don't like this"))
self.post["likes"]["count"] = l["likes"] self.post["likes"]["count"] = l["likes"]
self.post["likes"]["user_likes"] = 2 self.post["likes"]["user_likes"] = 2
self.send_message("set_label", control="like", label=_("&Like")) self.send_message("set_label", control="like", label=_("&Like"))
else: else:
l = self.session.vk.client.likes.add(owner_id=self.post["group_id"], item_id=id, type="topic_comment") l = self.session.vk.client.likes.add(owner_id=self.post["group_id"], item_id=id, type="topic_comment")
output.speak(_("You liked this")) output.speak(_("You liked this"))
self.send_message("set_label", control="like", label=_("&Dislike")) self.send_message("set_label", control="like", label=_("&Dislike"))
self.post["likes"]["count"] = l["likes"] self.post["likes"]["count"] = l["likes"]
self.post["likes"]["user_likes"] = 1 self.post["likes"]["user_likes"] = 1
self.get_likes() self.get_likes()
def show_likes(self): def show_likes(self):
""" show likes for the specified post.""" """ show likes for the specified post."""
data = dict(type="topic_comment", owner_id=self.post["group_id"], item_id=self.post["id"], extended=True, count=100, skip_own=True) data = dict(type="topic_comment", owner_id=self.post["group_id"], item_id=self.post["id"], extended=True, count=100, skip_own=True)
result = self.session.vk.client.likes.getList(**data) result = self.session.vk.client.likes.getList(**data)
if result["count"] > 0: if result["count"] > 0:
post = {"source_id": self.post["group_id"], "friends": {"items": result["items"]}} post = {"source_id": self.post["group_id"], "friends": {"items": result["items"]}}
pub.sendMessage("open-post", post_object=post, controller_="displayFriendship", vars=dict(caption=_("people who liked this"))) pub.sendMessage("open-post", post_object=post, controller_="displayFriendship", vars=dict(caption=_("people who liked this")))

View File

@ -8,22 +8,22 @@ from logging import getLogger
log = getLogger("controller.longpolThread") log = getLogger("controller.longpolThread")
class worker(threading.Thread): class worker(threading.Thread):
def __init__(self, session): def __init__(self, session):
super(worker, self).__init__() super(worker, self).__init__()
log.debug("Instantiating longPoll server") log.debug("Instantiating longPoll server")
self.session = session self.session = session
self.longpoll = VkLongPoll(self.session.vk.session_object) self.longpoll = VkLongPoll(self.session.vk.session_object)
def run(self): def run(self):
try: try:
for event in self.longpoll.listen(): for event in self.longpoll.listen():
if event.type == VkEventType.MESSAGE_NEW: if event.type == VkEventType.MESSAGE_NEW:
pub.sendMessage("order-sent-message", obj=event) pub.sendMessage("order-sent-message", obj=event)
elif event.type == VkEventType.USER_ONLINE: elif event.type == VkEventType.USER_ONLINE:
pub.sendMessage("user-online", event=event) pub.sendMessage("user-online", event=event)
elif event.type == VkEventType.USER_OFFLINE: elif event.type == VkEventType.USER_OFFLINE:
pub.sendMessage("user-offline", event=event) pub.sendMessage("user-offline", event=event)
elif event.type == VkEventType.USER_TYPING: elif event.type == VkEventType.USER_TYPING:
pub.sendMessage("user-typing", obj=event) pub.sendMessage("user-typing", obj=event)
except: except:
pub.sendMessage("longpoll-read-timeout") pub.sendMessage("longpoll-read-timeout")

File diff suppressed because it is too large Load Diff

View File

@ -21,234 +21,234 @@ player = None
log = logging.getLogger("player") log = logging.getLogger("player")
def setup(): def setup():
global player global player
if player == None: if player == None:
player = audioPlayer() player = audioPlayer()
class audioPlayer(object): class audioPlayer(object):
""" A media player which will play all passed URLS.""" """ A media player which will play all passed URLS."""
def __init__(self): def __init__(self):
# control variable for checking if another file has been sent to the player before, # control variable for checking if another file has been sent to the player before,
# thus avoiding double file playback and other oddities happening in sound_lib from time to time. # thus avoiding double file playback and other oddities happening in sound_lib from time to time.
self.is_playing = False self.is_playing = False
# This will be the URLStream handler # This will be the URLStream handler
self.stream = None self.stream = None
self.message = None self.message = None
self.vol = config.app["sound"]["volume"] self.vol = config.app["sound"]["volume"]
# this variable is set to true when the URLPlayer is decoding something, thus it will block other calls to the play method. # this variable is set to true when the URLPlayer is decoding something, thus it will block other calls to the play method.
self.is_working = False self.is_working = False
# Playback queue. # Playback queue.
self.queue = [] self.queue = []
# Index of the currently playing track. # Index of the currently playing track.
self.playing_track = 0 self.playing_track = 0
self.playing_all = False self.playing_all = False
self.worker = RepeatingTimer(5, self.player_function) self.worker = RepeatingTimer(5, self.player_function)
self.worker.start() self.worker.start()
# Status of the player. # Status of the player.
self.stopped = True self.stopped = True
# Modify some default settings present in Bass so it will increase timeout connection, thus causing less "connection timed out" errors when playing. # Modify some default settings present in Bass so it will increase timeout connection, thus causing less "connection timed out" errors when playing.
bassconfig = BassConfig() bassconfig = BassConfig()
# Set timeout connection to 30 seconds. # Set timeout connection to 30 seconds.
bassconfig["net_timeout"] = 30000 bassconfig["net_timeout"] = 30000
# subscribe all pubsub events. # subscribe all pubsub events.
pub.subscribe(self.play, "play") pub.subscribe(self.play, "play")
pub.subscribe(self.play_message, "play-message") pub.subscribe(self.play_message, "play-message")
pub.subscribe(self.play_all, "play-all") pub.subscribe(self.play_all, "play-all")
pub.subscribe(self.pause, "pause") pub.subscribe(self.pause, "pause")
pub.subscribe(self.stop, "stop") pub.subscribe(self.stop, "stop")
pub.subscribe(self.play_next, "play-next") pub.subscribe(self.play_next, "play-next")
pub.subscribe(self.play_previous, "play-previous") pub.subscribe(self.play_previous, "play-previous")
pub.subscribe(self.seek, "seek") pub.subscribe(self.seek, "seek")
# Stopped has a special function here, hence the decorator # Stopped has a special function here, hence the decorator
# when stopped will be set to True, it will send a pubsub event to inform other parts of the application about the status change. # when stopped will be set to True, it will send a pubsub event to inform other parts of the application about the status change.
# this is useful for changing labels between play and pause, and so on, in buttons. # this is useful for changing labels between play and pause, and so on, in buttons.
@property @property
def stopped(self): def stopped(self):
return self._stopped return self._stopped
@stopped.setter @stopped.setter
def stopped(self, value): def stopped(self, value):
self._stopped = value self._stopped = value
pub.sendMessage("playback-changed", stopped=value) pub.sendMessage("playback-changed", stopped=value)
def play(self, object, set_info=True, fresh=False): def play(self, object, set_info=True, fresh=False):
""" Play an URl Stream. """ Play an URl Stream.
@object dict: typically an audio object as returned by VK, with a "url" component which must be a valid URL to a media file. @object dict: typically an audio object as returned by VK, with a "url" component which must be a valid URL to a media file.
@set_info bool: If true, will set information about the currently playing audio in the application status bar. @set_info bool: If true, will set information about the currently playing audio in the application status bar.
@fresh bool: If True, will remove everything playing in the queue and start this file only. otherwise it will play the new file but not remove the current queue.""" @fresh bool: If True, will remove everything playing in the queue and start this file only. otherwise it will play the new file but not remove the current queue."""
if "url" in object and object["url"] =="": if "url" in object and object["url"] =="":
pub.sendMessage("notify", message=_("This file could not be played because it is not allowed in your country")) pub.sendMessage("notify", message=_("This file could not be played because it is not allowed in your country"))
return return
if self.stream != None and (self.stream.is_playing == True or self.stream.is_stalled == True): if self.stream != None and (self.stream.is_playing == True or self.stream.is_stalled == True):
try: try:
self.stream.stop() self.stream.stop()
except BassError: except BassError:
log.exception("error when stopping the file") log.exception("error when stopping the file")
self.stream = None self.stream = None
self.stopped = True self.stopped = True
if fresh == True: if fresh == True:
self.queue = [] self.queue = []
# Make sure that there are no other sounds trying to be played. # Make sure that there are no other sounds trying to be played.
if self.is_working == False: if self.is_working == False:
self.is_working = True self.is_working = True
url_ = utils.transform_audio_url(object["url"]) url_ = utils.transform_audio_url(object["url"])
try: try:
self.stream = URLStream(url=url_) self.stream = URLStream(url=url_)
except: except:
log.error("Unable to play URL %s" % (url_)) log.error("Unable to play URL %s" % (url_))
return return
# Translators: {0} will be replaced with a song's title and {1} with the artist. # Translators: {0} will be replaced with a song's title and {1} with the artist.
if set_info: if set_info:
msg = _("Playing {0} by {1}").format(object["title"], object["artist"]) msg = _("Playing {0} by {1}").format(object["title"], object["artist"])
pub.sendMessage("update-status-bar", status=msg) pub.sendMessage("update-status-bar", status=msg)
self.stream.volume = self.vol/100.0 self.stream.volume = self.vol/100.0
self.stream.play() self.stream.play()
self.stopped = False self.stopped = False
self.is_working = False self.is_working = False
def play_message(self, message_url): def play_message(self, message_url):
if self.message != None and (self.message.is_playing == True or self.message.is_stalled == True): if self.message != None and (self.message.is_playing == True or self.message.is_stalled == True):
return self.stop_message() return self.stop_message()
output.speak(_("Playing...")) output.speak(_("Playing..."))
url_ = utils.transform_audio_url(message_url) url_ = utils.transform_audio_url(message_url)
try: try:
self.message = URLStream(url=url_) self.message = URLStream(url=url_)
except: except:
log.error("Unable to play URL %s" % (url_)) log.error("Unable to play URL %s" % (url_))
return return
self.message.volume = self.vol/100.0 self.message.volume = self.vol/100.0
self.message.play() self.message.play()
volume_percent = self.volume*0.25 volume_percent = self.volume*0.25
volume_step = self.volume*0.15 volume_step = self.volume*0.15
while self.stream.volume*100 > volume_percent: while self.stream.volume*100 > volume_percent:
self.stream.volume = self.stream.volume-(volume_step/100) self.stream.volume = self.stream.volume-(volume_step/100)
time.sleep(0.1) time.sleep(0.1)
def stop(self): def stop(self):
""" Stop audio playback. """ """ Stop audio playback. """
if self.stream != None and self.stream.is_playing == True: if self.stream != None and self.stream.is_playing == True:
self.stream.stop() self.stream.stop()
self.stopped = True self.stopped = True
self.queue = [] self.queue = []
def stop_message(self): def stop_message(self):
if hasattr(self, "message") and self.message != None and self.message.is_playing == True: if hasattr(self, "message") and self.message != None and self.message.is_playing == True:
self.message.stop() self.message.stop()
volume_step = self.volume*0.15 volume_step = self.volume*0.15
while self.stream.volume*100 < self.volume: while self.stream.volume*100 < self.volume:
self.stream.volume = self.stream.volume+(volume_step/100) self.stream.volume = self.stream.volume+(volume_step/100)
time.sleep(0.1) time.sleep(0.1)
self.message = None self.message = None
def pause(self): def pause(self):
""" pause the current playback, without destroying the queue or the current stream. If the stream is already paused this function will resume the playback. """ """ pause the current playback, without destroying the queue or the current stream. If the stream is already paused this function will resume the playback. """
if self.stream != None: if self.stream != None:
if self.stream.is_playing == True: if self.stream.is_playing == True:
self.stream.pause() self.stream.pause()
self.stopped = True self.stopped = True
else: else:
try: try:
self.stream.play() self.stream.play()
self.stopped = False self.stopped = False
except BassError: except BassError:
pass pass
if self.playing_all == False and len(self.queue) > 0: if self.playing_all == False and len(self.queue) > 0:
self.playing_all = True self.playing_all = True
@property @property
def volume(self): def volume(self):
return self.vol return self.vol
@volume.setter @volume.setter
def volume(self, vol): def volume(self, vol):
if vol <= 100 and vol >= 0: if vol <= 100 and vol >= 0:
self.vol = vol self.vol = vol
elif vol < 0: elif vol < 0:
self.vol = 0 self.vol = 0
elif vol > 100: elif vol > 100:
self.vol = 100 self.vol = 100
if self.stream != None: if self.stream != None:
if self.message != None and self.message.is_playing: if self.message != None and self.message.is_playing:
self.stream.volume = (self.vol*0.25)/100.0 self.stream.volume = (self.vol*0.25)/100.0
self.message.volume = self.vol/100.0 self.message.volume = self.vol/100.0
else: else:
self.stream.volume = self.vol/100.0 self.stream.volume = self.vol/100.0
def play_all(self, list_of_songs, shuffle=False): def play_all(self, list_of_songs, shuffle=False):
""" Play all passed songs and adds all of those to the queue. """ Play all passed songs and adds all of those to the queue.
@list_of_songs list: A list of audio objects returned by VK. @list_of_songs list: A list of audio objects returned by VK.
@shuffle bool: If True, the files will be played randomly.""" @shuffle bool: If True, the files will be played randomly."""
if self.is_working: if self.is_working:
return return
self.playing_track = 0 self.playing_track = 0
self.stop() self.stop()
# Skip all country restricted tracks as they are not playable here. # Skip all country restricted tracks as they are not playable here.
self.queue = [i for i in list_of_songs if i["url"] != ""] self.queue = [i for i in list_of_songs if i["url"] != ""]
if shuffle: if shuffle:
random.shuffle(self.queue) random.shuffle(self.queue)
call_threaded(self.play, self.queue[self.playing_track]) call_threaded(self.play, self.queue[self.playing_track])
self.playing_all = True self.playing_all = True
def player_function(self): def player_function(self):
""" Check if the stream has reached the end of the file so it will play the next song. """ """ Check if the stream has reached the end of the file so it will play the next song. """
if self.message != None and self.message.is_playing == False and len(self.message) == self.message.position: if self.message != None and self.message.is_playing == False and len(self.message) == self.message.position:
volume_step = self.volume*0.15 volume_step = self.volume*0.15
while self.stream != None and self.stream.volume*100 < self.volume: while self.stream != None and self.stream.volume*100 < self.volume:
self.stream.volume = self.stream.volume+(volume_step/100) self.stream.volume = self.stream.volume+(volume_step/100)
time.sleep(0.1) time.sleep(0.1)
if self.stream != None and self.stream.is_playing == False and self.stopped == False and len(self.stream) == self.stream.position: if self.stream != None and self.stream.is_playing == False and self.stopped == False and len(self.stream) == self.stream.position:
if self.playing_track >= len(self.queue): if self.playing_track >= len(self.queue):
self.stopped = True self.stopped = True
self.playing_all = False self.playing_all = False
return return
elif self.playing_all == False: elif self.playing_all == False:
self.stopped = True self.stopped = True
return return
elif self.playing_track < len(self.queue): elif self.playing_track < len(self.queue):
self.playing_track += 1 self.playing_track += 1
self.play(self.queue[self.playing_track]) self.play(self.queue[self.playing_track])
def play_next(self): def play_next(self):
""" Play the next song in the queue. """ """ Play the next song in the queue. """
if len(self.queue) == 0: if len(self.queue) == 0:
return return
if self.is_working: if self.is_working:
return return
if self.playing_track < len(self.queue)-1: if self.playing_track < len(self.queue)-1:
self.playing_track += 1 self.playing_track += 1
else: else:
self.playing_track = 0 self.playing_track = 0
call_threaded(self.play, self.queue[self.playing_track]) call_threaded(self.play, self.queue[self.playing_track])
def play_previous(self): def play_previous(self):
""" Play the previous song in the queue. """ """ Play the previous song in the queue. """
if len(self.queue) == 0: if len(self.queue) == 0:
return return
if self.is_working: if self.is_working:
return return
if self.playing_track <= 0: if self.playing_track <= 0:
self.playing_track = len(self.queue)-1 self.playing_track = len(self.queue)-1
else: else:
self.playing_track -= 1 self.playing_track -= 1
call_threaded(self.play, self.queue[self.playing_track]) call_threaded(self.play, self.queue[self.playing_track])
def seek(self, ms=0): def seek(self, ms=0):
if self.check_is_playing(): if self.check_is_playing():
if self.stream.position < 500000 and ms < 0: if self.stream.position < 500000 and ms < 0:
self.stream.position = 0 self.stream.position = 0
else: else:
try: try:
self.stream.position = self.stream.position+ms self.stream.position = self.stream.position+ms
except: except:
pass pass
def check_is_playing(self): def check_is_playing(self):
""" check if the player is already playing a stream. """ """ check if the player is already playing a stream. """
if self.stream == None: if self.stream == None:
return False return False
if self.stream != None and self.stream.is_playing == False and self.stream.is_stalled == False: if self.stream != None and self.stream.is_playing == False and self.stream.is_stalled == False:
return False return False
else: else:
return True return True

View File

@ -15,154 +15,154 @@ log = logging.getLogger("controller.profiles")
class userProfilePresenter(base.basePresenter): class userProfilePresenter(base.basePresenter):
def __init__(self, session, user_id, view, interactor): def __init__(self, session, user_id, view, interactor):
""" Default constructor: """ Default constructor:
@session vk.session: The main session object, capable of calling VK methods. @session vk.session: The main session object, capable of calling VK methods.
@user_id integer: User ID to retrieve information of. @user_id integer: User ID to retrieve information of.
At the current time, only users (and not communities) are supported. At the current time, only users (and not communities) are supported.
""" """
super(userProfilePresenter, self).__init__(view=view, interactor=interactor, modulename="user_profile") super(userProfilePresenter, self).__init__(view=view, interactor=interactor, modulename="user_profile")
# self.person will hold a reference to the user object when retrieved from VK. # self.person will hold a reference to the user object when retrieved from VK.
self.person = None self.person = None
self.session = session self.session = session
self.user_id = user_id self.user_id = user_id
# Get information in a threaded way here. # Get information in a threaded way here.
# Note: We do not handle any race condition here because due to the presenter only sending pubsub messages, # Note: We do not handle any race condition here because due to the presenter only sending pubsub messages,
# Nothing happens if the pubsub send messages to the interactor after the latter has been destroyed. # Nothing happens if the pubsub send messages to the interactor after the latter has been destroyed.
# Pubsub messages are just skipped if there are no listeners for them. # Pubsub messages are just skipped if there are no listeners for them.
call_threaded(self.get_basic_information) call_threaded(self.get_basic_information)
self.run() self.run()
def get_basic_information(self): def get_basic_information(self):
""" Gets and inserts basic user information. """ Gets and inserts basic user information.
See https://vk.com/dev/users.get""" See https://vk.com/dev/users.get"""
# List of fields (information) to retrieve. For a list of fields available for user objects, # List of fields (information) to retrieve. For a list of fields available for user objects,
# see https://vk.com/dev/fields # see https://vk.com/dev/fields
fields = "first_name, last_name, bdate, city, country, home_town, photo_200_orig, online, site, status, last_seen, occupation, relation, relatives, personal, connections, activities, interests, music, movies, tv, books, games, about, quotes, can_write_private_message, contacts, has_mobile, universities, education, schools" fields = "first_name, last_name, bdate, city, country, home_town, photo_200_orig, online, site, status, last_seen, occupation, relation, relatives, personal, connections, activities, interests, music, movies, tv, books, games, about, quotes, can_write_private_message, contacts, has_mobile, universities, education, schools"
# ToDo: this method supports multiple user IDS, I'm not sure if this may be of any help for profile viewer. # ToDo: this method supports multiple user IDS, I'm not sure if this may be of any help for profile viewer.
person = self.session.vk.client.users.get(user_ids=self.user_id, fields=fields) person = self.session.vk.client.users.get(user_ids=self.user_id, fields=fields)
# If VK does not return anything it is very likely we have found a community. # If VK does not return anything it is very likely we have found a community.
if len(person) == 0: if len(person) == 0:
return output.speak(_("Information for groups is not supported, yet.")) return output.speak(_("Information for groups is not supported, yet."))
person = person[0] person = person[0]
# toDo: remove this print when I will be done with creation of profile viewer logic. # toDo: remove this print when I will be done with creation of profile viewer logic.
# print(person) # print(person)
# From this part we will format data from VK so users will see it in the GUI control. # From this part we will format data from VK so users will see it in the GUI control.
# Format full name. # Format full name.
n = "{0} {1}".format(person["first_name"], person["last_name"]) n = "{0} {1}".format(person["first_name"], person["last_name"])
# format phones # format phones
if person.get("mobile_phone") != None and person.get("mobile_phone") != "": if person.get("mobile_phone") != None and person.get("mobile_phone") != "":
self.send_message("enable_control", tab="main_info", control="mobile_phone") self.send_message("enable_control", tab="main_info", control="mobile_phone")
self.send_message("set", tab="main_info", control="mobile_phone", value=person["mobile_phone"]) self.send_message("set", tab="main_info", control="mobile_phone", value=person["mobile_phone"])
if person.get("home_phone") != None and person.get("home_phone") != "": if person.get("home_phone") != None and person.get("home_phone") != "":
self.send_message("enable_control", tab="main_info", control="home_phone") self.send_message("enable_control", tab="main_info", control="home_phone")
self.send_message("set", tab="main_info", control="home_phone", value=person["home_phone"]) self.send_message("set", tab="main_info", control="home_phone", value=person["home_phone"])
# Format birthdate. # Format birthdate.
if "bdate" in person and person["bdate"] != "": if "bdate" in person and person["bdate"] != "":
self.send_message("enable_control", tab="main_info", control="bdate") self.send_message("enable_control", tab="main_info", control="bdate")
# VK can display dd.mm or dd.mm.yyyy birthdates. So let's compare the string lenght to handle both cases accordingly. # VK can display dd.mm or dd.mm.yyyy birthdates. So let's compare the string lenght to handle both cases accordingly.
if len(person["bdate"]) <= 5: # dd.mm if len(person["bdate"]) <= 5: # dd.mm
d = arrow.get(person["bdate"], "D.M") d = arrow.get(person["bdate"], "D.M")
self.send_message("set", tab="main_info", control="bdate", value=d.format(_("MMMM D"), locale=languageHandler.curLang[:2])) self.send_message("set", tab="main_info", control="bdate", value=d.format(_("MMMM D"), locale=languageHandler.curLang[:2]))
else: # mm.dd.yyyy else: # mm.dd.yyyy
d = arrow.get(person["bdate"], "D.M.YYYY") d = arrow.get(person["bdate"], "D.M.YYYY")
# Calculate user's years. # Calculate user's years.
now = arrow.get() now = arrow.get()
timedelta = now-d timedelta = now-d
years = int(timedelta.days/365) years = int(timedelta.days/365)
date = d.format(_("MMMM D, YYYY"), locale=languageHandler.curLang[:2]) date = d.format(_("MMMM D, YYYY"), locale=languageHandler.curLang[:2])
msg = _("{date} ({age} years)").format(date=date, age=years) msg = _("{date} ({age} years)").format(date=date, age=years)
self.send_message("set", tab="main_info", control="bdate", value=msg) self.send_message("set", tab="main_info", control="bdate", value=msg)
# Format current city and home town # Format current city and home town
city = "" city = ""
if "home_town" in person and person["home_town"] != "": if "home_town" in person and person["home_town"] != "":
home_town = person["home_town"] home_town = person["home_town"]
self.send_message("enable_control", tab="main_info", control="home_town") self.send_message("enable_control", tab="main_info", control="home_town")
self.send_message("set", tab="main_info", control="home_town", value=home_town) self.send_message("set", tab="main_info", control="home_town", value=home_town)
if "city" in person and len(person["city"]) > 0: if "city" in person and len(person["city"]) > 0:
city = person["city"]["title"] city = person["city"]["title"]
if "country" in person and person["country"] != "": if "country" in person and person["country"] != "":
if city != "": if city != "":
city = city+", {0}".format(person["country"]["title"]) city = city+", {0}".format(person["country"]["title"])
else: else:
city = person["country"]["title"] city = person["country"]["title"]
self.send_message("enable_control", tab="main_info", control="city") self.send_message("enable_control", tab="main_info", control="city")
self.send_message("set", tab="main_info", control="city", value=city) self.send_message("set", tab="main_info", control="city", value=city)
self.send_message("set", tab="main_info", control="name", value=n) self.send_message("set", tab="main_info", control="name", value=n)
# Format title # Format title
user = self.session.get_user(person["id"]) user = self.session.get_user(person["id"])
self.send_message("set_title", value=_("{user1_nom}'s profile").format(**user)) self.send_message("set_title", value=_("{user1_nom}'s profile").format(**user))
# Format website (or websites, if there are multiple of them). # Format website (or websites, if there are multiple of them).
if "site" in person and person["site"] != "": if "site" in person and person["site"] != "":
self.send_message("enable_control", tab="main_info", control="website") self.send_message("enable_control", tab="main_info", control="website")
self.send_message("set", tab="main_info", control="website", value=person["site"]) self.send_message("set", tab="main_info", control="website", value=person["site"])
self.send_message("enable_control", tab="main_info", control="go_site") self.send_message("enable_control", tab="main_info", control="go_site")
# Format status message. # Format status message.
if "status" in person and person["status"] != "": if "status" in person and person["status"] != "":
self.send_message("enable_control", tab="main_info", control="status") self.send_message("enable_control", tab="main_info", control="status")
self.send_message("set", tab="main_info", control="status", value=person["status"]) self.send_message("set", tab="main_info", control="status", value=person["status"])
# Format occupation. # Format occupation.
# toDo: Research in this field is needed. Sometimes it returns university information even if users have active work places. # toDo: Research in this field is needed. Sometimes it returns university information even if users have active work places.
if "occupation" in person and person["occupation"] != None: if "occupation" in person and person["occupation"] != None:
if person["occupation"]["type"] == "work": c1 = _("Work ") if person["occupation"]["type"] == "work": c1 = _("Work ")
elif person["occupation"]["type"] == "school": c1 = _("Student ") elif person["occupation"]["type"] == "school": c1 = _("Student ")
elif person["occupation"]["type"] == "university": c1 = _("Student ") elif person["occupation"]["type"] == "university": c1 = _("Student ")
if "name" in person["occupation"] and person["occupation"]["name"] != "": if "name" in person["occupation"] and person["occupation"]["name"] != "":
c2 = _("In {0}").format(person["occupation"]["name"],) c2 = _("In {0}").format(person["occupation"]["name"],)
else: else:
c2 = "" c2 = ""
self.send_message("enable_control", tab="main_info", control="occupation") self.send_message("enable_control", tab="main_info", control="occupation")
self.send_message("set", tab="main_info", control="occupation", value=c1+c2) self.send_message("set", tab="main_info", control="occupation", value=c1+c2)
# format relationship status. # format relationship status.
# ToDo: When dating someone, the button associated to the information should point to the profile of the user. # ToDo: When dating someone, the button associated to the information should point to the profile of the user.
if "relation" in person and person["relation"] != 0: if "relation" in person and person["relation"] != 0:
if person["relation"] == 1: if person["relation"] == 1:
r = _("Single") r = _("Single")
elif person["relation"] == 2: elif person["relation"] == 2:
if "relation_partner" in person: if "relation_partner" in person:
r = _("Dating with {0} {1}").format(person["relation_partner"]["first_name"], person["relation_partner"]["last_name"]) r = _("Dating with {0} {1}").format(person["relation_partner"]["first_name"], person["relation_partner"]["last_name"])
else: else:
r = _("Dating") r = _("Dating")
elif person["relation"] == 3: elif person["relation"] == 3:
r = _("Engaged with {0} {1}").format(person["relation_partner"]["first_name"], person["relation_partner"]["last_name"]) r = _("Engaged with {0} {1}").format(person["relation_partner"]["first_name"], person["relation_partner"]["last_name"])
elif person["relation"] == 4: elif person["relation"] == 4:
if "relation_partner" in person: if "relation_partner" in person:
r = _("Married to {0} {1}").format(person["relation_partner"]["first_name"], person["relation_partner"]["last_name"]) r = _("Married to {0} {1}").format(person["relation_partner"]["first_name"], person["relation_partner"]["last_name"])
else: else:
r = _("Married") r = _("Married")
elif person["relation"] == 5: elif person["relation"] == 5:
r = _("It's complicated") r = _("It's complicated")
elif person["relation"] == 6: elif person["relation"] == 6:
r = _("Actively searching") r = _("Actively searching")
elif person["relation"] == 7: elif person["relation"] == 7:
r = _("In love") r = _("In love")
self.send_message("enable_control", tab="main_info", control="relation") self.send_message("enable_control", tab="main_info", control="relation")
self.send_message("set_label", tab="main_info", control="relation", value=_("Relationship: ")+r) self.send_message("set_label", tab="main_info", control="relation", value=_("Relationship: ")+r)
# format last seen. # format last seen.
if "last_seen" in person and person["last_seen"] != False: if "last_seen" in person and person["last_seen"] != False:
original_date = arrow.get(person["last_seen"]["time"]) original_date = arrow.get(person["last_seen"]["time"])
# Translators: This is the date of last seen # Translators: This is the date of last seen
last_seen = _("{0}").format(original_date.humanize(locale=languageHandler.curLang[:2]),) last_seen = _("{0}").format(original_date.humanize(locale=languageHandler.curLang[:2]),)
self.send_message("enable_control", tab="main_info", control="last_seen") self.send_message("enable_control", tab="main_info", control="last_seen")
self.send_message("set", tab="main_info", control="last_seen", value=last_seen) self.send_message("set", tab="main_info", control="last_seen", value=last_seen)
self.person = person self.person = person
# Adds photo to the dialog. # Adds photo to the dialog.
# ToDo: Need to ask if this has a visible effect in the dialog. # ToDo: Need to ask if this has a visible effect in the dialog.
if "photo_200_orig" in person: if "photo_200_orig" in person:
img = requests.get(person["photo_200_orig"]) img = requests.get(person["photo_200_orig"])
self.send_message("load_image", image=requests.get(person["photo_200_orig"])) self.send_message("load_image", image=requests.get(person["photo_200_orig"]))
output.speak(_("Profile loaded")) output.speak(_("Profile loaded"))
def get_urls(self, *args, **kwargs): def get_urls(self, *args, **kwargs):
""" Allows to visit an user's website. """ """ Allows to visit an user's website. """
text = self.person["site"] text = self.person["site"]
# Let's search for URLS with a regexp, as there are users with multiple websites in their profiles. # Let's search for URLS with a regexp, as there are users with multiple websites in their profiles.
urls = utils.find_urls_in_text(text) urls = utils.find_urls_in_text(text)
if len(urls) == 0: if len(urls) == 0:
output.speak(_("No URL addresses were detected.")) output.speak(_("No URL addresses were detected."))
return return
return urls return urls
def visit_url(self, url): def visit_url(self, url):
output.speak(_("Opening URL...")) output.speak(_("Opening URL..."))
webbrowser.open_new_tab(url) webbrowser.open_new_tab(url)

View File

@ -5,42 +5,42 @@ from validate import Validator, VdtValueError
import os import os
class ConfigurationResetException(Exception): class ConfigurationResetException(Exception):
pass pass
class Configuration (UserDict): class Configuration (UserDict):
def __init__ (self, file=None, spec=None, *args, **kwargs): def __init__ (self, file=None, spec=None, *args, **kwargs):
self.file = file self.file = file
self.spec = spec self.spec = spec
self.validator = Validator() self.validator = Validator()
self.setup_config(file=file, spec=spec) self.setup_config(file=file, spec=spec)
self.validated = self.config.validate(self.validator, copy=True) self.validated = self.config.validate(self.validator, copy=True)
if self.validated: if self.validated:
self.write() self.write()
UserDict.__init__(self, self.config) UserDict.__init__(self, self.config)
def setup_config (self, file, spec): def setup_config (self, file, spec):
spec = ConfigObj(spec, list_values=False, encoding="utf-8") spec = ConfigObj(spec, list_values=False, encoding="utf-8")
try: try:
self.config = ConfigObj(infile=file, configspec=spec, create_empty=True, stringify=True, encoding="utf-8") self.config = ConfigObj(infile=file, configspec=spec, create_empty=True, stringify=True, encoding="utf-8")
except ParseError: except ParseError:
os.remove(file) os.remove(file)
self.config = ConfigObj(infile=file, configspec=spec, create_empty=True, stringify=True) self.config = ConfigObj(infile=file, configspec=spec, create_empty=True, stringify=True)
raise ConfigurationResetException raise ConfigurationResetException
def __getitem__ (self, *args, **kwargs): def __getitem__ (self, *args, **kwargs):
return dict(self.config).__getitem__(*args, **kwargs) return dict(self.config).__getitem__(*args, **kwargs)
def __setitem__ (self, *args, **kwargs): def __setitem__ (self, *args, **kwargs):
self.config.__setitem__(*args, **kwargs) self.config.__setitem__(*args, **kwargs)
UserDict.__setitem__(self, *args, **kwargs) UserDict.__setitem__(self, *args, **kwargs)
def write (self): def write (self):
if hasattr(self.config, 'write'): if hasattr(self.config, 'write'):
self.config.write() self.config.write()
class SessionConfiguration (Configuration): class SessionConfiguration (Configuration):
def setup_config (self, file, spec): def setup_config (self, file, spec):
#No infile required. #No infile required.
spec = ConfigObj(spec, list_values=False) spec = ConfigObj(spec, list_values=False)
self.config = ConfigObj(configspec=spec, stringify=True) self.config = ConfigObj(configspec=spec, stringify=True)

View File

@ -12,296 +12,296 @@ log = logging.getLogger(__file__)
### Some util functions ### Some util functions
def extract_attachment(attachment): def extract_attachment(attachment):
""" Adds information about attachment files in posts. It only adds the text, I mean, no attachment file is added here. """ Adds information about attachment files in posts. It only adds the text, I mean, no attachment file is added here.
This will produce a result like: This will produce a result like:
'website: http://url.com'. 'website: http://url.com'.
'photo: A forest'.""" 'photo: A forest'."""
msg = "" msg = ""
if attachment["type"] == "link": if attachment["type"] == "link":
msg = "{0}: {1}".format(attachment["link"]["title"], attachment["link"]["url"]) msg = "{0}: {1}".format(attachment["link"]["title"], attachment["link"]["url"])
elif attachment["type"] == "photo": elif attachment["type"] == "photo":
msg = attachment["photo"]["text"] msg = attachment["photo"]["text"]
if msg == "": if msg == "":
return _("photo with no description available") return _("photo with no description available")
elif attachment["type"] == "video": elif attachment["type"] == "video":
msg = _("video: {0}").format(attachment["video"]["title"],) msg = _("video: {0}").format(attachment["video"]["title"],)
return msg return msg
def short_text(status): def short_text(status):
""" This shorts the text to 140 characters for displaying it in the list control of buffers.""" """ This shorts the text to 140 characters for displaying it in the list control of buffers."""
message = "" message = ""
# copy_story indicates that the post is a shared repost. # copy_story indicates that the post is a shared repost.
if "copy_history" in status: if "copy_history" in status:
txt = status["copy_history"][0]["text"] txt = status["copy_history"][0]["text"]
else: else:
txt = status["text"] txt = status["text"]
if len(txt) < 140: if len(txt) < 140:
message = clean_text(txt) message = clean_text(txt)
else: else:
message = clean_text(txt[:139]) message = clean_text(txt[:139])
return message return message
def clean_audio(audio): def clean_audio(audio):
""" Remove unavailable songs due to different reasons. This is used to clean the audio list when people adds audios and need to be displayed in the buffer.""" """ Remove unavailable songs due to different reasons. This is used to clean the audio list when people adds audios and need to be displayed in the buffer."""
for i in audio["items"][:]: for i in audio["items"][:]:
if type(i) == bool: if type(i) == bool:
audio["items"].remove(i) audio["items"].remove(i)
audio["count"] = audio["count"] -1 audio["count"] = audio["count"] -1
return audio return audio
def add_attachment(attachment): def add_attachment(attachment):
msg = "" msg = ""
tpe = "" tpe = ""
if attachment["type"] == "link": if attachment["type"] == "link":
msg = "{0}: {1}".format(attachment["link"]["title"], attachment["link"]["url"]) msg = "{0}: {1}".format(attachment["link"]["title"], attachment["link"]["url"])
tpe = _("Link") tpe = _("Link")
elif attachment["type"] == "photo": elif attachment["type"] == "photo":
tpe = _("Photo") tpe = _("Photo")
msg = attachment["photo"]["text"] msg = attachment["photo"]["text"]
if msg == "": if msg == "":
msg = _("no description available") msg = _("no description available")
elif attachment["type"] == "video": elif attachment["type"] == "video":
msg = "{0}".format(attachment["video"]["title"],) msg = "{0}".format(attachment["video"]["title"],)
tpe = _("Video") tpe = _("Video")
elif attachment["type"] == "audio": elif attachment["type"] == "audio":
msg = "{0}".format(" ".join(render_audio(attachment["audio"]))) msg = "{0}".format(" ".join(render_audio(attachment["audio"])))
tpe = _("Audio") tpe = _("Audio")
elif attachment["type"] == "doc": elif attachment["type"] == "doc":
msg = "{0}".format(attachment["doc"]["title"]) msg = "{0}".format(attachment["doc"]["title"])
tpe = _("{0} file").format(attachment["doc"]["ext"]) tpe = _("{0} file").format(attachment["doc"]["ext"])
elif attachment["type"] == "audio_message": elif attachment["type"] == "audio_message":
msg = "{0}".format(" ".join(render_audio_message(attachment["audio_message"]))) msg = "{0}".format(" ".join(render_audio_message(attachment["audio_message"])))
tpe = _("Voice message") tpe = _("Voice message")
elif attachment["type"] == "poll": elif attachment["type"] == "poll":
tpe = _("Poll") tpe = _("Poll")
msg = attachment["poll"]["question"] msg = attachment["poll"]["question"]
elif attachment["type"] == "wall": elif attachment["type"] == "wall":
tpe = _("Post") tpe = _("Post")
user = attachment["wall"]["from"]["name"] user = attachment["wall"]["from"]["name"]
if len(attachment["wall"]["text"]) > 140: if len(attachment["wall"]["text"]) > 140:
text = attachment["wall"]["text"][:145]+"..." text = attachment["wall"]["text"][:145]+"..."
else: else:
text = attachment["wall"]["text"] text = attachment["wall"]["text"]
msg = _("{user}: {post}").format(user=user, post=text) msg = _("{user}: {post}").format(user=user, post=text)
elif attachment["type"] == "article": elif attachment["type"] == "article":
tpe = _("Article") tpe = _("Article")
msg = "{author}: {article}".format(author=attachment["article"]["owner_name"], article=attachment["article"]["title"]) msg = "{author}: {article}".format(author=attachment["article"]["owner_name"], article=attachment["article"]["title"])
else: else:
print(attachment) print(attachment)
return [tpe, msg] return [tpe, msg]
### Render functions ### Render functions
def render_person(status, session): def render_person(status, session):
""" Render users in people buffers such as everything related to friendships or buffers created with only people. """ Render users in people buffers such as everything related to friendships or buffers created with only people.
Example result: ["John Doe", "An hour ago"] Example result: ["John Doe", "An hour ago"]
Reference: https://vk.com/dev/fields""" Reference: https://vk.com/dev/fields"""
# In case the user decided to not show his/her last seen information we must provide a default. # In case the user decided to not show his/her last seen information we must provide a default.
# ToDo: Shall we indicate this with a message? # ToDo: Shall we indicate this with a message?
online_status = "" online_status = ""
if "last_seen" in status: if "last_seen" in status:
original_date = arrow.get(status["last_seen"]["time"]) original_date = arrow.get(status["last_seen"]["time"])
now = arrow.now() now = arrow.now()
original_date.to(now.tzinfo) original_date.to(now.tzinfo)
diffdate = now-original_date diffdate = now-original_date
if diffdate.days == 0 and diffdate.seconds <= 360: if diffdate.days == 0 and diffdate.seconds <= 360:
online_status = _("Online") online_status = _("Online")
else: else:
# Translators: This is the date of last seen # Translators: This is the date of last seen
online_status = _("Last seen {0}").format(original_date.humanize(locale=languageHandler.curLang[:2]),) online_status = _("Last seen {0}").format(original_date.humanize(locale=languageHandler.curLang[:2]),)
# Account suspended or deleted. # Account suspended or deleted.
elif ("last_seen" in status) == False and "deactivated" in status: elif ("last_seen" in status) == False and "deactivated" in status:
online_status = _("Account deactivated") online_status = _("Account deactivated")
return ["{0} {1}".format(status["first_name"], status["last_name"]), online_status] return ["{0} {1}".format(status["first_name"], status["last_name"]), online_status]
def render_newsfeed_item(status, session): def render_newsfeed_item(status, session):
""" This me☻thod is used to render an item of the news feed. """ This me☻thod is used to render an item of the news feed.
References: References:
https://vk.com/dev/newsfeed.get https://vk.com/dev/newsfeed.get
https://vk.com/dev/post_source https://vk.com/dev/post_source
https://vk.com/dev/post https://vk.com/dev/post
""" """
user = session.get_user(status["source_id"], key="user1") user = session.get_user(status["source_id"], key="user1")
# See if this is a post or repost. # See if this is a post or repost.
if "copy_history" in status: if "copy_history" in status:
# Get the second user (whose post is been shared). # Get the second user (whose post is been shared).
user2 = session.get_user(status["copy_history"][0]["owner_id"], key="user2") user2 = session.get_user(status["copy_history"][0]["owner_id"], key="user2")
# Add contents of poster to the new dict, it will create both user1_nom and user2_nom. # Add contents of poster to the new dict, it will create both user1_nom and user2_nom.
user2.update(user) user2.update(user)
user = dict(user1_nom=_("{user1_nom} has shared the {user2_nom}'s post").format(**user2)) user = dict(user1_nom=_("{user1_nom} has shared the {user2_nom}'s post").format(**user2))
message = "" message = ""
original_date = arrow.get(status["date"]) original_date = arrow.get(status["date"])
created_at = original_date.humanize(locale=languageHandler.curLang[:2]) created_at = original_date.humanize(locale=languageHandler.curLang[:2])
# handle status updates. # handle status updates.
if status["type"] == "post": if status["type"] == "post":
message += short_text(status) message += short_text(status)
if "attachment" in status and len(status["attachment"]) > 0: if "attachment" in status and len(status["attachment"]) > 0:
message += extract_attachment(status["attachment"]) message += extract_attachment(status["attachment"])
# If there is no message after adding text, it's because a pphoto with no description has been found. # If there is no message after adding text, it's because a pphoto with no description has been found.
# so let's manually add the "no description" tag here. # so let's manually add the "no description" tag here.
if message == "": if message == "":
message = "no description available" message = "no description available"
# Handle audio rendering. # Handle audio rendering.
elif status["type"] == "audio" and "audio" in status: elif status["type"] == "audio" and "audio" in status:
# removes deleted audios. # removes deleted audios.
status["audio"] = clean_audio(status["audio"]) status["audio"] = clean_audio(status["audio"])
if status["audio"]["count"] == 1: if status["audio"]["count"] == 1:
data = dict(audio_file=", ".join(render_audio(status["audio"]["items"][0], session))) data = dict(audio_file=", ".join(render_audio(status["audio"]["items"][0], session)))
data.update(user) data.update(user)
message = _("{user1_nom} has added an audio: {audio_file}").format(**data) message = _("{user1_nom} has added an audio: {audio_file}").format(**data)
else: else:
prem = "" prem = ""
for i in range(0, status["audio"]["count"]): for i in range(0, status["audio"]["count"]):
composed_audio = render_audio(status["audio"]["items"][i], session) composed_audio = render_audio(status["audio"]["items"][i], session)
prem += "{0} - {1}, ".format(composed_audio[0], composed_audio[1]) prem += "{0} - {1}, ".format(composed_audio[0], composed_audio[1])
data = dict(audio_files=prem, total_audio_files=status["audio"]["count"]) data = dict(audio_files=prem, total_audio_files=status["audio"]["count"])
data.update(user) data.update(user)
message = _("{user1_nom} has added {total_audio_files} audios: {audio_files}").format(**data) message = _("{user1_nom} has added {total_audio_files} audios: {audio_files}").format(**data)
# Handle audio playlists # Handle audio playlists
elif status["type"] == "audio_playlist": elif status["type"] == "audio_playlist":
if status["audio_playlist"]["count"] == 1: if status["audio_playlist"]["count"] == 1:
data = dict(audio_album=status["audio_playlist"]["items"][0]["title"], audio_album_description=status["audio_playlist"]["items"][0]["description"]) data = dict(audio_album=status["audio_playlist"]["items"][0]["title"], audio_album_description=status["audio_playlist"]["items"][0]["description"])
data.update(user) data.update(user)
message = _("{user1_nom} has added an audio album: {audio_album}, {audio_album_description}").format(**data) message = _("{user1_nom} has added an audio album: {audio_album}, {audio_album_description}").format(**data)
else: else:
prestring = "" prestring = ""
for i in range(0, status["audio_playlist"]["count"]): for i in range(0, status["audio_playlist"]["count"]):
prestring += "{0} - {1}, ".format(status["audio_playlist"]["items"][i]["title"], status["audio_playlist"]["items"][i]["description"]) prestring += "{0} - {1}, ".format(status["audio_playlist"]["items"][i]["title"], status["audio_playlist"]["items"][i]["description"])
data = dict(audio_albums=prestring, total_audio_albums=status["audio_playlist"]["count"]) data = dict(audio_albums=prestring, total_audio_albums=status["audio_playlist"]["count"])
data.update(user) data.update(user)
message = _("{user1_nom} has added {total_audio_albums} audio albums: {audio_albums}").format(**data) message = _("{user1_nom} has added {total_audio_albums} audio albums: {audio_albums}").format(**data)
# handle new friends for people in the news buffer. # handle new friends for people in the news buffer.
elif status["type"] == "friend": elif status["type"] == "friend":
msg_users = "" msg_users = ""
if "friends" in status: if "friends" in status:
for i in status["friends"]["items"]: for i in status["friends"]["items"]:
msg_users = msg_users + "{0}, ".format(session.get_user(i["user_id"])["user1_nom"]) msg_users = msg_users + "{0}, ".format(session.get_user(i["user_id"])["user1_nom"])
else: else:
print(list(status.keys())) print(list(status.keys()))
data = dict(friends=msg_users) data = dict(friends=msg_users)
data.update(user) data.update(user)
message = _("{user1_nom} added friends: {friends}").format(**data) message = _("{user1_nom} added friends: {friends}").format(**data)
elif status["type"] == "video": elif status["type"] == "video":
if status["video"]["count"] == 1: if status["video"]["count"] == 1:
data = dict(video=", ".join(render_video(status["video"]["items"][0], session))) data = dict(video=", ".join(render_video(status["video"]["items"][0], session)))
data.update(user) data.update(user)
message = _("{user1_nom} has added a video: {video}").format(**data) message = _("{user1_nom} has added a video: {video}").format(**data)
else: else:
prem = "" prem = ""
for i in range(0, status["video"]["count"]): for i in range(0, status["video"]["count"]):
composed_video = render_video(status["video"]["items"][i], session) composed_video = render_video(status["video"]["items"][i], session)
prem += "{0} - {1}, ".format(composed_video[0], composed_video[1]) prem += "{0} - {1}, ".format(composed_video[0], composed_video[1])
data = dict(videos=prem, total_videos=status["video"]["count"]) data = dict(videos=prem, total_videos=status["video"]["count"])
data.update(user) data.update(user)
message = _("{user1_nom} has added {total_videos} videos: {videos}").format(**data) message = _("{user1_nom} has added {total_videos} videos: {videos}").format(**data)
else: else:
if status["type"] != "post": print(status) if status["type"] != "post": print(status)
return [user["user1_nom"], message, created_at] return [user["user1_nom"], message, created_at]
def render_message(message, session): def render_message(message, session):
""" Render a message posted in a private conversation. """ Render a message posted in a private conversation.
Reference: https://vk.com/dev/message""" Reference: https://vk.com/dev/message"""
user = session.get_user(message["from_id"], key="user1") user = session.get_user(message["from_id"], key="user1")
original_date = arrow.get(message["date"]) original_date = arrow.get(message["date"])
now = arrow.now() now = arrow.now()
original_date = original_date.to(now.tzinfo) original_date = original_date.to(now.tzinfo)
# Format the date here differently depending in if this is the same day for both dates or not. # Format the date here differently depending in if this is the same day for both dates or not.
if original_date.day == now.day: if original_date.day == now.day:
created_at = original_date.format(_("H:mm."), locale=languageHandler.curLang[:2]) created_at = original_date.format(_("H:mm."), locale=languageHandler.curLang[:2])
else: else:
created_at = original_date.format(_("H:mm. dddd, MMMM D, YYYY"), locale=languageHandler.curLang[:2]) created_at = original_date.format(_("H:mm. dddd, MMMM D, YYYY"), locale=languageHandler.curLang[:2])
# No idea why some messages send "text" instead "body" # No idea why some messages send "text" instead "body"
if "body" in message: if "body" in message:
body = message["body"] body = message["body"]
else: else:
body = message["text"] body = message["text"]
data = dict(body=body, created_at=created_at) data = dict(body=body, created_at=created_at)
data.update(user) data.update(user)
return ["{user1_nom}, {body} {created_at}".format(**data)] return ["{user1_nom}, {body} {created_at}".format(**data)]
def render_status(status, session): def render_status(status, session):
""" Render a wall post (shown in user's wall, not in newsfeed). """ Render a wall post (shown in user's wall, not in newsfeed).
Reference: https://vk.com/dev/post""" Reference: https://vk.com/dev/post"""
user = session.get_user(status["from_id"], key="user1") user = session.get_user(status["from_id"], key="user1")
if "copy_history" in status: if "copy_history" in status:
user2 = session.get_user(status["copy_history"][0]["owner_id"], key="user2") user2 = session.get_user(status["copy_history"][0]["owner_id"], key="user2")
user2.update(user) user2.update(user)
user = dict(user1_nom=_("{user1_nom} has shared the {user2_nom}'s post").format(**user2)) user = dict(user1_nom=_("{user1_nom} has shared the {user2_nom}'s post").format(**user2))
message = "" message = ""
original_date = arrow.get(status["date"]) original_date = arrow.get(status["date"])
created_at = original_date.humanize(locale=languageHandler.curLang[:2]) created_at = original_date.humanize(locale=languageHandler.curLang[:2])
if "copy_owner_id" in status: if "copy_owner_id" in status:
user2 = session.get_user(status["copy_owner_id"], key="user2") user2 = session.get_user(status["copy_owner_id"], key="user2")
user2.update(user) user2.update(user)
user = _("{user1_nom} has shared the {user2_nom}'s post").format(**user2) user = _("{user1_nom} has shared the {user2_nom}'s post").format(**user2)
if status["post_type"] == "post" or status["post_type"] == "copy": if status["post_type"] == "post" or status["post_type"] == "copy":
message += short_text(status) message += short_text(status)
if "attachment" in status and len(status["attachment"]) > 0: if "attachment" in status and len(status["attachment"]) > 0:
message += extract_attachment(status["attachment"]) message += extract_attachment(status["attachment"])
if message == "": if message == "":
message = "no description available" message = "no description available"
return [user["user1_nom"], message, created_at] return [user["user1_nom"], message, created_at]
def render_audio(audio, session=None): def render_audio(audio, session=None):
""" Render audio files added to VK. """ Render audio files added to VK.
Example result: Example result:
["Song title", "Artist", "03:15"] ["Song title", "Artist", "03:15"]
reference: https://vk.com/dev/audio_object""" reference: https://vk.com/dev/audio_object"""
if audio == False: return [_("Audio removed from library"), "", ""] if audio == False: return [_("Audio removed from library"), "", ""]
return [audio["title"], audio["artist"], seconds_to_string(audio["duration"])] return [audio["title"], audio["artist"], seconds_to_string(audio["duration"])]
def render_video(video, session=None): def render_video(video, session=None):
""" Render a video file from VK. """ Render a video file from VK.
Example result: Example result:
["Video title", "Video description", "01:30:28"] ["Video title", "Video description", "01:30:28"]
Reference: https://vk.com/dev/video_object""" Reference: https://vk.com/dev/video_object"""
if video == False: if video == False:
return [_("Video not available"), "", ""] return [_("Video not available"), "", ""]
return [video["title"], video["description"], seconds_to_string(video["duration"])] return [video["title"], video["description"], seconds_to_string(video["duration"])]
def render_audio_message(audio_message, session=None): def render_audio_message(audio_message, session=None):
""" Render a voice message from VK """ Render a voice message from VK
Example result: Example result:
["Voice message", "01:30:28"]""" ["Voice message", "01:30:28"]"""
if audio_message == False: if audio_message == False:
return [_("Voice message not available"), "", ""] return [_("Voice message not available"), "", ""]
return [seconds_to_string(audio_message["duration"])] return [seconds_to_string(audio_message["duration"])]
def render_topic(topic, session): def render_topic(topic, session):
""" Render topics for a community. """ Render topics for a community.
Reference: https://vk.com/dev/objects/topic""" Reference: https://vk.com/dev/objects/topic"""
user = session.get_user(topic["created_by"]) user = session.get_user(topic["created_by"])
title = topic["title"] title = topic["title"]
comments = topic["comments"] comments = topic["comments"]
last_commenter = session.get_user(topic["updated_by"]) last_commenter = session.get_user(topic["updated_by"])
last_update = arrow.get(topic["updated"]).humanize(locale=languageHandler.curLang[:2]) last_update = arrow.get(topic["updated"]).humanize(locale=languageHandler.curLang[:2])
last_commenter.update(date=last_update) last_commenter.update(date=last_update)
lastupdate = _("Last post by {user1_nom} {date}").format(**last_commenter) lastupdate = _("Last post by {user1_nom} {date}").format(**last_commenter)
return [user["user1_nom"], title, str(comments), lastupdate] return [user["user1_nom"], title, str(comments), lastupdate]
def render_document(document, session): def render_document(document, session):
doc_types = {1: _("Text document"), 2: _("Archive"), 3: _("Gif"), 4: _("Image"), 5: _("Audio"), 6: _("Video"), 7: _("Ebook"), 8: _("Unknown document")} doc_types = {1: _("Text document"), 2: _("Archive"), 3: _("Gif"), 4: _("Image"), 5: _("Audio"), 6: _("Video"), 7: _("Ebook"), 8: _("Unknown document")}
user = session.get_user(document["owner_id"]) user = session.get_user(document["owner_id"])
title = document["title"] title = document["title"]
size = convert_bytes(document["size"]) size = convert_bytes(document["size"])
date = arrow.get(document["date"]).humanize(locale=languageHandler.curLang[:2]) date = arrow.get(document["date"]).humanize(locale=languageHandler.curLang[:2])
doc_type = doc_types[document["type"]] doc_type = doc_types[document["type"]]
return [user["user1_nom"], title, doc_type, size, date] return [user["user1_nom"], title, doc_type, size, date]
def render_notification(notification, session): def render_notification(notification, session):
notification.pop("hide_buttons") notification.pop("hide_buttons")
print(notification["icon_type"]) print(notification["icon_type"])
# print(notification["header"]) # print(notification["header"])
print(notification) print(notification)
date = arrow.get(notification["date"]).humanize(locale=languageHandler.curLang[:2]) date = arrow.get(notification["date"]).humanize(locale=languageHandler.curLang[:2])
msg = notification["header"] msg = notification["header"]
# msg = notification["header"] # msg = notification["header"]
# if notification["type"] == "follow": # if notification["type"] == "follow":
# if len(notification["feedback"]) == 1: # if len(notification["feedback"]) == 1:
# user = session.get_user(notification["feedback"][0]) # user = session.get_user(notification["feedback"][0])
# msg = _("{user1_nom} subscribed to your account").format(**user) # msg = _("{user1_nom} subscribed to your account").format(**user)
# else: # else:
# users = ["{first_name} {last_name},".format(first_name=user["first_name"], last_name=user["last_name"]) for user in notification["feedback"]] # users = ["{first_name} {last_name},".format(first_name=user["first_name"], last_name=user["last_name"]) for user in notification["feedback"]]
# msg = " ".join(users) # msg = " ".join(users)
# print(msg) # print(msg)
return [msg, date] return [msg, date]

View File

@ -29,370 +29,370 @@ identifiers = ["aid", "gid", "uid", "pid", "id", "post_id", "nid", "date"]
post_types = dict(audio="audio", friend="friends", video="files", post="post_type", audio_playlist="audio_playlist") post_types = dict(audio="audio", friend="friends", video="files", post="post_type", audio_playlist="audio_playlist")
def find_item(list, item): def find_item(list, item):
""" Find an item in a list by taking an identifier. """ Find an item in a list by taking an identifier.
@list list: A list of dict objects. @list list: A list of dict objects.
@ item dict: A dictionary containing at least an identifier. @ item dict: A dictionary containing at least an identifier.
""" """
# determine the kind of identifier that we are using # determine the kind of identifier that we are using
global identifiers global identifiers
identifier = None identifier = None
for i in identifiers: for i in identifiers:
if i in item: if i in item:
identifier = i identifier = i
break break
if identifier == None: if identifier == None:
# if there are objects that can't be processed by lack of identifier, let's print keys for finding one. # if there are objects that can't be processed by lack of identifier, let's print keys for finding one.
log.exception("Can't find an identifier for the following object: %r" % (item,)) log.exception("Can't find an identifier for the following object: %r" % (item,))
return False return False
for i in list: for i in list:
if identifier in i and i[identifier] == item[identifier]: if identifier in i and i[identifier] == item[identifier]:
return True return True
return False return False
class vkSession(object): class vkSession(object):
""" The only session available in socializer. Manages everything related to a model in an MVC app: calls to VK, sound handling, settings and a cache database.""" """ The only session available in socializer. Manages everything related to a model in an MVC app: calls to VK, sound handling, settings and a cache database."""
def order_buffer(self, name, data, show_nextpage): def order_buffer(self, name, data, show_nextpage):
""" Put new items on the local cache database. """ Put new items on the local cache database.
@name str: The name for the buffer stored in the dictionary. @name str: The name for the buffer stored in the dictionary.
@data list: A list with items and some information about cursors. @data list: A list with items and some information about cursors.
returns the number of items that have been added in this execution""" returns the number of items that have been added in this execution"""
global post_types global post_types
# When this method is called by friends.getOnlyne, it gives only friend IDS so we need to retrieve full objects from VK. # When this method is called by friends.getOnlyne, it gives only friend IDS so we need to retrieve full objects from VK.
# ToDo: It would be nice to investigate whether reusing some existing objects would be a good idea, whenever possible. # ToDo: It would be nice to investigate whether reusing some existing objects would be a good idea, whenever possible.
if name == "online_friends": if name == "online_friends":
newdata = self.vk.client.users.get(user_ids=",".join([str(z) for z in data]), fields="last_seen") newdata = self.vk.client.users.get(user_ids=",".join([str(z) for z in data]), fields="last_seen")
data = newdata data = newdata
first_addition = False first_addition = False
num = 0 num = 0
if (name in self.db) == False: if (name in self.db) == False:
self.db[name] = {} self.db[name] = {}
self.db[name]["items"] = [] self.db[name]["items"] = []
first_addition = True first_addition = True
# Handles chat messages case, as the buffer is inverted # Handles chat messages case, as the buffer is inverted
if name.endswith("_messages") and show_nextpage == True: if name.endswith("_messages") and show_nextpage == True:
show_nextpage = False show_nextpage = False
for i in data: for i in data:
if "type" in i and (i["type"] == "wall_photo" or i["type"] == "photo_tag" or i["type"] == "photo" or i["type"] == False or i["type"] == True): if "type" in i and (i["type"] == "wall_photo" or i["type"] == "photo_tag" or i["type"] == "photo" or i["type"] == False or i["type"] == True):
log.debug("Skipping unsupported item... %r" % (i,)) log.debug("Skipping unsupported item... %r" % (i,))
continue continue
# for some reason, VK sends post data if the post has been deleted already. # for some reason, VK sends post data if the post has been deleted already.
# Example of this behaviour is when you upload an audio and inmediately delete the audio, VK still sends the post stating that you uploaded an audio file, # Example of this behaviour is when you upload an audio and inmediately delete the audio, VK still sends the post stating that you uploaded an audio file,
# But without the audio data, making socializer to render an empty post. # But without the audio data, making socializer to render an empty post.
# Here we check if the post contains data of the type it advertises. # Here we check if the post contains data of the type it advertises.
if i.get("type") != None and isinstance(i["type"], str) and post_types.get(i["type"]) not in i: if i.get("type") != None and isinstance(i["type"], str) and post_types.get(i["type"]) not in i:
log.error("Detected invalid or unsupported post. Skipping...") log.error("Detected invalid or unsupported post. Skipping...")
log.error(i) log.error(i)
continue continue
if find_item(self.db[name]["items"], i) == False: if find_item(self.db[name]["items"], i) == False:
# if i not in self.db[name]["items"]: # if i not in self.db[name]["items"]:
if first_addition == True or show_nextpage == True: if first_addition == True or show_nextpage == True:
if self.settings["general"]["reverse_timelines"] == False: self.db[name]["items"].append(i) if self.settings["general"]["reverse_timelines"] == False: self.db[name]["items"].append(i)
else: self.db[name]["items"].insert(0, i) else: self.db[name]["items"].insert(0, i)
else: else:
if self.settings["general"]["reverse_timelines"] == False: self.db[name]["items"].insert(0, i) if self.settings["general"]["reverse_timelines"] == False: self.db[name]["items"].insert(0, i)
else: self.db[name]["items"].append(i) else: self.db[name]["items"].append(i)
num = num+1 num = num+1
log.debug("There are %d items in the %s buffer" % (len(self.db[name]["items"]), name)) log.debug("There are %d items in the %s buffer" % (len(self.db[name]["items"]), name))
return num return num
def __init__(self, session_id): def __init__(self, session_id):
self.session_id = session_id self.session_id = session_id
self.logged = False self.logged = False
self.settings = None self.settings = None
self.vk = vkSessionHandler.vkObject() self.vk = vkSessionHandler.vkObject()
self.db = {} self.db = {}
self.db["users"] = {} self.db["users"] = {}
self.db["groups"] = {} self.db["groups"] = {}
self.db["group_info"] = {} self.db["group_info"] = {}
@property @property
def is_logged(self): def is_logged(self):
return self.logged return self.logged
def get_configuration(self, nosound=False): def get_configuration(self, nosound=False):
""" Gets settings for a session.""" """ Gets settings for a session."""
file_ = "%s/session.conf" % (self.session_id,) file_ = "%s/session.conf" % (self.session_id,)
# try: # try:
log.debug("Creating config file %s" % (file_,)) log.debug("Creating config file %s" % (file_,))
self.settings = Configuration(os.path.join(paths.config_path(), file_), os.path.join(paths.app_path(), "session.defaults")) self.settings = Configuration(os.path.join(paths.config_path(), file_), os.path.join(paths.app_path(), "session.defaults"))
if nosound == False: if nosound == False:
self.soundplayer = sound.soundSystem(config.app["sound"]) self.soundplayer = sound.soundSystem(config.app["sound"])
pub.subscribe(self.play_sound, "play-sound") pub.subscribe(self.play_sound, "play-sound")
pub.subscribe(self.post, "post") pub.subscribe(self.post, "post")
# except: # except:
# log.exception("The session configuration has failed.") # log.exception("The session configuration has failed.")
def play_sound(self, sound): def play_sound(self, sound):
self.soundplayer.play(sound) self.soundplayer.play(sound)
def login(self): def login(self):
""" Logging in VK.com. This is basically the first method interacting with VK. """ """ Logging in VK.com. This is basically the first method interacting with VK. """
# If user is already logged in, we should skip this method. # If user is already logged in, we should skip this method.
if self.logged == True: if self.logged == True:
return return
try: try:
config_filename = os.path.join(paths.config_path(), self.session_id, "vkconfig.json") config_filename = os.path.join(paths.config_path(), self.session_id, "vkconfig.json")
self.vk.login(self.settings["vk"]["user"], self.settings["vk"]["password"], token=self.settings["vk"]["token"], alt_token=self.settings["vk"]["use_alternative_tokens"], filename=config_filename) self.vk.login(self.settings["vk"]["user"], self.settings["vk"]["password"], token=self.settings["vk"]["token"], alt_token=self.settings["vk"]["use_alternative_tokens"], filename=config_filename)
self.settings["vk"]["token"] = self.vk.session_object.token["access_token"] self.settings["vk"]["token"] = self.vk.session_object.token["access_token"]
self.settings.write() self.settings.write()
self.logged = True self.logged = True
self.get_my_data() self.get_my_data()
except VkApiError as error: except VkApiError as error:
print(error) print(error)
if error.code == 5: # this means invalid access token. if error.code == 5: # this means invalid access token.
self.settings["vk"]["user"] = "" self.settings["vk"]["user"] = ""
self.settings["vk"]["password"] = "" self.settings["vk"]["password"] = ""
self.settings["vk"]["token"] = "" self.settings["vk"]["token"] = ""
self.settings.write() self.settings.write()
pub.sendMessage("authorisation-failed") pub.sendMessage("authorisation-failed")
else: # print out error so we we will handle it in future versions. else: # print out error so we we will handle it in future versions.
log.exception("Fatal error when authenticating the application.") log.exception("Fatal error when authenticating the application.")
log.exception(error.code) log.exception(error.code)
log.exception(error.message) log.exception(error.message)
except (ProxyError, ConnectionError): except (ProxyError, ConnectionError):
pub.sendMessage("connection_error") pub.sendMessage("connection_error")
def post_wall_status(self, message, *args, **kwargs): def post_wall_status(self, message, *args, **kwargs):
""" Sends a post to an user, group or community wall.""" """ Sends a post to an user, group or community wall."""
log.debug("Making a post to the user's wall with the following params: %r" % (kwargs,)) log.debug("Making a post to the user's wall with the following params: %r" % (kwargs,))
response = self.vk.client.wall.post(message=message, *args, **kwargs) response = self.vk.client.wall.post(message=message, *args, **kwargs)
def get_newsfeed(self, name="newsfeed", show_nextpage=False, endpoint="", *args, **kwargs): def get_newsfeed(self, name="newsfeed", show_nextpage=False, endpoint="", *args, **kwargs):
log.debug("Updating news feed...") log.debug("Updating news feed...")
if show_nextpage == True and "cursor" in self.db[name]: if show_nextpage == True and "cursor" in self.db[name]:
log.debug("user has requested previous items") log.debug("user has requested previous items")
kwargs["start_from"] = self.db[name]["cursor"] kwargs["start_from"] = self.db[name]["cursor"]
log.debug("Params for sending to vk: %r" % (kwargs,)) log.debug("Params for sending to vk: %r" % (kwargs,))
data = getattr(self.vk.client.newsfeed, "get")(*args, **kwargs) data = getattr(self.vk.client.newsfeed, "get")(*args, **kwargs)
if data != None: if data != None:
self.process_usernames(data) self.process_usernames(data)
num = self.order_buffer(name, data["items"], show_nextpage) num = self.order_buffer(name, data["items"], show_nextpage)
log.debug("Keys of the returned data for debug purposes: %r" % (list(data.keys()),)) log.debug("Keys of the returned data for debug purposes: %r" % (list(data.keys()),))
if "next_from" in data: if "next_from" in data:
self.db[name]["cursor"] = data["next_from"] self.db[name]["cursor"] = data["next_from"]
log.debug("Next cursor saved for data: {cursor}".format(cursor=data["next_from"])) log.debug("Next cursor saved for data: {cursor}".format(cursor=data["next_from"]))
return num return num
def get_page(self, name="", show_nextpage=False, endpoint="", *args, **kwargs): def get_page(self, name="", show_nextpage=False, endpoint="", *args, **kwargs):
data = None data = None
if "audio" in endpoint and self.settings["vk"]["use_alternative_tokens"]: if "audio" in endpoint and self.settings["vk"]["use_alternative_tokens"]:
log.info("Using alternative audio methods.") log.info("Using alternative audio methods.")
c = self.vk.client_audio c = self.vk.client_audio
else: else:
c = self.vk.client c = self.vk.client
formatted_endpoint = "" formatted_endpoint = ""
if "parent_endpoint" in kwargs: if "parent_endpoint" in kwargs:
p = kwargs["parent_endpoint"] p = kwargs["parent_endpoint"]
formatted_endpoint = kwargs["parent_endpoint"] formatted_endpoint = kwargs["parent_endpoint"]
if "audio" in p and self.settings["vk"]["use_alternative_tokens"]: if "audio" in p and self.settings["vk"]["use_alternative_tokens"]:
log.info("Using alternative audio methods.") log.info("Using alternative audio methods.")
c = self.vk.client_audio c = self.vk.client_audio
kwargs.pop("parent_endpoint") kwargs.pop("parent_endpoint")
try: try:
p = getattr(c, p) p = getattr(c, p)
except AttributeError: except AttributeError:
p = c p = c
if name in self.db and "offset" in self.db[name] and show_nextpage == True: if name in self.db and "offset" in self.db[name] and show_nextpage == True:
kwargs.update(offset=self.db[name]["offset"]) kwargs.update(offset=self.db[name]["offset"])
else: else:
kwargs.update(offset=0) kwargs.update(offset=0)
formatted_endpoint = "{formatted_endpoint}.{new_path}".format(formatted_endpoint=formatted_endpoint, new_path=endpoint) formatted_endpoint = "{formatted_endpoint}.{new_path}".format(formatted_endpoint=formatted_endpoint, new_path=endpoint)
offset_deprecated = ["notifications.get"] offset_deprecated = ["notifications.get"]
if formatted_endpoint in offset_deprecated: if formatted_endpoint in offset_deprecated:
kwargs.update(offset=None) kwargs.update(offset=None)
log.debug("Calling endpoint %s with params %r" % (formatted_endpoint, kwargs,)) log.debug("Calling endpoint %s with params %r" % (formatted_endpoint, kwargs,))
data = getattr(p, endpoint)(*args, **kwargs) data = getattr(p, endpoint)(*args, **kwargs)
if data != None: if data != None:
if "count" not in kwargs: if "count" not in kwargs:
kwargs["count"] = 100 kwargs["count"] = 100
# Let's handle a little exception when dealing with conversation buffers. # Let's handle a little exception when dealing with conversation buffers.
# the first results of the query should be reversed before being sent to order_buffer. # the first results of the query should be reversed before being sent to order_buffer.
if type(data) == dict and "items" in data and endpoint == "getHistory" and kwargs["offset"] == 0: if type(data) == dict and "items" in data and endpoint == "getHistory" and kwargs["offset"] == 0:
data["items"].reverse() data["items"].reverse()
if type(data) == dict: if type(data) == dict:
num = self.order_buffer(name, data["items"], show_nextpage) num = self.order_buffer(name, data["items"], show_nextpage)
if formatted_endpoint not in offset_deprecated: if formatted_endpoint not in offset_deprecated:
self.db[name]["offset"] = kwargs["offset"]+kwargs["count"] self.db[name]["offset"] = kwargs["offset"]+kwargs["count"]
if len(data["items"]) > 0 and "first_name" in data["items"][0]: if len(data["items"]) > 0 and "first_name" in data["items"][0]:
data2 = {"profiles": [], "groups": []} data2 = {"profiles": [], "groups": []}
for i in data["items"]: for i in data["items"]:
data2["profiles"].append(i) data2["profiles"].append(i)
self.process_usernames(data2) self.process_usernames(data2)
if "profiles" in data and "groups" in data: if "profiles" in data and "groups" in data:
self.process_usernames(data) self.process_usernames(data)
else: else:
num = self.order_buffer(name, data, show_nextpage) num = self.order_buffer(name, data, show_nextpage)
self.db[name]["offset"] = kwargs["offset"]+kwargs["count"] self.db[name]["offset"] = kwargs["offset"]+kwargs["count"]
return num return num
def get_messages(self, name="", *args, **kwargs): def get_messages(self, name="", *args, **kwargs):
data = self.vk.client.messages.getHistory(*args, **kwargs) data = self.vk.client.messages.getHistory(*args, **kwargs)
data["items"].reverse() data["items"].reverse()
if data != None: if data != None:
num = self.order_buffer(name, data["items"], False) num = self.order_buffer(name, data["items"], False)
return num return num
def get_users(self, user_ids=None, group_ids=None): def get_users(self, user_ids=None, group_ids=None):
log.debug("Getting user information from the VK servers") log.debug("Getting user information from the VK servers")
if user_ids != None: if user_ids != None:
u = self.vk.client.users.get(user_ids=user_ids, fields="uid, first_name, last_name") u = self.vk.client.users.get(user_ids=user_ids, fields="uid, first_name, last_name")
for i in u: for i in u:
self.db["users"][i["id"]] = dict(nom="{0} {1}".format(i["first_name"], i["last_name"])) self.db["users"][i["id"]] = dict(nom="{0} {1}".format(i["first_name"], i["last_name"]))
if group_ids != None: if group_ids != None:
g = self.vk.client.groups.getById(group_ids=group_ids, fields="name") g = self.vk.client.groups.getById(group_ids=group_ids, fields="name")
for i in g: for i in g:
self.db["groups"][i["id"]] = dict(nom=i["name"], gen=i["name"], dat=i["name"], acc=i["name"], ins=i["name"], abl=i["name"]) self.db["groups"][i["id"]] = dict(nom=i["name"], gen=i["name"], dat=i["name"], acc=i["name"], ins=i["name"], abl=i["name"])
def get_user(self, user_id, key="user1"): def get_user(self, user_id, key="user1"):
if user_id > 0: if user_id > 0:
if user_id in self.db["users"]: if user_id in self.db["users"]:
user_data = {} user_data = {}
user_fields = "nom, gen, ins, dat, abl, acc".split(", ") user_fields = "nom, gen, ins, dat, abl, acc".split(", ")
for i in user_fields: for i in user_fields:
k = "{key}_{case}".format(key=key, case=i) k = "{key}_{case}".format(key=key, case=i)
v = "{first_name} {last_name}".format(first_name=self.db["users"][user_id]["first_name_"+i], last_name=self.db["users"][user_id]["last_name_"+i]) v = "{first_name} {last_name}".format(first_name=self.db["users"][user_id]["first_name_"+i], last_name=self.db["users"][user_id]["last_name_"+i])
user_data[k] = v user_data[k] = v
return user_data return user_data
# if User_id is not present in db. # if User_id is not present in db.
else: else:
user = dict(id=user_id) user = dict(id=user_id)
self.process_usernames(data=dict(profiles=[user], groups=[])) self.process_usernames(data=dict(profiles=[user], groups=[]))
return self.get_user(user_id) return self.get_user(user_id)
else: else:
if abs(user_id) in self.db["groups"]: if abs(user_id) in self.db["groups"]:
user_data = {} user_data = {}
user_fields = "nom, gen, ins, dat, abl, acc".split(", ") user_fields = "nom, gen, ins, dat, abl, acc".split(", ")
for i in user_fields: for i in user_fields:
k = "{key}_{case}".format(key=key, case=i) k = "{key}_{case}".format(key=key, case=i)
v = self.db["groups"][abs(user_id)][i] v = self.db["groups"][abs(user_id)][i]
user_data[k] = v user_data[k] = v
else: else:
group = self.vk.client.groups.getById(group_ids=-1*user_id)[0] group = self.vk.client.groups.getById(group_ids=-1*user_id)[0]
self.process_usernames(data=dict(profiles=[], groups=[group])) self.process_usernames(data=dict(profiles=[], groups=[group]))
return self.get_user(user_id=user_id, key=key) return self.get_user(user_id=user_id, key=key)
return user_data return user_data
def process_usernames(self, data): def process_usernames(self, data):
""" processes user IDS and saves them in a local storage system. """ processes user IDS and saves them in a local storage system.
Every function wich needs to convert from an ID to user or community name will have to call the get_user_name function in this session object. Every function wich needs to convert from an ID to user or community name will have to call the get_user_name function in this session object.
Every function that needs to save a set ot user ids for a future use needs to pass a data dictionary with a profiles key being a list of user objects. Every function that needs to save a set ot user ids for a future use needs to pass a data dictionary with a profiles key being a list of user objects.
It gets first and last name for people in the 6 russian cases and saves them for future reference.""" It gets first and last name for people in the 6 russian cases and saves them for future reference."""
log.debug("Adding usernames to the local database...") log.debug("Adding usernames to the local database...")
ids = "" ids = ""
for i in data["profiles"]: for i in data["profiles"]:
if (i["id"] in self.db["users"]) == False: if (i["id"] in self.db["users"]) == False:
ids = ids + "{0},".format(i["id"],) ids = ids + "{0},".format(i["id"],)
gids = "" gids = ""
for i in data["groups"]: for i in data["groups"]:
if i["id"] not in self.db["groups"]: if i["id"] not in self.db["groups"]:
self.db["groups"][i["id"]] = dict(nom=i["name"], gen=i["name"], dat=i["name"], acc=i["name"], ins=i["name"], abl=i["name"]) self.db["groups"][i["id"]] = dict(nom=i["name"], gen=i["name"], dat=i["name"], acc=i["name"], ins=i["name"], abl=i["name"])
gids = "{0},".format(i["id"],) gids = "{0},".format(i["id"],)
user_fields = "first_name_nom, last_name_nom, first_name_gen, last_name_gen, first_name_ins, last_name_ins, first_name_dat, last_name_dat, first_name_abl, last_name_abl, first_name_acc, last_name_acc, sex" user_fields = "first_name_nom, last_name_nom, first_name_gen, last_name_gen, first_name_ins, last_name_ins, first_name_dat, last_name_dat, first_name_abl, last_name_abl, first_name_acc, last_name_acc, sex"
user_fields_list = user_fields.split(", ") user_fields_list = user_fields.split(", ")
if ids != "": if ids != "":
users = self.vk.client.users.get(user_ids=ids, fields=user_fields) users = self.vk.client.users.get(user_ids=ids, fields=user_fields)
for i in users: for i in users:
if i["id"] not in self.db["users"]: if i["id"] not in self.db["users"]:
userdata = {} userdata = {}
for field in user_fields_list: for field in user_fields_list:
if field in i: if field in i:
userdata[field] = i[field] userdata[field] = i[field]
self.db["users"][i["id"]] = userdata self.db["users"][i["id"]] = userdata
def get_my_data(self): def get_my_data(self):
log.debug("Getting user identifier...") log.debug("Getting user identifier...")
user = self.vk.client.users.get(fields="uid, first_name, last_name") user = self.vk.client.users.get(fields="uid, first_name, last_name")
self.user_id = user[0]["id"] self.user_id = user[0]["id"]
def post(self, parent_endpoint, child_endpoint, from_buffer=None, attachments_list=[], post_arguments={}): def post(self, parent_endpoint, child_endpoint, from_buffer=None, attachments_list=[], post_arguments={}):
""" Generic function to be called whenever user wants to post something to VK. """ Generic function to be called whenever user wants to post something to VK.
This function should be capable of uploading all attachments before posting, and send a special event in case the post has failed, This function should be capable of uploading all attachments before posting, and send a special event in case the post has failed,
So the program can recreate the post and show it back to the user.""" So the program can recreate the post and show it back to the user."""
# Define a list of error codes that are handled by the application. # Define a list of error codes that are handled by the application.
handled_errors = [7, 900] handled_errors = [7, 900]
# ToDo: this function will occasionally be called with attachments already set to post_arguments, example if the user could upload the files but was unable to send the post due to a connection problem. # ToDo: this function will occasionally be called with attachments already set to post_arguments, example if the user could upload the files but was unable to send the post due to a connection problem.
# We should see what can be done (reuploading everything vs using the already added attachments). # We should see what can be done (reuploading everything vs using the already added attachments).
attachments = "" attachments = ""
# Firstly, let's try to upload the attachments here. If peer_id exists in post_arguments, # Firstly, let's try to upload the attachments here. If peer_id exists in post_arguments,
# It means we are talking about private messages, whose attachment procedures have their own methods. # It means we are talking about private messages, whose attachment procedures have their own methods.
if len(attachments_list) > 0: if len(attachments_list) > 0:
try: try:
attachments = self.upload_attachments(attachments_list, post_arguments.get("peer_id")) attachments = self.upload_attachments(attachments_list, post_arguments.get("peer_id"))
except Exception as error: except Exception as error:
log.error("Error calling method %s.%s with arguments: %r. Failed during loading attachments. Error: %s" % (parent_endpoint, child_endpoint, post_arguments, str(error))) log.error("Error calling method %s.%s with arguments: %r. Failed during loading attachments. Error: %s" % (parent_endpoint, child_endpoint, post_arguments, str(error)))
# Report a failed function here too with same arguments so the client should be able to recreate it again. # Report a failed function here too with same arguments so the client should be able to recreate it again.
wx.CallAfter(pub.sendMessage, "postFailed", parent_endpoint=parent_endpoint, child_endpoint=child_endpoint, from_buffer=from_buffer, attachments_list=attachments_list, post_arguments=post_arguments) wx.CallAfter(pub.sendMessage, "postFailed", parent_endpoint=parent_endpoint, child_endpoint=child_endpoint, from_buffer=from_buffer, attachments_list=attachments_list, post_arguments=post_arguments)
# After modifying everything, let's update the post arguments if needed. # After modifying everything, let's update the post arguments if needed.
if len(attachments) > 0: if len(attachments) > 0:
if parent_endpoint == "messages": if parent_endpoint == "messages":
post_arguments.update(attachment=attachments) post_arguments.update(attachment=attachments)
else: else:
post_arguments.update(attachments=attachments) post_arguments.update(attachments=attachments)
# Determines the correct functions to call here. # Determines the correct functions to call here.
endpoint = getattr(self.vk.client, parent_endpoint) endpoint = getattr(self.vk.client, parent_endpoint)
endpoint = getattr(endpoint, child_endpoint) endpoint = getattr(endpoint, child_endpoint)
try: try:
post = endpoint(**post_arguments) post = endpoint(**post_arguments)
# Once the post has been send, let's report it to the interested objects. # Once the post has been send, let's report it to the interested objects.
pub.sendMessage("posted", from_buffer=from_buffer) pub.sendMessage("posted", from_buffer=from_buffer)
except Exception as error: except Exception as error:
log.exception("Error calling method %s.%s with arguments: %r. Error: %s" % (parent_endpoint, child_endpoint, post_arguments, str(error))) log.exception("Error calling method %s.%s with arguments: %r. Error: %s" % (parent_endpoint, child_endpoint, post_arguments, str(error)))
# Send handled errors to the corresponding function, call the default handler otherwise. # Send handled errors to the corresponding function, call the default handler otherwise.
if error.code in handled_errors: if error.code in handled_errors:
wx.CallAfter(pub.sendMessage, "api-error", code=error.code) wx.CallAfter(pub.sendMessage, "api-error", code=error.code)
else: else:
# Report a failed function here too with same arguments so the client should be able to recreate it again. # Report a failed function here too with same arguments so the client should be able to recreate it again.
wx.CallAfter(pub.sendMessage, "postFailed", parent_endpoint=parent_endpoint, child_endpoint=child_endpoint, from_buffer=from_buffer, attachments_list=attachments_list, post_arguments=post_arguments) wx.CallAfter(pub.sendMessage, "postFailed", parent_endpoint=parent_endpoint, child_endpoint=child_endpoint, from_buffer=from_buffer, attachments_list=attachments_list, post_arguments=post_arguments)
def upload_attachments(self, attachments, peer_id=None): def upload_attachments(self, attachments, peer_id=None):
""" Upload attachments to VK before posting them. """ Upload attachments to VK before posting them.
Returns attachments formatted as string, as required by VK API. Returns attachments formatted as string, as required by VK API.
@ peer_id int: if this value is passed, let's assume attachments will be send in private messages. @ peer_id int: if this value is passed, let's assume attachments will be send in private messages.
""" """
# To do: Check the caption and description fields for this kind of attachments. # To do: Check the caption and description fields for this kind of attachments.
local_attachments = "" local_attachments = ""
uploader = upload.VkUpload(self.vk.session_object) uploader = upload.VkUpload(self.vk.session_object)
for i in attachments: for i in attachments:
if i["from"] == "online": if i["from"] == "online":
local_attachments += "{0}{1}_{2},".format(i["type"], i["owner_id"], i["id"]) local_attachments += "{0}{1}_{2},".format(i["type"], i["owner_id"], i["id"])
elif i["from"] == "local" and i["type"] == "photo": elif i["from"] == "local" and i["type"] == "photo":
photos = i["file"] photos = i["file"]
description = i["description"] description = i["description"]
if peer_id == None: if peer_id == None:
r = uploader.photo_wall(photos, caption=description) r = uploader.photo_wall(photos, caption=description)
else: else:
r = uploader.photo_messages(photos) r = uploader.photo_messages(photos)
id = r[0]["id"] id = r[0]["id"]
owner_id = r[0]["owner_id"] owner_id = r[0]["owner_id"]
local_attachments += "photo{0}_{1},".format(owner_id, id) local_attachments += "photo{0}_{1},".format(owner_id, id)
elif i["from"] == "local" and i["type"] == "audio": elif i["from"] == "local" and i["type"] == "audio":
audio = i["file"] audio = i["file"]
title = "untitled" title = "untitled"
artist = "unnamed" artist = "unnamed"
if "artist" in i: if "artist" in i:
artist = i["artist"] artist = i["artist"]
if "title" in i: if "title" in i:
title = i["title"] title = i["title"]
r = uploader.audio(audio, title=title, artist=artist) r = uploader.audio(audio, title=title, artist=artist)
id = r["id"] id = r["id"]
owner_id = r["owner_id"] owner_id = r["owner_id"]
local_attachments += "audio{0}_{1},".format(owner_id, id) local_attachments += "audio{0}_{1},".format(owner_id, id)
elif i["from"] == "local" and i["type"] == "voice_message": elif i["from"] == "local" and i["type"] == "voice_message":
r = uploader.audio_message(i["file"], peer_id=peer_id) r = uploader.audio_message(i["file"], peer_id=peer_id)
id = r["audio_message"]["id"] id = r["audio_message"]["id"]
owner_id = r["audio_message"]["owner_id"] owner_id = r["audio_message"]["owner_id"]
local_attachments += "audio_message{0}_{1},".format(owner_id, id) local_attachments += "audio_message{0}_{1},".format(owner_id, id)
elif i["from"] == "local" and i["type"] == "document": elif i["from"] == "local" and i["type"] == "document":
document = i["file"] document = i["file"]
title = i["title"] title = i["title"]
if peer_id == None: if peer_id == None:
r = uploader.document(document, title=title, to_wall=True) r = uploader.document(document, title=title, to_wall=True)
else: else:
r = uploader.document(document, title=title, message_peer_id=peer_id) r = uploader.document(document, title=title, message_peer_id=peer_id)
id = r["doc"]["id"] id = r["doc"]["id"]
owner_id = r["doc"]["owner_id"] owner_id = r["doc"]["owner_id"]
local_attachments += "doc{0}_{1},".format(owner_id, id) local_attachments += "doc{0}_{1},".format(owner_id, id)
return local_attachments return local_attachments

View File

@ -14,83 +14,83 @@ from .config_utils import Configuration
log = logging.getLogger("sessionmanager.sessionManager") log = logging.getLogger("sessionmanager.sessionManager")
class sessionManagerController(object): class sessionManagerController(object):
def __init__(self, starting=True): def __init__(self, starting=True):
super(sessionManagerController, self).__init__() super(sessionManagerController, self).__init__()
log.debug("Setting up the session manager.") log.debug("Setting up the session manager.")
if starting: if starting:
title=_("Select an account") title=_("Select an account")
else: else:
title = _("Manage accounts") title = _("Manage accounts")
self.view = view.sessionManagerWindow(starting=starting, title=title) self.view = view.sessionManagerWindow(starting=starting, title=title)
widgetUtils.connect_event(self.view.new, widgetUtils.BUTTON_PRESSED, self.manage_new_account) widgetUtils.connect_event(self.view.new, widgetUtils.BUTTON_PRESSED, self.manage_new_account)
widgetUtils.connect_event(self.view.remove, widgetUtils.BUTTON_PRESSED, self.remove) widgetUtils.connect_event(self.view.remove, widgetUtils.BUTTON_PRESSED, self.remove)
self.fill_list() self.fill_list()
if len(self.sessions) == 0: if len(self.sessions) == 0:
log.debug("the session list is empty, creating a new one...") log.debug("the session list is empty, creating a new one...")
self.manage_new_account() self.manage_new_account()
def fill_list(self): def fill_list(self):
self.sessions = [] self.sessions = []
log.debug("Filling the session list...") log.debug("Filling the session list...")
for i in os.listdir(paths.config_path()): for i in os.listdir(paths.config_path()):
if i != "dicts" and os.path.isdir(os.path.join(paths.config_path(), i)): if i != "dicts" and os.path.isdir(os.path.join(paths.config_path(), i)):
log.debug("Adding session %s" % (i,)) log.debug("Adding session %s" % (i,))
config_test = Configuration(os.path.join(paths.config_path(), i, "session.conf")) config_test = Configuration(os.path.join(paths.config_path(), i, "session.conf"))
name = config_test["vk"]["user"] name = config_test["vk"]["user"]
if name != "" and config_test["vk"]["password"] != "": if name != "" and config_test["vk"]["password"] != "":
self.sessions.append((i, name)) self.sessions.append((i, name))
self.view.list.insert_item(False, *[name]) self.view.list.insert_item(False, *[name])
def manage_new_account(self, *args, **kwargs): def manage_new_account(self, *args, **kwargs):
if view.new_account_dialog() == widgetUtils.YES: if view.new_account_dialog() == widgetUtils.YES:
location = (str(time.time())[-6:]) location = (str(time.time())[-6:])
log.debug("Creating session in the %s path" % (location,)) log.debug("Creating session in the %s path" % (location,))
s = session.vkSession(location) s = session.vkSession(location)
path = os.path.join(paths.config_path(), location) path = os.path.join(paths.config_path(), location)
if not os.path.exists(path): if not os.path.exists(path):
os.mkdir(path) os.mkdir(path)
s.get_configuration(True) s.get_configuration(True)
self.get_authorisation(s) self.get_authorisation(s)
name = s.settings["vk"]["user"] name = s.settings["vk"]["user"]
self.sessions.append((location, name)) self.sessions.append((location, name))
self.view.list.insert_item(False, *[name]) self.view.list.insert_item(False, *[name])
self.modified = True self.modified = True
def get_authorisation(self, c): def get_authorisation(self, c):
log.debug("Starting the authorisation process...") log.debug("Starting the authorisation process...")
dl = view.newSessionDialog() dl = view.newSessionDialog()
if dl.ShowModal() == widgetUtils.OK: if dl.ShowModal() == widgetUtils.OK:
c.settings["vk"]["user"] = dl.get_email() c.settings["vk"]["user"] = dl.get_email()
c.settings["vk"]["password"] = dl.get_password() c.settings["vk"]["password"] = dl.get_password()
try: try:
c.login() c.login()
except AuthenticationError: except AuthenticationError:
c.settings["vk"]["password"] = "" c.settings["vk"]["password"] = ""
c.settings["vk"]["user"] c.settings["vk"]["user"]
return self.get_authorisation(c) return self.get_authorisation(c)
def do_ok(self): def do_ok(self):
selected_session = self.sessions[self.view.list.get_selected()] selected_session = self.sessions[self.view.list.get_selected()]
self.session = selected_session[0] self.session = selected_session[0]
self.session = session.vkSession(self.session) self.session = session.vkSession(self.session)
self.session.get_configuration() self.session.get_configuration()
session.sessions[selected_session[1]] = self.session session.sessions[selected_session[1]] = self.session
def show(self): def show(self):
if len(self.sessions) > 1: if len(self.sessions) > 1:
answer = self.view.get_response() answer = self.view.get_response()
else: else:
answer = widgetUtils.OK answer = widgetUtils.OK
if answer == widgetUtils.OK: if answer == widgetUtils.OK:
self.do_ok() self.do_ok()
else: else:
sys.exit() sys.exit()
self.view.destroy() self.view.destroy()
def remove(self, *args, **kwargs): def remove(self, *args, **kwargs):
if self.view.remove_account_dialog() == widgetUtils.YES: if self.view.remove_account_dialog() == widgetUtils.YES:
selected_session = self.sessions[self.view.list.get_selected()] selected_session = self.sessions[self.view.list.get_selected()]
shutil.rmtree(path=os.path.join(paths.config_path(), selected_session[0]), ignore_errors=True) shutil.rmtree(path=os.path.join(paths.config_path(), selected_session[0]), ignore_errors=True)
self.sessions.remove(selected_session) self.sessions.remove(selected_session)
self.view.list.remove_item(self.view.list.get_selected()) self.view.list.remove_item(self.view.list.get_selected())
self.modified = True self.modified = True

View File

@ -12,93 +12,93 @@ url_re = re.compile("(?:\w+://|www\.)[^ ,.?!#%=+][^ ]*")
bad_chars = '\'\\.,[](){}:;"' bad_chars = '\'\\.,[](){}:;"'
def seconds_to_string(seconds, precision=0): def seconds_to_string(seconds, precision=0):
""" convert a number of seconds in a string representation.""" """ convert a number of seconds in a string representation."""
# ToDo: Improve it to handle properly Russian plurals. # ToDo: Improve it to handle properly Russian plurals.
day = seconds // 86400 day = seconds // 86400
hour = seconds // 3600 hour = seconds // 3600
min = (seconds // 60) % 60 min = (seconds // 60) % 60
sec = seconds - (hour * 3600) - (min * 60) sec = seconds - (hour * 3600) - (min * 60)
sec_spec = "." + str(precision) + "f" sec_spec = "." + str(precision) + "f"
sec_string = sec.__format__(sec_spec) sec_string = sec.__format__(sec_spec)
string = "" string = ""
if day == 1: if day == 1:
string += _("%d day, ") % day string += _("%d day, ") % day
elif day >= 2: elif day >= 2:
string += _("%d days, ") % day string += _("%d days, ") % day
if (hour == 1): if (hour == 1):
string += _("%d hour, ") % hour string += _("%d hour, ") % hour
elif (hour >= 2): elif (hour >= 2):
string += _("%d hours, ") % hour string += _("%d hours, ") % hour
if (min == 1): if (min == 1):
string += _("%d minute, ") % min string += _("%d minute, ") % min
elif (min >= 2): elif (min >= 2):
string += _("%d minutes, ") % min string += _("%d minutes, ") % min
if sec >= 0 and sec <= 2: if sec >= 0 and sec <= 2:
string += _("%s second") % sec_string string += _("%s second") % sec_string
else: else:
string += _("%s seconds") % sec_string string += _("%s seconds") % sec_string
return string return string
def find_urls_in_text(text): def find_urls_in_text(text):
return [s.strip(bad_chars) for s in url_re.findall(text)] return [s.strip(bad_chars) for s in url_re.findall(text)]
def download_file(url, local_filename): def download_file(url, local_filename):
r = requests.get(url, stream=True) r = requests.get(url, stream=True)
pub.sendMessage("change_status", status=_("Downloading {0}").format(local_filename,)) pub.sendMessage("change_status", status=_("Downloading {0}").format(local_filename,))
total_length = r.headers.get("content-length") total_length = r.headers.get("content-length")
dl = 0 dl = 0
total_length = int(total_length) total_length = int(total_length)
with open(local_filename, 'wb') as f: with open(local_filename, 'wb') as f:
for chunk in r.iter_content(chunk_size=512*1024): for chunk in r.iter_content(chunk_size=512*1024):
if chunk: # filter out keep-alive new chunks if chunk: # filter out keep-alive new chunks
dl += len(chunk) dl += len(chunk)
f.write(chunk) f.write(chunk)
done = int(100 * dl/total_length) done = int(100 * dl/total_length)
msg = _("Downloading {0} ({1}%)").format(os.path.basename(local_filename), done) msg = _("Downloading {0} ({1}%)").format(os.path.basename(local_filename), done)
# print(msg) # print(msg)
pub.sendMessage("change_status", status=msg) pub.sendMessage("change_status", status=msg)
pub.sendMessage("change_status", status=_("Ready")) pub.sendMessage("change_status", status=_("Ready"))
return local_filename return local_filename
def download_files(downloads): def download_files(downloads):
for download in downloads: for download in downloads:
download_file(download[0], download[1]) download_file(download[0], download[1])
def detect_users(text): def detect_users(text):
""" Detect all users and communities mentionned in any text posted in VK.""" """ Detect all users and communities mentionned in any text posted in VK."""
# This regexp gets group and users mentionned in topic comments. # This regexp gets group and users mentionned in topic comments.
for matched_data in re.finditer("(\[)(id|club)(\d+:bp-\d+_\d+\|)(\D+)(\])", text): for matched_data in re.finditer("(\[)(id|club)(\d+:bp-\d+_\d+\|)(\D+)(\])", text):
text = re.sub("\[(id|club)\d+:bp-\d+_\d+\|\D+\]", matched_data.groups()[3]+", ", text, count=1) text = re.sub("\[(id|club)\d+:bp-\d+_\d+\|\D+\]", matched_data.groups()[3]+", ", text, count=1)
# This is for users and communities just mentionned in wall comments or posts. # This is for users and communities just mentionned in wall comments or posts.
for matched_data in re.finditer("(\[)(id|club)(\d+\|)(\D+)(\])", text): for matched_data in re.finditer("(\[)(id|club)(\d+\|)(\D+)(\])", text):
text = re.sub("\[(id|club)\d+\|\D+\]", matched_data.groups()[3]+", ", text, count=1) text = re.sub("\[(id|club)\d+\|\D+\]", matched_data.groups()[3]+", ", text, count=1)
return text return text
def clean_text(text): def clean_text(text):
""" Clean text, removing all unneeded HTMl and converting HTML represented characters in their unicode counterparts.""" """ Clean text, removing all unneeded HTMl and converting HTML represented characters in their unicode counterparts."""
text = detect_users(text) text = detect_users(text)
text = html.unescape(text) text = html.unescape(text)
return text return text
def transform_audio_url(url): def transform_audio_url(url):
""" Transforms the URL offered by VK to the unencrypted stream so we can still play it. """ Transforms the URL offered by VK to the unencrypted stream so we can still play it.
This function will be updated every time VK decides to change something in their Audio API'S. This function will be updated every time VK decides to change something in their Audio API'S.
Changelog: Changelog:
30/04/2019: Re-enabled old methods as VK changed everything as how it was working on 16.04.2019. 30/04/2019: Re-enabled old methods as VK changed everything as how it was working on 16.04.2019.
17.04.2019: Updated function. Now it is not required to strip anything, just replacing /index.m3u8 with .mp3 should be enough. 17.04.2019: Updated function. Now it is not required to strip anything, just replacing /index.m3u8 with .mp3 should be enough.
16.04.2019: Implemented this function. For now it replaces /index.m3u8 by .mp3, also removes the path component before "/audios" if the URL contains the word /audios, or the last path component before the filename if doesn't. 16.04.2019: Implemented this function. For now it replaces /index.m3u8 by .mp3, also removes the path component before "/audios" if the URL contains the word /audios, or the last path component before the filename if doesn't.
""" """
if "vkuseraudio.net" not in url and "index.m3u8" not in url: if "vkuseraudio.net" not in url and "index.m3u8" not in url:
return url return url
url = url.replace("/index.m3u8", ".mp3") url = url.replace("/index.m3u8", ".mp3")
parts = url.split("/") parts = url.split("/")
if "/audios" not in url: if "/audios" not in url:
url = url.replace("/"+parts[-2], "") url = url.replace("/"+parts[-2], "")
else: else:
url = url.replace("/"+parts[-3], "") url = url.replace("/"+parts[-3], "")
url = url.split(".mp3?")[0]+".mp3" url = url.split(".mp3?")[0]+".mp3"
return url return url
def safe_filename(filename): def safe_filename(filename):
allowed_symbols = ["_", ".", ",", "-", "(", ")"] allowed_symbols = ["_", ".", ",", "-", "(", ")"]
return "".join([c for c in filename if c.isalpha() or c.isdigit() or c==' ' or c in allowed_symbols]).rstrip() return "".join([c for c in filename if c.isalpha() or c.isdigit() or c==' ' or c in allowed_symbols]).rstrip()

View File

@ -9,28 +9,28 @@ log = logging.getLogger("vkSessionHandler")
class vkObject(object): class vkObject(object):
def __init__(self): def __init__(self):
self.api_key = keys.keyring.get_api_key() self.api_key = keys.keyring.get_api_key()
def login(self, user, password, token, alt_token, filename): def login(self, user, password, token, alt_token, filename):
if alt_token == False: if alt_token == False:
log.info("Using kate's token...") log.info("Using kate's token...")
# Let's import the patched vk_api module for using a different user agent # Let's import the patched vk_api module for using a different user agent
from . import vk_api_patched as vk_api from . import vk_api_patched as vk_api
if token == "" or token == None: if token == "" or token == None:
log.info("Token is not valid. Generating one...") log.info("Token is not valid. Generating one...")
original_token = official.login(user, password) original_token = official.login(user, password)
token = original_token token = original_token
log.info("Token validated...") log.info("Token validated...")
self.session_object = vk_api.VkApi(app_id=self.api_key, login=user, password=password, token=token, scope="all", config_filename=filename) self.session_object = vk_api.VkApi(app_id=self.api_key, login=user, password=password, token=token, scope="all", config_filename=filename)
else: else:
import vk_api import vk_api
self.session_object = vk_api.VkApi(app_id=self.api_key, login=user, password=password, scope="offline, wall, notify, friends, photos, audio, video, docs, notes, pages, status, groups, messages, notifications, stats", config_filename=filename, auth_handler=two_factor_auth) self.session_object = vk_api.VkApi(app_id=self.api_key, login=user, password=password, scope="offline, wall, notify, friends, photos, audio, video, docs, notes, pages, status, groups, messages, notifications, stats", config_filename=filename, auth_handler=two_factor_auth)
self.session_object.auth() self.session_object.auth()
self.client = self.session_object.get_api() self.client = self.session_object.get_api()
# print self.client.audio.get() # print self.client.audio.get()
log.debug("Getting tokens for 24 hours...") log.debug("Getting tokens for 24 hours...")
# info = self.client.account.getProfileInfo() # info = self.client.account.getProfileInfo()
# Add session data to the application statistics. # Add session data to the application statistics.
self.client.stats.trackVisitor() self.client.stats.trackVisitor()
self.client_audio = VkAudio(self.session_object) self.client_audio = VkAudio(self.session_object)

View File

@ -4,71 +4,71 @@ import wx
import widgetUtils import widgetUtils
def new_account_dialog(): def new_account_dialog():
return wx.MessageDialog(None, _("In order to continue, you need to configure your VK account before. Would you like to autorhise a new account now?"), _("Authorisation"), wx.YES_NO).ShowModal() return wx.MessageDialog(None, _("In order to continue, you need to configure your VK account before. Would you like to autorhise a new account now?"), _("Authorisation"), wx.YES_NO).ShowModal()
class newSessionDialog(widgetUtils.BaseDialog): class newSessionDialog(widgetUtils.BaseDialog):
def __init__(self): def __init__(self):
super(newSessionDialog, self).__init__(parent=None, id=wx.NewId(), title=_("Authorise VK")) super(newSessionDialog, self).__init__(parent=None, id=wx.NewId(), title=_("Authorise VK"))
panel = wx.Panel(self) panel = wx.Panel(self)
lbl1 = wx.StaticText(panel, -1, _("&Email or phone number")) lbl1 = wx.StaticText(panel, -1, _("&Email or phone number"))
self.email = wx.TextCtrl(panel, -1) self.email = wx.TextCtrl(panel, -1)
lbl2 = wx.StaticText(panel, -1, _("&Password")) lbl2 = wx.StaticText(panel, -1, _("&Password"))
self.passw = wx.TextCtrl(panel, -1, style=wx.TE_PASSWORD) self.passw = wx.TextCtrl(panel, -1, style=wx.TE_PASSWORD)
sizer = wx.BoxSizer() sizer = wx.BoxSizer()
b1 = wx.BoxSizer(wx.HORIZONTAL) b1 = wx.BoxSizer(wx.HORIZONTAL)
b1.Add(lbl1, 0, wx.ALL, 5) b1.Add(lbl1, 0, wx.ALL, 5)
b1.Add(self.email, 0, wx.ALL, 5) b1.Add(self.email, 0, wx.ALL, 5)
b2 = wx.BoxSizer(wx.HORIZONTAL) b2 = wx.BoxSizer(wx.HORIZONTAL)
b2.Add(lbl2, 0, wx.ALL, 5) b2.Add(lbl2, 0, wx.ALL, 5)
b2.Add(self.passw, 0, wx.ALL, 5) b2.Add(self.passw, 0, wx.ALL, 5)
sizer.Add(b1, 0, wx.ALL, 5) sizer.Add(b1, 0, wx.ALL, 5)
sizer.Add(b2, 0, wx.ALL, 5) sizer.Add(b2, 0, wx.ALL, 5)
ok = wx.Button(panel, wx.ID_OK) ok = wx.Button(panel, wx.ID_OK)
ok.SetDefault() ok.SetDefault()
cancel = wx.Button(panel, wx.ID_CANCEL) cancel = wx.Button(panel, wx.ID_CANCEL)
btnb = wx.BoxSizer(wx.HORIZONTAL) btnb = wx.BoxSizer(wx.HORIZONTAL)
btnb.Add(ok, 0, wx.ALL, 5) btnb.Add(ok, 0, wx.ALL, 5)
btnb.Add(cancel, 0, wx.ALL, 5) btnb.Add(cancel, 0, wx.ALL, 5)
sizer.Add(btnb, 0, wx.ALL, 5) sizer.Add(btnb, 0, wx.ALL, 5)
panel.SetSizer(sizer) panel.SetSizer(sizer)
def get_email(self): def get_email(self):
return self.email.GetValue() return self.email.GetValue()
def get_password(self): def get_password(self):
return self.passw.GetValue() return self.passw.GetValue()
class sessionManagerWindow(widgetUtils.BaseDialog): class sessionManagerWindow(widgetUtils.BaseDialog):
def __init__(self, title, starting=True): def __init__(self, title, starting=True):
super(sessionManagerWindow, self).__init__(parent=None, title=title, size=wx.DefaultSize) super(sessionManagerWindow, self).__init__(parent=None, title=title, size=wx.DefaultSize)
panel = wx.Panel(self) panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
label = wx.StaticText(panel, -1, _(u"Accounts list"), size=wx.DefaultSize) label = wx.StaticText(panel, -1, _(u"Accounts list"), size=wx.DefaultSize)
listSizer = wx.BoxSizer(wx.HORIZONTAL) listSizer = wx.BoxSizer(wx.HORIZONTAL)
self.list = widgetUtils.list(panel, _("Account"), style=wx.LC_SINGLE_SEL|wx.LC_REPORT) self.list = widgetUtils.list(panel, _("Account"), style=wx.LC_SINGLE_SEL|wx.LC_REPORT)
listSizer.Add(label, 0, wx.ALL, 5) listSizer.Add(label, 0, wx.ALL, 5)
listSizer.Add(self.list.list, 0, wx.ALL, 5) listSizer.Add(self.list.list, 0, wx.ALL, 5)
sizer.Add(listSizer, 0, wx.ALL, 5) sizer.Add(listSizer, 0, wx.ALL, 5)
self.new = wx.Button(panel, -1, _("New account"), size=wx.DefaultSize) self.new = wx.Button(panel, -1, _("New account"), size=wx.DefaultSize)
self.remove = wx.Button(panel, -1, _(u"Remove account")) self.remove = wx.Button(panel, -1, _(u"Remove account"))
if starting: if starting:
id_ok = wx.ID_OK id_ok = wx.ID_OK
else: else:
id_ok = wx.ID_CANCEL id_ok = wx.ID_CANCEL
ok = wx.Button(panel, id_ok, size=wx.DefaultSize) ok = wx.Button(panel, id_ok, size=wx.DefaultSize)
ok.SetDefault() ok.SetDefault()
if starting: if starting:
cancel = wx.Button(panel, wx.ID_CANCEL, size=wx.DefaultSize) cancel = wx.Button(panel, wx.ID_CANCEL, size=wx.DefaultSize)
self.SetAffirmativeId(id_ok) self.SetAffirmativeId(id_ok)
buttons = wx.BoxSizer(wx.HORIZONTAL) buttons = wx.BoxSizer(wx.HORIZONTAL)
buttons.Add(self.new, 0, wx.ALL, 5) buttons.Add(self.new, 0, wx.ALL, 5)
buttons.Add(ok, 0, wx.ALL, 5) buttons.Add(ok, 0, wx.ALL, 5)
if starting: if starting:
buttons.Add(cancel, 0, wx.ALL, 5) buttons.Add(cancel, 0, wx.ALL, 5)
sizer.Add(buttons, 0, wx.ALL, 5) sizer.Add(buttons, 0, wx.ALL, 5)
panel.SetSizer(sizer) panel.SetSizer(sizer)
min = sizer.CalcMin() min = sizer.CalcMin()
self.SetClientSize(min) self.SetClientSize(min)
def remove_account_dialog(self): def remove_account_dialog(self):
return wx.MessageDialog(self, _("Do you really want to delete this account?"), _("Remove account"), wx.YES_NO).ShowModal() return wx.MessageDialog(self, _("Do you really want to delete this account?"), _("Remove account"), wx.YES_NO).ShowModal()

View File

@ -10,38 +10,38 @@ from babel.messages import frontend as babel
languageHandler.setLanguage("en") languageHandler.setLanguage("en")
def find_sound_lib_datafiles(): def find_sound_lib_datafiles():
import os import os
import platform import platform
import sound_lib import sound_lib
path = os.path.join(sound_lib.__path__[0], 'lib') path = os.path.join(sound_lib.__path__[0], 'lib')
if platform.architecture()[0] == '32bit' or platform.system() == 'Darwin': if platform.architecture()[0] == '32bit' or platform.system() == 'Darwin':
arch = 'x86' arch = 'x86'
else: else:
arch = 'x64' arch = 'x64'
dest_dir = os.path.join('sound_lib', 'lib', arch) dest_dir = os.path.join('sound_lib', 'lib', arch)
source = os.path.join(path, arch) source = os.path.join(path, arch)
return (source, dest_dir) return (source, dest_dir)
def find_accessible_output2_datafiles(): def find_accessible_output2_datafiles():
import os import os
import accessible_output2 import accessible_output2
path = os.path.join(accessible_output2.__path__[0], 'lib') path = os.path.join(accessible_output2.__path__[0], 'lib')
dest_dir = os.path.join('accessible_output2', 'lib') dest_dir = os.path.join('accessible_output2', 'lib')
return (path, dest_dir) return (path, dest_dir)
base = None base = None
if sys.platform == 'win32': if sys.platform == 'win32':
base = 'Win32GUI' base = 'Win32GUI'
build_exe_options = dict( build_exe_options = dict(
build_exe="dist", build_exe="dist",
optimize=1, optimize=1,
include_msvcr=True, include_msvcr=True,
zip_include_packages=["accessible_output2", "sound_lib", "arrow"], zip_include_packages=["accessible_output2", "sound_lib", "arrow"],
replace_paths = [("*", "")], replace_paths = [("*", "")],
include_files=["session.defaults", "cacert.pem", "app-configuration.defaults", "locales", "sounds", "documentation", "../windows-dependencies/x86/oggenc2.exe", "../windows-dependencies/x86/bootstrap.exe", find_sound_lib_datafiles(), find_accessible_output2_datafiles(), ("../windows-dependencies/msvc32", "."), ("../windows-dependencies/dictionaries", "lib/enchant/data/mingw32/share/enchant/hunspell")], include_files=["session.defaults", "cacert.pem", "app-configuration.defaults", "locales", "sounds", "documentation", "../windows-dependencies/x86/oggenc2.exe", "../windows-dependencies/x86/bootstrap.exe", find_sound_lib_datafiles(), find_accessible_output2_datafiles(), ("../windows-dependencies/msvc32", "."), ("../windows-dependencies/dictionaries", "lib/enchant/data/mingw32/share/enchant/hunspell")],
packages=["interactors", "presenters", "views", "wxUI"], packages=["interactors", "presenters", "views", "wxUI"],
) )
executables = [ executables = [
Executable('main.py', base=base, targetName="socializer") Executable('main.py', base=base, targetName="socializer")

View File

@ -18,72 +18,72 @@ from sound_lib import output, input
log = logging.getLogger("sound") log = logging.getLogger("sound")
def recode_audio(filename, quality=10): def recode_audio(filename, quality=10):
subprocess.call(r'"%s" --downmix -q %r "%s"' % (os.path.join(paths.app_path(), 'oggenc2.exe'), quality, filename)) subprocess.call(r'"%s" --downmix -q %r "%s"' % (os.path.join(paths.app_path(), 'oggenc2.exe'), quality, filename))
def get_recording(filename): def get_recording(filename):
# try: # try:
val = recording.WaveRecording(filename=filename) val = recording.WaveRecording(filename=filename)
# except sound_lib.main.BassError: # except sound_lib.main.BassError:
# sound_lib.input.Input() # sound_lib.input.Input()
# val = sound_lib.recording.WaveRecording(filename=filename) # val = sound_lib.recording.WaveRecording(filename=filename)
return val return val
class soundSystem(object): class soundSystem(object):
def check_soundpack(self): def check_soundpack(self):
""" Checks if the folder where live the current soundpack exists.""" """ Checks if the folder where live the current soundpack exists."""
self.soundpack_OK = False self.soundpack_OK = False
if os.path.exists(os.path.join(paths.sound_path(), self.config["current_soundpack"])): if os.path.exists(os.path.join(paths.sound_path(), self.config["current_soundpack"])):
self.path = os.path.join(paths.sound_path(), self.config["current_soundpack"]) self.path = os.path.join(paths.sound_path(), self.config["current_soundpack"])
self.soundpack_OK = True self.soundpack_OK = True
elif os.path.exists(os.path.join(paths.sound_path(), "default")): elif os.path.exists(os.path.join(paths.sound_path(), "default")):
log.error("The soundpack does not exist, using default...") log.error("The soundpack does not exist, using default...")
self.path = os.path.join(paths.sound_path(), "default") self.path = os.path.join(paths.sound_path(), "default")
self.soundpack_OK = True self.soundpack_OK = True
else: else:
log.error("The current soundpack could not be found and the default soundpack has been deleted, Socializer will not play sounds.") log.error("The current soundpack could not be found and the default soundpack has been deleted, Socializer will not play sounds.")
self.soundpack_OK = False self.soundpack_OK = False
def __init__(self, soundConfig): def __init__(self, soundConfig):
""" Sound Player.""" """ Sound Player."""
self.config = soundConfig self.config = soundConfig
# Set the output and input default devices. # Set the output and input default devices.
try: try:
self.output = output.Output() self.output = output.Output()
self.input = input.Input() self.input = input.Input()
except: except:
pass pass
# Try to use the selected device from the configuration. It can fail if the machine does not has a mic. # Try to use the selected device from the configuration. It can fail if the machine does not has a mic.
try: try:
log.debug("Setting input and output devices...") log.debug("Setting input and output devices...")
self.output.set_device(self.output.find_device_by_name(self.config["output_device"])) self.output.set_device(self.output.find_device_by_name(self.config["output_device"]))
self.input.set_device(self.input.find_device_by_name(self.config["input_device"])) self.input.set_device(self.input.find_device_by_name(self.config["input_device"]))
except: except:
log.error("Error in input or output devices, using defaults...") log.error("Error in input or output devices, using defaults...")
self.config["output_device"] = "Default" self.config["output_device"] = "Default"
self.config["input_device"] = "Default" self.config["input_device"] = "Default"
# Set proxy for audio. # Set proxy for audio.
if config.app["app-settings"]["use_proxy"]: if config.app["app-settings"]["use_proxy"]:
self.output.set_proxy(b"socializer:socializer@socializer.su:3128") self.output.set_proxy(b"socializer:socializer@socializer.su:3128")
self.files = [] self.files = []
self.cleaner = RepeatingTimer(60, self.clear_list) self.cleaner = RepeatingTimer(60, self.clear_list)
self.cleaner.start() self.cleaner.start()
self.check_soundpack() self.check_soundpack()
def clear_list(self): def clear_list(self):
if len(self.files) == 0: return if len(self.files) == 0: return
try: try:
for i in range(0, len(self.files)): for i in range(0, len(self.files)):
if self.files[i].is_playing == False: if self.files[i].is_playing == False:
self.files[i].free() self.files[i].free()
self.files.pop(i) self.files.pop(i)
except IndexError: except IndexError:
pass pass
def play(self, sound, argument=False): def play(self, sound, argument=False):
if self.soundpack_OK == False: return if self.soundpack_OK == False: return
if self.config["session_mute"] == True: return if self.config["session_mute"] == True: return
sound_object = sound_lib.stream.FileStream(file="%s/%s" % (self.path, sound)) sound_object = sound_lib.stream.FileStream(file="%s/%s" % (self.path, sound))
# sound_object.volume = self.config["volume"]/100 # sound_object.volume = self.config["volume"]/100
self.files.append(sound_object) self.files.append(sound_object)
sound_object.play() sound_object.play()

View File

@ -7,64 +7,64 @@ from interactors import audioRecorder as interactor
class audioRecorderTestCase(unittest.TestCase): class audioRecorderTestCase(unittest.TestCase):
""" Test both the presenter and interactor of the audio recorder feature. View stuff will be mocked.""" """ Test both the presenter and interactor of the audio recorder feature. View stuff will be mocked."""
@mock.patch("presenters.audioRecorder.sound_lib", esp_set=True) @mock.patch("presenters.audioRecorder.sound_lib", esp_set=True)
@mock.patch("presenters.base.pub", esp_set=True) @mock.patch("presenters.base.pub", esp_set=True)
@mock.patch("presenters.audioRecorder.tempfile", esp_set=True) @mock.patch("presenters.audioRecorder.tempfile", esp_set=True)
@mock.patch("presenters.audioRecorder.sound", esp_set=True) @mock.patch("presenters.audioRecorder.sound", esp_set=True)
@mock.patch("presenters.audioRecorder.output", esp_set=True) @mock.patch("presenters.audioRecorder.output", esp_set=True)
@mock.patch("presenters.audioRecorder.os", esp_set=True) @mock.patch("presenters.audioRecorder.os", esp_set=True)
def test_audiorecorder_presenter(self, os_mock, output_mock, sound_mock, tempfile_mock, pub_mock, soundlib_mock): def test_audiorecorder_presenter(self, os_mock, output_mock, sound_mock, tempfile_mock, pub_mock, soundlib_mock):
""" Test methods for audio recorder presenter. """ """ Test methods for audio recorder presenter. """
tempfile_mock.mktemp.return_value = "somefile.wav" tempfile_mock.mktemp.return_value = "somefile.wav"
sound_mock.get_recording.return_value = mock.MagicMock() sound_mock.get_recording.return_value = mock.MagicMock()
soundlib_mock.stream.fileStream.return_value = mock.MagicMock() soundlib_mock.stream.fileStream.return_value = mock.MagicMock()
view=mock.MagicMock(name="view") view=mock.MagicMock(name="view")
interactor_ = mock.MagicMock(name="interactor", esp_set=interactor.audioRecorderInteractor) interactor_ = mock.MagicMock(name="interactor", esp_set=interactor.audioRecorderInteractor)
presenter_ = presenter.audioRecorderPresenter(view=view, interactor=interactor_) presenter_ = presenter.audioRecorderPresenter(view=view, interactor=interactor_)
# Start sending events to the presenter and see its reactions. # Start sending events to the presenter and see its reactions.
presenter_.start_recording() presenter_.start_recording()
tempfile_mock.mktemp.assert_any_call(suffix=".wav") tempfile_mock.mktemp.assert_any_call(suffix=".wav")
sound_mock.get_recording.assert_any_call(presenter_.file) sound_mock.get_recording.assert_any_call(presenter_.file)
presenter_.recording.play.assert_any_call() presenter_.recording.play.assert_any_call()
pub_mock.sendMessage.assert_any_call("audiorecorder_set_label", control="record", label=_("&Stop")) pub_mock.sendMessage.assert_any_call("audiorecorder_set_label", control="record", label=_("&Stop"))
pub_mock.sendMessage.assert_any_call("audiorecorder_disable_control", control="ok") pub_mock.sendMessage.assert_any_call("audiorecorder_disable_control", control="ok")
presenter_.stop_recording() presenter_.stop_recording()
presenter_.recording.stop.assert_any_call() presenter_.recording.stop.assert_any_call()
presenter_.recording.free.assert_any_call() presenter_.recording.free.assert_any_call()
pub_mock.sendMessage.assert_any_call("audiorecorder_set_label", control="record", label=_("&Record")) pub_mock.sendMessage.assert_any_call("audiorecorder_set_label", control="record", label=_("&Record"))
pub_mock.sendMessage.assert_any_call("audiorecorder_disable_control", control="record") pub_mock.sendMessage.assert_any_call("audiorecorder_disable_control", control="record")
pub_mock.sendMessage.assert_any_call("audiorecorder_enable_control", control="play") pub_mock.sendMessage.assert_any_call("audiorecorder_enable_control", control="play")
pub_mock.sendMessage.assert_any_call("audiorecorder_enable_control", control="discard") pub_mock.sendMessage.assert_any_call("audiorecorder_enable_control", control="discard")
pub_mock.sendMessage.assert_any_call("audiorecorder_enable_control", control="ok") pub_mock.sendMessage.assert_any_call("audiorecorder_enable_control", control="ok")
pub_mock.sendMessage.assert_any_call("audiorecorder_focus_control", control="play") pub_mock.sendMessage.assert_any_call("audiorecorder_focus_control", control="play")
presenter_.discard_recording() presenter_.discard_recording()
self.assertTrue(presenter_.playing==None) self.assertTrue(presenter_.playing==None)
@mock.patch("interactors.audioRecorder.widgetUtils", esp_set=True) @mock.patch("interactors.audioRecorder.widgetUtils", esp_set=True)
def test_audiorecorder_interactor(self, widgetUtils_mock): def test_audiorecorder_interactor(self, widgetUtils_mock):
view=mock.MagicMock(name="view") view=mock.MagicMock(name="view")
interactor_ = interactor.audioRecorderInteractor() interactor_ = interactor.audioRecorderInteractor()
presenter_ = mock.MagicMock(name="Presenter", esp_set=presenter.audioRecorderPresenter) presenter_ = mock.MagicMock(name="Presenter", esp_set=presenter.audioRecorderPresenter)
interactor_.install(view=view, presenter=presenter_) interactor_.install(view=view, presenter=presenter_)
# Test if events have been connected to WX # Test if events have been connected to WX
widgetUtils_mock.connect_event.assert_any_call(view.play, widgetUtils_mock.BUTTON_PRESSED, interactor_.on_play) widgetUtils_mock.connect_event.assert_any_call(view.play, widgetUtils_mock.BUTTON_PRESSED, interactor_.on_play)
widgetUtils_mock.connect_event.assert_any_call(view.record, widgetUtils_mock.BUTTON_PRESSED, interactor_.on_record) widgetUtils_mock.connect_event.assert_any_call(view.record, widgetUtils_mock.BUTTON_PRESSED, interactor_.on_record)
widgetUtils_mock.connect_event.assert_any_call(view.discard, widgetUtils_mock.BUTTON_PRESSED, interactor_.on_discard) widgetUtils_mock.connect_event.assert_any_call(view.discard, widgetUtils_mock.BUTTON_PRESSED, interactor_.on_discard)
# Let's call some methods simulating user interaction. # Let's call some methods simulating user interaction.
interactor_.on_record() interactor_.on_record()
presenter_.toggle_recording.assert_called_with() presenter_.toggle_recording.assert_called_with()
interactor_.on_play() interactor_.on_play()
presenter_.play.assert_called_with() presenter_.play.assert_called_with()
# Let's simulate user response here # Let's simulate user response here
view.get_response.return_value = widgetUtils_mock.OK view.get_response.return_value = widgetUtils_mock.OK
interactor_.start() interactor_.start()
# this should call on_postprocess after receiving the OK signal. # this should call on_postprocess after receiving the OK signal.
presenter_.postprocess.assert_called_with() presenter_.postprocess.assert_called_with()
def setUp(self): def setUp(self):
languageHandler.setLanguage("en") languageHandler.setLanguage("en")
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

View File

@ -4,34 +4,34 @@ import mock
from interactors import base from interactors import base
class baseInteractorTestCase(unittest.TestCase): class baseInteractorTestCase(unittest.TestCase):
""" some tests for the base interactor implementation.""" """ some tests for the base interactor implementation."""
@mock.patch("interactors.base.pub", esp_set=True) @mock.patch("interactors.base.pub", esp_set=True)
def test_base_interactor(self, pub_mock): def test_base_interactor(self, pub_mock):
""" Test the base interactor class. """ """ Test the base interactor class. """
view=mock.MagicMock(name="view") view=mock.MagicMock(name="view")
interactor_ = base.baseInteractor() interactor_ = base.baseInteractor()
presenter_ = mock.MagicMock(name="Presenter") presenter_ = mock.MagicMock(name="Presenter")
interactor_.install(view=view, presenter=presenter_, modulename="base") interactor_.install(view=view, presenter=presenter_, modulename="base")
# Check if the interactor has called pubsub correctly. # Check if the interactor has called pubsub correctly.
pub_mock.subscribe.assert_any_call(interactor_.disable_control, "base_disable_control"), pub_mock.subscribe.assert_any_call(interactor_.disable_control, "base_disable_control"),
pub_mock.subscribe.assert_any_call(interactor_.enable_control, "base_enable_control"), pub_mock.subscribe.assert_any_call(interactor_.enable_control, "base_enable_control"),
pub_mock.subscribe.assert_any_call(interactor_.set_label, "base_set_label"), pub_mock.subscribe.assert_any_call(interactor_.set_label, "base_set_label"),
pub_mock.subscribe.assert_any_call(interactor_.focus_control, "base_focus_control") pub_mock.subscribe.assert_any_call(interactor_.focus_control, "base_focus_control")
# Now, simulate some event calls. # Now, simulate some event calls.
interactor_.disable_control(control="some_control") interactor_.disable_control(control="some_control")
view.disable.assert_called_with("some_control") view.disable.assert_called_with("some_control")
interactor_.enable_control(control="some_control") interactor_.enable_control(control="some_control")
view.enable.assert_called_with("some_control") view.enable.assert_called_with("some_control")
interactor_.set_label(control="some_control", label="label") interactor_.set_label(control="some_control", label="label")
view.set.assert_called_with("some_control", "label") view.set.assert_called_with("some_control", "label")
interactor_.focus_control(control="some_control") interactor_.focus_control(control="some_control")
view.some_control.SetFocus.assert_called_with() view.some_control.SetFocus.assert_called_with()
interactor_.uninstall() interactor_.uninstall()
pub_mock.unsubscribe.assert_any_call(interactor_.disable_control, "base_disable_control"), pub_mock.unsubscribe.assert_any_call(interactor_.disable_control, "base_disable_control"),
pub_mock.unsubscribe.assert_any_call(interactor_.enable_control, "base_enable_control"), pub_mock.unsubscribe.assert_any_call(interactor_.enable_control, "base_enable_control"),
pub_mock.unsubscribe.assert_any_call(interactor_.set_label, "base_set_label"), pub_mock.unsubscribe.assert_any_call(interactor_.set_label, "base_set_label"),
pub_mock.unsubscribe.assert_any_call(interactor_.focus_control, "base_focus_control") pub_mock.unsubscribe.assert_any_call(interactor_.focus_control, "base_focus_control")
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

View File

@ -7,22 +7,22 @@ from sessionmanager import renderers
class renderersTestCase(unittest.TestCase): class renderersTestCase(unittest.TestCase):
def setUp(self): def setUp(self):
languageHandler.setLanguage("en") languageHandler.setLanguage("en")
vk = testconfig.get_vk() vk = testconfig.get_vk()
self.vk = vk.get_api() self.vk = vk.get_api()
def test_render_person(self): def test_render_person(self):
""" Test the person renderer function.""" """ Test the person renderer function."""
user = self.vk.users.get(user_ids=1, fields="first_name, last_name, last_seen") user = self.vk.users.get(user_ids=1, fields="first_name, last_name, last_seen")
self.assertIsInstance(user, list) self.assertIsInstance(user, list)
self.assertEquals(len(user), 1) self.assertEquals(len(user), 1)
user = user[0] user = user[0]
rendered_object = renderers.render_person(user, user["last_seen"]) rendered_object = renderers.render_person(user, user["last_seen"])
self.assertIsInstance(rendered_object, list) self.assertIsInstance(rendered_object, list)
self.assertEquals(len(rendered_object), 2) self.assertEquals(len(rendered_object), 2)
self.assertIsInstance(rendered_object[0], str) self.assertIsInstance(rendered_object[0], str)
self.assertIsInstance(rendered_object[1], str) self.assertIsInstance(rendered_object[1], str)
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

View File

@ -4,14 +4,14 @@ import application
class py2exeTestCase(unittest.TestCase): class py2exeTestCase(unittest.TestCase):
@unittest.skipUnless(sys.version[0] == "2", "this only fails under Python 2") @unittest.skipUnless(sys.version[0] == "2", "this only fails under Python 2")
def test_application_not_unicode(self): def test_application_not_unicode(self):
""" Testing if some strings present in application have not changed to unicode. """ """ Testing if some strings present in application have not changed to unicode. """
self.assertIsInstance(application.name, str) self.assertIsInstance(application.name, str)
self.assertIsInstance(application.author, str) self.assertIsInstance(application.author, str)
self.assertIsInstance(application.authorEmail, str) self.assertIsInstance(application.authorEmail, str)
self.assertIsInstance(application.version, str) self.assertIsInstance(application.version, str)
self.assertIsInstance(application.url, str) self.assertIsInstance(application.url, str)
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

View File

@ -3,8 +3,8 @@ import os
from vk_api import VkApi from vk_api import VkApi
def get_vk(): def get_vk():
login = os.environ['LOGIN'] login = os.environ['LOGIN']
password = os.environ['PASSWORD'] password = os.environ['PASSWORD']
vk = VkApi(login, password) vk = VkApi(login, password)
vk.auth(token_only=True) vk.auth(token_only=True)
return vk return vk

View File

@ -3,10 +3,10 @@ import os.path
import platform import platform
def find_datafiles(): def find_datafiles():
system = platform.system() system = platform.system()
if system == 'Windows': if system == 'Windows':
file_ext = '*.exe' file_ext = '*.exe'
else: else:
file_ext = '*.sh' file_ext = '*.sh'
path = os.path.abspath(os.path.join(__path__[0], 'bootstrappers', file_ext)) path = os.path.abspath(os.path.join(__path__[0], 'bootstrappers', file_ext))
return [('', glob.glob(path))] return [('', glob.glob(path))]

View File

@ -11,123 +11,123 @@ import tempfile
import widgetUtils import widgetUtils
import webbrowser import webbrowser
try: try:
import czipfile as zipfile import czipfile as zipfile
except ImportError: except ImportError:
import zipfile import zipfile
from platform_utils import paths from platform_utils import paths
def perform_update(endpoint, current_version, update_type="stable", app_name='', password=None, update_available_callback=None, progress_callback=None, update_complete_callback=None): def perform_update(endpoint, current_version, update_type="stable", app_name='', password=None, update_available_callback=None, progress_callback=None, update_complete_callback=None):
requests_session = create_requests_session(app_name=app_name, version=current_version) requests_session = create_requests_session(app_name=app_name, version=current_version)
available_update = find_update(endpoint, requests_session=requests_session) available_update = find_update(endpoint, requests_session=requests_session)
if not available_update: if not available_update:
logger.debug("No update available") logger.debug("No update available")
return False return False
available_version, available_description, update_url = find_version_data(update_type, current_version, available_update) available_version, available_description, update_url = find_version_data(update_type, current_version, available_update)
if available_version == False: if available_version == False:
return False return False
logger.info("A new update is available. Version %s" % available_version) logger.info("A new update is available. Version %s" % available_version)
if callable(update_available_callback) and not update_available_callback(version=available_version, description=available_description): #update_available_callback should return a falsy value to stop the process if callable(update_available_callback) and not update_available_callback(version=available_version, description=available_description): #update_available_callback should return a falsy value to stop the process
logger.info("User canceled update.") logger.info("User canceled update.")
return return
base_path = tempfile.mkdtemp() base_path = tempfile.mkdtemp()
download_path = os.path.join(base_path, 'update.zip') download_path = os.path.join(base_path, 'update.zip')
update_path = os.path.join(base_path, 'update') update_path = os.path.join(base_path, 'update')
downloaded = download_update(update_url, download_path, requests_session=requests_session, progress_callback=progress_callback) downloaded = download_update(update_url, download_path, requests_session=requests_session, progress_callback=progress_callback)
extracted = extract_update(downloaded, update_path, password=password) extracted = extract_update(downloaded, update_path, password=password)
bootstrap_path = move_bootstrap(extracted) bootstrap_path = move_bootstrap(extracted)
execute_bootstrap(bootstrap_path, extracted) execute_bootstrap(bootstrap_path, extracted)
logger.info("Update prepared for installation.") logger.info("Update prepared for installation.")
if callable(update_complete_callback): if callable(update_complete_callback):
update_complete_callback() update_complete_callback()
def create_requests_session(app_name=None, version=None): def create_requests_session(app_name=None, version=None):
user_agent = '' user_agent = ''
session = requests.session() session = requests.session()
if app_name: if app_name:
user_agent = ' %s/%r' % (app_name, version) user_agent = ' %s/%r' % (app_name, version)
session.headers['User-Agent'] = session.headers['User-Agent'] + user_agent session.headers['User-Agent'] = session.headers['User-Agent'] + user_agent
return session return session
def find_update(endpoint, requests_session): def find_update(endpoint, requests_session):
response = requests_session.get(endpoint) response = requests_session.get(endpoint)
response.raise_for_status() response.raise_for_status()
content = response.json() content = response.json()
return content return content
def find_version_data(update_type, current_version, available_update): def find_version_data(update_type, current_version, available_update):
if update_type == "stable": if update_type == "stable":
available_version = float(available_update['current_version']) available_version = float(available_update['current_version'])
if not float(available_version) > float(current_version) or platform.system()+platform.architecture()[0][:2] not in available_update['downloads']: if not float(available_version) > float(current_version) or platform.system()+platform.architecture()[0][:2] not in available_update['downloads']:
logger.debug("No update for this architecture") logger.debug("No update for this architecture")
return (False, False, False) return (False, False, False)
available_description = available_update.get('description', None) available_description = available_update.get('description', None)
update_url = available_update ['downloads'][platform.system()+platform.architecture()[0][:2]] update_url = available_update ['downloads'][platform.system()+platform.architecture()[0][:2]]
return (available_version, available_description, update_url) return (available_version, available_description, update_url)
else: # Unstable versions, based in commits instead of version numbers. else: # Unstable versions, based in commits instead of version numbers.
available_version = available_update["current_version"] available_version = available_update["current_version"]
if available_version == current_version: if available_version == current_version:
return (False, False, False) return (False, False, False)
available_description = available_update["description"] available_description = available_update["description"]
update_url = available_update ['downloads'][platform.system()+platform.architecture()[0][:2]] update_url = available_update ['downloads'][platform.system()+platform.architecture()[0][:2]]
return (available_version, available_description, update_url) return (available_version, available_description, update_url)
def download_update(update_url, update_destination, requests_session, progress_callback=None, chunk_size=io.DEFAULT_BUFFER_SIZE): def download_update(update_url, update_destination, requests_session, progress_callback=None, chunk_size=io.DEFAULT_BUFFER_SIZE):
total_downloaded = total_size = 0 total_downloaded = total_size = 0
with io.open(update_destination, 'w+b') as outfile: with io.open(update_destination, 'w+b') as outfile:
download = requests_session.get(update_url, stream=True) download = requests_session.get(update_url, stream=True)
total_size = int(download.headers.get('content-length', 0)) total_size = int(download.headers.get('content-length', 0))
logger.debug("Total update size: %d" % total_size) logger.debug("Total update size: %d" % total_size)
download.raise_for_status() download.raise_for_status()
for chunk in download.iter_content(chunk_size): for chunk in download.iter_content(chunk_size):
outfile.write(chunk) outfile.write(chunk)
total_downloaded += len(chunk) total_downloaded += len(chunk)
if callable(progress_callback): if callable(progress_callback):
call_callback(progress_callback, total_downloaded, total_size) call_callback(progress_callback, total_downloaded, total_size)
logger.debug("Update downloaded") logger.debug("Update downloaded")
return update_destination return update_destination
def extract_update(update_archive, destination, password=None): def extract_update(update_archive, destination, password=None):
"""Given an update archive, extracts it. Returns the directory to which it has been extracted""" """Given an update archive, extracts it. Returns the directory to which it has been extracted"""
with contextlib.closing(zipfile.ZipFile(update_archive)) as archive: with contextlib.closing(zipfile.ZipFile(update_archive)) as archive:
if password: if password:
archive.setpassword(password) archive.setpassword(password)
archive.extractall(path=destination) archive.extractall(path=destination)
logger.debug("Update extracted") logger.debug("Update extracted")
return destination return destination
def move_bootstrap(extracted_path): def move_bootstrap(extracted_path):
working_path = os.path.abspath(os.path.join(extracted_path, '..')) working_path = os.path.abspath(os.path.join(extracted_path, '..'))
if platform.system() == 'Darwin': if platform.system() == 'Darwin':
extracted_path = os.path.join(extracted_path, 'Contents', 'Resources') extracted_path = os.path.join(extracted_path, 'Contents', 'Resources')
downloaded_bootstrap = os.path.join(extracted_path, bootstrap_name()) downloaded_bootstrap = os.path.join(extracted_path, bootstrap_name())
new_bootstrap_path = os.path.join(working_path, bootstrap_name()) new_bootstrap_path = os.path.join(working_path, bootstrap_name())
os.rename(downloaded_bootstrap, new_bootstrap_path) os.rename(downloaded_bootstrap, new_bootstrap_path)
return new_bootstrap_path return new_bootstrap_path
def execute_bootstrap(bootstrap_path, source_path): def execute_bootstrap(bootstrap_path, source_path):
arguments = r'"%s" "%s" "%s" "%s"' % (os.getpid(), source_path, paths.app_path(), paths.get_executable()) arguments = r'"%s" "%s" "%s" "%s"' % (os.getpid(), source_path, paths.app_path(), paths.get_executable())
if platform.system() == 'Windows': if platform.system() == 'Windows':
import win32api import win32api
win32api.ShellExecute(0, 'open', bootstrap_path, arguments, '', 5) win32api.ShellExecute(0, 'open', bootstrap_path, arguments, '', 5)
else: else:
import subprocess import subprocess
make_executable(bootstrap_path) make_executable(bootstrap_path)
subprocess.Popen(['%s %s' % (bootstrap_path, arguments)], shell=True) subprocess.Popen(['%s %s' % (bootstrap_path, arguments)], shell=True)
logger.info("Bootstrap executed") logger.info("Bootstrap executed")
def bootstrap_name(): def bootstrap_name():
if platform.system() == 'Windows': return 'bootstrap.exe' if platform.system() == 'Windows': return 'bootstrap.exe'
if platform.system() == 'Darwin': return 'bootstrap-mac.sh' if platform.system() == 'Darwin': return 'bootstrap-mac.sh'
return 'bootstrap-lin.sh' return 'bootstrap-lin.sh'
def make_executable(path): def make_executable(path):
import stat import stat
st = os.stat(path) st = os.stat(path)
os.chmod(path, st.st_mode | stat.S_IEXEC) os.chmod(path, st.st_mode | stat.S_IEXEC)
def call_callback(callback, *args, **kwargs): def call_callback(callback, *args, **kwargs):
# try: # try:
callback(*args, **kwargs) callback(*args, **kwargs)
# except: # except:
# logger.exception("Failed calling callback %r with args %r and kwargs %r" % (callback, args, kwargs)) # logger.exception("Failed calling callback %r with args %r and kwargs %r" % (callback, args, kwargs))

View File

@ -10,17 +10,17 @@ from .wxUpdater import *
logger = logging.getLogger("updater") logger = logging.getLogger("updater")
def do_update(update_type="stable"): def do_update(update_type="stable"):
# Updates cannot be performed in the source code version of Socializer. # Updates cannot be performed in the source code version of Socializer.
if hasattr(sys, "frozen") == False: if hasattr(sys, "frozen") == False:
return return
if update_type == "stable": if update_type == "stable":
endpoint = application.update_stable_url endpoint = application.update_stable_url
version = application.version version = application.version
else: else:
endpoint = application.update_next_url endpoint = application.update_next_url
version = application.update_next_version version = application.update_next_version
try: try:
return update.perform_update(endpoint=endpoint, current_version=version, app_name=application.name, update_type=update_type, update_available_callback=available_update_dialog, progress_callback=progress_callback, update_complete_callback=update_finished) return update.perform_update(endpoint=endpoint, current_version=version, app_name=application.name, update_type=update_type, update_available_callback=available_update_dialog, progress_callback=progress_callback, update_complete_callback=update_finished)
except ConnectionError: except ConnectionError:
logger.exception("Update failed.") logger.exception("Update failed.")
output.speak("An exception occurred while attempting to update " + application.name + ". If this message persists, contact the " + application.name + " developers. More information about the exception has been written to the error log.",True) output.speak("An exception occurred while attempting to update " + application.name + ". If this message persists, contact the " + application.name + " developers. More information about the exception has been written to the error log.",True)

View File

@ -2,42 +2,42 @@
from __future__ import unicode_literals from __future__ import unicode_literals
def convert_bytes(n): def convert_bytes(n):
K, M, G, T, P = 1 << 10, 1 << 20, 1 << 30, 1 << 40, 1 << 50 K, M, G, T, P = 1 << 10, 1 << 20, 1 << 30, 1 << 40, 1 << 50
if n >= P: if n >= P:
return '%.2fPb' % (float(n) / T) return '%.2fPb' % (float(n) / T)
elif n >= T: elif n >= T:
return '%.2fTb' % (float(n) / T) return '%.2fTb' % (float(n) / T)
elif n >= G: elif n >= G:
return '%.2fGb' % (float(n) / G) return '%.2fGb' % (float(n) / G)
elif n >= M: elif n >= M:
return '%.2fMb' % (float(n) / M) return '%.2fMb' % (float(n) / M)
elif n >= K: elif n >= K:
return '%.2fKb' % (float(n) / K) return '%.2fKb' % (float(n) / K)
else: else:
return '%d' % n return '%d' % n
def seconds_to_string(seconds, precision=0): def seconds_to_string(seconds, precision=0):
day = seconds // 86400 day = seconds // 86400
hour = seconds // 3600 hour = seconds // 3600
min = (seconds // 60) % 60 min = (seconds // 60) % 60
sec = seconds - (hour * 3600) - (min * 60) sec = seconds - (hour * 3600) - (min * 60)
sec_spec = "." + str(precision) + "f" sec_spec = "." + str(precision) + "f"
sec_string = sec.__format__(sec_spec) sec_string = sec.__format__(sec_spec)
string = "" string = ""
if day == 1: if day == 1:
string += _("%d day, ") % day string += _("%d day, ") % day
elif day >= 2: elif day >= 2:
string += _("%d days, ") % day string += _("%d days, ") % day
if (hour == 1): if (hour == 1):
string += _("%d hour, ") % hour string += _("%d hour, ") % hour
elif (hour >= 2): elif (hour >= 2):
string += _("%d hours, ") % hour string += _("%d hours, ") % hour
if (min == 1): if (min == 1):
string += _("%d minute, ") % min string += _("%d minute, ") % min
elif (min >= 2): elif (min >= 2):
string += _("%d minutes, ") % min string += _("%d minutes, ") % min
if sec >= 0 and sec <= 2: if sec >= 0 and sec <= 2:
string += _("%s second") % sec_string string += _("%s second") % sec_string
else: else:
string += _("%s seconds") % sec_string string += _("%s seconds") % sec_string
return string return string

View File

@ -8,27 +8,27 @@ from . import utils
progress_dialog = None progress_dialog = None
def available_update_dialog(version, description): def available_update_dialog(version, description):
dialog = wx.MessageDialog(None, _("There's a new {app_name} version available. Would you like to download it now?\n\n {app_name} version: {app_version}\n\nChanges:\n{changes}").format(app_name=application.name, app_version=version, changes=description), _("New version for %s") % application.name, style=wx.YES|wx.NO|wx.ICON_WARNING) dialog = wx.MessageDialog(None, _("There's a new {app_name} version available. Would you like to download it now?\n\n {app_name} version: {app_version}\n\nChanges:\n{changes}").format(app_name=application.name, app_version=version, changes=description), _("New version for %s") % application.name, style=wx.YES|wx.NO|wx.ICON_WARNING)
if dialog.ShowModal() == wx.ID_YES: if dialog.ShowModal() == wx.ID_YES:
return True return True
else: else:
return False return False
def create_progress_dialog(): def create_progress_dialog():
return wx.ProgressDialog(_("Download in Progress"), _("Downloading the new version..."), parent=None, maximum=100) return wx.ProgressDialog(_("Download in Progress"), _("Downloading the new version..."), parent=None, maximum=100)
def progress_callback(total_downloaded, total_size): def progress_callback(total_downloaded, total_size):
wx.CallAfter(_progress_callback, total_downloaded, total_size) wx.CallAfter(_progress_callback, total_downloaded, total_size)
def _progress_callback(total_downloaded, total_size): def _progress_callback(total_downloaded, total_size):
global progress_dialog global progress_dialog
if progress_dialog == None: if progress_dialog == None:
progress_dialog = create_progress_dialog() progress_dialog = create_progress_dialog()
progress_dialog.Show() progress_dialog.Show()
if total_downloaded == total_size: if total_downloaded == total_size:
progress_dialog.Destroy() progress_dialog.Destroy()
else: else:
progress_dialog.Update((total_downloaded*100)/total_size, _("Updating... {total_transferred} of {total_size}").format(total_transferred=utils.convert_bytes(total_downloaded), total_size=utils.convert_bytes(total_size))) progress_dialog.Update((total_downloaded*100)/total_size, _("Updating... {total_transferred} of {total_size}").format(total_transferred=utils.convert_bytes(total_downloaded), total_size=utils.convert_bytes(total_size)))
def update_finished(): def update_finished():
return wx.MessageDialog(None, _("The update has been downloaded and installed successfully. Press OK to continue."), _("Done!")).ShowModal() return wx.MessageDialog(None, _("The update has been downloaded and installed successfully. Press OK to continue."), _("Done!")).ShowModal()

View File

@ -1,7 +1,7 @@
""" Views package for socializer. A view is the Graphical user interface in the application. This package includes everything needed to render a window. """ Views package for socializer. A view is the Graphical user interface in the application. This package includes everything needed to render a window.
No other functionality is assumed in this package. No other functionality is assumed in this package.
All modules from here should be used via an interactor (read description of the interactors package). All modules from here should be used via an interactor (read description of the interactors package).
Interactors will be routing user events (like buttons pressed, menus activated and so on) to presenter functions. Interactors will be routing user events (like buttons pressed, menus activated and so on) to presenter functions.
""" """
from .dialogs.attach import * from .dialogs.attach import *
from .dialogs.audioRecorder import * from .dialogs.audioRecorder import *

View File

@ -4,65 +4,65 @@ import wx
import widgetUtils import widgetUtils
class attachDialog(widgetUtils.BaseDialog): class attachDialog(widgetUtils.BaseDialog):
def __init__(self, voice_messages=False): def __init__(self, voice_messages=False):
super(attachDialog, self).__init__(None, title=_("Add an attachment")) super(attachDialog, self).__init__(None, title=_("Add an attachment"))
panel = wx.Panel(self) panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
lbl1 = wx.StaticText(panel, wx.NewId(), _("Attachments")) lbl1 = wx.StaticText(panel, wx.NewId(), _("Attachments"))
self.attachments = widgetUtils.list(panel, _("Type"), _("Title"), style=wx.LC_REPORT) self.attachments = widgetUtils.list(panel, _("Type"), _("Title"), style=wx.LC_REPORT)
box = wx.BoxSizer(wx.HORIZONTAL) box = wx.BoxSizer(wx.HORIZONTAL)
box.Add(lbl1, 0, wx.ALL, 5) box.Add(lbl1, 0, wx.ALL, 5)
box.Add(self.attachments.list, 0, wx.ALL, 5) box.Add(self.attachments.list, 0, wx.ALL, 5)
sizer.Add(box, 0, wx.ALL, 5) sizer.Add(box, 0, wx.ALL, 5)
static = wx.StaticBoxSizer(parent=panel, orient=wx.HORIZONTAL, label=_("Add attachments")) static = wx.StaticBoxSizer(parent=panel, orient=wx.HORIZONTAL, label=_("Add attachments"))
self.photo = wx.Button(static.GetStaticBox(), wx.NewId(), _("&Photo")) self.photo = wx.Button(static.GetStaticBox(), wx.NewId(), _("&Photo"))
self.audio = wx.Button(static.GetStaticBox(), wx.NewId(), _("Audio file")) self.audio = wx.Button(static.GetStaticBox(), wx.NewId(), _("Audio file"))
self.document = wx.Button(static.GetStaticBox(), wx.NewId(), _("Document")) self.document = wx.Button(static.GetStaticBox(), wx.NewId(), _("Document"))
if voice_messages: if voice_messages:
self.voice_message = wx.Button(static.GetStaticBox(), wx.NewId(), _("Voice message")) self.voice_message = wx.Button(static.GetStaticBox(), wx.NewId(), _("Voice message"))
self.remove = wx.Button(static.GetStaticBox(), wx.NewId(), _("Remove attachment")) self.remove = wx.Button(static.GetStaticBox(), wx.NewId(), _("Remove attachment"))
self.remove.Enable(False) self.remove.Enable(False)
static.Add(self.photo, 0, wx.ALL, 5) static.Add(self.photo, 0, wx.ALL, 5)
static.Add(self.audio, 0, wx.ALL, 5) static.Add(self.audio, 0, wx.ALL, 5)
static.Add(self.document, 0, wx.ALL, 5) static.Add(self.document, 0, wx.ALL, 5)
if voice_messages: if voice_messages:
static.Add(self.voice_message, 0, wx.ALL, 5) static.Add(self.voice_message, 0, wx.ALL, 5)
sizer.Add(static, 0, wx.ALL, 5) sizer.Add(static, 0, wx.ALL, 5)
ok = wx.Button(panel, wx.ID_OK) ok = wx.Button(panel, wx.ID_OK)
ok.SetDefault() ok.SetDefault()
cancelBtn = wx.Button(panel, wx.ID_CANCEL) cancelBtn = wx.Button(panel, wx.ID_CANCEL)
btnSizer = wx.BoxSizer() btnSizer = wx.BoxSizer()
btnSizer.Add(ok, 0, wx.ALL, 5) btnSizer.Add(ok, 0, wx.ALL, 5)
btnSizer.Add(cancelBtn, 0, wx.ALL, 5) btnSizer.Add(cancelBtn, 0, wx.ALL, 5)
sizer.Add(btnSizer, 0, wx.ALL, 5) sizer.Add(btnSizer, 0, wx.ALL, 5)
panel.SetSizer(sizer) panel.SetSizer(sizer)
self.SetClientSize(sizer.CalcMin()) self.SetClientSize(sizer.CalcMin())
def get_image(self): def get_image(self):
openFileDialog = wx.FileDialog(self, _("Select the picture to be uploaded"), "", "", _("Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif"), wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) openFileDialog = wx.FileDialog(self, _("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: if openFileDialog.ShowModal() == wx.ID_CANCEL:
return (None, None) return (None, None)
dsc = self.ask_description() dsc = self.ask_description()
return (openFileDialog.GetPath(), dsc) return (openFileDialog.GetPath(), dsc)
def ask_description(self): def ask_description(self):
dlg = wx.TextEntryDialog(self, _("please provide a description"), _("Description")) dlg = wx.TextEntryDialog(self, _("please provide a description"), _("Description"))
dlg.ShowModal() dlg.ShowModal()
result = dlg.GetValue() result = dlg.GetValue()
dlg.Destroy() dlg.Destroy()
return result return result
def get_audio(self): def get_audio(self):
openFileDialog = wx.FileDialog(self, _("Select the audio file to be uploaded"), "", "", _("Audio files (*.mp3)|*.mp3"), wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) openFileDialog = wx.FileDialog(self, _("Select the audio file to be uploaded"), "", "", _("Audio files (*.mp3)|*.mp3"), wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)
if openFileDialog.ShowModal() == wx.ID_CANCEL: if openFileDialog.ShowModal() == wx.ID_CANCEL:
return None return None
return openFileDialog.GetPath() return openFileDialog.GetPath()
def get_document(self): def get_document(self):
openFileDialog = wx.FileDialog(self, _("Select the file to be uploaded. All extensions are allowed except .mp3 and .exe."), "", "", _("All files (*.*)|*.*"), wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) openFileDialog = wx.FileDialog(self, _("Select the file to be uploaded. All extensions are allowed except .mp3 and .exe."), "", "", _("All files (*.*)|*.*"), wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)
if openFileDialog.ShowModal() == wx.ID_CANCEL: if openFileDialog.ShowModal() == wx.ID_CANCEL:
return None return None
return openFileDialog.GetPath() return openFileDialog.GetPath()
def invalid_attachment(self): def invalid_attachment(self):
return wx.MessageDialog(None, _("The file you are trying to upload contains an extension that is not allowed by VK."), _("Error"), style=wx.ICON_ERROR).ShowModal() return wx.MessageDialog(None, _("The file you are trying to upload contains an extension that is not allowed by VK."), _("Error"), style=wx.ICON_ERROR).ShowModal()

View File

@ -4,33 +4,33 @@ import wx
import widgetUtils import widgetUtils
class audioRecorderDialog(widgetUtils.BaseDialog): class audioRecorderDialog(widgetUtils.BaseDialog):
def __init__(self): def __init__(self):
super(audioRecorderDialog, self).__init__(None, title=_("Record voice message")) super(audioRecorderDialog, self).__init__(None, title=_("Record voice message"))
panel = wx.Panel(self) panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
self.play = wx.Button(panel, -1, _("&Play")) self.play = wx.Button(panel, -1, _("&Play"))
self.play.Disable() self.play.Disable()
self.record = wx.Button(panel, -1, _("&Record")) self.record = wx.Button(panel, -1, _("&Record"))
self.record.SetFocus() self.record.SetFocus()
self.discard = wx.Button(panel, -1, _("&Discard")) self.discard = wx.Button(panel, -1, _("&Discard"))
self.discard.Disable() self.discard.Disable()
self.ok = wx.Button(panel, wx.ID_OK, _("&Add")) self.ok = wx.Button(panel, wx.ID_OK, _("&Add"))
cancel = wx.Button(panel, wx.ID_CANCEL, _("&Cancel")) cancel = wx.Button(panel, wx.ID_CANCEL, _("&Cancel"))
btnSizer = wx.BoxSizer(wx.HORIZONTAL) btnSizer = wx.BoxSizer(wx.HORIZONTAL)
btnSizer2 = wx.BoxSizer(wx.HORIZONTAL) btnSizer2 = wx.BoxSizer(wx.HORIZONTAL)
btnSizer.Add(self.play, 0, wx.ALL, 5) btnSizer.Add(self.play, 0, wx.ALL, 5)
btnSizer.Add(self.record, 0, wx.ALL, 5) btnSizer.Add(self.record, 0, wx.ALL, 5)
btnSizer2.Add(self.ok, 0, wx.ALL, 5) btnSizer2.Add(self.ok, 0, wx.ALL, 5)
btnSizer2.Add(cancel, 0, wx.ALL, 5) btnSizer2.Add(cancel, 0, wx.ALL, 5)
sizer.Add(btnSizer, 0, wx.ALL, 5) sizer.Add(btnSizer, 0, wx.ALL, 5)
sizer.Add(btnSizer2, 0, wx.ALL, 5) sizer.Add(btnSizer2, 0, wx.ALL, 5)
panel.SetSizer(sizer) panel.SetSizer(sizer)
self.SetClientSize(sizer.CalcMin()) self.SetClientSize(sizer.CalcMin())
def enable_control(self, control): def enable_control(self, control):
if hasattr(self, control): if hasattr(self, control):
getattr(self, control).Enable() getattr(self, control).Enable()
def disable_control(self, control): def disable_control(self, control):
if hasattr(self, control): if hasattr(self, control):
getattr(self, control).Disable() getattr(self, control).Disable()

View File

@ -3,17 +3,17 @@ import wx
import widgetUtils import widgetUtils
class blacklistDialog(widgetUtils.BaseDialog): class blacklistDialog(widgetUtils.BaseDialog):
def __init__(self): def __init__(self):
super(blacklistDialog, self).__init__(parent=None, title=_("blacklist")) super(blacklistDialog, self).__init__(parent=None, title=_("blacklist"))
panel = wx.Panel(self) panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
box1 = wx.StaticBoxSizer(parent=panel, orient=wx.HORIZONTAL, label=_("blocked users")) box1 = wx.StaticBoxSizer(parent=panel, orient=wx.HORIZONTAL, label=_("blocked users"))
self.persons = widgetUtils.list(panel, _("User"), style=wx.LC_REPORT) self.persons = widgetUtils.list(panel, _("User"), style=wx.LC_REPORT)
box1.Add(self.persons.list, 0, wx.ALL, 5) box1.Add(self.persons.list, 0, wx.ALL, 5)
sizer.Add(box1, 0, wx.ALL, 5) sizer.Add(box1, 0, wx.ALL, 5)
self.unblock = wx.Button(panel, wx.NewId(), _("Unblock")) self.unblock = wx.Button(panel, wx.NewId(), _("Unblock"))
sizer.Add(self.unblock, 0, wx.ALL, 5) sizer.Add(self.unblock, 0, wx.ALL, 5)
close = wx.Button(panel, wx.ID_CANCEL, _("Close")) close = wx.Button(panel, wx.ID_CANCEL, _("Close"))
sizer.Add(close, 0, wx.ALL, 5) sizer.Add(close, 0, wx.ALL, 5)
panel.SetSizer(sizer) panel.SetSizer(sizer)
self.SetClientSize(sizer.CalcMin()) self.SetClientSize(sizer.CalcMin())

View File

@ -4,179 +4,179 @@ import wx
import widgetUtils import widgetUtils
class general(wx.Panel, widgetUtils.BaseDialog): class general(wx.Panel, widgetUtils.BaseDialog):
def __init__(self, panel, languages): def __init__(self, panel, languages):
super(general, self).__init__(panel) super(general, self).__init__(panel)
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
langBox = wx.StaticBoxSizer(parent=self, orient=wx.HORIZONTAL, label=_("Language")) langBox = wx.StaticBoxSizer(parent=self, orient=wx.HORIZONTAL, label=_("Language"))
self.language = wx.ListBox(langBox.GetStaticBox(), wx.NewId(), choices=languages) self.language = wx.ListBox(langBox.GetStaticBox(), wx.NewId(), choices=languages)
self.language.SetSize(self.language.GetBestSize()) self.language.SetSize(self.language.GetBestSize())
langBox.Add(self.language, 0, wx.ALL, 5) langBox.Add(self.language, 0, wx.ALL, 5)
sizer.Add(langBox, 0, wx.ALL, 5) sizer.Add(langBox, 0, wx.ALL, 5)
self.load_images = wx.CheckBox(self, wx.NewId(), _("Load images in posts")) self.load_images = wx.CheckBox(self, wx.NewId(), _("Load images in posts"))
sizer.Add(self.load_images, 0, wx.ALL, 5) sizer.Add(self.load_images, 0, wx.ALL, 5)
self.use_proxy = wx.CheckBox(self, wx.NewId(), _("Use proxy")) self.use_proxy = wx.CheckBox(self, wx.NewId(), _("Use proxy"))
sizer.Add(self.use_proxy, 0, wx.ALL, 5) sizer.Add(self.use_proxy, 0, wx.ALL, 5)
self.debug_logging = wx.CheckBox(self, wx.NewId(), _("Enable debug logging (useful for reporting errors)")) self.debug_logging = wx.CheckBox(self, wx.NewId(), _("Enable debug logging (useful for reporting errors)"))
sizer.Add(self.debug_logging, 0, wx.ALL, 5) sizer.Add(self.debug_logging, 0, wx.ALL, 5)
lbl4 = wx.StaticText(self, wx.NewId(), _("Update channel")) lbl4 = wx.StaticText(self, wx.NewId(), _("Update channel"))
self.update_channel = wx.ComboBox(self, wx.NewId(), choices=[_("Stable"), _("Alpha")], value=_("Native"), style=wx.CB_READONLY) self.update_channel = wx.ComboBox(self, wx.NewId(), choices=[_("Stable"), _("Alpha")], value=_("Native"), style=wx.CB_READONLY)
box4 = wx.BoxSizer(wx.HORIZONTAL) box4 = wx.BoxSizer(wx.HORIZONTAL)
box4.Add(lbl4, 0, wx.ALL, 5) box4.Add(lbl4, 0, wx.ALL, 5)
box4.Add(self.update_channel, 0, wx.ALL, 5) box4.Add(self.update_channel, 0, wx.ALL, 5)
sizer.Add(box4, 0, wx.ALL, 5) sizer.Add(box4, 0, wx.ALL, 5)
self.SetSizer(sizer) self.SetSizer(sizer)
class buffers(wx.Panel, widgetUtils.BaseDialog): class buffers(wx.Panel, widgetUtils.BaseDialog):
def __init__(self, panel): def __init__(self, panel):
super(buffers, self).__init__(panel) super(buffers, self).__init__(panel)
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
lbl1 = wx.StaticText(self, wx.NewId(), _("Number of items to load for newsfeed and wall buffers (maximun 100)")) lbl1 = wx.StaticText(self, wx.NewId(), _("Number of items to load for newsfeed and wall buffers (maximun 100)"))
self.wall_buffer_count = wx.SpinCtrl(self, wx.NewId()) self.wall_buffer_count = wx.SpinCtrl(self, wx.NewId())
self.wall_buffer_count.SetRange(1, 100) self.wall_buffer_count.SetRange(1, 100)
box1 = wx.BoxSizer(wx.HORIZONTAL) box1 = wx.BoxSizer(wx.HORIZONTAL)
box1.Add(lbl1, 0, wx.ALL, 5) box1.Add(lbl1, 0, wx.ALL, 5)
box1.Add(self.wall_buffer_count, 0, wx.ALL, 5) box1.Add(self.wall_buffer_count, 0, wx.ALL, 5)
sizer.Add(box1, 0, wx.ALL, 5) sizer.Add(box1, 0, wx.ALL, 5)
lbl3 = wx.StaticText(self, wx.NewId(), _("Number of items to load in video buffers (maximun 200)")) lbl3 = wx.StaticText(self, wx.NewId(), _("Number of items to load in video buffers (maximun 200)"))
self.video_buffers_count = wx.SpinCtrl(self, wx.NewId()) self.video_buffers_count = wx.SpinCtrl(self, wx.NewId())
self.video_buffers_count.SetRange(1, 200) self.video_buffers_count.SetRange(1, 200)
box3 = wx.BoxSizer(wx.HORIZONTAL) box3 = wx.BoxSizer(wx.HORIZONTAL)
box3.Add(lbl3, 0, wx.ALL, 5) box3.Add(lbl3, 0, wx.ALL, 5)
box3.Add(self.video_buffers_count, 0, wx.ALL, 5) box3.Add(self.video_buffers_count, 0, wx.ALL, 5)
sizer.Add(box3, 0, wx.ALL, 5) sizer.Add(box3, 0, wx.ALL, 5)
lbl4 = wx.StaticText(self, wx.NewId(), _("Number of items to load in conversation buffers (maximun 200)")) lbl4 = wx.StaticText(self, wx.NewId(), _("Number of items to load in conversation buffers (maximun 200)"))
self.chat_buffers_count = wx.SpinCtrl(self, wx.NewId()) self.chat_buffers_count = wx.SpinCtrl(self, wx.NewId())
self.chat_buffers_count.SetRange(1, 200) self.chat_buffers_count.SetRange(1, 200)
box4 = wx.BoxSizer(wx.HORIZONTAL) box4 = wx.BoxSizer(wx.HORIZONTAL)
box4.Add(lbl4, 0, wx.ALL, 5) box4.Add(lbl4, 0, wx.ALL, 5)
box4.Add(self.chat_buffers_count, 0, wx.ALL, 5) box4.Add(self.chat_buffers_count, 0, wx.ALL, 5)
sizer.Add(box4, 0, wx.ALL, 5) sizer.Add(box4, 0, wx.ALL, 5)
self.SetSizer(sizer) self.SetSizer(sizer)
class chat(wx.Panel, widgetUtils.BaseDialog): class chat(wx.Panel, widgetUtils.BaseDialog):
def __init__(self, panel): def __init__(self, panel):
super(chat, self).__init__(panel) super(chat, self).__init__(panel)
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
self.notify_online = wx.CheckBox(self, wx.NewId(), _("Show notifications when users are online")) self.notify_online = wx.CheckBox(self, wx.NewId(), _("Show notifications when users are online"))
sizer.Add(self.notify_online, 0, wx.ALL, 5) sizer.Add(self.notify_online, 0, wx.ALL, 5)
self.notify_offline = wx.CheckBox(self, wx.NewId(), _("Show notifications when users are offline")) self.notify_offline = wx.CheckBox(self, wx.NewId(), _("Show notifications when users are offline"))
sizer.Add(self.notify_offline, 0, wx.ALL, 5) sizer.Add(self.notify_offline, 0, wx.ALL, 5)
lbl = wx.StaticText(self, wx.NewId(), _("Notification type")) lbl = wx.StaticText(self, wx.NewId(), _("Notification type"))
self.notifications = wx.ComboBox(self, wx.NewId(), choices=[_("Native"), _("Custom"),], value=_("Native"), style=wx.CB_READONLY) self.notifications = wx.ComboBox(self, wx.NewId(), choices=[_("Native"), _("Custom"),], value=_("Native"), style=wx.CB_READONLY)
nbox = wx.BoxSizer(wx.HORIZONTAL) nbox = wx.BoxSizer(wx.HORIZONTAL)
nbox.Add(lbl, 0, wx.ALL, 5) nbox.Add(lbl, 0, wx.ALL, 5)
nbox.Add(self.notifications, 0, wx.ALL, 5) nbox.Add(self.notifications, 0, wx.ALL, 5)
sizer.Add(nbox, 0, wx.ALL, 5) sizer.Add(nbox, 0, wx.ALL, 5)
self.SetSizer(sizer) self.SetSizer(sizer)
class loadAtStartup(wx.Panel, widgetUtils.BaseDialog): class loadAtStartup(wx.Panel, widgetUtils.BaseDialog):
def __init__(self, panel): def __init__(self, panel):
super(loadAtStartup, self).__init__(panel) super(loadAtStartup, self).__init__(panel)
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
self.audio_albums = wx.CheckBox(self, wx.NewId(), _("Create buffers for audio albums at startup")) self.audio_albums = wx.CheckBox(self, wx.NewId(), _("Create buffers for audio albums at startup"))
sizer.Add(self.audio_albums, 0, wx.ALL, 5) sizer.Add(self.audio_albums, 0, wx.ALL, 5)
self.video_albums = wx.CheckBox(self, wx.NewId(), _("Create buffers for video albums at startup")) self.video_albums = wx.CheckBox(self, wx.NewId(), _("Create buffers for video albums at startup"))
sizer.Add(self.video_albums, 0, wx.ALL, 5) sizer.Add(self.video_albums, 0, wx.ALL, 5)
self.communities = wx.CheckBox(self, wx.NewId(), _("Create buffers for communities and public pages at startup")) self.communities = wx.CheckBox(self, wx.NewId(), _("Create buffers for communities and public pages at startup"))
sizer.Add(self.communities, 0, wx.ALL, 5) sizer.Add(self.communities, 0, wx.ALL, 5)
self.SetSizer(sizer) self.SetSizer(sizer)
class sound(wx.Panel, widgetUtils.BaseDialog): class sound(wx.Panel, widgetUtils.BaseDialog):
def __init__(self, panel, input_devices, output_devices, soundpacks): def __init__(self, panel, input_devices, output_devices, soundpacks):
super(sound, self).__init__(panel) super(sound, self).__init__(panel)
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
output_label = wx.StaticText(self, wx.NewId(), _("Output device")) output_label = wx.StaticText(self, wx.NewId(), _("Output device"))
self.output = wx.ComboBox(self, wx.NewId(), choices=output_devices, style=wx.CB_READONLY) self.output = wx.ComboBox(self, wx.NewId(), choices=output_devices, style=wx.CB_READONLY)
self.output.SetSize(self.output.GetBestSize()) self.output.SetSize(self.output.GetBestSize())
outputBox = wx.BoxSizer(wx.HORIZONTAL) outputBox = wx.BoxSizer(wx.HORIZONTAL)
outputBox.Add(output_label, 0, wx.ALL, 5) outputBox.Add(output_label, 0, wx.ALL, 5)
outputBox.Add(self.output, 0, wx.ALL, 5) outputBox.Add(self.output, 0, wx.ALL, 5)
sizer.Add(outputBox, 0, wx.ALL, 5) sizer.Add(outputBox, 0, wx.ALL, 5)
input_label = wx.StaticText(self, wx.NewId(), _("Input device")) input_label = wx.StaticText(self, wx.NewId(), _("Input device"))
self.input = wx.ComboBox(self, wx.NewId(), choices=input_devices, style=wx.CB_READONLY) self.input = wx.ComboBox(self, wx.NewId(), choices=input_devices, style=wx.CB_READONLY)
self.input.SetSize(self.input.GetBestSize()) self.input.SetSize(self.input.GetBestSize())
inputBox = wx.BoxSizer(wx.HORIZONTAL) inputBox = wx.BoxSizer(wx.HORIZONTAL)
inputBox.Add(input_label, 0, wx.ALL, 5) inputBox.Add(input_label, 0, wx.ALL, 5)
inputBox.Add(self.input, 0, wx.ALL, 5) inputBox.Add(self.input, 0, wx.ALL, 5)
sizer.Add(inputBox, 0, wx.ALL, 5) sizer.Add(inputBox, 0, wx.ALL, 5)
# soundBox = wx.BoxSizer(wx.VERTICAL) # soundBox = wx.BoxSizer(wx.VERTICAL)
# soundpack_label = wx.StaticText(self, wx.NewId(), _(u"Sound pack")) # soundpack_label = wx.StaticText(self, wx.NewId(), _(u"Sound pack"))
# self.soundpack = wx.ComboBox(self, -1, choices=soundpacks, style=wx.CB_READONLY) # self.soundpack = wx.ComboBox(self, -1, choices=soundpacks, style=wx.CB_READONLY)
# self.soundpack.SetSize(self.soundpack.GetBestSize()) # self.soundpack.SetSize(self.soundpack.GetBestSize())
# soundBox.Add(soundpack_label, 0, wx.ALL, 5) # soundBox.Add(soundpack_label, 0, wx.ALL, 5)
# soundBox.Add(self.soundpack, 0, wx.ALL, 5) # soundBox.Add(self.soundpack, 0, wx.ALL, 5)
# sizer.Add(soundBox, 0, wx.ALL, 5) # sizer.Add(soundBox, 0, wx.ALL, 5)
self.SetSizer(sizer) self.SetSizer(sizer)
def on_keypress(self, event, *args, **kwargs): def on_keypress(self, event, *args, **kwargs):
""" Invert movement of up and down arrow keys when dealing with a wX Slider. """ Invert movement of up and down arrow keys when dealing with a wX Slider.
See https://github.com/manuelcortez/TWBlue/issues/261 See https://github.com/manuelcortez/TWBlue/issues/261
and http://trac.wxwidgets.org/ticket/2068 and http://trac.wxwidgets.org/ticket/2068
""" """
keycode = event.GetKeyCode() keycode = event.GetKeyCode()
if keycode == wx.WXK_UP: if keycode == wx.WXK_UP:
return self.volumeCtrl.SetValue(self.volumeCtrl.GetValue()+1) return self.volumeCtrl.SetValue(self.volumeCtrl.GetValue()+1)
elif keycode == wx.WXK_DOWN: elif keycode == wx.WXK_DOWN:
return self.volumeCtrl.SetValue(self.volumeCtrl.GetValue()-1) return self.volumeCtrl.SetValue(self.volumeCtrl.GetValue()-1)
event.Skip() event.Skip()
def get(self, control): def get(self, control):
return getattr(self, control).GetStringSelection() return getattr(self, control).GetStringSelection()
class configurationDialog(widgetUtils.BaseDialog): class configurationDialog(widgetUtils.BaseDialog):
def __init__(self, title): def __init__(self, title):
super(configurationDialog, self).__init__(None, -1, title=title) super(configurationDialog, self).__init__(None, -1, title=title)
self.panel = wx.Panel(self) self.panel = wx.Panel(self)
self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer = wx.BoxSizer(wx.VERTICAL)
self.notebook = wx.Notebook(self.panel) self.notebook = wx.Notebook(self.panel)
def create_general(self, languages): def create_general(self, languages):
self.general = general(self.notebook, languages) self.general = general(self.notebook, languages)
self.notebook.AddPage(self.general, _("General")) self.notebook.AddPage(self.general, _("General"))
self.general.SetFocus() self.general.SetFocus()
def create_buffers(self): def create_buffers(self):
self.buffers = buffers(self.notebook) self.buffers = buffers(self.notebook)
self.notebook.AddPage(self.buffers, _("Buffer settings")) self.notebook.AddPage(self.buffers, _("Buffer settings"))
def create_chat(self): def create_chat(self):
self.chat = chat(self.notebook) self.chat = chat(self.notebook)
self.notebook.AddPage(self.chat, _("Chat settings")) self.notebook.AddPage(self.chat, _("Chat settings"))
def create_startup_options(self): def create_startup_options(self):
self.startup = loadAtStartup(self.notebook) self.startup = loadAtStartup(self.notebook)
self.notebook.AddPage(self.startup, _("Optional buffers")) self.notebook.AddPage(self.startup, _("Optional buffers"))
def create_sound(self, input_devices, output_devices, soundpacks): def create_sound(self, input_devices, output_devices, soundpacks):
self.sound = sound(self.notebook, input_devices, output_devices, soundpacks) self.sound = sound(self.notebook, input_devices, output_devices, soundpacks)
self.notebook.AddPage(self.sound, _("Sound settings")) self.notebook.AddPage(self.sound, _("Sound settings"))
def realize(self): def realize(self):
self.sizer.Add(self.notebook, 0, wx.ALL, 5) self.sizer.Add(self.notebook, 0, wx.ALL, 5)
ok_cancel_box = wx.BoxSizer(wx.HORIZONTAL) ok_cancel_box = wx.BoxSizer(wx.HORIZONTAL)
ok = wx.Button(self.panel, wx.ID_OK, _("Save")) ok = wx.Button(self.panel, wx.ID_OK, _("Save"))
ok.SetDefault() ok.SetDefault()
cancel = wx.Button(self.panel, wx.ID_CANCEL, _("Close")) cancel = wx.Button(self.panel, wx.ID_CANCEL, _("Close"))
self.SetEscapeId(cancel.GetId()) self.SetEscapeId(cancel.GetId())
ok_cancel_box.Add(ok, 0, wx.ALL, 5) ok_cancel_box.Add(ok, 0, wx.ALL, 5)
ok_cancel_box.Add(cancel, 0, wx.ALL, 5) ok_cancel_box.Add(cancel, 0, wx.ALL, 5)
self.sizer.Add(ok_cancel_box, 0, wx.ALL, 5) self.sizer.Add(ok_cancel_box, 0, wx.ALL, 5)
self.panel.SetSizer(self.sizer) self.panel.SetSizer(self.sizer)
self.SetClientSize(self.sizer.CalcMin()) self.SetClientSize(self.sizer.CalcMin())
def get_value(self, panel, key): def get_value(self, panel, key):
p = getattr(self, panel) p = getattr(self, panel)
return getattr(p, key).GetValue() return getattr(p, key).GetValue()
def set_value(self, panel, key, value): def set_value(self, panel, key, value):
p = getattr(self, panel) p = getattr(self, panel)
control = getattr(p, key) control = getattr(p, key)
getattr(control, "SetValue")(value) getattr(control, "SetValue")(value)
def alpha_channel(self): def alpha_channel(self):
return wx.MessageDialog(self, _("The alpha channel contains bleeding edge changes introduced to Socializer. A new alpha update is generated every time there are new changes in the project. Take into account that updates are generated automatically and may fail at any time due to errors in the build process. Use alpha channels when you are sure you want to try the latest changes and contribute with reports to fix bugs. Never use alpha channel updates for everyday use. Do you want to continue?"), _("Attention"), style=wx.ICON_QUESTION|wx.YES_NO).ShowModal() return wx.MessageDialog(self, _("The alpha channel contains bleeding edge changes introduced to Socializer. A new alpha update is generated every time there are new changes in the project. Take into account that updates are generated automatically and may fail at any time due to errors in the build process. Use alpha channels when you are sure you want to try the latest changes and contribute with reports to fix bugs. Never use alpha channel updates for everyday use. Do you want to continue?"), _("Attention"), style=wx.ICON_QUESTION|wx.YES_NO).ShowModal()
def weekly_channel(self): def weekly_channel(self):
return wx.MessageDialog(self, _("The weekly channel generates an update automatically every week by building the source code present in the project. This version is used to test features added to the next stable version. Do you want to continue?"), _("Attention"), style=wx.ICON_QUESTION|wx.YES_NO).ShowModal() return wx.MessageDialog(self, _("The weekly channel generates an update automatically every week by building the source code present in the project. This version is used to test features added to the next stable version. Do you want to continue?"), _("Attention"), style=wx.ICON_QUESTION|wx.YES_NO).ShowModal()

View File

@ -4,168 +4,167 @@ import wx
import widgetUtils import widgetUtils
class createTextMessage(widgetUtils.BaseDialog): class createTextMessage(widgetUtils.BaseDialog):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(createTextMessage, self).__init__(parent=None, *args, **kwargs) super(createTextMessage, self).__init__(parent=None, *args, **kwargs)
def createTextArea(self, message="", text=""): def createTextArea(self, message="", text=""):
self.panel = wx.Panel(self) self.panel = wx.Panel(self)
self.label = wx.StaticText(self.panel, -1, message) self.label = wx.StaticText(self.panel, -1, message)
self.text = wx.TextCtrl(self.panel, -1, text, size=(439, -1), style=wx.TE_MULTILINE) self.text = wx.TextCtrl(self.panel, -1, text, size=(439, -1), style=wx.TE_MULTILINE)
self.text.SetFocus() self.text.SetFocus()
self.textBox = wx.BoxSizer(wx.HORIZONTAL) self.textBox = wx.BoxSizer(wx.HORIZONTAL)
self.textBox.Add(self.label, 0, wx.ALL, 5) self.textBox.Add(self.label, 0, wx.ALL, 5)
self.textBox.Add(self.text, 0, wx.ALL, 5) self.textBox.Add(self.text, 0, wx.ALL, 5)
def create_privacy_box(self): def create_privacy_box(self):
lbl = wx.StaticText(self.panel, wx.NewId(), _("&Privacy")) lbl = wx.StaticText(self.panel, wx.NewId(), _("&Privacy"))
self.privacy = wx.ComboBox(self.panel, wx.NewId(), choices=[_("All users"), _("Friends of friends"),], value=_("All users"), style=wx.CB_READONLY) self.privacy = wx.ComboBox(self.panel, wx.NewId(), choices=[_("All users"), _("Friends of friends"),], value=_("All users"), style=wx.CB_READONLY)
self.privacyBox = wx.BoxSizer(wx.HORIZONTAL) self.privacyBox = wx.BoxSizer(wx.HORIZONTAL)
self.privacyBox.Add(lbl, 0, wx.ALL, 5) self.privacyBox.Add(lbl, 0, wx.ALL, 5)
self.privacyBox.Add(self.privacy, 0, wx.ALL, 5) self.privacyBox.Add(self.privacy, 0, wx.ALL, 5)
def text_focus(self): def text_focus(self):
self.text.SetFocus() self.text.SetFocus()
def get_text(self): def get_text(self):
return self.text.GetValue() return self.text.GetValue()
def set_text(self, text): def set_text(self, text):
return self.text.ChangeValue(text) return self.text.ChangeValue(text)
def enable_button(self, buttonName): def enable_button(self, buttonName):
if getattr(self, buttonName): if getattr(self, buttonName):
return getattr(self, buttonName).Enable() return getattr(self, buttonName).Enable()
def disable_button(self, buttonName): def disable_button(self, buttonName):
if getattr(self, buttonName): if getattr(self, buttonName):
return getattr(self, buttonName).Disable() return getattr(self, buttonName).Disable()
def onSelect(self, ev): def onSelect(self, ev):
self.text.SelectAll() self.text.SelectAll()
def set_cursor_at_end(self): def set_cursor_at_end(self):
self.text.SetInsertionPoint(len(self.text.GetValue())) self.text.SetInsertionPoint(len(self.text.GetValue()))
def set_cursor_at_position(self, position): def set_cursor_at_position(self, position):
self.text.SetInsertionPoint(position) self.text.SetInsertionPoint(position)
def get_position(self): def get_position(self):
return self.text.GetInsertionPoint() return self.text.GetInsertionPoint()
class createPostDialog(createTextMessage): class createPostDialog(createTextMessage):
def createControls(self, title, message, text, mode): def createControls(self, title, message, text, mode):
self.mainBox = wx.BoxSizer(wx.VERTICAL) self.mainBox = wx.BoxSizer(wx.VERTICAL)
self.createTextArea(message, text) self.createTextArea(message, text)
self.mainBox.Add(self.textBox, 0, wx.ALL, 5) self.mainBox.Add(self.textBox, 0, wx.ALL, 5)
if mode == "post": if mode == "post":
self.create_privacy_box() self.create_privacy_box()
self.mainBox.Add(self.privacyBox, 0, wx.ALL, 5) self.mainBox.Add(self.privacyBox, 0, wx.ALL, 5)
self.attach = wx.Button(self.panel, -1, _("Attach"), size=wx.DefaultSize) self.attach = wx.Button(self.panel, -1, _("Attach"), size=wx.DefaultSize)
self.mention = wx.Button(self.panel, wx.NewId(), _("Tag a friend")) self.mention = wx.Button(self.panel, wx.NewId(), _("Tag a friend"))
self.spellcheck = wx.Button(self.panel, -1, _("Spelling &correction"), size=wx.DefaultSize) self.spellcheck = wx.Button(self.panel, -1, _("Spelling &correction"), size=wx.DefaultSize)
self.translateButton = wx.Button(self.panel, -1, _("&Translate message"), size=wx.DefaultSize) self.translateButton = wx.Button(self.panel, -1, _("&Translate message"), size=wx.DefaultSize)
self.okButton = wx.Button(self.panel, wx.ID_OK, _("Send"), size=wx.DefaultSize) self.okButton = wx.Button(self.panel, wx.ID_OK, _("Send"), size=wx.DefaultSize)
self.okButton.SetDefault() self.okButton.SetDefault()
cancelButton = wx.Button(self.panel, wx.ID_CANCEL, _("Close"), size=wx.DefaultSize) cancelButton = wx.Button(self.panel, wx.ID_CANCEL, _("Close"), size=wx.DefaultSize)
self.buttonsBox1 = wx.BoxSizer(wx.HORIZONTAL) self.buttonsBox1 = wx.BoxSizer(wx.HORIZONTAL)
self.buttonsBox1.Add(self.attach, 0, wx.ALL, 10) self.buttonsBox1.Add(self.attach, 0, wx.ALL, 10)
self.buttonsBox1.Add(self.mention, 0, wx.ALL, 10) self.buttonsBox1.Add(self.mention, 0, wx.ALL, 10)
self.buttonsBox1.Add(self.spellcheck, 0, wx.ALL, 10) self.buttonsBox1.Add(self.spellcheck, 0, wx.ALL, 10)
self.buttonsBox1.Add(self.translateButton, 0, wx.ALL, 10) self.buttonsBox1.Add(self.translateButton, 0, wx.ALL, 10)
self.mainBox.Add(self.buttonsBox1, 0, wx.ALL, 10) self.mainBox.Add(self.buttonsBox1, 0, wx.ALL, 10)
self.ok_cancelSizer = wx.BoxSizer(wx.HORIZONTAL) self.ok_cancelSizer = wx.BoxSizer(wx.HORIZONTAL)
self.ok_cancelSizer.Add(self.okButton, 0, wx.ALL, 10) self.ok_cancelSizer.Add(self.okButton, 0, wx.ALL, 10)
self.ok_cancelSizer.Add(cancelButton, 0, wx.ALL, 10) self.ok_cancelSizer.Add(cancelButton, 0, wx.ALL, 10)
self.mainBox.Add(self.ok_cancelSizer) self.mainBox.Add(self.ok_cancelSizer)
selectId = wx.NewId() selectId = wx.NewId()
self.Bind(wx.EVT_MENU, self.onSelect, id=selectId) self.Bind(wx.EVT_MENU, self.onSelect, id=selectId)
self.accel_tbl = wx.AcceleratorTable([ self.accel_tbl = wx.AcceleratorTable([
(wx.ACCEL_CTRL, ord('A'), selectId),]) (wx.ACCEL_CTRL, ord('A'), selectId),])
self.SetAcceleratorTable(self.accel_tbl) self.SetAcceleratorTable(self.accel_tbl)
self.panel.SetSizer(self.mainBox) self.panel.SetSizer(self.mainBox)
self.SetTitle(title) self.SetTitle(title)
def __init__(self, title, message, text, mode="post"): def __init__(self, title, message, text, mode="post"):
super(createPostDialog, self).__init__() super(createPostDialog, self).__init__()
self.createControls(title, message, text, mode) self.createControls(title, message, text, mode)
self.SetClientSize(self.mainBox.CalcMin()) self.SetClientSize(self.mainBox.CalcMin())
class createCommentDialog(createTextMessage): class createCommentDialog(createTextMessage):
def createControls(self, title, message, text, **kwargs): def createControls(self, title, message, text, **kwargs):
self.mainBox = wx.BoxSizer(wx.VERTICAL) self.mainBox = wx.BoxSizer(wx.VERTICAL)
self.createTextArea(message, text) self.createTextArea(message, text)
self.mainBox.Add(self.textBox, 0, wx.ALL, 5) self.mainBox.Add(self.textBox, 0, wx.ALL, 5)
self.spellcheck = wx.Button(self.panel, -1, _("Spelling correction"), size=wx.DefaultSize) self.spellcheck = wx.Button(self.panel, -1, _("Spelling correction"), size=wx.DefaultSize)
self.mention = wx.Button(self.panel, wx.NewId(), _("Tag a friend")) self.mention = wx.Button(self.panel, wx.NewId(), _("Tag a friend"))
self.translateButton = wx.Button(self.panel, -1, _("Translate message"), size=wx.DefaultSize) self.translateButton = wx.Button(self.panel, -1, _("Translate message"), size=wx.DefaultSize)
self.okButton = wx.Button(self.panel, wx.ID_OK, _("Send"), size=wx.DefaultSize) self.okButton = wx.Button(self.panel, wx.ID_OK, _("Send"), size=wx.DefaultSize)
self.okButton.SetDefault() self.okButton.SetDefault()
cancelButton = wx.Button(self.panel, wx.ID_CANCEL, _("Close"), size=wx.DefaultSize) cancelButton = wx.Button(self.panel, wx.ID_CANCEL, _("Close"), size=wx.DefaultSize)
self.buttonsBox1 = wx.BoxSizer(wx.HORIZONTAL) self.buttonsBox1 = wx.BoxSizer(wx.HORIZONTAL)
self.buttonsBox1.Add(self.spellcheck, 0, wx.ALL, 10) self.buttonsBox1.Add(self.spellcheck, 0, wx.ALL, 10)
self.buttonsBox1.Add(self.mention, 0, wx.ALL, 10) self.buttonsBox1.Add(self.mention, 0, wx.ALL, 10)
self.buttonsBox1.Add(self.translateButton, 0, wx.ALL, 10) self.buttonsBox1.Add(self.translateButton, 0, wx.ALL, 10)
self.mainBox.Add(self.buttonsBox1, 0, wx.ALL, 10) self.mainBox.Add(self.buttonsBox1, 0, wx.ALL, 10)
self.ok_cancelSizer = wx.BoxSizer(wx.HORIZONTAL) self.ok_cancelSizer = wx.BoxSizer(wx.HORIZONTAL)
self.ok_cancelSizer.Add(self.okButton, 0, wx.ALL, 10) self.ok_cancelSizer.Add(self.okButton, 0, wx.ALL, 10)
self.ok_cancelSizer.Add(cancelButton, 0, wx.ALL, 10) self.ok_cancelSizer.Add(cancelButton, 0, wx.ALL, 10)
self.mainBox.Add(self.ok_cancelSizer) self.mainBox.Add(self.ok_cancelSizer)
selectId = wx.NewId() selectId = wx.NewId()
self.Bind(wx.EVT_MENU, self.onSelect, id=selectId) self.Bind(wx.EVT_MENU, self.onSelect, id=selectId)
self.accel_tbl = wx.AcceleratorTable([(wx.ACCEL_CTRL, ord('A'), selectId),]) self.accel_tbl = wx.AcceleratorTable([(wx.ACCEL_CTRL, ord('A'), selectId),])
self.SetAcceleratorTable(self.accel_tbl) self.SetAcceleratorTable(self.accel_tbl)
self.panel.SetSizer(self.mainBox) self.panel.SetSizer(self.mainBox)
self.SetTitle(title) self.SetTitle(title)
def __init__(self, title, message, text, *args, **kwargs): def __init__(self, title, message, text, *args, **kwargs):
super(createCommentDialog, self).__init__() super(createCommentDialog, self).__init__()
self.createControls(message, title, text, **kwargs) self.createControls(message, title, text, **kwargs)
self.SetClientSize(self.mainBox.CalcMin()) self.SetClientSize(self.mainBox.CalcMin())
self.SetTitle(title) self.SetTitle(title)
class createTopicDialog(createCommentDialog): class createTopicDialog(createCommentDialog):
def createTextArea(self, message="", text="", topic_title=""): def createTextArea(self, message="", text="", topic_title=""):
self.panel = wx.Panel(self) self.panel = wx.Panel(self)
label = wx.StaticText(self.panel, -1, _("Title")) label = wx.StaticText(self.panel, -1, _("Title"))
self.title = wx.TextCtrl(self.panel, wx.NewId(), topic_title) self.title = wx.TextCtrl(self.panel, wx.NewId(), topic_title)
label2 = wx.StaticText(self.panel, -1, _("Message")) label2 = wx.StaticText(self.panel, -1, _("Message"))
self.text = wx.TextCtrl(self.panel, -1, text, size=(439, -1), style=wx.TE_MULTILINE) self.text = wx.TextCtrl(self.panel, -1, text, size=(439, -1), style=wx.TE_MULTILINE)
self.title.SetFocus() self.title.SetFocus()
self.textBox = wx.BoxSizer(wx.VERTICAL) self.textBox = wx.BoxSizer(wx.VERTICAL)
titleb = wx.BoxSizer(wx.HORIZONTAL) titleb = wx.BoxSizer(wx.HORIZONTAL)
titleb.Add(label, 0, wx.ALL, 5) titleb.Add(label, 0, wx.ALL, 5)
titleb.Add(self.title, 0, wx.ALL, 5) titleb.Add(self.title, 0, wx.ALL, 5)
self.textBox.Add(titleb, 0, wx.ALL, 5) self.textBox.Add(titleb, 0, wx.ALL, 5)
textb = wx.BoxSizer(wx.HORIZONTAL) textb = wx.BoxSizer(wx.HORIZONTAL)
textb.Add(label2, 0, wx.ALL, 5) textb.Add(label2, 0, wx.ALL, 5)
textb.Add(self.text, 0, wx.ALL, 5) textb.Add(self.text, 0, wx.ALL, 5)
self.textBox.Add(textb, 0, wx.ALL, 5) self.textBox.Add(textb, 0, wx.ALL, 5)
def createControls(self, title, message, text, topic_title):
self.mainBox = wx.BoxSizer(wx.VERTICAL)
self.createTextArea(message, text, topic_title)
self.mainBox.Add(self.textBox, 0, wx.ALL, 5)
self.attach = wx.Button(self.panel, -1, _("Attach"), size=wx.DefaultSize)
self.mention = wx.Button(self.panel, wx.NewId(), _("Tag a friend"))
self.spellcheck = wx.Button(self.panel, -1, _("Spelling &correction"), size=wx.DefaultSize)
self.translateButton = wx.Button(self.panel, -1, _("&Translate message"), size=wx.DefaultSize)
self.okButton = wx.Button(self.panel, wx.ID_OK, _("Send"), size=wx.DefaultSize)
self.okButton.SetDefault()
cancelButton = wx.Button(self.panel, wx.ID_CANCEL, _("Close"), size=wx.DefaultSize)
self.buttonsBox1 = wx.BoxSizer(wx.HORIZONTAL)
self.buttonsBox1.Add(self.attach, 0, wx.ALL, 10)
self.buttonsBox1.Add(self.mention, 0, wx.ALL, 10)
self.buttonsBox1.Add(self.spellcheck, 0, wx.ALL, 10)
self.buttonsBox1.Add(self.translateButton, 0, wx.ALL, 10)
self.mainBox.Add(self.buttonsBox1, 0, wx.ALL, 10)
self.ok_cancelSizer = wx.BoxSizer(wx.HORIZONTAL)
self.ok_cancelSizer.Add(self.okButton, 0, wx.ALL, 10)
self.ok_cancelSizer.Add(cancelButton, 0, wx.ALL, 10)
self.mainBox.Add(self.ok_cancelSizer)
selectId = wx.NewId()
self.Bind(wx.EVT_MENU, self.onSelect, id=selectId)
self.accel_tbl = wx.AcceleratorTable([
(wx.ACCEL_CTRL, ord('A'), selectId),])
self.SetAcceleratorTable(self.accel_tbl)
self.panel.SetSizer(self.mainBox)
def createControls(self, title, message, text, topic_title):
self.mainBox = wx.BoxSizer(wx.VERTICAL)
self.createTextArea(message, text, topic_title)
self.mainBox.Add(self.textBox, 0, wx.ALL, 5)
self.attach = wx.Button(self.panel, -1, _("Attach"), size=wx.DefaultSize)
self.mention = wx.Button(self.panel, wx.NewId(), _("Tag a friend"))
self.spellcheck = wx.Button(self.panel, -1, _("Spelling &correction"), size=wx.DefaultSize)
self.translateButton = wx.Button(self.panel, -1, _("&Translate message"), size=wx.DefaultSize)
self.okButton = wx.Button(self.panel, wx.ID_OK, _("Send"), size=wx.DefaultSize)
self.okButton.SetDefault()
cancelButton = wx.Button(self.panel, wx.ID_CANCEL, _("Close"), size=wx.DefaultSize)
self.buttonsBox1 = wx.BoxSizer(wx.HORIZONTAL)
self.buttonsBox1.Add(self.attach, 0, wx.ALL, 10)
self.buttonsBox1.Add(self.mention, 0, wx.ALL, 10)
self.buttonsBox1.Add(self.spellcheck, 0, wx.ALL, 10)
self.buttonsBox1.Add(self.translateButton, 0, wx.ALL, 10)
self.mainBox.Add(self.buttonsBox1, 0, wx.ALL, 10)
self.ok_cancelSizer = wx.BoxSizer(wx.HORIZONTAL)
self.ok_cancelSizer.Add(self.okButton, 0, wx.ALL, 10)
self.ok_cancelSizer.Add(cancelButton, 0, wx.ALL, 10)
self.mainBox.Add(self.ok_cancelSizer)
selectId = wx.NewId()
self.Bind(wx.EVT_MENU, self.onSelect, id=selectId)
self.accel_tbl = wx.AcceleratorTable([
(wx.ACCEL_CTRL, ord('A'), selectId),])
self.SetAcceleratorTable(self.accel_tbl)
self.panel.SetSizer(self.mainBox)

View File

@ -3,420 +3,419 @@ import wx
import widgetUtils import widgetUtils
class displayBasicPost(widgetUtils.BaseDialog): class displayBasicPost(widgetUtils.BaseDialog):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(displayBasicPost, self).__init__(parent=None, *args, **kwargs) super(displayBasicPost, self).__init__(parent=None, *args, **kwargs)
self.panel = wx.Panel(self, -1) self.panel = wx.Panel(self, -1)
self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer = wx.BoxSizer(wx.VERTICAL)
def done(self): def done(self):
self.panel.SetSizer(self.sizer) self.panel.SetSizer(self.sizer)
self.SetClientSize(self.sizer.CalcMin()) self.SetClientSize(self.sizer.CalcMin())
def create_post_view(self, label=_("Message")): def create_post_view(self, label=_("Message")):
lbl = wx.StaticText(self.panel, -1, label) lbl = wx.StaticText(self.panel, -1, label)
self.post_view = wx.TextCtrl(self.panel, -1, size=(730, -1), style=wx.TE_READONLY|wx.TE_MULTILINE) self.post_view = wx.TextCtrl(self.panel, -1, size=(730, -1), style=wx.TE_READONLY|wx.TE_MULTILINE)
selectId = wx.NewId() selectId = wx.NewId()
self.Bind(wx.EVT_MENU, self.onSelect, id=selectId) self.Bind(wx.EVT_MENU, self.onSelect, id=selectId)
self.accel_tbl = wx.AcceleratorTable([ self.accel_tbl = wx.AcceleratorTable([
(wx.ACCEL_CTRL, ord('A'), selectId),]) (wx.ACCEL_CTRL, ord('A'), selectId),])
self.SetAcceleratorTable(self.accel_tbl) self.SetAcceleratorTable(self.accel_tbl)
box = wx.BoxSizer(wx.HORIZONTAL) box = wx.BoxSizer(wx.HORIZONTAL)
box.Add(lbl, 0, wx.ALL, 5) box.Add(lbl, 0, wx.ALL, 5)
box.Add(self.post_view, 0, wx.ALL, 5) box.Add(self.post_view, 0, wx.ALL, 5)
return box return box
def onSelect(self, event): def onSelect(self, event):
self.post_view.SelectAll() self.post_view.SelectAll()
def create_views_control(self): def create_views_control(self):
lbl = wx.StaticText(self.panel, -1, _("Views")) lbl = wx.StaticText(self.panel, -1, _("Views"))
self.views = wx.TextCtrl(self.panel, -1, style=wx.TE_READONLY|wx.TE_MULTILINE) self.views = wx.TextCtrl(self.panel, -1, style=wx.TE_READONLY|wx.TE_MULTILINE)
box = wx.BoxSizer(wx.HORIZONTAL) box = wx.BoxSizer(wx.HORIZONTAL)
box.Add(lbl, 0, wx.ALL, 5) box.Add(lbl, 0, wx.ALL, 5)
box.Add(self.views, 0, wx.ALL, 5) box.Add(self.views, 0, wx.ALL, 5)
return box return box
def create_comments_list(self): def create_comments_list(self):
lbl = wx.StaticText(self.panel, -1, _("Comments")) lbl = wx.StaticText(self.panel, -1, _("Comments"))
self.comments = widgetUtils.list(self.panel, _("User"), _("Comment"), _("Date"), _("Likes"), style=wx.LC_REPORT) self.comments = widgetUtils.list(self.panel, _("User"), _("Comment"), _("Date"), _("Likes"), style=wx.LC_REPORT)
self.reply = wx.Button(self.panel, -1, _("Reply to comment")) self.reply = wx.Button(self.panel, -1, _("Reply to comment"))
self.reply.Enable(False) self.reply.Enable(False)
box = wx.BoxSizer(wx.HORIZONTAL) box = wx.BoxSizer(wx.HORIZONTAL)
box.Add(lbl, 0, wx.ALL, 5) box.Add(lbl, 0, wx.ALL, 5)
box.Add(self.comments.list, 0, wx.ALL, 5) box.Add(self.comments.list, 0, wx.ALL, 5)
box.Add(self.reply, 0, wx.ALL, 5) box.Add(self.reply, 0, wx.ALL, 5)
return box return box
def create_attachments(self): def create_attachments(self):
lbl = wx.StaticText(self.panel, -1, _("Attachments")) lbl = wx.StaticText(self.panel, -1, _("Attachments"))
self.attachments = widgetUtils.list(self.panel, _("Type"), _("Title"), style=wx.LC_REPORT) self.attachments = widgetUtils.list(self.panel, _("Type"), _("Title"), style=wx.LC_REPORT)
box = wx.BoxSizer(wx.HORIZONTAL) box = wx.BoxSizer(wx.HORIZONTAL)
box.Add(lbl, 0, wx.ALL, 5) box.Add(lbl, 0, wx.ALL, 5)
box.Add(self.attachments.list, 0, wx.ALL, 5) box.Add(self.attachments.list, 0, wx.ALL, 5)
return box return box
def create_photo_viewer(self): def create_photo_viewer(self):
self.image = wx.StaticBitmap(self.panel, bitmap=wx.Bitmap(1280, 860), size=(604, 604)) self.image = wx.StaticBitmap(self.panel, bitmap=wx.Bitmap(1280, 860), size=(604, 604))
self.sizer.Add(self.image, 1, wx.ALL, 10) self.sizer.Add(self.image, 1, wx.ALL, 10)
self.previous_photo = wx.Button(self.panel, wx.NewId(), _("Previous photo")) self.previous_photo = wx.Button(self.panel, wx.NewId(), _("Previous photo"))
self.view_photo = wx.Button(self.panel, wx.NewId(), _("View in full screen")) self.view_photo = wx.Button(self.panel, wx.NewId(), _("View in full screen"))
self.next_photo = wx.Button(self.panel, wx.NewId(), _("Next photo")) self.next_photo = wx.Button(self.panel, wx.NewId(), _("Next photo"))
actionsS = wx.BoxSizer(wx.HORIZONTAL) actionsS = wx.BoxSizer(wx.HORIZONTAL)
actionsS.Add(self.previous_photo, 0, wx.ALL, 5) actionsS.Add(self.previous_photo, 0, wx.ALL, 5)
actionsS.Add(self.view_photo, 0, wx.ALL, 5) actionsS.Add(self.view_photo, 0, wx.ALL, 5)
actionsS.Add(self.next_photo, wx.ALL, 5) actionsS.Add(self.next_photo, wx.ALL, 5)
self.previous_photo.Enable(False) self.previous_photo.Enable(False)
self.view_photo.Enable(False) self.view_photo.Enable(False)
self.next_photo.Enable(False) self.next_photo.Enable(False)
self.sizer.Add(actionsS, 0, wx.ALL, 5) self.sizer.Add(actionsS, 0, wx.ALL, 5)
def enable_photo_controls(self, navigation=True): def enable_photo_controls(self, navigation=True):
self.view_photo.Enable(True) self.view_photo.Enable(True)
if navigation: if navigation:
self.previous_photo.Enable(True) self.previous_photo.Enable(True)
self.next_photo.Enable(True) self.next_photo.Enable(True)
def create_likes_box(self): def create_likes_box(self):
self.likes = wx.Button(self.panel, -1, _("Loading data...")) self.likes = wx.Button(self.panel, -1, _("Loading data..."))
return self.likes return self.likes
def create_shares_box(self): def create_shares_box(self):
self.shares = wx.Button(self.panel, -1, _("Loading data...")) self.shares = wx.Button(self.panel, -1, _("Loading data..."))
return self.shares return self.shares
def create_action_buttons(self, comment=True): def create_action_buttons(self, comment=True):
self.like = wx.Button(self.panel, -1, _("&Like")) self.like = wx.Button(self.panel, -1, _("&Like"))
self.repost = wx.Button(self.panel, -1, _("Repost")) self.repost = wx.Button(self.panel, -1, _("Repost"))
if comment: self.comment = wx.Button(self.panel, -1, _("Add comment")) if comment: self.comment = wx.Button(self.panel, -1, _("Add comment"))
box = wx.BoxSizer(wx.HORIZONTAL) box = wx.BoxSizer(wx.HORIZONTAL)
box.Add(self.like, 0, wx.ALL, 5) box.Add(self.like, 0, wx.ALL, 5)
box.Add(self.repost, 0, wx.ALL, 5) box.Add(self.repost, 0, wx.ALL, 5)
if comment: box.Add(self.comment, 0, wx.ALL, 5) if comment: box.Add(self.comment, 0, wx.ALL, 5)
return box return box
def create_tools_button(self): def create_tools_button(self):
self.tools = wx.Button(self.panel, -1, _("Actions")) self.tools = wx.Button(self.panel, -1, _("Actions"))
def create_dialog_buttons(self): def create_dialog_buttons(self):
self.close = wx.Button(self.panel, wx.ID_CANCEL, _("Close")) self.close = wx.Button(self.panel, wx.ID_CANCEL, _("Close"))
return self.close return self.close
def set_post(self, text): def set_post(self, text):
if hasattr(self, "post_view"): if hasattr(self, "post_view"):
self.post_view.ChangeValue(text) self.post_view.ChangeValue(text)
else: else:
return False return False
def insert_comments(self, comments): def insert_comments(self, comments):
for i in comments: for i in comments:
self.comments.insert_item(False, *i) self.comments.insert_item(False, *i)
def insert_attachments(self, attachments): def insert_attachments(self, attachments):
for i in attachments: for i in attachments:
self.attachments.insert_item(False, *i) self.attachments.insert_item(False, *i)
def set_likes(self, likes): def set_likes(self, likes):
if hasattr(self, "likes"): if hasattr(self, "likes"):
self.likes.SetLabel(_("{0} people like this").format(likes,)) self.likes.SetLabel(_("{0} people like this").format(likes,))
else: else:
return False return False
def set_shares(self, shares): def set_shares(self, shares):
if hasattr(self, "shares"): if hasattr(self, "shares"):
self.shares.SetLabel(_("Shared {0} times").format(shares,)) self.shares.SetLabel(_("Shared {0} times").format(shares,))
else: else:
return False return False
class displayPost(displayBasicPost): class displayPost(displayBasicPost):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(displayPost, self).__init__(*args, **kwargs) super(displayPost, self).__init__(*args, **kwargs)
post_view_box = self.create_post_view() post_view_box = self.create_post_view()
self.sizer.Add(post_view_box, 0, wx.ALL, 5) self.sizer.Add(post_view_box, 0, wx.ALL, 5)
views_box = self.create_views_control() views_box = self.create_views_control()
self.sizer.Add(views_box, 0, wx.ALL, 5) self.sizer.Add(views_box, 0, wx.ALL, 5)
attachments_box = self.create_attachments() attachments_box = self.create_attachments()
self.sizer.Add(attachments_box, 0, wx.ALL, 5) self.sizer.Add(attachments_box, 0, wx.ALL, 5)
self.attachments.list.Enable(False) self.attachments.list.Enable(False)
self.create_photo_viewer() self.create_photo_viewer()
self.image.Enable(False) self.image.Enable(False)
self.create_tools_button() self.create_tools_button()
self.sizer.Add(self.tools, 0, wx.ALL, 5) self.sizer.Add(self.tools, 0, wx.ALL, 5)
likes_box = self.create_likes_box() likes_box = self.create_likes_box()
self.sizer.Add(likes_box, 0, wx.ALL, 5) self.sizer.Add(likes_box, 0, wx.ALL, 5)
shares_box = self.create_shares_box() shares_box = self.create_shares_box()
self.sizer.Add(shares_box, 0, wx.ALL, 5) self.sizer.Add(shares_box, 0, wx.ALL, 5)
actions_box = self.create_action_buttons() actions_box = self.create_action_buttons()
self.sizer.Add(actions_box, 0, wx.ALL, 5) self.sizer.Add(actions_box, 0, wx.ALL, 5)
comments_box = self.create_comments_list() comments_box = self.create_comments_list()
self.sizer.Add(comments_box, 0, wx.ALL, 5) self.sizer.Add(comments_box, 0, wx.ALL, 5)
self.sizer.Add(self.create_dialog_buttons()) self.sizer.Add(self.create_dialog_buttons())
self.done() self.done()
class displayComment(displayBasicPost): class displayComment(displayBasicPost):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(displayComment, self).__init__(*args, **kwargs) super(displayComment, self).__init__(*args, **kwargs)
post_view_box = self.create_post_view() post_view_box = self.create_post_view()
self.sizer.Add(post_view_box, 0, wx.ALL, 5) self.sizer.Add(post_view_box, 0, wx.ALL, 5)
attachments_box = self.create_attachments() attachments_box = self.create_attachments()
self.sizer.Add(attachments_box, 0, wx.ALL, 5) self.sizer.Add(attachments_box, 0, wx.ALL, 5)
self.attachments.list.Enable(False) self.attachments.list.Enable(False)
self.create_photo_viewer() self.create_photo_viewer()
self.image.Enable(False) self.image.Enable(False)
self.create_tools_button() self.create_tools_button()
self.sizer.Add(self.tools, 0, wx.ALL, 5) self.sizer.Add(self.tools, 0, wx.ALL, 5)
likes_box = self.create_likes_box() likes_box = self.create_likes_box()
self.sizer.Add(likes_box, 0, wx.ALL, 5) self.sizer.Add(likes_box, 0, wx.ALL, 5)
actions_box = self.create_action_buttons() actions_box = self.create_action_buttons()
self.sizer.Add(actions_box, 0, wx.ALL, 5) self.sizer.Add(actions_box, 0, wx.ALL, 5)
self.sizer.Add(self.create_dialog_buttons()) self.sizer.Add(self.create_dialog_buttons())
self.done() self.done()
def create_action_buttons(self, comment=True): def create_action_buttons(self, comment=True):
self.like = wx.Button(self.panel, -1, _("&Like")) self.like = wx.Button(self.panel, -1, _("&Like"))
self.reply = wx.Button(self.panel, -1, _("Reply")) self.reply = wx.Button(self.panel, -1, _("Reply"))
if comment: self.comment = wx.Button(self.panel, -1, _("Add comment")) if comment: self.comment = wx.Button(self.panel, -1, _("Add comment"))
box = wx.BoxSizer(wx.HORIZONTAL) box = wx.BoxSizer(wx.HORIZONTAL)
box.Add(self.like, 0, wx.ALL, 5) box.Add(self.like, 0, wx.ALL, 5)
box.Add(self.reply, 0, wx.ALL, 5) box.Add(self.reply, 0, wx.ALL, 5)
if comment: box.Add(self.comment, 0, wx.ALL, 5) if comment: box.Add(self.comment, 0, wx.ALL, 5)
return box return box
class displayTopic(displayBasicPost): class displayTopic(displayBasicPost):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(displayTopic, self).__init__(*args, **kwargs) super(displayTopic, self).__init__(*args, **kwargs)
comments_box = self.create_comments_list() comments_box = self.create_comments_list()
self.sizer.Add(comments_box, 0, wx.ALL, 5) self.sizer.Add(comments_box, 0, wx.ALL, 5)
attachments_box = self.create_attachments() attachments_box = self.create_attachments()
self.sizer.Add(attachments_box, 0, wx.ALL, 5) self.sizer.Add(attachments_box, 0, wx.ALL, 5)
self.attachments.list.Enable(False) self.attachments.list.Enable(False)
self.create_photo_viewer() self.create_photo_viewer()
self.image.Enable(False) self.image.Enable(False)
self.create_tools_button() self.create_tools_button()
self.sizer.Add(self.tools, 0, wx.ALL, 5) self.sizer.Add(self.tools, 0, wx.ALL, 5)
actions_box = self.create_action_buttons() actions_box = self.create_action_buttons()
self.sizer.Add(actions_box, 0, wx.ALL, 5) self.sizer.Add(actions_box, 0, wx.ALL, 5)
self.sizer.Add(self.create_dialog_buttons()) self.sizer.Add(self.create_dialog_buttons())
self.done() self.done()
def create_action_buttons(self, comment=True): def create_action_buttons(self, comment=True):
self.like = wx.Button(self.panel, -1, _("&Like")) self.like = wx.Button(self.panel, -1, _("&Like"))
if comment: self.comment = wx.Button(self.panel, -1, _("Add comment")) if comment: self.comment = wx.Button(self.panel, -1, _("Add comment"))
box = wx.BoxSizer(wx.HORIZONTAL) box = wx.BoxSizer(wx.HORIZONTAL)
box.Add(self.like, 0, wx.ALL, 5) box.Add(self.like, 0, wx.ALL, 5)
if comment: box.Add(self.comment, 0, wx.ALL, 5) if comment: box.Add(self.comment, 0, wx.ALL, 5)
return box return box
def create_comments_list(self): def create_comments_list(self):
lbl = wx.StaticText(self.panel, -1, _("Posts")) lbl = wx.StaticText(self.panel, -1, _("Posts"))
self.comments = widgetUtils.list(self.panel, _("User"), _("Comment"), _("Date"), _("Likes"), style=wx.LC_REPORT) self.comments = widgetUtils.list(self.panel, _("User"), _("Comment"), _("Date"), _("Likes"), style=wx.LC_REPORT)
self.load_more_comments = wx.Button(self.panel, wx.NewId(), _("Load previous comments")) self.load_more_comments = wx.Button(self.panel, wx.NewId(), _("Load previous comments"))
self.reply = wx.Button(self.panel, -1, _("Reply")) self.reply = wx.Button(self.panel, -1, _("Reply"))
box = wx.BoxSizer(wx.HORIZONTAL) box = wx.BoxSizer(wx.HORIZONTAL)
box.Add(lbl, 0, wx.ALL, 5) box.Add(lbl, 0, wx.ALL, 5)
box.Add(self.comments.list, 0, wx.ALL, 5) box.Add(self.comments.list, 0, wx.ALL, 5)
box.Add(self.reply, 0, wx.ALL, 5) box.Add(self.reply, 0, wx.ALL, 5)
return box return box
class displayAudio(widgetUtils.BaseDialog): class displayAudio(widgetUtils.BaseDialog):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(displayAudio, self).__init__(parent=None, *args, **kwargs) super(displayAudio, self).__init__(parent=None, *args, **kwargs)
panel = wx.Panel(self) panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
lbl_list = wx.StaticText(panel, wx.NewId(), _("Audio &files")) lbl_list = wx.StaticText(panel, wx.NewId(), _("Audio &files"))
self.list = wx.ListBox(panel, wx.NewId()) self.list = wx.ListBox(panel, wx.NewId())
listS = wx.BoxSizer(wx.HORIZONTAL) listS = wx.BoxSizer(wx.HORIZONTAL)
listS.Add(lbl_list, 0, wx.ALL, 5) listS.Add(lbl_list, 0, wx.ALL, 5)
listS.Add(self.list, 0, wx.ALL, 5) listS.Add(self.list, 0, wx.ALL, 5)
sizer.Add(listS, 0, wx.ALL, 5) sizer.Add(listS, 0, wx.ALL, 5)
lbl_title = wx.StaticText(panel, wx.NewId(), _("&Title")) lbl_title = wx.StaticText(panel, wx.NewId(), _("&Title"))
self.title = wx.TextCtrl(panel, wx.NewId(), size=(413, -1), style=wx.TE_READONLY|wx.TE_MULTILINE) self.title = wx.TextCtrl(panel, wx.NewId(), size=(413, -1), style=wx.TE_READONLY|wx.TE_MULTILINE)
titleBox = wx.BoxSizer(wx.HORIZONTAL) titleBox = wx.BoxSizer(wx.HORIZONTAL)
titleBox.Add(lbl_title, 0, wx.ALL, 5) titleBox.Add(lbl_title, 0, wx.ALL, 5)
titleBox.Add(self.title, 0, wx.ALL, 5) titleBox.Add(self.title, 0, wx.ALL, 5)
sizer.Add(titleBox, 0, wx.ALL, 5) sizer.Add(titleBox, 0, wx.ALL, 5)
lbl_artist = wx.StaticText(panel, wx.NewId(), _("&Artist")) lbl_artist = wx.StaticText(panel, wx.NewId(), _("&Artist"))
self.artist = wx.TextCtrl(panel, wx.NewId(), size=(413, -1), style=wx.TE_READONLY|wx.TE_MULTILINE) self.artist = wx.TextCtrl(panel, wx.NewId(), size=(413, -1), style=wx.TE_READONLY|wx.TE_MULTILINE)
artistBox = wx.BoxSizer(wx.HORIZONTAL) artistBox = wx.BoxSizer(wx.HORIZONTAL)
artistBox.Add(lbl_artist, 0, wx.ALL, 5) artistBox.Add(lbl_artist, 0, wx.ALL, 5)
artistBox.Add(self.artist, 0, wx.ALL, 5) artistBox.Add(self.artist, 0, wx.ALL, 5)
sizer.Add(artistBox, 0, wx.ALL, 5) sizer.Add(artistBox, 0, wx.ALL, 5)
lbl_duration = wx.StaticText(panel, wx.NewId(), _("&Duration")) lbl_duration = wx.StaticText(panel, wx.NewId(), _("&Duration"))
self.duration = wx.TextCtrl(panel, wx.NewId(), size=(413, -1), style=wx.TE_READONLY|wx.TE_MULTILINE) self.duration = wx.TextCtrl(panel, wx.NewId(), size=(413, -1), style=wx.TE_READONLY|wx.TE_MULTILINE)
durationBox = wx.BoxSizer(wx.HORIZONTAL) durationBox = wx.BoxSizer(wx.HORIZONTAL)
durationBox.Add(lbl_duration, 0, wx.ALL, 5) durationBox.Add(lbl_duration, 0, wx.ALL, 5)
durationBox.Add(self.duration, 0, wx.ALL, 5) durationBox.Add(self.duration, 0, wx.ALL, 5)
sizer.Add(durationBox, 0, wx.ALL, 5) sizer.Add(durationBox, 0, wx.ALL, 5)
lbl_lyrics = wx.StaticText(panel, wx.NewId(), _("&Lyric")) lbl_lyrics = wx.StaticText(panel, wx.NewId(), _("&Lyric"))
self.lyric = wx.TextCtrl(panel, wx.NewId(), size=(500, 500), style=wx.TE_READONLY|wx.TE_MULTILINE) self.lyric = wx.TextCtrl(panel, wx.NewId(), size=(500, 500), style=wx.TE_READONLY|wx.TE_MULTILINE)
lbox = wx.BoxSizer(wx.HORIZONTAL) lbox = wx.BoxSizer(wx.HORIZONTAL)
lbox.Add(lbl_lyrics, 0, wx.ALL, 5) lbox.Add(lbl_lyrics, 0, wx.ALL, 5)
lbox.Add(self.lyric, 0, wx.ALL, 5) lbox.Add(self.lyric, 0, wx.ALL, 5)
sizer.Add(lbox, 0, wx.ALL, 5) sizer.Add(lbox, 0, wx.ALL, 5)
self.play = wx.Button(panel, wx.NewId(), _("&Play")) self.play = wx.Button(panel, wx.NewId(), _("&Play"))
self.download = wx.Button(panel, wx.NewId(), _("&Download")) self.download = wx.Button(panel, wx.NewId(), _("&Download"))
self.add = wx.Button(panel, wx.NewId(), _("&Add to your library")) self.add = wx.Button(panel, wx.NewId(), _("&Add to your library"))
self.remove = wx.Button(panel, wx.NewId(), _("&Remove from your library")) self.remove = wx.Button(panel, wx.NewId(), _("&Remove from your library"))
self.add.Enable(False) self.add.Enable(False)
self.remove.Enable(False) self.remove.Enable(False)
close = wx.Button(panel, wx.ID_CANCEL) close = wx.Button(panel, wx.ID_CANCEL)
bbox = wx.BoxSizer(wx.HORIZONTAL) bbox = wx.BoxSizer(wx.HORIZONTAL)
bbox.Add(self.play, 0, wx.ALL, 5) bbox.Add(self.play, 0, wx.ALL, 5)
bbox.Add(self.download, 0, wx.ALL, 5) bbox.Add(self.download, 0, wx.ALL, 5)
bbox.Add(self.add, 0, wx.ALL, 5) bbox.Add(self.add, 0, wx.ALL, 5)
bbox.Add(self.remove, 0, wx.ALL, 5) bbox.Add(self.remove, 0, wx.ALL, 5)
bbox.Add(close, 0, wx.ALL, 5) bbox.Add(close, 0, wx.ALL, 5)
def change_state(self, button_name, state): def change_state(self, button_name, state):
getattr(self, button_name).Enable(state) getattr(self, button_name).Enable(state)
def get_destination_path(self, filename): def get_destination_path(self, filename):
saveFileDialog = wx.FileDialog(self, _("Save this file"), "", filename, _("Audio Files(*.mp3)|*.mp3"), wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) saveFileDialog = wx.FileDialog(self, _("Save this file"), "", filename, _("Audio Files(*.mp3)|*.mp3"), wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
if saveFileDialog.ShowModal() == wx.ID_OK: if saveFileDialog.ShowModal() == wx.ID_OK:
return saveFileDialog.GetPath() return saveFileDialog.GetPath()
saveFileDialog.Destroy() saveFileDialog.Destroy()
def insert_audio(self, audio_): def insert_audio(self, audio_):
self.list.Append(audio_) self.list.Append(audio_)
def get_audio(self): def get_audio(self):
return self.list.GetSelection() return self.list.GetSelection()
class displayArticle(widgetUtils.BaseDialog): class displayArticle(widgetUtils.BaseDialog):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(displayArticle, self).__init__(parent=None, *args, **kwargs) super(displayArticle, self).__init__(parent=None, *args, **kwargs)
self.panel = wx.Panel(self, -1) self.panel = wx.Panel(self, -1)
self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer = wx.BoxSizer(wx.VERTICAL)
article_view_box = self.create_article_view() article_view_box = self.create_article_view()
self.sizer.Add(article_view_box, 0, wx.ALL, 5) self.sizer.Add(article_view_box, 0, wx.ALL, 5)
views_box = self.create_views_control() views_box = self.create_views_control()
self.sizer.Add(views_box, 0, wx.ALL, 5) self.sizer.Add(views_box, 0, wx.ALL, 5)
attachments_box = self.create_attachments() attachments_box = self.create_attachments()
self.sizer.Add(attachments_box, 0, wx.ALL, 5) self.sizer.Add(attachments_box, 0, wx.ALL, 5)
self.attachments.list.Enable(False) self.attachments.list.Enable(False)
self.create_tools_button() self.create_tools_button()
self.sizer.Add(self.tools, 0, wx.ALL, 5) self.sizer.Add(self.tools, 0, wx.ALL, 5)
self.sizer.Add(self.create_dialog_buttons()) self.sizer.Add(self.create_dialog_buttons())
self.done() self.done()
def done(self): def done(self):
self.panel.SetSizer(self.sizer) self.panel.SetSizer(self.sizer)
self.SetClientSize(self.sizer.CalcMin()) self.SetClientSize(self.sizer.CalcMin())
def create_article_view(self, label=_("Article")): def create_article_view(self, label=_("Article")):
lbl = wx.StaticText(self.panel, -1, label) lbl = wx.StaticText(self.panel, -1, label)
self.article_view = wx.TextCtrl(self.panel, -1, size=(730, -1), style=wx.TE_READONLY|wx.TE_MULTILINE|wx.BORDER_SIMPLE) self.article_view = wx.TextCtrl(self.panel, -1, size=(730, -1), style=wx.TE_READONLY|wx.TE_MULTILINE|wx.BORDER_SIMPLE)
selectId = wx.NewId() selectId = wx.NewId()
self.Bind(wx.EVT_MENU, self.onSelect, id=selectId) self.Bind(wx.EVT_MENU, self.onSelect, id=selectId)
self.accel_tbl = wx.AcceleratorTable([ self.accel_tbl = wx.AcceleratorTable([
(wx.ACCEL_CTRL, ord('A'), selectId),]) (wx.ACCEL_CTRL, ord('A'), selectId),])
self.SetAcceleratorTable(self.accel_tbl) self.SetAcceleratorTable(self.accel_tbl)
box = wx.BoxSizer(wx.HORIZONTAL) box = wx.BoxSizer(wx.HORIZONTAL)
box.Add(lbl, 0, wx.ALL, 5) box.Add(lbl, 0, wx.ALL, 5)
box.Add(self.article_view, 0, wx.ALL, 5) box.Add(self.article_view, 0, wx.ALL, 5)
return box return box
def onSelect(self, event): def onSelect(self, event):
self.article_view.SelectAll() self.article_view.SelectAll()
def create_views_control(self): def create_views_control(self):
lbl = wx.StaticText(self.panel, -1, _("Views")) lbl = wx.StaticText(self.panel, -1, _("Views"))
self.views = wx.TextCtrl(self.panel, -1, style=wx.TE_READONLY|wx.TE_MULTILINE) self.views = wx.TextCtrl(self.panel, -1, style=wx.TE_READONLY|wx.TE_MULTILINE)
box = wx.BoxSizer(wx.HORIZONTAL) box = wx.BoxSizer(wx.HORIZONTAL)
box.Add(lbl, 0, wx.ALL, 5) box.Add(lbl, 0, wx.ALL, 5)
box.Add(self.views, 0, wx.ALL, 5) box.Add(self.views, 0, wx.ALL, 5)
return box return box
def create_tools_button(self): def create_tools_button(self):
self.tools = wx.Button(self.panel, -1, _("Actions")) self.tools = wx.Button(self.panel, -1, _("Actions"))
def create_dialog_buttons(self): def create_dialog_buttons(self):
self.close = wx.Button(self.panel, wx.ID_CANCEL, _("Close")) self.close = wx.Button(self.panel, wx.ID_CANCEL, _("Close"))
return self.close return self.close
def create_attachments(self): def create_attachments(self):
lbl = wx.StaticText(self.panel, -1, _("Attachments")) lbl = wx.StaticText(self.panel, -1, _("Attachments"))
self.attachments = widgetUtils.list(self.panel, _("Type"), _("Title"), style=wx.LC_REPORT) self.attachments = widgetUtils.list(self.panel, _("Type"), _("Title"), style=wx.LC_REPORT)
box = wx.BoxSizer(wx.HORIZONTAL) box = wx.BoxSizer(wx.HORIZONTAL)
box.Add(lbl, 0, wx.ALL, 5) box.Add(lbl, 0, wx.ALL, 5)
box.Add(self.attachments.list, 0, wx.ALL, 5) box.Add(self.attachments.list, 0, wx.ALL, 5)
return box return box
def set_article(self, text): def set_article(self, text):
if hasattr(self, "article_view"): if hasattr(self, "article_view"):
self.article_view.ChangeValue(text) self.article_view.ChangeValue(text)
else: else:
return False return False
def insert_attachments(self, attachments): def insert_attachments(self, attachments):
for i in attachments: for i in attachments:
self.attachments.insert_item(False, *i) self.attachments.insert_item(False, *i)
class displayFriendship(widgetUtils.BaseDialog): class displayFriendship(widgetUtils.BaseDialog):
def __init__(self): def __init__(self):
super(displayFriendship, self).__init__(parent=None) super(displayFriendship, self).__init__(parent=None)
panel = wx.Panel(self) panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
self.friends = widgetUtils.list(panel, [_("Friend")], style=wx.LC_REPORT) self.friends = widgetUtils.list(panel, [_("Friend")], style=wx.LC_REPORT)
sizer.Add(self.friends.list, 0, wx.ALL, 5) sizer.Add(self.friends.list, 0, wx.ALL, 5)
close = wx.Button(panel, wx.ID_CANCEL) close = wx.Button(panel, wx.ID_CANCEL)
btnbox = wx.BoxSizer(wx.HORIZONTAL) btnbox = wx.BoxSizer(wx.HORIZONTAL)
btnbox.Add(close, 0, wx.ALL, 5) btnbox.Add(close, 0, wx.ALL, 5)
sizer.Add(btnbox, 0, wx.ALL, 5) sizer.Add(btnbox, 0, wx.ALL, 5)
panel.SetSizer(sizer) panel.SetSizer(sizer)
self.SetClientSize(sizer.CalcMin()) self.SetClientSize(sizer.CalcMin())
class displayPoll(widgetUtils.BaseDialog): class displayPoll(widgetUtils.BaseDialog):
def __init__(self, question="", *args, **kwargs): def __init__(self, question="", *args, **kwargs):
super(displayPoll, self).__init__(parent=None, *args, **kwargs) super(displayPoll, self).__init__(parent=None, *args, **kwargs)
self.panel = wx.Panel(self, -1) self.panel = wx.Panel(self, -1)
self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer = wx.BoxSizer(wx.VERTICAL)
label = wx.StaticText(self.panel, wx.NewId(), _("Question")) label = wx.StaticText(self.panel, wx.NewId(), _("Question"))
self.question = wx.TextCtrl(self.panel, wx.NewId(), question, style=wx.TE_MULTILINE|wx.TE_READONLY, size=(730, -1)) self.question = wx.TextCtrl(self.panel, wx.NewId(), question, style=wx.TE_MULTILINE|wx.TE_READONLY, size=(730, -1))
self.sizer.Add(label, 0, wx.ALL, 5) self.sizer.Add(label, 0, wx.ALL, 5)
self.sizer.Add(self.question, 0, wx.ALL, 5) self.sizer.Add(self.question, 0, wx.ALL, 5)
def add_options(self, options, multiple=False): def add_options(self, options, multiple=False):
if not isinstance(options[0], str): if not isinstance(options[0], str):
return self.add_results(options) return self.add_results(options)
self.options = [] self.options = []
sizer = wx.StaticBoxSizer(parent=self.panel, orient=wx.VERTICAL, label=_("Options")) sizer = wx.StaticBoxSizer(parent=self.panel, orient=wx.VERTICAL, label=_("Options"))
for i in options: for i in options:
if multiple == False: if multiple == False:
if len(self.options) == 0: if len(self.options) == 0:
control = wx.RadioButton(sizer.GetStaticBox(), wx.NewId(), i, style=wx.RB_GROUP) control = wx.RadioButton(sizer.GetStaticBox(), wx.NewId(), i, style=wx.RB_GROUP)
else: else:
control = wx.RadioButton(sizer.GetStaticBox(), wx.NewId(), i) control = wx.RadioButton(sizer.GetStaticBox(), wx.NewId(), i)
else: else:
control = wx.CheckBox(sizer.GetStaticBox(), wx.NewId(), i) control = wx.CheckBox(sizer.GetStaticBox(), wx.NewId(), i)
self.options.append(control) self.options.append(control)
sizer.Add(control, 0, wx.ALL, 5) sizer.Add(control, 0, wx.ALL, 5)
self.sizer.Add(sizer, 0, wx.ALL, 5) self.sizer.Add(sizer, 0, wx.ALL, 5)
def get_answers(self): def get_answers(self):
answers = [] answers = []
for i in self.options: for i in self.options:
answers.append(i.GetValue()) answers.append(i.GetValue())
return answers return answers
def add_results(self, options): def add_results(self, options):
sizer = wx.StaticBoxSizer(parent=self.panel, orient=wx.VERTICAL, label=_("Poll results")) sizer = wx.StaticBoxSizer(parent=self.panel, orient=wx.VERTICAL, label=_("Poll results"))
for i in options: for i in options:
sizer2 = wx.StaticBoxSizer(parent=sizer.GetStaticBox(), orient=wx.HORIZONTAL, label=i[0]) sizer2 = wx.StaticBoxSizer(parent=sizer.GetStaticBox(), orient=wx.HORIZONTAL, label=i[0])
staticcontrol = wx.StaticText(sizer2.GetStaticBox(), wx.NewId(), i[0]) staticcontrol = wx.StaticText(sizer2.GetStaticBox(), wx.NewId(), i[0])
control = wx.TextCtrl(sizer2.GetStaticBox(), wx.NewId(), _("{votes} ({rate}%)").format(votes=i[1], rate=i[2]), style=wx.TE_READONLY|wx.TE_MULTILINE) control = wx.TextCtrl(sizer2.GetStaticBox(), wx.NewId(), _("{votes} ({rate}%)").format(votes=i[1], rate=i[2]), style=wx.TE_READONLY|wx.TE_MULTILINE)
sizer2.Add(staticcontrol, 0, wx.ALL, 5) sizer2.Add(staticcontrol, 0, wx.ALL, 5)
sizer2.Add(control, 0, wx.ALL, 5) sizer2.Add(control, 0, wx.ALL, 5)
sizer.Add(sizer2, 0, wx.ALL, 5) sizer.Add(sizer2, 0, wx.ALL, 5)
self.sizer.Add(sizer, 0, wx.ALL, 5) self.sizer.Add(sizer, 0, wx.ALL, 5)
def done(self):
self.ok = wx.Button(self.panel, wx.ID_OK, _("Vote"))
cancel = wx.Button(self.panel, wx.ID_CANCEL)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(self.ok, 0, wx.ALL, 5)
sizer.Add(cancel, 0, wx.ALL, 5)
self.panel.SetSizer(self.sizer)
self.SetClientSize(self.sizer.CalcMin())
def done(self):
self.ok = wx.Button(self.panel, wx.ID_OK, _("Vote"))
cancel = wx.Button(self.panel, wx.ID_CANCEL)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(self.ok, 0, wx.ALL, 5)
sizer.Add(cancel, 0, wx.ALL, 5)
self.panel.SetSizer(self.sizer)
self.SetClientSize(self.sizer.CalcMin())

View File

@ -5,173 +5,173 @@ import wx
import widgetUtils import widgetUtils
def text_size(wxObject, chars): def text_size(wxObject, chars):
""" Takes a wx object and the amount of characters supposed to hold and gives the best size for the control. """ Takes a wx object and the amount of characters supposed to hold and gives the best size for the control.
wxObject wx.TextCtrl: Text control to be taken as a reference. wxObject wx.TextCtrl: Text control to be taken as a reference.
chars int: Number of characters the control would hold. chars int: Number of characters the control would hold.
returns (x, y)""" returns (x, y)"""
dc = wx.WindowDC(wxObject) dc = wx.WindowDC(wxObject)
dc.SetFont(wxObject.GetFont()) dc.SetFont(wxObject.GetFont())
(x, y) = dc.GetMultiLineTextExtent("0"*chars) (x, y) = dc.GetMultiLineTextExtent("0"*chars)
return (x, -1) return (x, -1)
class baseTab(wx.Panel): class baseTab(wx.Panel):
""" Panel to store main user information in a profile viewer.""" """ Panel to store main user information in a profile viewer."""
def get(self, control): def get(self, control):
if hasattr(self, control): if hasattr(self, control):
control = getattr(self, control) control = getattr(self, control)
if hasattr(control, "GetValue"): return getattr(control, "GetValue")() if hasattr(control, "GetValue"): return getattr(control, "GetValue")()
elif hasattr(control, "GetLabel"): return getattr(control, "GetLabel")() elif hasattr(control, "GetLabel"): return getattr(control, "GetLabel")()
else: return -1 else: return -1
else: return 0 else: return 0
def set(self, control, text): def set(self, control, text):
if hasattr(self, control): if hasattr(self, control):
control = getattr(self, control) control = getattr(self, control)
if hasattr(control, "SetValue"): return getattr(control, "SetValue")(text) if hasattr(control, "SetValue"): return getattr(control, "SetValue")(text)
elif hasattr(control, "SetLabel"): return getattr(control, "SetLabel")(text) elif hasattr(control, "SetLabel"): return getattr(control, "SetLabel")(text)
elif hasattr(control, "ChangeValue"): return getattr(control, "ChangeValue")(text) elif hasattr(control, "ChangeValue"): return getattr(control, "ChangeValue")(text)
else: return -1 else: return -1
else: return 0 else: return 0
def enable(self, control): def enable(self, control):
getattr(self, control).Enable(True) getattr(self, control).Enable(True)
def disable(self, control): def disable(self, control):
getattr(self, control).Enable(False) getattr(self, control).Enable(False)
class mainInfo(baseTab): class mainInfo(baseTab):
def __init__(self, panel): def __init__(self, panel):
super(mainInfo, self).__init__(panel) super(mainInfo, self).__init__(panel)
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
lblName = wx.StaticText(self, wx.NewId(), _("Name")) lblName = wx.StaticText(self, wx.NewId(), _("Name"))
self.name = wx.TextCtrl(self, wx.NewId(), style=wx.TE_READONLY|wx.TE_MULTILINE) self.name = wx.TextCtrl(self, wx.NewId(), style=wx.TE_READONLY|wx.TE_MULTILINE)
self.name.SetMinSize(text_size(self.name, 60)) self.name.SetMinSize(text_size(self.name, 60))
sizerName = wx.BoxSizer(wx.HORIZONTAL) sizerName = wx.BoxSizer(wx.HORIZONTAL)
sizerName.Add(lblName, 0, wx.ALL, 5) sizerName.Add(lblName, 0, wx.ALL, 5)
sizerName.Add(self.name, 0, wx.ALL, 5) sizerName.Add(self.name, 0, wx.ALL, 5)
sizer.Add(sizerName, 0, wx.ALL, 5) sizer.Add(sizerName, 0, wx.ALL, 5)
lblStatus = wx.StaticText(self, wx.NewId(), _("Status")) lblStatus = wx.StaticText(self, wx.NewId(), _("Status"))
self.status = wx.TextCtrl(self, wx.NewId(), style=wx.TE_READONLY|wx.TE_MULTILINE) self.status = wx.TextCtrl(self, wx.NewId(), style=wx.TE_READONLY|wx.TE_MULTILINE)
self.status.Enable(False) self.status.Enable(False)
self.status.SetMinSize(text_size(self.status, 300)) self.status.SetMinSize(text_size(self.status, 300))
sizerStatus = wx.BoxSizer(wx.HORIZONTAL) sizerStatus = wx.BoxSizer(wx.HORIZONTAL)
sizerStatus.Add(lblStatus, 0, wx.ALL, 5) sizerStatus.Add(lblStatus, 0, wx.ALL, 5)
sizerStatus.Add(self.status, 0, wx.ALL, 5) sizerStatus.Add(self.status, 0, wx.ALL, 5)
sizer.Add(sizerStatus, 0, wx.ALL, 5) sizer.Add(sizerStatus, 0, wx.ALL, 5)
lblLastSeen = wx.StaticText(self, wx.NewId(), _("Last seen")) lblLastSeen = wx.StaticText(self, wx.NewId(), _("Last seen"))
self.last_seen = wx.TextCtrl(self, wx.NewId(), style=wx.TE_READONLY|wx.TE_MULTILINE) self.last_seen = wx.TextCtrl(self, wx.NewId(), style=wx.TE_READONLY|wx.TE_MULTILINE)
self.last_seen.Enable(False) self.last_seen.Enable(False)
sizerLastSeen = wx.BoxSizer(wx.HORIZONTAL) sizerLastSeen = wx.BoxSizer(wx.HORIZONTAL)
sizerLastSeen.Add(lblLastSeen, 0, wx.ALL, 5) sizerLastSeen.Add(lblLastSeen, 0, wx.ALL, 5)
sizerLastSeen.Add(self.last_seen, 0, wx.ALL, 5) sizerLastSeen.Add(self.last_seen, 0, wx.ALL, 5)
sizer.Add(sizerLastSeen, 0, wx.ALL, 5) sizer.Add(sizerLastSeen, 0, wx.ALL, 5)
lblMobilePhone = wx.StaticText(self, wx.NewId(), _("Mobile phone")) lblMobilePhone = wx.StaticText(self, wx.NewId(), _("Mobile phone"))
self.mobile_phone = wx.TextCtrl(self, wx.NewId(), style=wx.TE_READONLY|wx.TE_MULTILINE) self.mobile_phone = wx.TextCtrl(self, wx.NewId(), style=wx.TE_READONLY|wx.TE_MULTILINE)
self.mobile_phone.Enable(False) self.mobile_phone.Enable(False)
sizerMobilePhone = wx.BoxSizer(wx.HORIZONTAL) sizerMobilePhone = wx.BoxSizer(wx.HORIZONTAL)
sizerMobilePhone.Add(lblMobilePhone, 0, wx.ALL, 5) sizerMobilePhone.Add(lblMobilePhone, 0, wx.ALL, 5)
sizerMobilePhone.Add(self.mobile_phone, 0, wx.ALL, 5) sizerMobilePhone.Add(self.mobile_phone, 0, wx.ALL, 5)
sizer.Add(sizerMobilePhone, 0, wx.ALL, 5) sizer.Add(sizerMobilePhone, 0, wx.ALL, 5)
lblHomePhone = wx.StaticText(self, wx.NewId(), _("Home phone")) lblHomePhone = wx.StaticText(self, wx.NewId(), _("Home phone"))
self.home_phone = wx.TextCtrl(self, wx.NewId(), style=wx.TE_READONLY|wx.TE_MULTILINE) self.home_phone = wx.TextCtrl(self, wx.NewId(), style=wx.TE_READONLY|wx.TE_MULTILINE)
self.home_phone.Enable(False) self.home_phone.Enable(False)
sizerHomePhone = wx.BoxSizer(wx.HORIZONTAL) sizerHomePhone = wx.BoxSizer(wx.HORIZONTAL)
sizerHomePhone.Add(lblHomePhone, 0, wx.ALL, 5) sizerHomePhone.Add(lblHomePhone, 0, wx.ALL, 5)
sizerHomePhone.Add(self.home_phone, 0, wx.ALL, 5) sizerHomePhone.Add(self.home_phone, 0, wx.ALL, 5)
sizer.Add(sizerHomePhone, 0, wx.ALL, 5) sizer.Add(sizerHomePhone, 0, wx.ALL, 5)
lblBDate = wx.StaticText(self, wx.NewId(), _("Birthdate")) lblBDate = wx.StaticText(self, wx.NewId(), _("Birthdate"))
self.bdate = wx.TextCtrl(self, wx.NewId(), style=wx.TE_READONLY|wx.TE_MULTILINE) self.bdate = wx.TextCtrl(self, wx.NewId(), style=wx.TE_READONLY|wx.TE_MULTILINE)
self.bdate.Enable(False) self.bdate.Enable(False)
sizerBDate = wx.BoxSizer(wx.HORIZONTAL) sizerBDate = wx.BoxSizer(wx.HORIZONTAL)
sizerBDate.Add(lblBDate, 0, wx.ALL, 5) sizerBDate.Add(lblBDate, 0, wx.ALL, 5)
sizerBDate.Add(self.bdate, 0, wx.ALL, 5) sizerBDate.Add(self.bdate, 0, wx.ALL, 5)
sizer.Add(sizerBDate, 0, wx.ALL, 5) sizer.Add(sizerBDate, 0, wx.ALL, 5)
self.relation = wx.Button(self, -1, "") self.relation = wx.Button(self, -1, "")
self.relation.Enable(False) self.relation.Enable(False)
sizer.Add(self.relation, 0, wx.ALL, 5) sizer.Add(self.relation, 0, wx.ALL, 5)
lblCity = wx.StaticText(self, wx.NewId(), _("Current city")) lblCity = wx.StaticText(self, wx.NewId(), _("Current city"))
self.city = wx.TextCtrl(self, wx.NewId(), style=wx.TE_READONLY|wx.TE_MULTILINE) self.city = wx.TextCtrl(self, wx.NewId(), style=wx.TE_READONLY|wx.TE_MULTILINE)
self.city.SetMinSize(text_size(self.city, 40)) self.city.SetMinSize(text_size(self.city, 40))
self.city.Enable(False) self.city.Enable(False)
sizerCity = wx.BoxSizer(wx.HORIZONTAL) sizerCity = wx.BoxSizer(wx.HORIZONTAL)
sizerCity.Add(lblCity, 0, wx.ALL, 5) sizerCity.Add(lblCity, 0, wx.ALL, 5)
sizerCity.Add(self.city, 0, wx.ALL, 5) sizerCity.Add(self.city, 0, wx.ALL, 5)
sizer.Add(sizerCity, 0, wx.ALL, 5) sizer.Add(sizerCity, 0, wx.ALL, 5)
lblHometown = wx.StaticText(self, wx.NewId(), _("Home Town")) lblHometown = wx.StaticText(self, wx.NewId(), _("Home Town"))
self.home_town = wx.TextCtrl(self, wx.NewId(), style=wx.TE_READONLY|wx.TE_MULTILINE) self.home_town = wx.TextCtrl(self, wx.NewId(), style=wx.TE_READONLY|wx.TE_MULTILINE)
self.home_town.SetMinSize(text_size(self.home_town, 40)) self.home_town.SetMinSize(text_size(self.home_town, 40))
self.home_town.Enable(False) self.home_town.Enable(False)
sizerHometown = wx.BoxSizer(wx.HORIZONTAL) sizerHometown = wx.BoxSizer(wx.HORIZONTAL)
sizerHometown.Add(lblHometown, 0, wx.ALL, 5) sizerHometown.Add(lblHometown, 0, wx.ALL, 5)
sizerHometown.Add(self.home_town, 0, wx.ALL, 5) sizerHometown.Add(self.home_town, 0, wx.ALL, 5)
sizer.Add(sizerHometown, 0, wx.ALL, 5) sizer.Add(sizerHometown, 0, wx.ALL, 5)
lblWebsite = wx.StaticText(self, wx.NewId(), _("Website")) lblWebsite = wx.StaticText(self, wx.NewId(), _("Website"))
self.website = wx.TextCtrl(self, wx.NewId(), style=wx.TE_READONLY|wx.TE_MULTILINE)#size=(500, -1)) self.website = wx.TextCtrl(self, wx.NewId(), style=wx.TE_READONLY|wx.TE_MULTILINE)#size=(500, -1))
self.website.SetMinSize(text_size(self.website, 90)) self.website.SetMinSize(text_size(self.website, 90))
self.website.Enable(False) self.website.Enable(False)
self.go_site = wx.Button(self, -1, _("Visit website")) self.go_site = wx.Button(self, -1, _("Visit website"))
self.go_site.Enable(False) self.go_site.Enable(False)
sizerWebsite = wx.BoxSizer(wx.HORIZONTAL) sizerWebsite = wx.BoxSizer(wx.HORIZONTAL)
sizerWebsite.Add(lblWebsite, 0, wx.ALL, 5) sizerWebsite.Add(lblWebsite, 0, wx.ALL, 5)
sizerWebsite.Add(self.website, 1, wx.ALL, 5) sizerWebsite.Add(self.website, 1, wx.ALL, 5)
sizerWebsite.Add(self.go_site, 1, wx.ALL, 5) sizerWebsite.Add(self.go_site, 1, wx.ALL, 5)
sizer.Add(sizerWebsite, 1, wx.ALL, 5) sizer.Add(sizerWebsite, 1, wx.ALL, 5)
lblOccupation = wx.StaticText(self, wx.NewId(), _("Occupation")) lblOccupation = wx.StaticText(self, wx.NewId(), _("Occupation"))
self.occupation = wx.TextCtrl(self, wx.NewId(), style=wx.TE_READONLY|wx.TE_MULTILINE) self.occupation = wx.TextCtrl(self, wx.NewId(), style=wx.TE_READONLY|wx.TE_MULTILINE)
self.occupation.SetMinSize(text_size(self.occupation, 90)) self.occupation.SetMinSize(text_size(self.occupation, 90))
self.occupation.Enable(False) self.occupation.Enable(False)
sizerOccupation = wx.BoxSizer(wx.HORIZONTAL) sizerOccupation = wx.BoxSizer(wx.HORIZONTAL)
sizerOccupation.Add(lblOccupation, 0, wx.ALL, 5) sizerOccupation.Add(lblOccupation, 0, wx.ALL, 5)
sizerOccupation.Add(self.occupation, 0, wx.ALL, 5) sizerOccupation.Add(self.occupation, 0, wx.ALL, 5)
sizer.Add(sizerOccupation, 0, wx.ALL, 5) sizer.Add(sizerOccupation, 0, wx.ALL, 5)
self.SetSizer(sizer) self.SetSizer(sizer)
class userProfileDialog(widgetUtils.BaseDialog): class userProfileDialog(widgetUtils.BaseDialog):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(userProfileDialog, self).__init__(parent=None, *args, **kwargs) super(userProfileDialog, self).__init__(parent=None, *args, **kwargs)
self.panel = wx.Panel(self) self.panel = wx.Panel(self)
self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer = wx.BoxSizer(wx.VERTICAL)
self.notebook = wx.Notebook(self.panel) self.notebook = wx.Notebook(self.panel)
def create_controls(self, section): def create_controls(self, section):
if section == "main_info": if section == "main_info":
self.main_info = mainInfo(self.notebook) self.main_info = mainInfo(self.notebook)
self.notebook.AddPage(self.main_info, _("Basic information")) self.notebook.AddPage(self.main_info, _("Basic information"))
self.main_info.SetFocus() self.main_info.SetFocus()
def realice(self): def realice(self):
self.image = wx.StaticBitmap(self.panel, bitmap=wx.Bitmap(200, 200), size=(200, 200)) self.image = wx.StaticBitmap(self.panel, bitmap=wx.Bitmap(200, 200), size=(200, 200))
self.sizer.Add(self.image, 1, wx.ALL, 10) self.sizer.Add(self.image, 1, wx.ALL, 10)
self.sizer.Add(self.notebook, 1, wx.ALL, 5) self.sizer.Add(self.notebook, 1, wx.ALL, 5)
cancel = wx.Button(self.panel, wx.ID_CANCEL) cancel = wx.Button(self.panel, wx.ID_CANCEL)
btnSizer = wx.BoxSizer(wx.HORIZONTAL) btnSizer = wx.BoxSizer(wx.HORIZONTAL)
btnSizer.Add(cancel, 0, wx.ALL, 5) btnSizer.Add(cancel, 0, wx.ALL, 5)
self.sizer.Add(btnSizer, 0, wx.ALL, 5) self.sizer.Add(btnSizer, 0, wx.ALL, 5)
self.panel.SetSizer(self.sizer) self.panel.SetSizer(self.sizer)
self.SetClientSize(self.sizer.CalcMin()) self.SetClientSize(self.sizer.CalcMin())
def get_value(self, panel, key): def get_value(self, panel, key):
p = getattr(self, panel) p = getattr(self, panel)
return getattr(p, key).GetValue() return getattr(p, key).GetValue()
def set_value(self, panel, key, value): def set_value(self, panel, key, value):
p = getattr(self, panel) p = getattr(self, panel)
control = getattr(p, key) control = getattr(p, key)
getattr(control, "SetValue")(value) getattr(control, "SetValue")(value)
def enable(self, panel, key, value=False): def enable(self, panel, key, value=False):
p = getattr(self, panel) p = getattr(self, panel)
control = getattr(p, key) control = getattr(p, key)
getattr(control, "Enable")(value) getattr(control, "Enable")(value)

View File

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

View File

@ -63,172 +63,172 @@ LISTBOX_CHANGED = wx.EVT_LISTBOX
LISTBOX_ITEM_ACTIVATED = wx.EVT_LIST_ITEM_ACTIVATED LISTBOX_ITEM_ACTIVATED = wx.EVT_LIST_ITEM_ACTIVATED
def exit_application(): def exit_application():
""" Closes the current window cleanly. """ """ Closes the current window cleanly. """
wx.GetApp().ExitMainLoop() wx.GetApp().ExitMainLoop()
def connect_event(parent, event, func, menuitem=None, *args, **kwargs): def connect_event(parent, event, func, menuitem=None, *args, **kwargs):
""" Connects an event to a function. """ Connects an event to a function.
parent wx.window: The widget that will listen for the event. parent wx.window: The widget that will listen for the event.
event widgetUtils.event: The event that will be listened for the parent. The event should be one of the widgetUtils events. event widgetUtils.event: The event that will be listened for the parent. The event should be one of the widgetUtils events.
function func: The function that will be connected to the event.""" function func: The function that will be connected to the event."""
if menuitem == None: if menuitem == None:
return getattr(parent, "Bind")(event, func, *args, **kwargs) return getattr(parent, "Bind")(event, func, *args, **kwargs)
else: else:
return getattr(parent, "Bind")(event, func, menuitem, *args, **kwargs) return getattr(parent, "Bind")(event, func, menuitem, *args, **kwargs)
def connectExitFunction(exitFunction): def connectExitFunction(exitFunction):
""" This connect the events in WX when an user is turning off the machine.""" """ This connect the events in WX when an user is turning off the machine."""
wx.GetApp().Bind(wx.EVT_QUERY_END_SESSION, exitFunction) wx.GetApp().Bind(wx.EVT_QUERY_END_SESSION, exitFunction)
wx.GetApp().Bind(wx.EVT_END_SESSION, exitFunction) wx.GetApp().Bind(wx.EVT_END_SESSION, exitFunction)
class BaseDialog(wx.Dialog): class BaseDialog(wx.Dialog):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(BaseDialog, self).__init__(*args, **kwargs) super(BaseDialog, self).__init__(*args, **kwargs)
def get_response(self): def get_response(self):
return self.ShowModal() return self.ShowModal()
def get(self, control): def get(self, control):
if hasattr(self, control): if hasattr(self, control):
control = getattr(self, control) control = getattr(self, control)
if hasattr(control, "GetValue"): return getattr(control, "GetValue")() if hasattr(control, "GetValue"): return getattr(control, "GetValue")()
elif hasattr(control, "GetLabel"): return getattr(control, "GetLabel")() elif hasattr(control, "GetLabel"): return getattr(control, "GetLabel")()
else: return -1 else: return -1
else: return 0 else: return 0
def set(self, control, text): def set(self, control, text):
if hasattr(self, control): if hasattr(self, control):
control = getattr(self, control) control = getattr(self, control)
if hasattr(control, "SetValue"): return getattr(control, "SetValue")(text) if hasattr(control, "SetValue"): return getattr(control, "SetValue")(text)
elif hasattr(control, "SetLabel"): return getattr(control, "SetLabel")(text) elif hasattr(control, "SetLabel"): return getattr(control, "SetLabel")(text)
elif hasattr(control, "ChangeValue"): return getattr(control, "ChangeValue")(text) elif hasattr(control, "ChangeValue"): return getattr(control, "ChangeValue")(text)
else: return -1 else: return -1
else: return 0 else: return 0
def destroy(self): def destroy(self):
self.Destroy() self.Destroy()
def set_title(self, title): def set_title(self, title):
self.SetTitle(title) self.SetTitle(title)
def get_title(self): def get_title(self):
return self.GetTitle() return self.GetTitle()
def enable(self, control): def enable(self, control):
getattr(self, control).Enable(True) getattr(self, control).Enable(True)
def disable(self, control): def disable(self, control):
getattr(self, control).Enable(False) getattr(self, control).Enable(False)
class mainLoopObject(wx.App): class mainLoopObject(wx.App):
def __init__(self): def __init__(self):
self.app = wx.App() self.app = wx.App()
self.lc = wx.Locale() self.lc = wx.Locale()
lang=languageHandler.getLanguage() lang=languageHandler.getLanguage()
wxLang=self.lc.FindLanguageInfo(lang) wxLang=self.lc.FindLanguageInfo(lang)
if not wxLang and '_' in lang: if not wxLang and '_' in lang:
wxLang=self.lc.FindLanguageInfo(lang.split('_')[0]) wxLang=self.lc.FindLanguageInfo(lang.split('_')[0])
self.lc.AddCatalogLookupPathPrefix(paths.locale_path()) self.lc.AddCatalogLookupPathPrefix(paths.locale_path())
if wxLang: if wxLang:
self.lc.Init(wxLang.Language) self.lc.Init(wxLang.Language)
def run(self): def run(self):
self.app.MainLoop() self.app.MainLoop()
class multiselectionBaseList(wx.ListCtrl, listmix.CheckListCtrlMixin): class multiselectionBaseList(wx.ListCtrl, listmix.CheckListCtrlMixin):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(multiselectionBaseList, self).__init__(*args, **kwargs) super(multiselectionBaseList, self).__init__(*args, **kwargs)
# wx.ListCtrl.__init__(self, *args, **kwargs) # wx.ListCtrl.__init__(self, *args, **kwargs)
# listmix.CheckListCtrlMixin.__init__(self) # listmix.CheckListCtrlMixin.__init__(self)
self.Bind(wx.EVT_CHAR_HOOK, self.on_keydown) self.Bind(wx.EVT_CHAR_HOOK, self.on_keydown)
self.Bind(wx.EVT_LIST_ITEM_FOCUSED, self.on_focus) self.Bind(wx.EVT_LIST_ITEM_FOCUSED, self.on_focus)
def on_focus(self, event): def on_focus(self, event):
currentItem = self.GetFocusedItem() currentItem = self.GetFocusedItem()
if self.IsChecked(currentItem): if self.IsChecked(currentItem):
pub.sendMessage("play-sound", sound="selected.ogg") pub.sendMessage("play-sound", sound="selected.ogg")
event.Skip() event.Skip()
def OnCheckItem(self, index, flag): def OnCheckItem(self, index, flag):
if flag == True: if flag == True:
pub.sendMessage("play-sound", sound="checked.ogg") pub.sendMessage("play-sound", sound="checked.ogg")
else: else:
pub.sendMessage("play-sound", sound="unchecked.ogg") pub.sendMessage("play-sound", sound="unchecked.ogg")
def on_keydown(self, event): def on_keydown(self, event):
if event.GetKeyCode() == wx.WXK_SPACE: if event.GetKeyCode() == wx.WXK_SPACE:
# In the example of wx multiselection list they call ToggleItem. # In the example of wx multiselection list they call ToggleItem.
# however this didn't worked quite well. So let's implement it manually. # however this didn't worked quite well. So let's implement it manually.
if self.IsChecked(self.GetFocusedItem()): if self.IsChecked(self.GetFocusedItem()):
self.SetItemImage(self.GetFocusedItem(), 0) self.SetItemImage(self.GetFocusedItem(), 0)
self.OnCheckItem(self.GetFocusedItem(), False) self.OnCheckItem(self.GetFocusedItem(), False)
else: else:
self.SetItemImage(self.GetFocusedItem(), 1) self.SetItemImage(self.GetFocusedItem(), 1)
self.OnCheckItem(self.GetFocusedItem(), True) self.OnCheckItem(self.GetFocusedItem(), True)
event.Skip() event.Skip()
class list(object): class list(object):
def __init__(self, parent, *columns, **listArguments): def __init__(self, parent, *columns, **listArguments):
self.columns = columns self.columns = columns
self.listArguments = listArguments self.listArguments = listArguments
self.create_list(parent) self.create_list(parent)
def set_windows_size(self, column, characters_max): def set_windows_size(self, column, characters_max):
self.list.SetColumnWidth(column, characters_max*2) self.list.SetColumnWidth(column, characters_max*2)
def set_size(self): def set_size(self):
self.list.SetSize((self.list.GetBestSize()[0], 1000)) self.list.SetSize((self.list.GetBestSize()[0], 1000))
def create_list(self, parent): def create_list(self, parent):
self.list = wx.ListCtrl(parent, -1, **self.listArguments) self.list = wx.ListCtrl(parent, -1, **self.listArguments)
for i in range(0, len(self.columns)): for i in range(0, len(self.columns)):
self.list.InsertColumn(i, "%s" % (self.columns[i])) self.list.InsertColumn(i, "%s" % (self.columns[i]))
def insert_item(self, reversed, *item): def insert_item(self, reversed, *item):
""" Inserts an item on the list.""" """ Inserts an item on the list."""
if reversed == False: items = self.list.GetItemCount() if reversed == False: items = self.list.GetItemCount()
else: items = 0 else: items = 0
self.list.InsertItem(items, item[0]) self.list.InsertItem(items, item[0])
for i in range(1, len(self.columns)): for i in range(1, len(self.columns)):
self.list.SetItem(items, i, item[i]) self.list.SetItem(items, i, item[i])
def remove_item(self, pos): def remove_item(self, pos):
""" Deletes an item from the list.""" """ Deletes an item from the list."""
if pos > 0: self.list.Focus(pos-1) if pos > 0: self.list.Focus(pos-1)
self.list.DeleteItem(pos) self.list.DeleteItem(pos)
def clear(self): def clear(self):
self.list.DeleteAllItems() self.list.DeleteAllItems()
def get_selected(self): def get_selected(self):
return self.list.GetFocusedItem() return self.list.GetFocusedItem()
def select_item(self, pos): def select_item(self, pos):
self.list.Focus(pos) self.list.Focus(pos)
def get_count(self): def get_count(self):
selected = self.list.GetItemCount() selected = self.list.GetItemCount()
if selected == -1: if selected == -1:
return 0 return 0
else: else:
return selected return selected
def Enable(self, value): def Enable(self, value):
return self.list.Enable(value) return self.list.Enable(value)
class multiselectionList(list): class multiselectionList(list):
def create_list(self, parent): def create_list(self, parent):
self.list = multiselectionBaseList(parent, -1, **self.listArguments) self.list = multiselectionBaseList(parent, -1, **self.listArguments)
for i in range(0, len(self.columns)): for i in range(0, len(self.columns)):
self.list.InsertColumn(i, "%s" % (self.columns[i])) self.list.InsertColumn(i, "%s" % (self.columns[i]))
def get_multiple_selection(self): def get_multiple_selection(self):
selected = [] selected = []
for item in range(0, self.list.GetItemCount()): for item in range(0, self.list.GetItemCount()):
if self.list.IsChecked(item): if self.list.IsChecked(item):
selected.append(item) selected.append(item)
if len(selected) == 0 and self.list.GetFocusedItem() != -1: if len(selected) == 0 and self.list.GetFocusedItem() != -1:
selected.append(self.list.GetFocusedItem()) selected.append(self.list.GetFocusedItem())
return selected return selected

Some files were not shown because too many files have changed in this diff Show More