dark mode refinements

This commit is contained in:
Sam Schott 2019-07-14 23:51:24 +01:00
parent a39e182e11
commit a4b456d315
6 changed files with 95 additions and 46 deletions

View File

@ -40,9 +40,9 @@ _Added:_
- Added progress messages for uploads and downloads, e.g., "Downloading 3/98...". These
are output as info messages and shown in the status field of the system tray menu.
- When unlinking your Dropbox account through the GUI, Maestral is restarted to enter the
setup dialog.
- Refinements for dark interface themes such as Dark Mode in macOS Mojave
_Changed:_

View File

@ -28,7 +28,7 @@ from maestral.gui.first_sync_dialog import FirstSyncDialog
from maestral.gui.sync_issues_window import SyncIssueWindow
from maestral.gui.rebuild_index_dialog import RebuildIndexDialog
from maestral.gui.resources import TRAY_ICON_PATH
from maestral.gui.utils import truncate_string, get_scaled_font, get_theme
from maestral.gui.utils import truncate_string, get_scaled_font, isDarkStatusBar
FIRST_SYNC = (not CONF.get("internal", "lastsync") or
@ -127,8 +127,7 @@ class MaestralApp(QtWidgets.QSystemTrayIcon):
icon_color = "dark"
if not platform.system() == "Darwin":
THEME = get_theme()
if THEME is "dark":
if isDarkStatusBar():
icon_color = "light"
short = ("idle", "syncing", "paused", "disconnected", "error")
for l, s in zip((IDLE, SYNCING, PAUSED, DISCONNECTED, SYNC_ERROR), short):
@ -292,9 +291,10 @@ class MaestralApp(QtWidgets.QSystemTrayIcon):
"""Update account usage info in UI."""
usage_string = str(space_usage)
self.accountUsageAction.setText(usage_string)
self.settings.labelSpaceUsage2.setText(usage_string)
self.settings.labelSpaceUsage.setText(usage_string)
def on_error(self, exc_info):
@staticmethod
def on_error(exc_info):
exc_type, exc, tb = exc_info
if isinstance(exc, CorruptedRevFileError):

View File

@ -21,7 +21,7 @@
<number>20</number>
</property>
<item row="5" column="0">
<widget class="QLabel" name="label_10">
<widget class="QLabel" name="labelExcludedFoldersTitle">
<property name="text">
<string>Select folders to sync:</string>
</property>
@ -46,18 +46,8 @@
</property>
</widget>
</item>
<item row="12" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_9">
<widget class="QLabel" name="labelDropboxPathTitle">
<property name="text">
<string>Dropbox folder location:</string>
</property>
@ -74,7 +64,7 @@
</widget>
</item>
<item row="10" column="0">
<widget class="QLabel" name="labelSpaceUsage1">
<widget class="QLabel" name="labelSpaceUsageTitle">
<property name="text">
<string>Your space:</string>
</property>
@ -84,7 +74,7 @@
</widget>
</item>
<item row="8" column="0" colspan="2" alignment="Qt::AlignHCenter">
<widget class="Line" name="line_1">
<widget class="Line" name="line1">
<property name="minimumSize">
<size>
<width>350</width>
@ -109,7 +99,7 @@
</widget>
</item>
<item row="20" column="0" colspan="2" alignment="Qt::AlignHCenter">
<widget class="Line" name="line_2">
<widget class="Line" name="line2">
<property name="minimumSize">
<size>
<width>350</width>
@ -166,7 +156,7 @@
</widget>
</item>
<item row="21" column="0">
<widget class="QLabel" name="label">
<widget class="QLabel" name="labelAboutTitle">
<property name="text">
<string>About Maestral:</string>
</property>
@ -176,7 +166,7 @@
</widget>
</item>
<item row="3" column="0" colspan="2" alignment="Qt::AlignHCenter">
<widget class="Line" name="line_0">
<widget class="Line" name="line0">
<property name="minimumSize">
<size>
<width>350</width>
@ -211,7 +201,7 @@
</widget>
</item>
<item row="10" column="1">
<widget class="QLabel" name="labelSpaceUsage2">
<widget class="QLabel" name="labelSpaceUsage">
<property name="text">
<string>30.3% out of 1,000,000GB used</string>
</property>
@ -231,7 +221,7 @@
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_3">
<widget class="QLabel" name="labelAccountEmailTitle">
<property name="text">
<string>Account:</string>
</property>

View File

@ -19,7 +19,8 @@ from maestral.config.base import get_home_dir
from maestral.gui.folders_dialog import FoldersDialog
from maestral.gui.resources import (get_native_item_icon, UNLINK_DIALOG_PATH,
SETTINGS_WINDOW_PATH)
from maestral.gui.utils import get_scaled_font
from maestral.gui.utils import (get_scaled_font, isDarkWindow, LINE_COLOR_DARK,
LINE_COLOR_LIGHT)
class UnlinkDialog(QtWidgets.QDialog):
@ -39,6 +40,7 @@ class SettingsWindow(QtWidgets.QWidget):
def __init__(self, mdbx, parent=None):
super(self.__class__, self).__init__(parent=parent)
uic.loadUi(SETTINGS_WINDOW_PATH, self)
self.update_dark_mode()
# self.setFixedSize(560, 320)
self.mdbx = mdbx
@ -61,10 +63,10 @@ class SettingsWindow(QtWidgets.QWidget):
self.labelAccountEmail.setText(CONF.get("account", "email"))
usage_type = CONF.get("account", "usage_type")
if usage_type == "team":
self.labelSpaceUsage1.setText("Your team's space:")
self.labelSpaceUsageTitle.setText("Your team's space:")
elif usage_type == "individual":
self.labelSpaceUsage1.setText("Your space:")
self.labelSpaceUsage2.setText(CONF.get("account", "usage"))
self.labelSpaceUsageTitle.setText("Your space:")
self.labelSpaceUsage.setText(CONF.get("account", "usage"))
self.pushButtonUnlink.clicked.connect(self.unlink_dialog.open)
self.unlink_dialog.accepted.connect(self.on_unlink)
@ -147,3 +149,16 @@ class SettingsWindow(QtWidgets.QWidget):
return osp.relpath(path, usr)
else:
return path
def changeEvent(self, QEvent):
if QEvent.type() == QtCore.QEvent.PaletteChange:
self.update_dark_mode()
def update_dark_mode(self):
rgb = LINE_COLOR_DARK if isDarkWindow() else LINE_COLOR_LIGHT
line_style = "color: rgb({0}, {1}, {2})".format(*rgb)
self.line0.setStyleSheet(line_style)
self.line1.setStyleSheet(line_style)
self.line2.setStyleSheet(line_style)

View File

@ -13,7 +13,8 @@ from PyQt5 import QtCore, QtGui, QtWidgets, uic
from maestral.gui.resources import (SYNC_ISSUES_WINDOW_PATH, SYNC_ISSUE_WIDGET_PATH,
get_native_item_icon)
from maestral.gui.utils import truncate_string, get_scaled_font
from maestral.gui.utils import (truncate_string, get_scaled_font, isDarkWindow,
LINE_COLOR_DARK, LINE_COLOR_LIGHT)
HAS_GTK_LAUNCH = shutil.which("gtk-launch") is not None
@ -32,20 +33,11 @@ class SyncIssueWidget(QtWidgets.QWidget):
self.errorLabel.setFont(get_scaled_font(scaling=0.85))
# set appropriate background color
bg_color = self.palette().color(QtGui.QPalette.Background)
bg_color_rgb = [bg_color.red(), bg_color.green(), bg_color.blue()]
frame_bg_color = [min([c + 20, 255]) for c in bg_color_rgb]
self.frame.setStyleSheet("""
.QFrame {{
border: 1px solid rgb(205, 203, 205);
background-color: rgb({0},{1},{2});
border-radius: 7px;
}}""".format(*frame_bg_color))
self.update_dark_mode()
# fill with content
icon = get_native_item_icon(self.sync_issue.local_path)
pixmap = icon.pixmap(2*self.iconLabel.width(), 2*self.iconLabel.height())
pixmap.setDevicePixelRatio(2.0)
pixmap = icon.pixmap(self.iconLabel.width(), self.iconLabel.height())
self.iconLabel.setPixmap(pixmap)
self.pathLabel.setText(self.to_display_path(self.sync_issue.local_path))
@ -97,6 +89,22 @@ class SyncIssueWidget(QtWidgets.QWidget):
else:
subprocess.run(["xdg-open", path])
def changeEvent(self, QEvent):
if QEvent.type() == QtCore.QEvent.PaletteChange:
self.update_dark_mode()
def update_dark_mode(self):
line_rgb = LINE_COLOR_DARK if isDarkWindow() else LINE_COLOR_LIGHT
bg_color = self.palette().color(QtGui.QPalette.Background)
bg_color_rgb = [bg_color.red(), bg_color.green(), bg_color.blue()]
frame_bg_color = [min([c + 16, 255]) for c in bg_color_rgb]
self.frame.setStyleSheet("""
.QFrame {{
border: 1px solid rgb({0},{1},{2});
background-color: rgb({3},{4},{5});
border-radius: 7px;
}}""".format(*line_rgb, *frame_bg_color))
class SyncIssueWindow(QtWidgets.QWidget):
"""
@ -147,7 +155,9 @@ if __name__ == "__main__":
from maestral.client import MaestralApiError
import queue
app = QtWidgets.QApplication([])
app = QtWidgets.QApplication([""])
app.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps)
text1 = ("Something went wrong with the job on Dropboxs end. Please "
"verify on the Dropbox website if the move succeeded and try "
"again if it failed. This should happen very rarely.")
@ -155,7 +165,9 @@ if __name__ == "__main__":
text2 = ("There are too many write operations your "
"Dropbox. Please try again later.")
err1 = MaestralApiError("Could not download", text1, local_path="/MyLargeFile")
path = "/Users/samschott/Dropbox/MATLAB_scripts/CuSCN2 fitting/CuSCN2_5K_HFI_fit.mat"
err1 = MaestralApiError("Could not download", text1, local_path=path)
err2 = MaestralApiError("Could not delete folder", text2, local_path="/test_folder")
err_queue = queue.Queue()

View File

@ -11,6 +11,9 @@ from PyQt5 import QtGui, QtWidgets
THEME_DARK = "dark"
THEME_LIGHT = "light"
LINE_COLOR_DARK = (95, 104, 104)
LINE_COLOR_LIGHT = (205, 203, 205)
def truncate_string(string, font=None, pixels=200, side="right"):
@ -128,12 +131,41 @@ def __pixel_at(x, y):
return ((color >> 16) & 0xff), ((color >> 8) & 0xff), (color & 0xff)
def get_theme():
def statusBarTheme():
"""
Returns one of THEME_LIGHT or THEME_DARK, corresponding to current user's UI theme
Returns one of THEME_LIGHT or THEME_DARK, corresponding to current status bar theme
"""
# getting color of a pixel on a top bar, and identifying best-fitting color
# theme based on its luminance
pixel_rgb = __pixel_at(2, 2)
luminance = _luminance(*pixel_rgb)
return THEME_LIGHT if luminance >= 0.5 else THEME_DARK
return THEME_LIGHT if luminance >= 0.4 else THEME_DARK
def windowTheme():
"""
Returns one of THEME_LIGHT or THEME_DARK, corresponding to current user's UI theme
"""
# getting color of a pixel on a top bar, and identifying best-fitting color
# theme based on its luminance
w = QtWidgets.QWidget()
bg_color = w.palette().color(QtGui.QPalette.Background)
bg_color_rgb = [bg_color.red(), bg_color.green(), bg_color.blue()]
luminance = _luminance(*bg_color_rgb)
return THEME_LIGHT if luminance >= 0.4 else THEME_DARK
def isDarkWindow():
return windowTheme() == THEME_DARK
def isLightWindow():
return windowTheme() == THEME_LIGHT
def isDarkStatusBar():
return statusBarTheme() == THEME_DARK
def isLightStatusBar():
return statusBarTheme() == THEME_LIGHT