ui: empty space. pseudo offline file transfers

This commit is contained in:
ingvar1995 2016-06-15 15:38:42 +03:00
parent 63774ba5df
commit d3c8c99048
9 changed files with 192 additions and 57 deletions

View File

@ -68,6 +68,7 @@ def friend_status(tox, friend_num, new_status, user_data):
if friend.status is None and Settings.get_instance()['sound_notifications'] and profile.status != TOX_USER_STATUS['BUSY']: if friend.status is None and Settings.get_instance()['sound_notifications'] and profile.status != TOX_USER_STATUS['BUSY']:
sound_notification(SOUND_NOTIFICATION['FRIEND_CONNECTION_STATUS']) sound_notification(SOUND_NOTIFICATION['FRIEND_CONNECTION_STATUS'])
invoke_in_main_thread(friend.set_status, new_status) invoke_in_main_thread(friend.set_status, new_status)
invoke_in_main_thread(profile.send_files, friend_num)
invoke_in_main_thread(profile.update_filtration) invoke_in_main_thread(profile.update_filtration)
@ -85,7 +86,6 @@ def friend_connection_status(tox, friend_num, new_status, user_data):
sound_notification(SOUND_NOTIFICATION['FRIEND_CONNECTION_STATUS']) sound_notification(SOUND_NOTIFICATION['FRIEND_CONNECTION_STATUS'])
elif friend.status is None: elif friend.status is None:
invoke_in_main_thread(profile.send_avatar, friend_num) invoke_in_main_thread(profile.send_avatar, friend_num)
profile.friend_online(friend_num)
invoke_in_main_thread(PluginLoader.get_instance().friend_online, friend_num) invoke_in_main_thread(PluginLoader.get_instance().friend_online, friend_num)

View File

@ -116,6 +116,18 @@ class Friend(contact.Contact):
self._corr = filter(lambda x: x.get_type() in (2, 3) and x.get_status() >= 2, self._corr) self._corr = filter(lambda x: x.get_type() in (2, 3) and x.get_status() >= 2, self._corr)
self._unsaved_messages = 0 self._unsaved_messages = 0
def get_curr_text(self):
return self._curr_text
def set_curr_text(self, value):
self._curr_text = value
curr_text = property(get_curr_text, set_curr_text)
# -----------------------------------------------------------------------------------------------------------------
# File transfers support
# -----------------------------------------------------------------------------------------------------------------
def update_transfer_data(self, file_number, status, inline=None): def update_transfer_data(self, file_number, status, inline=None):
""" """
Update status of active transfer and load inline if needed Update status of active transfer and load inline if needed
@ -131,13 +143,15 @@ class Friend(contact.Contact):
except: except:
pass pass
def get_curr_text(self): def get_unsent_files(self):
return self._curr_text messages = filter(lambda x: type(x) is UnsentFile, self._corr)
return messages
def set_curr_text(self, value): def clear_unsent_files(self):
self._curr_text = value self._corr = filter(lambda x: type(x) is not UnsentFile, self._corr)
curr_text = property(get_curr_text, set_curr_text) def delete_one_unsent_file(self, time):
self._corr = filter(lambda x: not (type(x) is UnsentFile and x.get_data()[2] == time), self._corr)
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
# Alias support # Alias support

BIN
src/images/search.png Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -356,6 +356,60 @@ class FileTransferItem(QtGui.QListWidget):
self.state = state self.state = state
class UnsentFileItem(QtGui.QListWidget):
def __init__(self, file_name, size, user, time, width, parent=None):
QtGui.QListWidget.__init__(self, parent)
self.resize(QtCore.QSize(width, 34))
self.time = time
self.setStyleSheet('QListWidget { border: 1px solid #FF8000; }')
self.name = DataLabel(self)
self.name.setGeometry(QtCore.QRect(3, 7, 95, 20))
self.name.setTextFormat(QtCore.Qt.PlainText)
font = QtGui.QFont()
font.setFamily("Times New Roman")
font.setPointSize(11)
font.setBold(True)
self.name.setFont(font)
self.name.setText(user)
self.time = QtGui.QLabel(self)
self.time.setGeometry(QtCore.QRect(width - 53, 7, 50, 20))
font.setPointSize(10)
font.setBold(False)
self.time.setFont(font)
self.time.setText(convert_time(time))
self.cancel = QtGui.QPushButton(self)
self.cancel.setGeometry(QtCore.QRect(width - 120, 2, 30, 30))
pixmap = QtGui.QPixmap(curr_directory() + '/images/decline.png')
icon = QtGui.QIcon(pixmap)
self.cancel.setIcon(icon)
self.cancel.setIconSize(QtCore.QSize(30, 30))
self.cancel.clicked.connect(self.cancel_transfer)
self.cancel.setStyleSheet('QPushButton:hover { border: 1px solid #3A3939; background-color: none;}')
self.file_name = DataLabel(self)
self.file_name.setGeometry(QtCore.QRect(210, 7, width - 400, 20))
font.setPointSize(12)
self.file_name.setFont(font)
file_size = size / 1024
if not file_size:
file_size = '{}B'.format(size)
elif file_size >= 1024:
file_size = '{}MB'.format(file_size / 1024)
else:
file_size = '{}KB'.format(file_size)
file_data = u'{} {}'.format(file_size, file_name)
self.file_name.setText(file_data)
self.setFocusPolicy(QtCore.Qt.NoFocus)
def cancel_transfer(self):
pr = profile.Profile.get_instance()
pr.cancel_not_started_transfer(self.time)
class InlineImageItem(QtGui.QWidget): class InlineImageItem(QtGui.QWidget):
def __init__(self, data, width, parent=None): def __init__(self, data, width, parent=None):

View File

@ -3,7 +3,7 @@
from menu import * from menu import *
from profile import * from profile import *
from list_items import * from list_items import *
from widgets import QRightClickButton, RubberBand, MultilineEdit from widgets import MultilineEdit
import plugin_support import plugin_support
from mainscreen_widgets import * from mainscreen_widgets import *
@ -142,33 +142,34 @@ class MainWindow(QtGui.QMainWindow):
def setup_left_center_menu(self, Form): def setup_left_center_menu(self, Form):
Form.resize(270, 25) Form.resize(270, 25)
self.search_label = QtGui.QLabel(Form) self.search_label = QtGui.QLabel(Form)
self.search_label.setGeometry(QtCore.QRect(3, 0, 25, 25)) self.search_label.setGeometry(QtCore.QRect(3, 2, 20, 20))
pixmap = QtGui.QPixmap(QtCore.QSize(25, 25)) pixmap = QtGui.QPixmap()
pixmap.load(curr_directory() + '/images/search.png') pixmap.load(curr_directory() + '/images/search.png')
self.search_label.setScaledContents(False) self.search_label.setScaledContents(False)
self.search_label.setPixmap(pixmap.scaled(25, 25, QtCore.Qt.KeepAspectRatio)) self.search_label.setPixmap(pixmap)
self.contact_name = QtGui.QLineEdit(Form) self.contact_name = QtGui.QLineEdit(Form)
self.contact_name.setGeometry(QtCore.QRect(30, 0, 120, 25)) self.contact_name.setGeometry(QtCore.QRect(0, 0, 150, 25))
self.contact_name.setObjectName("contact_name") self.contact_name.setObjectName("contact_name")
self.contact_name.textChanged.connect(self.filtering) self.contact_name.textChanged.connect(self.filtering)
self.online_contacts = QtGui.QComboBox(Form) self.online_contacts = QtGui.QComboBox(Form)
self.online_contacts.setGeometry(QtCore.QRect(150, 0, 120, 25)) self.online_contacts.setGeometry(QtCore.QRect(150, 0, 120, 25))
self.online_contacts.activated[int].connect(lambda x: self.filtering()) self.online_contacts.activated[int].connect(lambda x: self.filtering())
self.search_label.raise_()
QtCore.QMetaObject.connectSlotsByName(Form) QtCore.QMetaObject.connectSlotsByName(Form)
def setup_left_top(self, Form): def setup_left_top(self, Form):
Form.setObjectName("left_top") Form.setObjectName("left_top")
Form.setCursor(QtCore.Qt.PointingHandCursor) Form.setCursor(QtCore.Qt.PointingHandCursor)
Form.setMinimumSize(QtCore.QSize(270, 80)) Form.setMinimumSize(QtCore.QSize(270, 100))
Form.setMaximumSize(QtCore.QSize(270, 80)) Form.setMaximumSize(QtCore.QSize(270, 100))
Form.setBaseSize(QtCore.QSize(270, 80)) Form.setBaseSize(QtCore.QSize(270, 100))
self.avatar_label = Form.avatar_label = QtGui.QLabel(Form) self.avatar_label = Form.avatar_label = QtGui.QLabel(Form)
self.avatar_label.setGeometry(QtCore.QRect(5, 15, 64, 64)) self.avatar_label.setGeometry(QtCore.QRect(5, 30, 64, 64))
self.avatar_label.setScaledContents(True) self.avatar_label.setScaledContents(True)
self.name = Form.name = DataLabel(Form) self.name = Form.name = DataLabel(Form)
Form.name.setGeometry(QtCore.QRect(80, 25, 150, 25)) Form.name.setGeometry(QtCore.QRect(80, 40, 150, 25))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Times New Roman") font.setFamily("Times New Roman")
font.setPointSize(14) font.setPointSize(14)
@ -176,7 +177,7 @@ class MainWindow(QtGui.QMainWindow):
Form.name.setFont(font) Form.name.setFont(font)
Form.name.setObjectName("name") Form.name.setObjectName("name")
self.status_message = Form.status_message = DataLabel(Form) self.status_message = Form.status_message = DataLabel(Form)
Form.status_message.setGeometry(QtCore.QRect(80, 55, 170, 20)) Form.status_message.setGeometry(QtCore.QRect(80, 60, 170, 25))
font.setPointSize(12) font.setPointSize(12)
font.setBold(False) font.setBold(False)
Form.status_message.setFont(font) Form.status_message.setFont(font)
@ -194,9 +195,9 @@ class MainWindow(QtGui.QMainWindow):
def setup_right_top(self, Form): def setup_right_top(self, Form):
Form.setObjectName("Form") Form.setObjectName("Form")
Form.resize(650, 80) Form.resize(650, 100)
self.account_avatar = QtGui.QLabel(Form) self.account_avatar = QtGui.QLabel(Form)
self.account_avatar.setGeometry(QtCore.QRect(10, 17, 64, 64)) self.account_avatar.setGeometry(QtCore.QRect(10, 30, 64, 64))
self.account_avatar.setScaledContents(True) self.account_avatar.setScaledContents(True)
self.account_name = DataLabel(Form) self.account_name = DataLabel(Form)
self.account_name.setGeometry(QtCore.QRect(100, 25, 400, 25)) self.account_name.setGeometry(QtCore.QRect(100, 25, 400, 25))
@ -224,7 +225,7 @@ class MainWindow(QtGui.QMainWindow):
self.videocallButton.clicked.connect(lambda: self.profile.call_click(True, True)) self.videocallButton.clicked.connect(lambda: self.profile.call_click(True, True))
self.update_call_state('call') self.update_call_state('call')
self.typing = QtGui.QLabel(Form) self.typing = QtGui.QLabel(Form)
self.typing.setGeometry(QtCore.QRect(500, 40, 50, 30)) self.typing.setGeometry(QtCore.QRect(500, 50, 50, 30))
pixmap = QtGui.QPixmap(QtCore.QSize(50, 30)) pixmap = QtGui.QPixmap(QtCore.QSize(50, 30))
pixmap.load(curr_directory() + '/images/typing.png') pixmap.load(curr_directory() + '/images/typing.png')
self.typing.setScaledContents(False) self.typing.setScaledContents(False)
@ -299,11 +300,13 @@ class MainWindow(QtGui.QMainWindow):
self.setup_left_center(main_list) self.setup_left_center(main_list)
grid.addWidget(main_list, 2, 1, 2, 1) grid.addWidget(main_list, 2, 1, 2, 1)
grid.setColumnMinimumWidth(0, 500) grid.setColumnMinimumWidth(0, 500)
grid.setColumnMinimumWidth(1, 270) grid.setColumnMinimumWidth(1, 280)
grid.setRowMinimumHeight(0, 82) grid.setSpacing(0)
grid.setContentsMargins(0, 0, 0, 0)
grid.setRowMinimumHeight(0, 100)
grid.setRowMinimumHeight(1, 25) grid.setRowMinimumHeight(1, 25)
grid.setRowMinimumHeight(2, 410) grid.setRowMinimumHeight(2, 320)
grid.setRowMinimumHeight(3, 60) grid.setRowMinimumHeight(3, 55)
grid.setColumnStretch(1, 1) grid.setColumnStretch(1, 1)
grid.setRowStretch(2, 1) grid.setRowStretch(2, 1)
main.setLayout(grid) main.setLayout(grid)
@ -321,19 +324,19 @@ class MainWindow(QtGui.QMainWindow):
QtGui.QApplication.closeAllWindows() QtGui.QApplication.closeAllWindows()
def resizeEvent(self, *args, **kwargs): def resizeEvent(self, *args, **kwargs):
self.messages.setGeometry(0, 0, self.width() - 294, self.height() - 172) self.messages.setGeometry(0, 0, self.width() - 270, self.height() - 155)
self.friends_list.setGeometry(0, 0, 270, self.height() - 135) self.friends_list.setGeometry(0, 0, 270, self.height() - 125)
self.videocallButton.setGeometry(QtCore.QRect(self.width() - 350, 20, 50, 50)) self.videocallButton.setGeometry(QtCore.QRect(self.width() - 330, 40, 50, 50))
self.callButton.setGeometry(QtCore.QRect(self.width() - 410, 20, 50, 50)) self.callButton.setGeometry(QtCore.QRect(self.width() - 390, 40, 50, 50))
self.typing.setGeometry(QtCore.QRect(self.width() - 470, 30, 50, 30)) self.typing.setGeometry(QtCore.QRect(self.width() - 450, 50, 50, 30))
self.messageEdit.setGeometry(QtCore.QRect(60, 2, self.width() - 430, 55)) self.messageEdit.setGeometry(QtCore.QRect(55, 0, self.width() - 395, 55))
self.menuButton.setGeometry(QtCore.QRect(0, 2, 55, 55)) self.menuButton.setGeometry(QtCore.QRect(0, 0, 55, 55))
self.sendMessageButton.setGeometry(QtCore.QRect(self.width() - 360, 2, 60, 55)) self.sendMessageButton.setGeometry(QtCore.QRect(self.width() - 340, 0, 70, 55))
self.account_name.setGeometry(QtCore.QRect(100, 30, self.width() - 600, 25)) self.account_name.setGeometry(QtCore.QRect(100, 40, self.width() - 560, 25))
self.account_status.setGeometry(QtCore.QRect(100, 50, self.width() - 520, 25)) self.account_status.setGeometry(QtCore.QRect(100, 60, self.width() - 560, 25))
self.messageEdit.setFocus() self.messageEdit.setFocus()
self.profile.update() self.profile.update()
@ -391,9 +394,10 @@ class MainWindow(QtGui.QMainWindow):
if hasattr(self, 'menu') and self.menu.isVisible(): if hasattr(self, 'menu') and self.menu.isVisible():
self.menu.hide() self.menu.hide()
return return
elif not hasattr(self, 'menu'):
self.menu = DropdownMenu(self) self.menu = DropdownMenu(self)
self.menu.setGeometry(QtCore.QRect(0 if Settings.get_instance()['mirror_mode'] else 270, self.menu.setGeometry(QtCore.QRect(0 if Settings.get_instance()['mirror_mode'] else 270,
self.height() - 160, self.height() - 100,
150, 150,
100)) 100))
self.menu.show() self.menu.show()
@ -408,7 +412,6 @@ class MainWindow(QtGui.QMainWindow):
def send_file(self): def send_file(self):
self.menu.hide() self.menu.hide()
if self.profile.is_active_online(): # active friend exists and online
choose_file = QtGui.QApplication.translate("MainWindow", 'Choose file', None, QtGui.QApplication.UnicodeUTF8) choose_file = QtGui.QApplication.translate("MainWindow", 'Choose file', None, QtGui.QApplication.UnicodeUTF8)
choose = QtGui.QApplication.translate("MainWindow", choose_file, None, QtGui.QApplication.UnicodeUTF8) choose = QtGui.QApplication.translate("MainWindow", choose_file, None, QtGui.QApplication.UnicodeUTF8)
name = QtGui.QFileDialog.getOpenFileName(self, choose) name = QtGui.QFileDialog.getOpenFileName(self, choose)
@ -417,7 +420,6 @@ class MainWindow(QtGui.QMainWindow):
def send_screenshot(self, hide=False): def send_screenshot(self, hide=False):
self.menu.hide() self.menu.hide()
if self.profile.is_active_online(): # active friend exists and online
self.sw = ScreenShotWindow(self) self.sw = ScreenShotWindow(self)
self.sw.show() self.sw.show()
if hide: if hide:

View File

@ -80,6 +80,18 @@ class TransferMessage(Message):
return self._file_name, self._size, self._time, self._owner, self._friend_number, self._file_number, self._status return self._file_name, self._size, self._time, self._owner, self._friend_number, self._file_number, self._status
class UnsentFile(Message):
def __init__(self, path, data, time):
super(UnsentFile, self).__init__(MESSAGE_TYPE['FILE_TRANSFER'], 0, time)
self._data, self._path = data, path
def get_data(self):
return self._path, self._data, self._time
def get_status(self):
return None
class InlineImage(Message): class InlineImage(Message):
""" """
Inline image Inline image

View File

@ -1,4 +1,4 @@
from list_items import MessageItem, ContactItem, FileTransferItem, InlineImageItem from list_items import *
try: try:
from PySide import QtCore, QtGui from PySide import QtCore, QtGui
except ImportError: except ImportError:
@ -169,6 +169,9 @@ class Profile(contact.Contact, Singleton):
friend.name if data[1] == MESSAGE_OWNER['FRIEND'] else self._name, friend.name if data[1] == MESSAGE_OWNER['FRIEND'] else self._name,
data[3]) data[3])
elif message.get_type() == MESSAGE_TYPE['FILE_TRANSFER']: elif message.get_type() == MESSAGE_TYPE['FILE_TRANSFER']:
if message.get_status() is None:
self.create_unsent_file_item(message)
continue
item = self.create_file_transfer_item(message) item = self.create_file_transfer_item(message)
if message.get_status() >= 2: # active file transfer if message.get_status() >= 2: # active file transfer
try: try:
@ -246,9 +249,23 @@ class Profile(contact.Contact, Singleton):
# Friend connection status callbacks # Friend connection status callbacks
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
def friend_online(self, friend_number): def send_files(self, friend_number):
for key in filter(lambda x: x[0] == friend_number, self._file_transfers.keys()): # for key in filter(lambda x: x[0] == friend_number, self._file_transfers.keys()):
self.resume_transfer(key[0], key[1], True) # self.resume_transfer(key[0], key[1], True)
friend = self.get_friend_by_number(friend_number)
files = friend.get_unsent_files()
try:
for fl in files:
data = fl.get_data()
if data[1] is not None:
self.send_inline(data[1], data[0], friend_number, True)
else:
self.send_file(data[0], friend_number, True)
friend.clear_unsent_files()
if friend_number == self.get_active_number():
self.update()
except:
pass
def friend_exit(self, friend_number): def friend_exit(self, friend_number):
""" """
@ -483,6 +500,21 @@ class Profile(contact.Contact, Singleton):
self._messages.setItemWidget(elem, item) self._messages.setItemWidget(elem, item)
return item return item
def create_unsent_file_item(self, message, append=True):
data = message.get_data()
item = UnsentFileItem(os.path.basename(data[0]),
os.path.getsize(data[0]) if data[1] is None else len(data[1]),
self.name,
data[2],
self._messages.width())
elem = QtGui.QListWidgetItem()
elem.setSizeHint(QtCore.QSize(self._messages.width() - 30, 34))
if append:
self._messages.addItem(elem)
else:
self._messages.insertItem(0, elem)
self._messages.setItemWidget(elem, item)
def create_inline_item(self, data, append=True): def create_inline_item(self, data, append=True):
item = InlineImageItem(data, self._messages.width()) item = InlineImageItem(data, self._messages.width())
elem = QtGui.QListWidgetItem() elem = QtGui.QListWidgetItem()
@ -786,6 +818,10 @@ class Profile(contact.Contact, Singleton):
else: else:
self._tox.file_control(friend_number, file_number, TOX_FILE_CONTROL['CANCEL']) self._tox.file_control(friend_number, file_number, TOX_FILE_CONTROL['CANCEL'])
def cancel_not_started_transfer(self, time):
self._friends[self._active_friend].delete_one_unsent_file(time)
self.update()
def pause_transfer(self, friend_number, file_number, by_friend=False): def pause_transfer(self, friend_number, file_number, by_friend=False):
""" """
Pause transfer with specified data Pause transfer with specified data
@ -840,10 +876,16 @@ class Profile(contact.Contact, Singleton):
data = fl.read() data = fl.read()
self.send_inline(data, 'sticker.png') self.send_inline(data, 'sticker.png')
def send_inline(self, data, file_name): def send_inline(self, data, file_name, friend_number=None, is_resend=False):
friend = self._friends[self._active_friend] friend_number = friend_number or self.get_active_number()
if friend.status is None: friend = self.get_friend_by_number(friend_number)
if friend.status is None and not is_resend:
m = UnsentFile(file_name, data, time.time())
friend.append_message(m)
self.update()
return return
elif friend.status is None and is_resend:
raise Exception()
st = SendFromBuffer(self._tox, friend.number, data, file_name) st = SendFromBuffer(self._tox, friend.number, data, file_name)
self._file_transfers[(friend.number, st.get_file_number())] = st self._file_transfers[(friend.number, st.get_file_number())] = st
tm = TransferMessage(MESSAGE_OWNER['ME'], tm = TransferMessage(MESSAGE_OWNER['ME'],
@ -858,15 +900,21 @@ class Profile(contact.Contact, Singleton):
st.set_state_changed_handler(item.update) st.set_state_changed_handler(item.update)
self._messages.scrollToBottom() self._messages.scrollToBottom()
def send_file(self, path, number=None): def send_file(self, path, number=None, is_resend=False):
""" """
Send file to current active friend Send file to current active friend
:param path: file path :param path: file path
:param number: friend_number :param number: friend_number
""" """
friend_number = number or self.get_active_number() friend_number = number or self.get_active_number()
if self.get_friend_by_number(friend_number).status is None: friend = self.get_friend_by_number(friend_number)
if friend.status is None and not is_resend:
m = UnsentFile(path, None, time.time())
friend.append_message(m)
self.update()
return return
elif friend.status is None and is_resend:
raise Exception()
st = SendTransfer(path, self._tox, friend_number) st = SendTransfer(path, self._tox, friend_number)
self._file_transfers[(friend_number, st.get_file_number())] = st self._file_transfers[(friend_number, st.get_file_number())] = st
tm = TransferMessage(MESSAGE_OWNER['ME'], tm = TransferMessage(MESSAGE_OWNER['ME'],

View File

@ -72,7 +72,7 @@ class SmileyLoader(util.Singleton):
def sticker_loader(): def sticker_loader():
""" """
:return dict of stickers :return list of stickers
""" """
result = [] result = []
d = util.curr_directory() + '/stickers/' d = util.curr_directory() + '/stickers/'

View File

@ -1272,3 +1272,8 @@ QListWidget > QLabel
{ {
color: #A9A9A9; color: #A9A9A9;
} }
#contact_name
{
padding-left: 22px;
}