Refactored attachment code so it will match to the MVP pattern
This commit is contained in:
parent
71ce8597e5
commit
589a7da53b
@ -6,6 +6,9 @@ import logging
|
||||
import webbrowser
|
||||
import arrow
|
||||
import wx
|
||||
import presenters
|
||||
import views
|
||||
import interactors
|
||||
import languageHandler
|
||||
import widgetUtils
|
||||
from . import messages
|
||||
@ -13,7 +16,6 @@ from presenters import player
|
||||
import output
|
||||
from . import selector
|
||||
from . import posts
|
||||
from . import attach
|
||||
from pubsub import pub
|
||||
from vk_api.exceptions import VkApiError
|
||||
from vk_api import upload
|
||||
@ -840,7 +842,7 @@ class chatBuffer(baseBuffer):
|
||||
return retrieved
|
||||
|
||||
def add_attachment(self, *args, **kwargs):
|
||||
a = attach.attach(self.session, True)
|
||||
a = presenters.attachPresenter(session=self.session, view=views.attachDialog(voice_messages=True), interactor=interactors.attachInteractor())
|
||||
if len(a.attachments) != 0:
|
||||
self.attachments_to_be_sent = a.attachments
|
||||
|
||||
|
@ -2,9 +2,11 @@
|
||||
from __future__ import unicode_literals
|
||||
import time
|
||||
import widgetUtils
|
||||
import presenters
|
||||
import views
|
||||
import interactors
|
||||
import output
|
||||
from pubsub import pub
|
||||
from . import attach
|
||||
from wxUI.dialogs import message, selector
|
||||
from extra import SpellChecker, translator
|
||||
from logging import getLogger
|
||||
@ -71,7 +73,7 @@ class post(object):
|
||||
checker.clean()
|
||||
|
||||
def show_attach_dialog(self, *args, **kwargs):
|
||||
a = attach.attach(self.session)
|
||||
a = presenters.attachPresenter(session=self.session, view=views.attachDialog(), interactor=interactors.attachInteractor())
|
||||
if len(a.attachments) != 0:
|
||||
self.attachments = a.attachments
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
from .attach import *
|
||||
from . audioRecorder import *
|
||||
from .configuration import *
|
||||
from .profiles import *
|
74
src/interactors/attach.py
Normal file
74
src/interactors/attach.py
Normal file
@ -0,0 +1,74 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
import widgetUtils
|
||||
from pubsub import pub
|
||||
from wxUI.dialogs import selector
|
||||
from wxUI.menus import attachMenu
|
||||
from . import base
|
||||
|
||||
class attachInteractor(base.baseInteractor):
|
||||
|
||||
def insert_attachment(self, attachment):
|
||||
self.view.attachments.insert_item(False, *attachment)
|
||||
|
||||
def remove_attachment(self, attachment):
|
||||
self.view.attachments.remove_item(attachment)
|
||||
|
||||
def install(self, *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.audio, widgetUtils.BUTTON_PRESSED, self.on_audio)
|
||||
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.remove, widgetUtils.BUTTON_PRESSED, self.on_remove_attachment)
|
||||
pub.subscribe(self.insert_attachment, self.modulename+"_insert_attachment")
|
||||
pub.subscribe(self.remove_attachment, self.modulename+"_remove_attachment")
|
||||
|
||||
def uninstall(self):
|
||||
super(attachInteractor, self).uninstall()
|
||||
pub.unsubscribe(self.insert_attachment, self.modulename+"_insert_attachment")
|
||||
pub.unsubscribe(self.remove_attachment, self.modulename+"_remove_attachment")
|
||||
|
||||
def on_image(self, *args, **kwargs):
|
||||
""" display menu for adding image attachments. """
|
||||
m = attachMenu()
|
||||
# disable add from VK as it is not supported in images, yet.
|
||||
m.add.Enable(False)
|
||||
widgetUtils.connect_event(m, widgetUtils.MENU, self.on_upload_image, menuitem=m.upload)
|
||||
self.view.PopupMenu(m, self.view.photo.GetPosition())
|
||||
|
||||
def on_audio(self, *args, **kwargs):
|
||||
""" display menu to add audio attachments."""
|
||||
m = attachMenu()
|
||||
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)
|
||||
self.view.PopupMenu(m, self.view.audio.GetPosition())
|
||||
|
||||
def on_upload_image(self, *args, **kwargs):
|
||||
""" allows uploading an image from the computer.
|
||||
"""
|
||||
image, description = self.view.get_image()
|
||||
if image != None:
|
||||
self.presenter.upload_image(image, description)
|
||||
|
||||
def on_upload_audio(self, *args, **kwargs):
|
||||
""" Allows uploading an audio file from the computer. Only mp3 files are supported. """
|
||||
audio = self.view.get_audio()
|
||||
if audio != None:
|
||||
self.presenter.upload_audio(audio)
|
||||
|
||||
def on_upload_voice_message(self, *args, **kwargs):
|
||||
self.presenter.upload_voice_message()
|
||||
|
||||
def on_add_audio(self, *args, **kwargs):
|
||||
""" Allow adding an audio directly from the user's audio library."""
|
||||
audios = self.presenter.get_available_audios()
|
||||
select = selector.selectAttachment(_("Select the audio files you want to send"), audios)
|
||||
if select.get_response() == widgetUtils.OK and select.attachments.GetCount() > 0:
|
||||
attachments = select.get_all_attachments()
|
||||
self.presenter.take_audios(attachments)
|
||||
|
||||
def on_remove_attachment(self, *args, **kwargs):
|
||||
""" Remove the currently focused item from the attachments list."""
|
||||
current_item = self.view.attachments.get_selected()
|
||||
self.presenter.remove_attachment(current_item)
|
@ -1,4 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from .attach import *
|
||||
from .audioRecorder import *
|
||||
from .configuration import *
|
||||
from .profiles import *
|
108
src/presenters/attach.py
Normal file
108
src/presenters/attach.py
Normal file
@ -0,0 +1,108 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
""" Attachment controller for different kind of posts in VK.
|
||||
this controller will take care of preparing data structures to be uploaded later, when the user decides to start the upload process by sending the post.
|
||||
"""
|
||||
from __future__ import unicode_literals
|
||||
import os
|
||||
import logging
|
||||
import interactors
|
||||
import views
|
||||
from mutagen.id3 import ID3
|
||||
from sessionmanager.utils import seconds_to_string
|
||||
from . import audioRecorder, base
|
||||
|
||||
log = logging.getLogger(__file__)
|
||||
|
||||
class attachPresenter(base.basePresenter):
|
||||
""" 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).
|
||||
* 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.
|
||||
"""
|
||||
|
||||
def __init__(self, session, view, interactor, voice_messages=False):
|
||||
""" Constructor.
|
||||
@ 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. Functionality for this button has not been added yet.
|
||||
"""
|
||||
super(attachPresenter, self).__init__(view=view, interactor=interactor, modulename="attach")
|
||||
self.session = session
|
||||
# Self.attachments will hold a reference to all attachments added to the dialog.
|
||||
self.attachments = list()
|
||||
self.run()
|
||||
|
||||
def upload_image(self, image, description):
|
||||
""" allows uploading an image from the computer.
|
||||
"""
|
||||
imageInfo = {"type": "photo", "file": image, "description": description, "from": "local"}
|
||||
self.attachments.append(imageInfo)
|
||||
# Translators: This is the text displayed in the attachments dialog, when the user adds a photo.
|
||||
info = [_("Photo"), description]
|
||||
self.send_message("insert_attachment", attachment=info)
|
||||
self.send_message("enable_control", control="remove")
|
||||
|
||||
def upload_audio(self, audio):
|
||||
""" Allows uploading an audio file from the computer. Only mp3 files are supported. """
|
||||
if audio != None:
|
||||
# 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.
|
||||
audio_tags = ID3(audio)
|
||||
if "TIT2" in audio_tags:
|
||||
title = audio_tags["TIT2"].text[0]
|
||||
else:
|
||||
title = _("Untitled")
|
||||
if "TPE1" in audio_tags:
|
||||
artist = audio_tags["TPE1"].text[0]
|
||||
else:
|
||||
artist = _("Unknown artist")
|
||||
audioInfo = {"type": "audio", "file": audio, "from": "local", "title": title, "artist": artist}
|
||||
self.attachments.append(audioInfo)
|
||||
# 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)]
|
||||
self.send_message("insert_attachment", attachment=info)
|
||||
self.send_message("enable_control", control="remove")
|
||||
|
||||
def upload_voice_message(self):
|
||||
a = audioRecorder.audioRecorderPresenter(view=views.audioRecorderDialog(), interactor=interactors.audioRecorderInteractor())
|
||||
if a.file != None and a.duration != 0:
|
||||
audioInfo = {"type": "voice_message", "file": a.file, "from": "local"}
|
||||
self.attachments.append(audioInfo)
|
||||
# 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,)]
|
||||
self.send_message("insert_attachment", attachment=info)
|
||||
self.send_message("enable_control", control="remove")
|
||||
|
||||
####### ToDo: replace this with selector presenter when finished.
|
||||
def get_available_audios(self):
|
||||
# Let's reuse the already downloaded audios.
|
||||
list_of_audios = self.session.db["me_audio"]["items"]
|
||||
audios = []
|
||||
for i in list_of_audios:
|
||||
audios.append("{0}, {1}".format(i["title"], i["artist"]))
|
||||
return audios
|
||||
|
||||
def take_audios(self, audios_list):
|
||||
list_of_audios = self.session.db["me_audio"]["items"]
|
||||
for i in audios_list:
|
||||
info = dict(type="audio", id=list_of_audios[i]["id"], owner_id=list_of_audios[i]["owner_id"])
|
||||
info["from"] = "online"
|
||||
self.attachments.append(info)
|
||||
# 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"])]
|
||||
self.send_message("insert_attachment", attachment=info2)
|
||||
self.check_remove_status()
|
||||
|
||||
def remove_attachment(self, item_index):
|
||||
""" Remove the currently focused item from the attachments list."""
|
||||
log.debug("Removing item %d" % (item_index,))
|
||||
if item_index == -1: item_index = 0
|
||||
self.attachments.pop(item_index)
|
||||
self.send_message("remove_attachment", attachment=item_index)
|
||||
self.check_remove_status()
|
||||
log.debug("Removed")
|
||||
|
||||
def check_remove_status(self):
|
||||
""" Checks whether the remove button should remain enabled."""
|
||||
if len(self.attachments) == 0:
|
||||
self.send_message("disable_control", control="remove")
|
@ -16,6 +16,7 @@ class audioRecorderPresenter(base.basePresenter):
|
||||
self.recording = None
|
||||
self.duration = 0
|
||||
self.playing = None
|
||||
self.file = None
|
||||
self.run()
|
||||
|
||||
def toggle_recording(self, *args, **kwargs):
|
||||
|
@ -1,3 +1,9 @@
|
||||
""" 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.
|
||||
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.
|
||||
"""
|
||||
from .dialogs.attach import *
|
||||
from .dialogs.audioRecorder import *
|
||||
from .dialogs.configuration import *
|
||||
from .dialogs.profiles import *
|
58
src/views/dialogs/attach.py
Normal file
58
src/views/dialogs/attach.py
Normal file
@ -0,0 +1,58 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
import wx
|
||||
import widgetUtils
|
||||
|
||||
class attachDialog(widgetUtils.BaseDialog):
|
||||
def __init__(self, voice_messages=False):
|
||||
super(attachDialog, self).__init__(None, title=_("Add an attachment"))
|
||||
panel = wx.Panel(self)
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
lbl1 = wx.StaticText(panel, wx.NewId(), _("Attachments"))
|
||||
self.attachments = widgetUtils.list(panel, _("Type"), _("Title"), style=wx.LC_REPORT)
|
||||
box = wx.BoxSizer(wx.HORIZONTAL)
|
||||
box.Add(lbl1, 0, wx.ALL, 5)
|
||||
box.Add(self.attachments.list, 0, wx.ALL, 5)
|
||||
sizer.Add(box, 0, wx.ALL, 5)
|
||||
static = wx.StaticBox(panel, label=_("Add attachments"))
|
||||
self.photo = wx.Button(panel, wx.NewId(), _("&Photo"))
|
||||
self.audio = wx.Button(panel, wx.NewId(), _("Audio file"))
|
||||
if voice_messages:
|
||||
self.voice_message = wx.Button(panel, wx.NewId(), _("Voice message"))
|
||||
self.remove = wx.Button(panel, wx.NewId(), _("Remove attachment"))
|
||||
self.remove.Enable(False)
|
||||
btnsizer = wx.StaticBoxSizer(static, wx.HORIZONTAL)
|
||||
btnsizer.Add(self.photo, 0, wx.ALL, 5)
|
||||
btnsizer.Add(self.audio, 0, wx.ALL, 5)
|
||||
if voice_messages:
|
||||
btnsizer.Add(self.voice_message, 0, wx.ALL, 5)
|
||||
sizer.Add(btnsizer, 0, wx.ALL, 5)
|
||||
ok = wx.Button(panel, wx.ID_OK)
|
||||
ok.SetDefault()
|
||||
cancelBtn = wx.Button(panel, wx.ID_CANCEL)
|
||||
btnSizer = wx.BoxSizer()
|
||||
btnSizer.Add(ok, 0, wx.ALL, 5)
|
||||
btnSizer.Add(cancelBtn, 0, wx.ALL, 5)
|
||||
sizer.Add(btnSizer, 0, wx.ALL, 5)
|
||||
panel.SetSizer(sizer)
|
||||
self.SetClientSize(sizer.CalcMin())
|
||||
|
||||
def 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)
|
||||
if openFileDialog.ShowModal() == wx.ID_CANCEL:
|
||||
return None
|
||||
dsc = self.ask_description()
|
||||
return (openFileDialog.GetPath(), dsc)
|
||||
|
||||
def ask_description(self):
|
||||
dlg = wx.TextEntryDialog(self, _("please provide a description"), _("Description"))
|
||||
dlg.ShowModal()
|
||||
result = dlg.GetValue()
|
||||
dlg.Destroy()
|
||||
return result
|
||||
|
||||
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)
|
||||
if openFileDialog.ShowModal() == wx.ID_CANCEL:
|
||||
return None
|
||||
return openFileDialog.GetPath()
|
Loading…
Reference in New Issue
Block a user