Skip to content

Commit

Permalink
Revert scroll to bottom (to be addressed in existing separate PR).
Browse files Browse the repository at this point in the history
Fix #61 to supercede #685.
Make on_reply_sent work properly without duplicate entries.
  • Loading branch information
ntoll authored and sssoleileraaa committed Jan 29, 2020
1 parent 426028f commit 6d969ab
Show file tree
Hide file tree
Showing 3 changed files with 225 additions and 74 deletions.
51 changes: 35 additions & 16 deletions securedrop_client/gui/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
QPushButton, QVBoxLayout, QLineEdit, QScrollArea, QDialog, QAction, QMenu, QMessageBox, \
QToolButton, QSizePolicy, QPlainTextEdit, QStatusBar, QGraphicsDropShadowEffect

from securedrop_client.db import DraftReply, Source, Message, File, Reply, User
from securedrop_client.db import (DraftReply, Source, Message, File, Reply, User,
ReplySendStatusCodes)
from securedrop_client.storage import source_exists
from securedrop_client.export import ExportStatus, ExportError
from securedrop_client.gui import SecureQLabel, SvgLabel, SvgPushButton, SvgToggleButton
Expand Down Expand Up @@ -2392,7 +2393,8 @@ def __init__(self, source_db_object: Source, controller: Controller):
self.source = source_db_object
self.controller = controller

self.current_messages = {} # To hold currently displayed messages.
# To hold currently displayed messages.
self.current_messages = {} # type: Dict[str, QWidget]

# Set styles
self.setStyleSheet(self.CSS)
Expand All @@ -2419,6 +2421,9 @@ def __init__(self, source_db_object: Source, controller: Controller):
self.scroll.setWidget(self.container)
self.scroll.setWidgetResizable(True)

# Flag to show if the current user has sent a reply. See issue #61.
self.reply_flag = False

# Completely unintuitive way to ensure the view remains scrolled to the bottom.
sb = self.scroll.verticalScrollBar()
sb.rangeChanged.connect(self.update_conversation_position)
Expand Down Expand Up @@ -2462,12 +2467,21 @@ def update_conversation(self, collection: list) -> None:
# and update index details.
self.conversation_layout.removeWidget(item_widget)
item_widget.index = index
self.conversation_layout.insertWidget(index, item_widget)
# TODO: Check if text in item has changed, then update the
if isinstance(item_widget, ReplyWidget):
self.conversation_layout.insertWidget(index, item_widget,
alignment=Qt.AlignRight)
else:
self.conversation_layout.insertWidget(index, item_widget,
alignment=Qt.AlignLeft)
# Check if text in item has changed, then update the
# widget to reflect this change.
# TODO: Check for any other possible changes of state in the
# message so this can be reflected in the widget.
# TODO: Get rid of the damn todos and write/update tests. ;-)
if not isinstance(item_widget, FileWidget):
if item_widget.message.text() != conversation_item.content:
item_widget.message.setText(conversation_item.content)
# Check if this is a draft reply then ensure it's removed.
if isinstance(conversation_item, DraftReply):
if conversation_item.send_status.name == ReplySendStatusCodes.PENDING.value:
self.conversation_layout.removeWidget(item_widget)
else:
# add a new item to be displayed.
if isinstance(conversation_item, Message):
Expand All @@ -2481,7 +2495,8 @@ def add_file(self, file: File, index):
"""
Add a file from the source.
"""
conversation_item = FileWidget(file.uuid, self.controller, self.controller.file_ready, index)
conversation_item = FileWidget(file.uuid, self.controller, self.controller.file_ready,
index)
self.conversation_layout.insertWidget(index, conversation_item, alignment=Qt.AlignLeft)
self.current_messages[file.uuid] = conversation_item

Expand All @@ -2490,13 +2505,16 @@ def update_conversation_position(self, min_val, max_val):
Handler called when a new item is added to the conversation. Ensures
it's scrolled to the bottom and thus visible.
"""
self.scroll.verticalScrollBar().setValue(max_val)
if self.reply_flag and max_val > 0:
self.scroll.verticalScrollBar().setValue(max_val)
self.reply_flag = False

def add_message(self, message: Message, index) -> None:
"""
Add a message from the source.
"""
conversation_item = MessageWidget(message.uuid, str(message), self.controller.message_ready, index)
conversation_item = MessageWidget(message.uuid, str(message), self.controller.message_ready,
index)
self.conversation_layout.insertWidget(index, conversation_item, alignment=Qt.AlignLeft)
self.current_messages[message.uuid] = conversation_item

Expand Down Expand Up @@ -2534,16 +2552,16 @@ def add_reply_from_reply_box(self, uuid: str, content: str) -> None:
self.controller.reply_succeeded,
self.controller.reply_failed,
index)
self.conversation_layout.addWidget(conversation_item, alignment=Qt.AlignRight)
self.conversation_layout.insertWidget(index, conversation_item, alignment=Qt.AlignRight)
self.current_messages[uuid] = conversation_item

def on_reply_sent(self, source_uuid: str, reply_uuid: str, reply_text: str) -> None:
"""
Add the reply text sent from ReplyBoxWidget to the conversation.
"""
# TODO: replace this with UI indication that the reply is "in flight"
# For now, just do nothing.
# if source_uuid == self.source.uuid:
# self.add_reply_from_reply_box(reply_uuid, reply_text)
self.reply_flag = True
if source_uuid == self.source.uuid:
self.add_reply_from_reply_box(reply_uuid, reply_text)


class SourceConversationWrapper(QWidget):
Expand Down Expand Up @@ -2692,10 +2710,11 @@ def send_reply(self) -> None:
"""
reply_text = self.text_edit.toPlainText().strip()
if reply_text:
self.text_edit.clearFocus() # Fixes #691
self.text_edit.setText('')
reply_uuid = str(uuid4())
self.controller.send_reply(self.source.uuid, reply_uuid, reply_text)
self.reply_sent.emit(self.source.uuid, reply_uuid, reply_text)
self.text_edit.setText('')

def _on_authentication_changed(self, authenticated: bool) -> None:
if authenticated:
Expand Down
20 changes: 17 additions & 3 deletions tests/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
FILE_COUNT = 0
REPLY_COUNT = 0
DRAFT_REPLY_COUNT = 0
REPLY_SEND_STATUS_COUNT = 0
USER_COUNT = 0


Expand Down Expand Up @@ -54,7 +55,7 @@ def Message(**attrs):
global MESSAGE_COUNT
MESSAGE_COUNT += 1
defaults = dict(
uuid='source-uuid-{}'.format(MESSAGE_COUNT),
uuid='msg-uuid-{}'.format(MESSAGE_COUNT),
filename='{}-msg.gpg'.format(MESSAGE_COUNT),
size=123,
download_url='http://wat.onion/abc',
Expand All @@ -72,7 +73,7 @@ def Reply(**attrs):
global REPLY_COUNT
REPLY_COUNT += 1
defaults = dict(
uuid='source-uuid-{}'.format(REPLY_COUNT),
uuid='reply-uuid-{}'.format(REPLY_COUNT),
filename='{}-reply.gpg'.format(REPLY_COUNT),
size=123,
is_decrypted=True,
Expand All @@ -95,18 +96,31 @@ def DraftReply(**attrs):
file_counter=1,
uuid='draft-reply-uuid-{}'.format(REPLY_COUNT),
content='content',
send_status_id=1,
)

defaults.update(attrs)

return db.DraftReply(**defaults)


def ReplySendStatus(**attrs):
global REPLY_SEND_STATUS_COUNT
REPLY_SEND_STATUS_COUNT += 1
defaults = dict(
name=db.ReplySendStatusCodes.PENDING.value,
)

defaults.update(attrs)

return db.ReplySendStatus(**defaults)


def File(**attrs):
global FILE_COUNT
FILE_COUNT += 1
defaults = dict(
uuid='source-uuid-{}'.format(FILE_COUNT),
uuid='file-uuid-{}'.format(FILE_COUNT),
filename='{}-doc.gz.gpg'.format(FILE_COUNT),
original_filename='{}-doc.txt'.format(FILE_COUNT),
size=123,
Expand Down
Loading

0 comments on commit 6d969ab

Please sign in to comment.