Code cleanup regarding context menu. Pause/resume logic implemented. Halfway through remodeling account menu.

Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
This commit is contained in:
Dominique Fuchs 2020-01-05 21:06:42 +01:00
Родитель a90995cf15
Коммит 330ff96ee2
9 изменённых файлов: 83 добавлений и 545 удалений

Просмотреть файл

@ -72,19 +72,24 @@ ownCloudGui::ownCloudGui(Application *parent)
, _app(parent)
{
_tray = new Systray();
//qmlRegisterType<Systray>("nc.desktop.systray.backend", 1, 0, "Systray");
_tray->setParent(this);
// for the beginning, set the offline icon until the account was verified
_tray->setIcon(Theme::instance()->folderOfflineIcon(/*systray?*/ true, /*currently visible?*/ false));
setupActions();
setupContextMenu();
_tray->setIcon(Theme::instance()->folderOfflineIcon(/*systray?*/ true));
_tray->show();
connect(_tray.data(), &QSystemTrayIcon::activated,
this, &ownCloudGui::slotTrayClicked);
connect(_tray.data(), &Systray::pauseSync,
this, &ownCloudGui::slotPauseAllFolders);
connect(_tray.data(), &Systray::pauseSync,
this, &ownCloudGui::slotUnpauseAllFolders);
connect(_tray.data(), &Systray::openHelp,
this, &ownCloudGui::slotHelp);
connect(_tray.data(), &Systray::openSettings,
this, &ownCloudGui::slotShowSettings);
@ -99,11 +104,6 @@ ownCloudGui::ownCloudGui(Application *parent)
connect(folderMan, &FolderMan::folderSyncStateChange,
this, &ownCloudGui::slotSyncStateChange);
connect(AccountManager::instance(), &AccountManager::accountAdded,
this, &ownCloudGui::updateContextMenuNeeded);
connect(AccountManager::instance(), &AccountManager::accountRemoved,
this, &ownCloudGui::updateContextMenuNeeded);
connect(Logger::instance(), &Logger::guiLog,
this, &ownCloudGui::slotShowTrayMessage);
connect(Logger::instance(), &Logger::optionalGuiLog,
@ -158,13 +158,6 @@ void ownCloudGui::slotOpenSettingsDialog()
void ownCloudGui::slotTrayClicked(QSystemTrayIcon::ActivationReason reason)
{
if (_workaroundFakeDoubleClick) {
static QElapsedTimer last_click;
if (last_click.isValid() && last_click.elapsed() < 200) {
return;
}
last_click.start();
}
// Left click
if (reason == QSystemTrayIcon::Trigger) {
@ -189,7 +182,6 @@ void ownCloudGui::slotTrayClicked(QSystemTrayIcon::ActivationReason reason)
void ownCloudGui::slotSyncStateChange(Folder *folder)
{
slotComputeOverallSyncStatus();
updateContextMenuNeeded();
if (!folder) {
return; // Valid, just a general GUI redraw was needed.
@ -210,7 +202,6 @@ void ownCloudGui::slotSyncStateChange(Folder *folder)
void ownCloudGui::slotFoldersChanged()
{
slotComputeOverallSyncStatus();
updateContextMenuNeeded();
}
void ownCloudGui::slotOpenPath(const QString &path)
@ -220,7 +211,6 @@ void ownCloudGui::slotOpenPath(const QString &path)
void ownCloudGui::slotAccountStateChanged()
{
updateContextMenuNeeded();
slotComputeOverallSyncStatus();
}
@ -246,7 +236,7 @@ void ownCloudGui::slotComputeOverallSyncStatus()
// Don't overwrite the status if we're currently syncing
if (FolderMan::instance()->currentSyncFolder())
return;
_actionStatus->setText(text);
//_actionStatus->setText(text);
};
foreach (auto a, AccountManager::instance()->accounts()) {
@ -266,7 +256,7 @@ void ownCloudGui::slotComputeOverallSyncStatus()
}
if (!problemAccounts.empty()) {
_tray->setIcon(Theme::instance()->folderOfflineIcon(true, contextMenuVisible()));
_tray->setIcon(Theme::instance()->folderOfflineIcon(true));
if (allDisconnected) {
setStatusText(tr("Disconnected"));
} else {
@ -296,12 +286,12 @@ void ownCloudGui::slotComputeOverallSyncStatus()
}
if (allSignedOut) {
_tray->setIcon(Theme::instance()->folderOfflineIcon(true, contextMenuVisible()));
_tray->setIcon(Theme::instance()->folderOfflineIcon(true));
_tray->setToolTip(tr("Please sign in"));
setStatusText(tr("Signed out"));
return;
} else if (allPaused) {
_tray->setIcon(Theme::instance()->syncStateIcon(SyncResult::Paused, true, contextMenuVisible()));
_tray->setIcon(Theme::instance()->syncStateIcon(SyncResult::Paused, true));
_tray->setToolTip(tr("Account synchronization is disabled"));
setStatusText(tr("Synchronization is paused"));
return;
@ -328,7 +318,7 @@ void ownCloudGui::slotComputeOverallSyncStatus()
iconStatus = SyncResult::Problem;
}
QIcon statusIcon = Theme::instance()->syncStateIcon(iconStatus, true, contextMenuVisible());
QIcon statusIcon = Theme::instance()->syncStateIcon(iconStatus, true);
_tray->setIcon(statusIcon);
// create the tray blob message, check if we have an defined state
@ -366,377 +356,6 @@ void ownCloudGui::slotComputeOverallSyncStatus()
}
}
void ownCloudGui::addAccountContextMenu(AccountStatePtr accountState, QMenu *menu, bool separateMenu)
{
// Only show the name in the action if it's not part of an
// account sub menu.
QString browserOpen = tr("Open in browser");
if (!separateMenu) {
browserOpen = tr("Open %1 in browser").arg(Theme::instance()->appNameGUI());
}
auto actionOpenoC = menu->addAction(browserOpen);
actionOpenoC->setProperty(propertyAccountC, QVariant::fromValue(accountState->account()));
QObject::connect(actionOpenoC, &QAction::triggered, this, &ownCloudGui::slotOpenOwnCloud);
FolderMan *folderMan = FolderMan::instance();
bool firstFolder = true;
bool singleSyncFolder = folderMan->map().size() == 1 && Theme::instance()->singleSyncFolder();
bool onePaused = false;
bool allPaused = true;
foreach (Folder *folder, folderMan->map()) {
if (folder->accountState() != accountState.data()) {
continue;
}
if (folder->syncPaused()) {
onePaused = true;
} else {
allPaused = false;
}
if (firstFolder && !singleSyncFolder) {
firstFolder = false;
menu->addSeparator();
menu->addAction(tr("Managed Folders:"))->setDisabled(true);
}
QAction *action = menu->addAction(tr("Open folder '%1'").arg(folder->shortGuiLocalPath()));
auto alias = folder->alias();
connect(action, &QAction::triggered, this, [this, alias] { this->slotFolderOpenAction(alias); });
}
menu->addSeparator();
if (separateMenu) {
if (onePaused) {
QAction *enable = menu->addAction(tr("Resume all folders"));
enable->setProperty(propertyAccountC, QVariant::fromValue(accountState));
connect(enable, &QAction::triggered, this, &ownCloudGui::slotUnpauseAllFolders);
}
if (!allPaused) {
QAction *enable = menu->addAction(tr("Pause all folders"));
enable->setProperty(propertyAccountC, QVariant::fromValue(accountState));
connect(enable, &QAction::triggered, this, &ownCloudGui::slotPauseAllFolders);
}
if (accountState->isSignedOut()) {
QAction *signin = menu->addAction(tr("Log in …"));
signin->setProperty(propertyAccountC, QVariant::fromValue(accountState));
connect(signin, &QAction::triggered, this, &ownCloudGui::slotLogin);
} else {
QAction *signout = menu->addAction(tr("Log out"));
signout->setProperty(propertyAccountC, QVariant::fromValue(accountState));
connect(signout, &QAction::triggered, this, &ownCloudGui::slotLogout);
}
}
}
void ownCloudGui::slotContextMenuAboutToShow()
{
_contextMenuVisibleManual = true;
// Update icon in sys tray, as it might change depending on the context menu state
slotComputeOverallSyncStatus();
if (!_workaroundNoAboutToShowUpdate) {
updateContextMenu();
}
}
void ownCloudGui::slotContextMenuAboutToHide()
{
_contextMenuVisibleManual = false;
// Update icon in sys tray, as it might change depending on the context menu state
slotComputeOverallSyncStatus();
}
bool ownCloudGui::contextMenuVisible() const
{
// On some platforms isVisible doesn't work and always returns false,
// elsewhere aboutToHide is unreliable.
if (_workaroundManualVisibility)
return _contextMenuVisibleManual;
return _contextMenu->isVisible();
}
static bool minimalTrayMenu()
{
static QByteArray var = qgetenv("OWNCLOUD_MINIMAL_TRAY_MENU");
return !var.isEmpty();
}
static bool updateWhileVisible()
{
static QByteArray var = qgetenv("OWNCLOUD_TRAY_UPDATE_WHILE_VISIBLE");
if (var == "1") {
return true;
} else if (var == "0") {
return false;
} else {
// triggers bug on OS X: https://bugreports.qt.io/browse/QTBUG-54845
// or flickering on Xubuntu
return false;
}
}
static QByteArray envForceQDBusTrayWorkaround()
{
static QByteArray var = qgetenv("OWNCLOUD_FORCE_QDBUS_TRAY_WORKAROUND");
return var;
}
static QByteArray envForceWorkaroundShowAndHideTray()
{
static QByteArray var = qgetenv("OWNCLOUD_FORCE_TRAY_SHOW_HIDE");
return var;
}
static QByteArray envForceWorkaroundNoAboutToShowUpdate()
{
static QByteArray var = qgetenv("OWNCLOUD_FORCE_TRAY_NO_ABOUT_TO_SHOW");
return var;
}
static QByteArray envForceWorkaroundFakeDoubleClick()
{
static QByteArray var = qgetenv("OWNCLOUD_FORCE_TRAY_FAKE_DOUBLE_CLICK");
return var;
}
static QByteArray envForceWorkaroundManualVisibility()
{
static QByteArray var = qgetenv("OWNCLOUD_FORCE_TRAY_MANUAL_VISIBILITY");
return var;
}
void ownCloudGui::setupContextMenu()
{
if (_contextMenu) {
return;
}
_contextMenu.reset(new QMenu());
_contextMenu->setTitle(Theme::instance()->appNameGUI());
_recentActionsMenu = new QMenu(tr("Recent Changes"), _contextMenu.data());
// The tray menu is surprisingly problematic. Being able to switch to
// a minimal version of it is a useful workaround and testing tool.
if (minimalTrayMenu()) {
_contextMenu->addAction(_actionQuit);
return;
}
auto applyEnvVariable = [](bool *sw, const QByteArray &value) {
if (value == "1")
*sw = true;
if (value == "0")
*sw = false;
};
// This is an old compound flag that people might still depend on
bool qdbusmenuWorkarounds = false;
applyEnvVariable(&qdbusmenuWorkarounds, envForceQDBusTrayWorkaround());
if (qdbusmenuWorkarounds) {
_workaroundFakeDoubleClick = true;
_workaroundNoAboutToShowUpdate = true;
_workaroundShowAndHideTray = true;
}
#ifdef Q_OS_MAC
// https://bugreports.qt.io/browse/QTBUG-54633
_workaroundNoAboutToShowUpdate = true;
_workaroundManualVisibility = true;
#endif
#ifdef Q_OS_LINUX
// For KDE sessions if the platform plugin is missing,
// neither aboutToShow() updates nor the isVisible() call
// work. At least aboutToHide is reliable.
// https://github.com/owncloud/client/issues/6545
static QByteArray xdgCurrentDesktop = qgetenv("XDG_CURRENT_DESKTOP");
static QByteArray desktopSession = qgetenv("DESKTOP_SESSION");
bool isKde =
xdgCurrentDesktop.contains("KDE")
|| desktopSession.contains("plasma")
|| desktopSession.contains("kde");
QObject *platformMenu = reinterpret_cast<QObject *>(_tray->contextMenu()->platformMenu());
if (isKde && platformMenu && platformMenu->metaObject()->className() == QLatin1String("QDBusPlatformMenu")) {
_workaroundManualVisibility = true;
_workaroundNoAboutToShowUpdate = true;
}
#endif
applyEnvVariable(&_workaroundNoAboutToShowUpdate, envForceWorkaroundNoAboutToShowUpdate());
applyEnvVariable(&_workaroundFakeDoubleClick, envForceWorkaroundFakeDoubleClick());
applyEnvVariable(&_workaroundShowAndHideTray, envForceWorkaroundShowAndHideTray());
applyEnvVariable(&_workaroundManualVisibility, envForceWorkaroundManualVisibility());
qCInfo(lcApplication) << "Tray menu workarounds:"
<< "noabouttoshow:" << _workaroundNoAboutToShowUpdate
<< "fakedoubleclick:" << _workaroundFakeDoubleClick
<< "showhide:" << _workaroundShowAndHideTray
<< "manualvisibility:" << _workaroundManualVisibility;
connect(&_delayedTrayUpdateTimer, &QTimer::timeout, this, &ownCloudGui::updateContextMenu);
_delayedTrayUpdateTimer.setInterval(2 * 1000);
_delayedTrayUpdateTimer.setSingleShot(true);
connect(_contextMenu.data(), SIGNAL(aboutToShow()), SLOT(slotContextMenuAboutToShow()));
// unfortunately aboutToHide is unreliable, it seems to work on OSX though
connect(_contextMenu.data(), SIGNAL(aboutToHide()), SLOT(slotContextMenuAboutToHide()));
// Populate the context menu now.
updateContextMenu();
}
void ownCloudGui::updateContextMenu()
{
if (minimalTrayMenu()) {
return;
}
// If it's visible, we can't update live, and it won't be updated lazily: reschedule
if (contextMenuVisible() && !updateWhileVisible() && _workaroundNoAboutToShowUpdate) {
if (!_delayedTrayUpdateTimer.isActive()) {
_delayedTrayUpdateTimer.start();
}
return;
}
if (_workaroundShowAndHideTray) {
// To make tray menu updates work with these bugs (see setupContextMenu)
// we need to hide and show the tray icon. We don't want to do that
// while it's visible!
if (contextMenuVisible()) {
if (!_delayedTrayUpdateTimer.isActive()) {
_delayedTrayUpdateTimer.start();
}
return;
}
_tray->hide();
}
_contextMenu->clear();
slotRebuildRecentMenus();
// We must call deleteLater because we might be called from the press in one of the actions.
foreach (auto menu, _accountMenus) {
menu->deleteLater();
}
_accountMenus.clear();
auto accountList = AccountManager::instance()->accounts();
bool isConfigured = (!accountList.isEmpty());
bool atLeastOneConnected = false;
bool atLeastOnePaused = false;
bool atLeastOneNotPaused = false;
foreach (auto a, accountList) {
if (a->isConnected()) {
atLeastOneConnected = true;
}
}
foreach (auto f, FolderMan::instance()->map()) {
if (f->syncPaused()) {
atLeastOnePaused = true;
} else {
atLeastOneNotPaused = true;
}
}
if (accountList.count() > 1) {
foreach (AccountStatePtr account, accountList) {
QMenu *accountMenu = new QMenu(account->account()->displayName(), _contextMenu.data());
_accountMenus.append(accountMenu);
_contextMenu->addMenu(accountMenu);
addAccountContextMenu(account, accountMenu, true);
fetchNavigationApps(account);
}
} else if (accountList.count() == 1) {
addAccountContextMenu(accountList.first(), _contextMenu.data(), false);
fetchNavigationApps(accountList.first());
}
_contextMenu->addSeparator();
_contextMenu->addAction(_actionStatus);
if (isConfigured && atLeastOneConnected) {
_contextMenu->addMenu(_recentActionsMenu);
}
_contextMenu->addSeparator();
if (_navLinksMenu) {
_contextMenu->addMenu(_navLinksMenu);
}
_contextMenu->addSeparator();
if (accountList.isEmpty()) {
_contextMenu->addAction(_actionNewAccountWizard);
}
_contextMenu->addAction(_actionSettings);
if (!Theme::instance()->helpUrl().isEmpty()) {
_contextMenu->addAction(_actionHelp);
}
if (_actionCrash) {
_contextMenu->addAction(_actionCrash);
}
_contextMenu->addSeparator();
if (atLeastOnePaused) {
QString text;
if (accountList.count() > 1) {
text = tr("Resume all synchronization");
} else {
text = tr("Resume synchronization");
}
QAction *action = _contextMenu->addAction(text);
connect(action, &QAction::triggered, this, &ownCloudGui::slotUnpauseAllFolders);
}
if (atLeastOneNotPaused) {
QString text;
if (accountList.count() > 1) {
text = tr("Pause all synchronization");
} else {
text = tr("Pause synchronization");
}
QAction *action = _contextMenu->addAction(text);
connect(action, &QAction::triggered, this, &ownCloudGui::slotPauseAllFolders);
}
_contextMenu->addAction(_actionQuit);
if (_workaroundShowAndHideTray) {
_tray->show();
}
}
void ownCloudGui::updateContextMenuNeeded()
{
// if it's visible and we can update live: update now
if (contextMenuVisible() && updateWhileVisible()) {
// Note: don't update while visible on OSX
// https://bugreports.qt.io/browse/QTBUG-54845
updateContextMenu();
return;
}
// if we can't lazily update: update later
if (_workaroundNoAboutToShowUpdate) {
// Note: don't update immediately even in the invisible case
// as that can lead to extremely frequent menu updates
if (!_delayedTrayUpdateTimer.isActive()) {
_delayedTrayUpdateTimer.start();
}
return;
}
}
void ownCloudGui::slotShowTrayMessage(const QString &title, const QString &msg)
{
if (_tray)
@ -774,30 +393,6 @@ void ownCloudGui::slotFolderOpenAction(const QString &alias)
}
}
void ownCloudGui::setupActions()
{
_actionStatus = new QAction(tr("Unknown status"), this);
_actionStatus->setEnabled(false);
_navLinksMenu = new QMenu(tr("Apps"));
_navLinksMenu->setEnabled(false);
_actionSettings = new QAction(tr("Settings …"), this);
_actionNewAccountWizard = new QAction(tr("New account …"), this);
QObject::connect(_actionSettings, &QAction::triggered, this, &ownCloudGui::slotShowSettings);
QObject::connect(_actionNewAccountWizard, &QAction::triggered, this, &ownCloudGui::slotNewAccountWizard);
_actionHelp = new QAction(tr("Help"), this);
QObject::connect(_actionHelp, &QAction::triggered, this, &ownCloudGui::slotHelp);
_actionQuit = new QAction(tr("Quit %1").arg(Theme::instance()->appNameGUI()), this);
QObject::connect(_actionQuit, SIGNAL(triggered(bool)), _app, SLOT(quit()));
if (_app->debugMode()) {
_actionCrash = new QAction(tr("Crash now", "Only shows in debug mode to allow testing the crash handler"), this);
connect(_actionCrash, &QAction::triggered, _app, &Application::slotCrash);
} else {
_actionCrash = nullptr;
}
}
void ownCloudGui::slotEtagResponseHeaderReceived(const QByteArray &value, int statusCode){
if(statusCode == 200){
qCDebug(lcApplication) << "New navigation apps ETag Response Header received " << value;
@ -875,7 +470,7 @@ void ownCloudGui::slotNavigationAppsFetched(const QJsonDocument &reply, int stat
}
}
} else if(accountList.size() == 1){
buildNavigationAppsMenu(account, _contextMenu.data());
//buildNavigationAppsMenu(account, _contextMenu.data());
}
}
}
@ -885,40 +480,17 @@ void ownCloudGui::slotOcsError(int statusCode, const QString &message)
emit serverError(statusCode, message);
}
void ownCloudGui::slotRebuildRecentMenus()
{
_recentActionsMenu->clear();
if (!_recentItemsActions.isEmpty()) {
foreach (QAction *a, _recentItemsActions) {
_recentActionsMenu->addAction(a);
}
_recentActionsMenu->addSeparator();
} else {
_recentActionsMenu->addAction(tr("No items synced recently"))->setEnabled(false);
}
}
/// Returns true if the completion of a given item should show up in the
/// 'Recent Activity' menu
static bool shouldShowInRecentsMenu(const SyncFileItem &item)
{
return !Progress::isIgnoredKind(item._status)
&& item._instruction != CSYNC_INSTRUCTION_EVAL
&& item._instruction != CSYNC_INSTRUCTION_NONE;
}
void ownCloudGui::slotUpdateProgress(const QString &folder, const ProgressInfo &progress)
{
Q_UNUSED(folder);
if (progress.status() == ProgressInfo::Discovery) {
if (!progress._currentDiscoveredRemoteFolder.isEmpty()) {
_actionStatus->setText(tr("Checking for changes in remote '%1'")
.arg(progress._currentDiscoveredRemoteFolder));
//_actionStatus->setText(tr("Checking for changes in remote '%1'")
//.arg(progress._currentDiscoveredRemoteFolder));
} else if (!progress._currentDiscoveredLocalFolder.isEmpty()) {
_actionStatus->setText(tr("Checking for changes in local '%1'")
.arg(progress._currentDiscoveredLocalFolder));
//_actionStatus->setText(tr("Checking for changes in local '%1'")
//.arg(progress._currentDiscoveredLocalFolder));
}
} else if (progress.status() == ProgressInfo::Done) {
QTimer::singleShot(2000, this, &ownCloudGui::slotComputeOverallSyncStatus);
@ -941,7 +513,7 @@ void ownCloudGui::slotUpdateProgress(const QString &folder, const ProgressInfo &
.arg(currentFile)
.arg(totalFileCount);
}
_actionStatus->setText(msg);
//_actionStatus->setText(msg);
} else {
QString totalSizeStr = Utility::octetsToString(progress.totalSize());
QString msg;
@ -952,16 +524,10 @@ void ownCloudGui::slotUpdateProgress(const QString &folder, const ProgressInfo &
msg = tr("Syncing %1")
.arg(totalSizeStr);
}
_actionStatus->setText(msg);
//_actionStatus->setText(msg);
}
if (!progress._lastCompletedItem.isEmpty()
&& shouldShowInRecentsMenu(progress._lastCompletedItem)) {
if (Progress::isWarningKind(progress._lastCompletedItem._status)) {
// display a warn icon if warnings happened.
QIcon warnIcon(":/client/resources/warning");
_actionRecent->setIcon(warnIcon);
}
if (!progress._lastCompletedItem.isEmpty()) {
QString kindStr = Progress::asResultString(progress._lastCompletedItem);
QString timeStr = QTime::currentTime().toString("hh:mm");
@ -980,12 +546,6 @@ void ownCloudGui::slotUpdateProgress(const QString &folder, const ProgressInfo &
_recentItemsActions.takeFirst()->deleteLater();
}
_recentItemsActions.append(action);
// Update the "Recent" menu if the context menu is being shown,
// otherwise it'll be updated later, when the context menu is opened.
if (updateWhileVisible() && contextMenuVisible()) {
slotRebuildRecentMenus();
}
}
}

Просмотреть файл

@ -64,25 +64,16 @@ public:
bool cloudProviderApiAvailable();
#endif
/// Whether the tray menu is visible
bool contextMenuVisible() const;
signals:
void setupProxy();
void serverError(int code, const QString &message);
void isShowingSettingsDialog();
public slots:
void setupContextMenu();
void updateContextMenu();
void updateContextMenuNeeded();
void slotContextMenuAboutToShow();
void slotContextMenuAboutToHide();
void slotComputeOverallSyncStatus();
void slotShowTrayMessage(const QString &title, const QString &msg);
void slotShowOptionalTrayMessage(const QString &title, const QString &msg);
void slotFolderOpenAction(const QString &alias);
void slotRebuildRecentMenus();
void slotUpdateProgress(const QString &folder, const ProgressInfo &progress);
void slotShowGuiMessage(const QString &title, const QString &message);
void slotFoldersChanged();
@ -126,22 +117,12 @@ private slots:
private:
void setPauseOnAllFoldersHelper(bool pause);
void setupActions();
void addAccountContextMenu(AccountStatePtr accountState, QMenu *menu, bool separateMenu);
void fetchNavigationApps(AccountStatePtr account);
void buildNavigationAppsMenu(AccountStatePtr account, QMenu *accountMenu);
QPointer<Systray> _tray;
QPointer<SettingsDialog> _settingsDialog;
QPointer<LogBrowser> _logBrowser;
// tray's menu
QScopedPointer<QMenu> _contextMenu;
// Manually tracking whether the context menu is visible via aboutToShow
// and aboutToHide. Unfortunately aboutToHide isn't reliable everywhere
// so this only gets used with _workaroundManualVisibility (when the tray's
// isVisible() is unreliable)
bool _contextMenuVisibleManual = false;
#ifdef WITH_LIBCLOUDPROVIDERS
QDBusConnection _bus;
@ -149,21 +130,12 @@ private:
QMenu *_recentActionsMenu;
QVector<QMenu *> _accountMenus;
bool _workaroundShowAndHideTray = false;
bool _workaroundNoAboutToShowUpdate = false;
bool _workaroundFakeDoubleClick = false;
bool _workaroundManualVisibility = false;
QTimer _delayedTrayUpdateTimer;
QMap<QString, QPointer<ShareDialog>> _shareDialogs;
QAction *_actionNewAccountWizard;
QAction *_actionSettings;
QAction *_actionStatus;
QAction *_actionEstimate;
QAction *_actionRecent;
QAction *_actionHelp;
QAction *_actionQuit;
QAction *_actionCrash;
QMenu *_navLinksMenu;
QMap<AccountStatePtr, QJsonArray> _navApps;

Просмотреть файл

@ -38,6 +38,7 @@ namespace OCC {
Systray::Systray() // TODO: make singleton, provide ::instance()
: _isOpen(false)
, _syncIsPaused(false)
, _trayComponent(nullptr)
, _trayContext(nullptr)
{
@ -182,4 +183,21 @@ int Systray::calcTrayWindowY()
}
#endif
}
bool Systray::syncIsPaused()
{
return _syncIsPaused;
}
void Systray::pauseResumeSync()
{
if (_syncIsPaused) {
_syncIsPaused = false;
emit resumeSync();
} else {
_syncIsPaused = true;
emit pauseSync();
}
}
} // namespace OCC

Просмотреть файл

@ -49,15 +49,20 @@ public:
void setToolTip(const QString &tip);
bool isOpen();
Q_INVOKABLE void pauseResumeSync();
Q_INVOKABLE int calcTrayWindowX();
Q_INVOKABLE int calcTrayWindowY();
Q_INVOKABLE bool syncIsPaused();
Q_INVOKABLE void setOpened();
Q_INVOKABLE void setClosed();
signals:
void currentUserChanged();
void openSettings();
void openHelp();
void shutdown();
void pauseSync();
void resumeSync();
Q_INVOKABLE void hideWindow();
Q_INVOKABLE void showWindow();
@ -67,6 +72,7 @@ private slots:
private:
bool _isOpen;
bool _syncIsPaused;
QQmlEngine *_trayEngine;
QQmlComponent *_trayComponent;
QQmlContext *_trayContext;

Просмотреть файл

@ -8,15 +8,12 @@ MenuItem {
Connections {
target: userModelBackend
onRefreshUserMenu: {
userLine.visible = isCurrentUser ? false : true
userLine.height = isCurrentUser ? 0 : 60
}
}
id: userLine
visible: isCurrentUser ? false : true
width: 216
height: isCurrentUser ? 0 : 60
height: 60
Rectangle {
id: userLineBackground
@ -52,7 +49,7 @@ MenuItem {
spacing: 0
Image {
id: accountAvatar
Layout.leftMargin: 4
Layout.leftMargin: 2
verticalAlignment: Qt.AlignCenter
source: ("image://avatars/" + index)
Layout.preferredHeight: (userLineBackground.height -16)
@ -66,14 +63,18 @@ MenuItem {
Layout.leftMargin: 12
Label {
id: accountUser
width: 120
text: name
elide: Text.ElideRight
color: "black"
font.pixelSize: 12
font.bold: true
}
Label {
id: accountServer
width: 120
text: server
elide: Text.ElideRight
color: "black"
font.pixelSize: 10
}

Просмотреть файл

@ -50,10 +50,6 @@ QString User::name() const
if (name == "") {
name = _account->account()->credentials()->user();
}
if (name.size() > 19) {
name.truncate(17);
name.append("...");
}
return name;
}
@ -63,10 +59,6 @@ QString User::server(bool shortened) const
if (shortened) {
serverUrl.replace(QLatin1String("https://"), QLatin1String(""));
serverUrl.replace(QLatin1String("http://"), QLatin1String(""));
if (serverUrl.size() > 21) {
serverUrl.truncate(19);
serverUrl.append("...");
}
}
return serverUrl;
}
@ -278,4 +270,4 @@ QImage ImageProvider::requestImage(const QString &id, QSize *size, const QSize &
}
}
}
}

Просмотреть файл

@ -100,7 +100,7 @@ Window {
hoverEnabled: true
onClicked:
{
accMenuLoginButton.text = (userModelBackend.isCurrentUserConnected() ? "Log out" : "Log in")
syncPauseButton.text = systrayBackend.syncIsPaused() ? "Resume sync for all" : "Pause sync for all"
accountMenu.open()
}
@ -109,6 +109,7 @@ Window {
x: (currentAccountButton.x + 2)
y: (currentAccountButton.y + currentAccountButton.height + 2)
width: (currentAccountButton.width - 4)
closePolicy: "CloseOnPressOutside"
background: Rectangle {
border.color: "#0082c9"
@ -118,33 +119,19 @@ Window {
Instantiator {
model: userModelBackend
delegate: UserLine {}
onObjectAdded: accountMenu.insertItem(3, object)
onObjectAdded: accountMenu.insertItem(index, object)
onObjectRemoved: accountMenu.removeItem(object)
}
MenuItem {
id: accMenuLoginButton
onClicked: (userModelBackend.isCurrentUserConnected()
? userModelBackend.logout()
: userModelBackend.login() )
}
MenuItem {
text: "Remove account"
onClicked: userModelBackend.removeAccount()
}
MenuSeparator { id: accountMenuSeparator }
MenuItem {
text: "Add account"
onClicked: userModelBackend.addAccount()
}
MenuSeparator { id: otherMenuSeparator }
MenuSeparator { id: accountMenuSeparator }
MenuItem {
text: systrayBackend.syncIsPaused() ? "Resume syncing" : "Pause syncing"
id: syncPauseButton
onClicked: systrayBackend.pauseResumeSync()
}
@ -153,6 +140,11 @@ Window {
onClicked: systrayBackend.openSettings()
}
MenuItem {
text: "Help"
onClicked: systrayBackend.openHelp()
}
MenuItem {
text: "Quit Nextcloud"
onClicked: systrayBackend.shutdown()
@ -236,23 +228,27 @@ Window {
Layout.leftMargin: 6
Label {
id: currentAccountUser
width: 128
text: userModelBackend.currentUserName()
elide: Text.ElideRight
color: "white"
font.pixelSize: 12
font.bold: true
}
Label {
id: currentAccountServer
width: 128
text: userModelBackend.currentUserServer()
elide: Text.ElideRight
color: "white"
font.pixelSize: 10
}
}
Image {
Layout.alignment: Qt.AlignLeft
Layout.alignment: Qt.AlignRight
verticalAlignment: Qt.AlignCenter
Layout.margins: 12
Layout.margins: 8
source: "qrc:///client/theme/white/caret-down.svg"
sourceSize.width: 20
sourceSize.height: 20

Просмотреть файл

@ -123,11 +123,11 @@ QIcon Theme::applicationIcon() const
* helper to load a icon from either the icon theme the desktop provides or from
* the apps Qt resources.
*/
QIcon Theme::themeIcon(const QString &name, bool sysTray, bool sysTrayMenuVisible) const
QIcon Theme::themeIcon(const QString &name, bool sysTray) const
{
QString flavor;
if (sysTray) {
flavor = systrayIconFlavor(_mono, sysTrayMenuVisible);
flavor = systrayIconFlavor(_mono);
} else {
flavor = QLatin1String("colored");
}
@ -170,7 +170,7 @@ QIcon Theme::themeIcon(const QString &name, bool sysTray, bool sysTrayMenuVisibl
#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
// This defines the icon as a template and enables automatic macOS color handling
// See https://bugreports.qt.io/browse/QTBUG-42109
cached.setIsMask(_mono && sysTray && !sysTrayMenuVisible);
cached.setIsMask(_mono && sysTray);
#endif
#endif
@ -270,18 +270,11 @@ QString Theme::defaultClientFolder() const
return appName();
}
QString Theme::systrayIconFlavor(bool mono, bool sysTrayMenuVisible) const
QString Theme::systrayIconFlavor(bool mono) const
{
Q_UNUSED(sysTrayMenuVisible)
QString flavor;
if (mono) {
flavor = Utility::hasDarkSystray() ? QLatin1String("white") : QLatin1String("black");
#ifdef Q_OS_MAC
if (sysTrayMenuVisible) {
flavor = QLatin1String("white");
}
#endif
} else {
flavor = QLatin1String("colored");
}
@ -395,7 +388,7 @@ QVariant Theme::customMedia(CustomMediaType type)
return re;
}
QIcon Theme::syncStateIcon(SyncResult::Status status, bool sysTray, bool sysTrayMenuVisible) const
QIcon Theme::syncStateIcon(SyncResult::Status status, bool sysTray) const
{
// FIXME: Mind the size!
QString statusIcon;
@ -427,7 +420,7 @@ QIcon Theme::syncStateIcon(SyncResult::Status status, bool sysTray, bool sysTray
statusIcon = QLatin1String("state-error");
}
return themeIcon(statusIcon, sysTray, sysTrayMenuVisible);
return themeIcon(statusIcon, sysTray);
}
QIcon Theme::folderDisabledIcon() const
@ -435,9 +428,9 @@ QIcon Theme::folderDisabledIcon() const
return themeIcon(QLatin1String("state-pause"));
}
QIcon Theme::folderOfflineIcon(bool sysTray, bool sysTrayMenuVisible) const
QIcon Theme::folderOfflineIcon(bool sysTray) const
{
return themeIcon(QLatin1String("state-offline"), sysTray, sysTrayMenuVisible);
return themeIcon(QLatin1String("state-offline"), sysTray);
}
QColor Theme::wizardHeaderTitleColor() const

Просмотреть файл

@ -93,10 +93,10 @@ public:
/**
* get an sync state icon
*/
virtual QIcon syncStateIcon(SyncResult::Status, bool sysTray = false, bool sysTrayMenuVisible = false) const;
virtual QIcon syncStateIcon(SyncResult::Status, bool sysTray = false) const;
virtual QIcon folderDisabledIcon() const;
virtual QIcon folderOfflineIcon(bool sysTray = false, bool sysTrayMenuVisible = false) const;
virtual QIcon folderOfflineIcon(bool sysTray = false) const;
virtual QIcon applicationIcon() const;
#endif
@ -166,7 +166,7 @@ public:
virtual QString enforcedLocale() const { return QString(); }
/** colored, white or black */
QString systrayIconFlavor(bool mono, bool sysTrayMenuVisible = false) const;
QString systrayIconFlavor(bool mono) const;
#ifndef TOKEN_AUTH_ONLY
/**
@ -449,7 +449,7 @@ public:
protected:
#ifndef TOKEN_AUTH_ONLY
QIcon themeIcon(const QString &name, bool sysTray = false, bool sysTrayMenuVisible = false) const;
QIcon themeIcon(const QString &name, bool sysTray = false) const;
#endif
Theme();