Skip to content

Commit

Permalink
add and update tests to reflect new pane design
Browse files Browse the repository at this point in the history
  • Loading branch information
Allie Crevier committed Apr 9, 2019
1 parent 63d164c commit 59a375f
Show file tree
Hide file tree
Showing 4 changed files with 529 additions and 279 deletions.
224 changes: 117 additions & 107 deletions securedrop_client/gui/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from typing import List
from uuid import uuid4

from securedrop_client.db import Source, Message, File, Reply
from securedrop_client.db import Source, Message, File
from securedrop_client.gui import SvgLabel, SvgPushButton
from securedrop_client.logic import Client
from securedrop_client.resources import load_svg, load_icon, load_image
Expand Down Expand Up @@ -62,7 +62,7 @@ def __init__(self):
layout.setSpacing(0)

# Refresh button
self.refresh = RefreshWidget()
self.refresh = RefreshButton()
self.refresh.disable()

# Activity status bar
Expand Down Expand Up @@ -112,8 +112,63 @@ def clear_error_status(self):
self.error_status_bar.clear_message()


class RefreshWidget(SvgPushButton):
class LeftPane(QWidget):
"""
Represents the left side pane that contains user authentication actions and information.
"""

def __init__(self):
super().__init__()

# Set layout
layout = QVBoxLayout(self)
self.setLayout(layout)

# Remove margins and spacing
layout.setContentsMargins(12, 12, 12, 12)
layout.setSpacing(0)

# Use a background gradient
palette = QPalette()
gradient = QLinearGradient(0, 0, 0, 700)
gradient.setColorAt(0, QColor('#0093da'))
gradient.setColorAt(1, QColor('#0c3e75'))
palette.setBrush(QPalette.Background, QBrush(gradient))
self.setPalette(palette)
self.setAutoFillBackground(True)

# User profile
self.user_profile = UserProfile()

# Hide user profile widget until user logs in
self.user_profile.hide()

# Add widgets to layout
layout.addWidget(self.user_profile)

# Align content to the top of pane
layout.addStretch()

def setup(self, window, controller):
self.user_profile.setup(window, controller)

def set_logged_in_as(self, username):
"""
Update the UI to reflect that the user is logged in as "username".
"""
self.user_profile.set_username(username)
self.user_profile.show()

def set_logged_out(self):
"""
Update the UI to a logged out state.
"""
self.user_profile.hide()


class RefreshButton(SvgPushButton):
"""
A button that shows an icon for different refresh states.
"""

css = '''
Expand Down Expand Up @@ -151,18 +206,21 @@ def setup(self, controller):

def _on_clicked(self):
self.controller.sync_api()
# Set the icon's Qt.Normal state image to an active state image. This is a temporary fix to
# show that the icon was clicked. The icon image is later replaced in _on_refresh_complete.
# This is a temporary solution for showing the icon as active for the entire duration of a
# refresh, rather than for just the duration of a click. The icon image will be replaced
# when the controller tells us the refresh has finished. A cleaner solution would be to
# store and update our own icon mode so we don't have to reload any images.
self.setIcon(load_icon(
normal='refresh_active.svg',
disabled='refresh_offline.svg'))

def _on_refresh_complete(self):
self.setIcon(load_icon(
normal='refresh.svg',
disabled='refresh_offline.svg',
active='refresh_active.svg',
selected='refresh.svg'))
def _on_refresh_complete(self, data):
if (data == 'synced'):
self.setIcon(load_icon(
normal='refresh.svg',
disabled='refresh_offline.svg',
active='refresh_active.svg',
selected='refresh.svg'))

def enable(self):
self.setEnabled(True)
Expand All @@ -171,8 +229,41 @@ def disable(self):
self.setEnabled(False)


class ActivityStatusBar(QStatusBar):
"""
A status bar for displaying messages about application activity to the user. Messages will be
displayed for a given duration or until the message updated with a new message.
"""

css = '''
#activity_status_bar {
color: #fff;
}
'''

def __init__(self):
super().__init__()

# Set css id
self.setObjectName('activity_status_bar')

# Set styles
self.setStyleSheet(self.css)

# Remove grip image at bottom right-hand corner
self.setSizeGripEnabled(False)

def update_message(self, message: str, duration: int):
"""
Display a status message to the user.
"""
self.showMessage(message, duration)


class ErrorStatusBar(QWidget):
"""
A pop-up status bar for displaying messages about application errors to the user. Messages will
be displayed for a given duration or until the message is cleared or updated with a new message.
"""

css = '''
Expand Down Expand Up @@ -276,89 +367,6 @@ def clear_message(self):
self.status_bar.clearMessage()


class ActivityStatusBar(QStatusBar):
"""
"""

css = '''
#activity_status_bar {
color: #fff;
}
'''

def __init__(self):
super().__init__()

# Set css id
self.setObjectName('activity_status_bar')

# Set styles
self.setStyleSheet(self.css)

# Remove grip image at bottom right-hand corner
self.setSizeGripEnabled(False)

def update_message(self, message: str, duration: int):
"""
Display a status message to the user.
"""
self.showMessage(message, duration)


class LeftPane(QWidget):
"""
Represents the left side pane that contains user authentication actions and information.
"""

def __init__(self):
super().__init__()

# Set layout
layout = QVBoxLayout(self)
self.setLayout(layout)

# Remove margins and spacing
layout.setContentsMargins(12, 12, 12, 12)
layout.setSpacing(0)

# Use a background gradient
palette = QPalette()
gradient = QLinearGradient(0, 0, 0, 700)
gradient.setColorAt(0, QColor('#0093da'))
gradient.setColorAt(1, QColor('#0c3e75'))
palette.setBrush(QPalette.Background, QBrush(gradient))
self.setPalette(palette)
self.setAutoFillBackground(True)

# User profile
self.user_profile = UserProfile()

# Hide user profile widget until user logs in
self.user_profile.hide()

# Add widgets to layout
layout.addWidget(self.user_profile)

# Align content to the top of pane
layout.addStretch()

def setup(self, window, controller):
self.user_profile.setup(window, controller)

def set_logged_in_as(self, username):
"""
Update the UI to reflect that the user is logged in as "username".
"""
self.user_profile.set_username(username)
self.user_profile.show()

def set_logged_out(self):
"""
Update the UI to a logged out state.
"""
self.user_profile.hide()


class UserProfile(QWidget):
"""
A widget that contains user profile information and options.
Expand Down Expand Up @@ -439,8 +447,6 @@ class UserButton(SvgPushButton):
css = '''
SvgPushButton#user_button {
border: none;
padding-top: 12px;
padding-bottom: 12px;
padding-left: 6px;
background-color: #0093da;
font-family: Open Sans;
Expand All @@ -459,6 +465,7 @@ def __init__(self):
super().__init__('dropdown_arrow.svg', svg_size=QSize())

self.setStyleSheet(self.css)
self.setFixedHeight(40)

self.setObjectName('user_button')

Expand Down Expand Up @@ -533,7 +540,7 @@ def __init__(self):

# Set styles
self.setStyleSheet(self.css)
self.setFixedSize(200, 40)
self.setFixedHeight(40)

# Set drop shadow effect
effect = QGraphicsDropShadowEffect(self)
Expand Down Expand Up @@ -1256,9 +1263,11 @@ def __init__(
self.conversation = ConversationView(self.source, self.sdc_home, self.controller,
parent=self)
self.source_profile = SourceProfileShortWidget(self.source, self.controller)
self.reply_box = ReplyBoxWidget(self)

self.layout.addWidget(self.source_profile, 1)
self.layout.addWidget(self.conversation, 9)
self.layout.addWidget(self.reply_box, 3)

self.controller.authentication_state.connect(self._show_or_hide_replybox)
self._show_or_hide_replybox(is_authenticated)
Expand All @@ -1269,21 +1278,13 @@ def send_reply(self, message: str) -> None:
self.controller.send_reply(self.source.uuid, msg_uuid, message)

def _show_or_hide_replybox(self, show: bool) -> None:
if show:
new_widget = ReplyBoxWidget(self)
else:
new_widget = ReplyBoxWidget(self)
new_widget.text_edit.setText(_('You need to log in to send replies.'))
new_widget.text_edit.setEnabled(False)
new_widget.send_button.hide()
if not show:
self.reply_box.disable()

old_widget = self.layout.takeAt(2)
if old_widget is not None:
old_widget.widget().deleteLater()

self.reply_box = new_widget
self.layout.addWidget(new_widget, 3)


class ReplyBoxWidget(QWidget):
"""
Expand Down Expand Up @@ -1322,6 +1323,15 @@ def send_reply(self) -> None:
self.conversation.send_reply(msg)
self.text_edit.clear()

def enable(self):
self.text_edit.setEnabled(True)
self.send_button.show()

def disable(self):
self.text_edit.setText(_('You need to log in to send replies.'))
self.text_edit.setEnabled(False)
self.send_button.hide()


class DeleteSourceAction(QAction):
"""Use this action to delete the source record."""
Expand Down
Loading

0 comments on commit 59a375f

Please sign in to comment.