Improve first launch message in preparation for adding a setup wizard
This commit is contained in:
parent
04a4fe89ec
commit
394af9bce7
|
@ -67,6 +67,7 @@ set(REQUIRED_ICONS
|
|||
go-down
|
||||
go-up
|
||||
help-about
|
||||
help-contents
|
||||
internet-web-browser
|
||||
list-add
|
||||
list-remove
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <syncthingwidgets/misc/syncthinglauncher.h>
|
||||
#include <syncthingwidgets/settings/settings.h>
|
||||
#include <syncthingwidgets/settings/wizard.h>
|
||||
|
||||
#include <syncthingconnector/syncthingprocess.h>
|
||||
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
|
||||
|
@ -22,6 +23,7 @@
|
|||
#include <c++utilities/application/commandlineutils.h>
|
||||
#include <c++utilities/misc/parseerror.h>
|
||||
|
||||
#include <qtutilities/misc/dialogutils.h>
|
||||
#include <qtutilities/resources/importplugin.h>
|
||||
#include <qtutilities/resources/qtconfigarguments.h>
|
||||
#include <qtutilities/resources/resources.h>
|
||||
|
@ -60,6 +62,14 @@ void handleSystemdServiceError(const QString &context, const QString &name, cons
|
|||
}
|
||||
#endif
|
||||
|
||||
static void showWizard(const TrayWidget *trayWidget)
|
||||
{
|
||||
auto *const wizard = Wizard::instance();
|
||||
QtUtilities::centerWidget(wizard);
|
||||
QObject::connect(wizard, &Wizard::settingsRequested, trayWidget, &TrayWidget::showSettingsDialog);
|
||||
wizard->show();
|
||||
}
|
||||
|
||||
int initSyncthingTray(bool windowed, bool waitForTray, const Argument &connectionConfigArg)
|
||||
{
|
||||
// get settings
|
||||
|
@ -105,17 +115,10 @@ int initSyncthingTray(bool windowed, bool waitForTray, const Argument &connectio
|
|||
widget = &trayIcon->trayMenu().widget();
|
||||
}
|
||||
|
||||
// show "first launch" message box
|
||||
if (!settings.firstLaunch) {
|
||||
return 0;
|
||||
// show wizard on first launch
|
||||
if (settings.firstLaunch || settings.fakeFirstLaunch) {
|
||||
showWizard(widget);
|
||||
}
|
||||
QMessageBox msgBox;
|
||||
msgBox.setIcon(QMessageBox::Information);
|
||||
msgBox.setText(QCoreApplication::translate("main", "You must configure how to connect to Syncthing when using Syncthing Tray the first time."));
|
||||
msgBox.setInformativeText(QCoreApplication::translate(
|
||||
"main", "Note that the settings dialog allows importing URL, credentials and API-key from the local Syncthing configuration."));
|
||||
msgBox.exec();
|
||||
widget->showSettingsDialog();
|
||||
return 0;
|
||||
|
||||
#else
|
||||
|
@ -128,9 +131,9 @@ int initSyncthingTray(bool windowed, bool waitForTray, const Argument &connectio
|
|||
#endif
|
||||
}
|
||||
|
||||
void trigger(bool tray, bool webUi)
|
||||
static void trigger(bool tray, bool webUi, bool wizard)
|
||||
{
|
||||
if (TrayWidget::instances().empty() || !(tray || webUi)) {
|
||||
if (TrayWidget::instances().empty() || !(tray || webUi || wizard)) {
|
||||
return;
|
||||
}
|
||||
auto *const trayWidget = TrayWidget::instances().front();
|
||||
|
@ -140,6 +143,9 @@ void trigger(bool tray, bool webUi)
|
|||
if (tray) {
|
||||
trayWidget->showUsingPositioningSettings();
|
||||
}
|
||||
if (wizard) {
|
||||
showWizard(trayWidget);
|
||||
}
|
||||
}
|
||||
|
||||
void shutdownSyncthingTray()
|
||||
|
@ -159,6 +165,10 @@ int runApplication(int argc, const char *const *argv)
|
|||
auto windowedArg = ConfigValueArgument("windowed", 'w', "opens the tray menu as a regular window");
|
||||
auto showWebUiArg = ConfigValueArgument("webui", '\0', "instantly shows the web UI - meant for creating shortcut to web UI");
|
||||
auto triggerArg = ConfigValueArgument("trigger", '\0', "instantly shows the left-click tray menu - meant for creating a shortcut");
|
||||
auto showWizardArg = ConfigValueArgument("show-wizard", '\0', "instantly shows the setup wizard");
|
||||
showWizardArg.setFlags(Argument::Flags::Deprecated, true); // hide as it is WIP
|
||||
auto assumeFirstLaunchArg = ConfigValueArgument("assume-first-launch", '\0', "assumes first launch");
|
||||
assumeFirstLaunchArg.setFlags(Argument::Flags::Deprecated, true); // hide as it is debug-only
|
||||
auto waitForTrayArg = ConfigValueArgument("wait", '\0',
|
||||
"wait until the system tray becomes available instead of showing an error message if the system tray is not available on start-up");
|
||||
auto connectionArg = ConfigValueArgument("connection", '\0', "specifies one or more connection configurations to be used", { "config name" });
|
||||
|
@ -168,8 +178,8 @@ int runApplication(int argc, const char *const *argv)
|
|||
auto singleInstance = Argument("single-instance", '\0', "does nothing if a tray icon is already shown");
|
||||
auto newInstanceArg = Argument("new-instance", '\0', "disable the usual single-process behavior");
|
||||
auto &widgetsGuiArg = qtConfigArgs.qtWidgetsGuiArg();
|
||||
widgetsGuiArg.addSubArguments(
|
||||
{ &windowedArg, &showWebUiArg, &triggerArg, &waitForTrayArg, &connectionArg, &configPathArg, &singleInstance, &newInstanceArg });
|
||||
widgetsGuiArg.addSubArguments({ &windowedArg, &showWebUiArg, &triggerArg, &waitForTrayArg, &connectionArg, &configPathArg, &singleInstance,
|
||||
&newInstanceArg, &showWizardArg, &assumeFirstLaunchArg });
|
||||
#ifdef SYNCTHINGTRAY_USE_LIBSYNCTHING
|
||||
auto cliArg = OperationArgument("cli", 'c', "run Syncthing's CLI");
|
||||
auto cliHelp = ConfigValueArgument("help", 'h', "show help for Syncthing's CLI");
|
||||
|
@ -214,6 +224,9 @@ int runApplication(int argc, const char *const *argv)
|
|||
Settings::restore();
|
||||
Settings::values().qt.apply();
|
||||
qtConfigArgs.applySettings(true);
|
||||
if (assumeFirstLaunchArg.isPresent()) {
|
||||
Settings::values().fakeFirstLaunch = true;
|
||||
}
|
||||
LOAD_QT_TRANSLATIONS;
|
||||
SyncthingLauncher launcher;
|
||||
SyncthingLauncher::setMainInstance(&launcher);
|
||||
|
@ -232,14 +245,14 @@ int runApplication(int argc, const char *const *argv)
|
|||
|
||||
// trigger UI and enter event loop
|
||||
QObject::connect(&application, &QCoreApplication::aboutToQuit, &shutdownSyncthingTray);
|
||||
trigger(triggerArg.isPresent(), showWebUiArg.isPresent());
|
||||
trigger(triggerArg.isPresent(), showWebUiArg.isPresent(), showWizardArg.isPresent());
|
||||
return application.exec();
|
||||
}
|
||||
|
||||
// trigger actions if --webui or --trigger is present but don't create a new tray icon
|
||||
const auto firstInstance = TrayWidget::instances().empty();
|
||||
if (!firstInstance && (showWebUiArg.isPresent() || triggerArg.isPresent())) {
|
||||
trigger(triggerArg.isPresent(), showWebUiArg.isPresent());
|
||||
if (!firstInstance && (showWebUiArg.isPresent() || triggerArg.isPresent() || showWizardArg.isPresent())) {
|
||||
trigger(triggerArg.isPresent(), showWebUiArg.isPresent(), showWizardArg.isPresent());
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -251,7 +264,7 @@ int runApplication(int argc, const char *const *argv)
|
|||
// create new/additional tray icon
|
||||
const auto res = initSyncthingTray(windowedArg.isPresent(), waitForTrayArg.isPresent(), connectionArg);
|
||||
if (!res) {
|
||||
trigger(triggerArg.isPresent(), showWebUiArg.isPresent());
|
||||
trigger(triggerArg.isPresent(), showWebUiArg.isPresent(), showWizardArg.isPresent());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -233,7 +233,7 @@ TrayWidget::~TrayWidget()
|
|||
}
|
||||
}
|
||||
|
||||
void TrayWidget::showSettingsDialog()
|
||||
SettingsDialog *TrayWidget::settingsDialog()
|
||||
{
|
||||
if (!s_dialogParent) {
|
||||
s_dialogParent = new QWidget();
|
||||
|
@ -248,9 +248,14 @@ void TrayWidget::showSettingsDialog()
|
|||
// by simply saving the settings immediately.
|
||||
connect(s_settingsDlg, &SettingsDialog::applied, &Settings::save);
|
||||
}
|
||||
return s_settingsDlg;
|
||||
}
|
||||
|
||||
void TrayWidget::showSettingsDialog()
|
||||
{
|
||||
auto *const dlg = settingsDialog();
|
||||
// show settings dialog centered or maximized if the relatively big windows would overflow
|
||||
showDialog(s_settingsDlg, centerWidgetAvoidingOverflow(s_settingsDlg));
|
||||
showDialog(dlg, centerWidgetAvoidingOverflow(dlg));
|
||||
}
|
||||
|
||||
void TrayWidget::showAboutDialog()
|
||||
|
|
|
@ -56,6 +56,7 @@ public:
|
|||
QMenu *connectionsMenu();
|
||||
static const std::vector<TrayWidget *> &instances();
|
||||
Data::SyncthingConnectionSettings *selectedConnection();
|
||||
SettingsDialog *settingsDialog();
|
||||
|
||||
public Q_SLOTS:
|
||||
void showSettingsDialog();
|
||||
|
|
|
@ -11,6 +11,7 @@ set(META_WEBVIEW_SRC_DIR webview)
|
|||
set(WIDGETS_HEADER_FILES
|
||||
settings/settings.h
|
||||
settings/settingsdialog.h
|
||||
settings/wizard.h
|
||||
webview/webpage.h
|
||||
webview/webviewdialog.h
|
||||
misc/textviewdialog.h
|
||||
|
@ -25,6 +26,7 @@ set(WIDGETS_HEADER_FILES
|
|||
set(WIDGETS_SRC_FILES
|
||||
settings/settings.cpp
|
||||
settings/settingsdialog.cpp
|
||||
settings/wizard.cpp
|
||||
webview/webpage.cpp
|
||||
webview/webviewdialog.cpp
|
||||
webview/webviewinterceptor.h
|
||||
|
@ -71,7 +73,8 @@ set(REQUIRED_ICONS
|
|||
network-connect
|
||||
emblem-remove
|
||||
go-down
|
||||
go-up)
|
||||
go-up
|
||||
help-contents)
|
||||
|
||||
# find c++utilities
|
||||
find_package(${PACKAGE_NAMESPACE_PREFIX}c++utilities${CONFIGURATION_PACKAGE_SUFFIX} 5.11.0 REQUIRED)
|
||||
|
|
|
@ -150,6 +150,7 @@ struct SYNCTHINGWIDGETS_EXPORT WebView {
|
|||
|
||||
struct SYNCTHINGWIDGETS_EXPORT Settings {
|
||||
bool firstLaunch = false;
|
||||
bool fakeFirstLaunch = false; // not persistent, for testing purposes only
|
||||
Connection connection;
|
||||
NotifyOn notifyOn;
|
||||
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
#include "./wizard.h"
|
||||
#include "./settings.h"
|
||||
|
||||
// use meta-data of syncthingtray application here
|
||||
#include "resources/../../tray/resources/config.h"
|
||||
|
||||
#include <QCommandLinkButton>
|
||||
#include <QCoreApplication>
|
||||
#include <QDesktopServices>
|
||||
#include <QFrame>
|
||||
#include <QLabel>
|
||||
#include <QUrl>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace QtGui {
|
||||
|
||||
Wizard *Wizard::s_instance = nullptr;
|
||||
|
||||
Wizard::Wizard(QWidget *parent, Qt::WindowFlags flags)
|
||||
: QWizard(parent, flags)
|
||||
{
|
||||
setWindowTitle(tr("Setup wizard - ") + QStringLiteral(APP_NAME));
|
||||
|
||||
const auto &settings = Settings::values();
|
||||
if (settings.firstLaunch || settings.fakeFirstLaunch) {
|
||||
addPage(new WelcomeWizardPage());
|
||||
}
|
||||
}
|
||||
|
||||
Wizard::~Wizard()
|
||||
{
|
||||
if (this == s_instance) {
|
||||
s_instance = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Wizard *Wizard::instance()
|
||||
{
|
||||
if (!s_instance) {
|
||||
s_instance = new Wizard();
|
||||
s_instance->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
}
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
WelcomeWizardPage::WelcomeWizardPage(QWidget *parent)
|
||||
: QWizardPage(parent)
|
||||
{
|
||||
setTitle(tr("Welcome to ") + QStringLiteral(APP_NAME));
|
||||
setSubTitle(tr("It looks like you're launching %1 for the first time.").arg(QStringLiteral(APP_NAME)));
|
||||
|
||||
auto *const infoLabel = new QLabel(this);
|
||||
infoLabel->setText(QCoreApplication::translate("main",
|
||||
"You must configure how to connect to Syncthing and how to launch Syncthing (if that's wanted) when using Syncthing Tray the first time. A "
|
||||
"guided/automated setup is still in the works so the manual setup is currently the only option."));
|
||||
infoLabel->setWordWrap(true);
|
||||
|
||||
auto *const showSettingsCommand = new QCommandLinkButton(this);
|
||||
showSettingsCommand->setText(tr("Configure connection and launcher settings manually"));
|
||||
showSettingsCommand->setDescription(
|
||||
tr("Note that the connection settings allow importing URL, credentials and API-key from the local Syncthing configuration.")
|
||||
.arg(QStringLiteral(APP_NAME)));
|
||||
showSettingsCommand->setIcon(QIcon::fromTheme(QStringLiteral("preferences-other")));
|
||||
connect(showSettingsCommand, &QCommandLinkButton::clicked, this, [this] {
|
||||
if (auto *const wizard = qobject_cast<Wizard *>(this->wizard())) {
|
||||
emit wizard->settingsRequested();
|
||||
wizard->close();
|
||||
}
|
||||
});
|
||||
|
||||
auto *const line = new QFrame(this);
|
||||
line->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding));
|
||||
line->setFrameShape(QFrame::HLine);
|
||||
line->setFrameShadow(QFrame::Sunken);
|
||||
|
||||
auto *const showDocsCommand = new QCommandLinkButton(this);
|
||||
showDocsCommand->setText(tr("Show Syncthing's documentation"));
|
||||
showDocsCommand->setDescription(tr("It contains general information about configuring Syncthing.").arg(QStringLiteral(APP_NAME)));
|
||||
showDocsCommand->setIcon(QIcon::fromTheme(QStringLiteral("help-contents")));
|
||||
connect(showDocsCommand, &QCommandLinkButton::clicked, this, [] { QDesktopServices::openUrl(QStringLiteral("https://docs.syncthing.net/")); });
|
||||
|
||||
auto *const showReadmeCommand = new QCommandLinkButton(this);
|
||||
showReadmeCommand->setText(tr("Show %1's README").arg(QStringLiteral(APP_NAME)));
|
||||
showReadmeCommand->setDescription(tr("It contains documentation about this GUI integration specifically.").arg(QStringLiteral(APP_NAME)));
|
||||
showReadmeCommand->setIcon(showDocsCommand->icon());
|
||||
connect(showReadmeCommand, &QCommandLinkButton::clicked, this, [] {
|
||||
if constexpr (std::string_view(APP_VERSION).find('-') == std::string_view::npos) {
|
||||
QDesktopServices::openUrl(QStringLiteral(APP_URL "/blob/v" APP_VERSION "/README.md"));
|
||||
} else {
|
||||
QDesktopServices::openUrl(QStringLiteral(APP_URL "/blob/master/README.md"));
|
||||
}
|
||||
});
|
||||
|
||||
auto *const layout = new QVBoxLayout;
|
||||
layout->addWidget(infoLabel);
|
||||
layout->addWidget(showSettingsCommand);
|
||||
layout->addStretch();
|
||||
layout->addWidget(line);
|
||||
layout->addWidget(showDocsCommand);
|
||||
layout->addWidget(showReadmeCommand);
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
bool WelcomeWizardPage::isComplete() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace QtGui
|
|
@ -0,0 +1,38 @@
|
|||
#ifndef SETTINGS_WIZARD_H
|
||||
#define SETTINGS_WIZARD_H
|
||||
|
||||
#include "../global.h"
|
||||
|
||||
#include <QWizard>
|
||||
#include <QWizardPage>
|
||||
|
||||
namespace QtGui {
|
||||
|
||||
class SYNCTHINGWIDGETS_EXPORT Wizard : public QWizard {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Wizard(QWidget *parent = nullptr, Qt::WindowFlags flags = Qt::WindowFlags());
|
||||
~Wizard() override;
|
||||
|
||||
static Wizard *instance();
|
||||
|
||||
Q_SIGNALS:
|
||||
void settingsRequested();
|
||||
|
||||
private:
|
||||
static Wizard *s_instance;
|
||||
};
|
||||
|
||||
class SYNCTHINGWIDGETS_EXPORT WelcomeWizardPage : public QWizardPage {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit WelcomeWizardPage(QWidget *parent = nullptr);
|
||||
|
||||
bool isComplete() const override;
|
||||
};
|
||||
|
||||
} // namespace QtGui
|
||||
|
||||
#endif // SETTINGS_WIZARD_H
|
Loading…
Reference in New Issue