1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00

refactor(startup): decouple loginscreen from model

This commit is contained in:
jenli669 2019-06-24 01:15:33 +02:00
parent c524e52d86
commit ea2510157c
No known key found for this signature in database
GPG Key ID: 8267F9F7C2BF7E5E
8 changed files with 167 additions and 104 deletions

View File

@ -18,7 +18,6 @@
*/
#include "src/audio/audio.h"
#include "src/core/coreav.h"
#include "src/ipc.h"
#include "src/net/toxuri.h"
#include "src/nexus.h"
@ -194,8 +193,8 @@ int main(int argc, char* argv[])
#endif
qsrand(time(nullptr));
Settings::getInstance();
QString locale = Settings::getInstance().getTranslation();
Settings& settings = Settings::getInstance();
QString locale = settings.getTranslation();
Translator::translate(locale);
// Process arguments
@ -215,15 +214,14 @@ int main(int argc, char* argv[])
QObject::tr("Starts new instance and opens the login screen.")));
parser.process(*a);
uint32_t profileId = Settings::getInstance().getCurrentProfileId();
uint32_t profileId = settings.getCurrentProfileId();
IPC ipc(profileId);
if (!ipc.isAttached()) {
qCritical() << "Can't init IPC";
return EXIT_FAILURE;
}
QObject::connect(&Settings::getInstance(), &Settings::currentProfileIdChanged, &ipc,
&IPC::setProfileId);
QObject::connect(&settings, &Settings::currentProfileIdChanged, &ipc, &IPC::setProfileId);
// For the auto-updater
if (sodium_init() < 0) {
@ -232,7 +230,7 @@ int main(int argc, char* argv[])
}
#ifdef LOG_TO_FILE
QString logFileDir = Settings::getInstance().getAppCacheDirPath();
QString logFileDir = settings.getAppCacheDirPath();
QDir(logFileDir).mkpath(".");
QString logfile = logFileDir + "qtox.log";
@ -274,7 +272,7 @@ int main(int argc, char* argv[])
qDebug() << "commit: " << GIT_VERSION;
QString profileName;
bool autoLogin = Settings::getInstance().getAutoLogin();
bool autoLogin = settings.getAutoLogin();
uint32_t ipcDest = 0;
bool doIpc = true;
@ -294,7 +292,7 @@ int main(int argc, char* argv[])
doIpc = false;
autoLogin = false;
} else {
profileName = Settings::getInstance().getCurrentProfile();
profileName = settings.getCurrentProfile();
}
if (parser.positionalArguments().size() == 0) {
@ -330,38 +328,27 @@ int main(int argc, char* argv[])
}
}
Profile* profile = nullptr;
// TODO(sudden6): remove once we get rid of Nexus
Nexus& nexus = Nexus::getInstance();
// TODO(kriby): Consider moving application initializing variables into a globalSettings object
// note: Because Settings is shouldering global settings as well as model specific ones it
// cannot be integrated into a central model object yet
nexus.setSettings(&settings);
// Autologin
// TODO (kriby): Shift responsibility of linking views to model objects from nexus
// Further: generate view instances separately (loginScreen, mainGUI, audio)
if (autoLogin && Profile::exists(profileName) && !Profile::isEncrypted(profileName)) {
profile = Profile::loadProfile(profileName);
Profile* profile = Profile::loadProfile(profileName);
settings.updateProfileData(profile);
nexus.bootstrapWithProfile(profile);
} else {
LoginScreen loginScreen{profileName};
loginScreen.exec();
profile = loginScreen.getProfile();
if (profile) {
profileName = profile->getName();
int returnval = nexus.showLogin(profileName);
if (returnval != 0) {
return returnval;
}
}
if (!profile) {
return EXIT_FAILURE;
}
Nexus::getInstance().setProfile(profile);
Settings& s = Settings::getInstance();
s.setCurrentProfile(profileName);
auto audio = Audio::makeAudio(s);
assert(audio != nullptr);
// TODO(sudden6): init CoreAV audio backend somewhere else so main doesn't depend on coreav.h
profile->getCore()->getAv()->setAudio(*audio);
Nexus& nexus = Nexus::getInstance();
// TODO(sudden6): remove once we get rid of Nexus
nexus.audio = audio.get();
nexus.start();
// Start to accept Inter-process communication
ipc.registerEventHandler("uri", &toxURIEventHandler);
ipc.registerEventHandler("save", &toxSaveEventHandler);

View File

@ -35,6 +35,7 @@
#include <QThread>
#include <cassert>
#include <vpx/vpx_image.h>
#include <src/audio/audio.h>
#ifdef Q_OS_MAC
#include <QActionGroup>
@ -67,7 +68,7 @@ Nexus::~Nexus()
widget = nullptr;
delete profile;
profile = nullptr;
Settings::getInstance().saveGlobal();
emit saveGlobal();
#ifdef Q_OS_MAC
delete globalMenuBar;
#endif
@ -148,7 +149,7 @@ void Nexus::start()
/**
* @brief Hides the main GUI, delete the profile, and shows the login screen
*/
void Nexus::showLogin()
int Nexus::showLogin(const QString& profileName)
{
delete widget;
widget = nullptr;
@ -156,26 +157,71 @@ void Nexus::showLogin()
delete profile;
profile = nullptr;
LoginScreen loginScreen;
loginScreen.exec();
LoginScreen loginScreen{profileName};
connectLoginScreen(loginScreen);
profile = loginScreen.getProfile();
// TODO(kriby): Move core out of profile
// This is awkward because the core is in the profile
// The connection order ensures profile will be ready for bootstrap for now
connect(this, &Nexus::currentProfileChanged, this, &Nexus::bootstrapWithProfile);
int returnval = loginScreen.exec();
disconnect(this, &Nexus::currentProfileChanged, this, &Nexus::bootstrapWithProfile);
return returnval;
}
void Nexus::bootstrapWithProfile(Profile *p)
{
// kriby: This is a hack until a proper controller is written
profile = p;
if (profile) {
Nexus::getInstance().setProfile(profile);
Settings::getInstance().setCurrentProfile(profile->getName());
showMainGUI();
} else {
qApp->quit();
audioControl = std::unique_ptr<IAudioControl>(Audio::makeAudio(*settings));
assert(audioControl != nullptr);
profile->getCore()->getAv()->setAudio(*audioControl);
start();
}
}
void Nexus::setSettings(Settings* settings)
{
if (this->settings) {
QObject::disconnect(this, &Nexus::currentProfileChanged, this->settings,
&Settings::updateProfileData);
QObject::disconnect(this, &Nexus::saveGlobal, this->settings, &Settings::saveGlobal);
}
this->settings = settings;
if (this->settings) {
QObject::connect(this, &Nexus::currentProfileChanged, this->settings,
&Settings::updateProfileData);
QObject::connect(this, &Nexus::saveGlobal, this->settings, &Settings::saveGlobal);
}
}
void Nexus::connectLoginScreen(const LoginScreen& loginScreen)
{
// TODO(kriby): Move connect sequences to a controller class object instead
// Nexus -> LoginScreen
QObject::connect(this, &Nexus::profileLoaded, &loginScreen, &LoginScreen::onProfileLoaded);
QObject::connect(this, &Nexus::profileLoadFailed, &loginScreen, &LoginScreen::onProfileLoadFailed);
// LoginScreen -> Nexus
QObject::connect(&loginScreen, &LoginScreen::createNewProfile, this, &Nexus::onCreateNewProfile);
QObject::connect(&loginScreen, &LoginScreen::loadProfile, this, &Nexus::onLoadProfile);
// LoginScreen -> Settings
QObject::connect(&loginScreen, &LoginScreen::autoLoginChanged, settings, &Settings::onSetAutoLogin);
// Settings -> LoginScreen
QObject::connect(settings, &Settings::autoLoginChanged, &loginScreen,
&LoginScreen::onAutoLoginChanged);
}
void Nexus::showMainGUI()
{
// TODO(kriby): Rewrite as view-model connect sequence only, add to a controller class object
assert(profile);
// Create GUI
widget = Widget::getInstance(audio);
widget = Widget::getInstance(audioControl.get());
// Start GUI
widget->init();
@ -270,14 +316,36 @@ Profile* Nexus::getProfile()
}
/**
* @brief Unload the current profile, if any, and replaces it.
* @param profile Profile to set.
* @brief Creates a new profile and replaces the current one.
* @param name New username
* @param pass New password
*/
void Nexus::setProfile(Profile* profile)
void Nexus::onCreateNewProfile(const QString& name, const QString& pass)
{
getInstance().profile = profile;
if (profile)
Settings::getInstance().loadPersonal(profile->getName(), profile->getPasskey());
setProfile(Profile::createProfile(name, pass));
}
/**
* Loads an existing profile and replaces the current one.
*/
void Nexus::onLoadProfile(const QString& name, const QString& pass)
{
setProfile(Profile::loadProfile(name, pass));
}
/**
* Changes the loaded profile and notifies listeners.
* @param p
*/
void Nexus::setProfile(Profile* p) {
if (!p) {
emit profileLoadFailed();
// Warnings are issued during respective createNew/load calls
return;
} else {
emit profileLoaded();
}
emit currentProfileChanged(p);
}
/**

View File

@ -27,6 +27,8 @@
class Widget;
class Profile;
class Settings;
class LoginScreen;
class Core;
#ifdef Q_OS_MAC
@ -44,16 +46,13 @@ class Nexus : public QObject
public:
void start();
void showMainGUI();
void setSettings(Settings* settings);
static Nexus& getInstance();
static void destroyInstance();
static Core* getCore();
static Profile* getProfile();
static void setProfile(Profile* profile);
static Widget* getDesktopGUI();
public slots:
void showLogin();
#ifdef Q_OS_MAC
public:
@ -81,17 +80,29 @@ private:
QSignalMapper* windowMapper;
QActionGroup* windowActions = nullptr;
#endif
public:
// TODO(sudden6): hack to pass the audio instance
IAudioControl* audio = nullptr;
signals:
void currentProfileChanged(Profile* Profile);
void profileLoaded();
void profileLoadFailed();
void saveGlobal();
public slots:
void onCreateNewProfile(const QString& name, const QString& pass);
void onLoadProfile(const QString& name, const QString& pass);
int showLogin(const QString& profileName = QString());
void bootstrapWithProfile(Profile *p);
private:
explicit Nexus(QObject* parent = nullptr);
void connectLoginScreen(const LoginScreen& loginScreen);
void setProfile(Profile* p);
~Nexus();
private:
Profile* profile;
Settings* settings;
Widget* widget;
std::unique_ptr<IAudioControl> audioControl;
};
#endif // NEXUS_H

View File

@ -105,9 +105,6 @@ Profile::Profile(QString name, const QString& password, bool isNewProfile,
, encrypted{this->passkey != nullptr}
{
Settings& s = Settings::getInstance();
s.setCurrentProfile(name);
s.saveGlobal();
s.loadPersonal(name, this->passkey.get());
initCore(toxsave, s, isNewProfile);
const ToxId& selfId = core->getSelfId();

View File

@ -273,6 +273,19 @@ void Settings::loadGlobal()
loaded = true;
}
void Settings::updateProfileData(Profile *profile)
{
QMutexLocker locker{&bigLock};
if (profile == nullptr) {
qWarning() << QString("Could not load new settings (profile change to nullptr)");
return;
}
setCurrentProfile(profile->getName());
saveGlobal();
loadPersonal(profile->getName(), profile->getPasskey());
}
void Settings::loadPersonal(QString profileName, const ToxEncrypt* passKey)
{
QMutexLocker locker{&bigLock};
@ -1281,7 +1294,7 @@ void Settings::setCurrentProfile(const QString& profile)
if (profile != currentProfile) {
currentProfile = profile;
currentProfileId = makeProfileId(currentProfile);
emit currentProfileChanged(currentProfile);
emit currentProfileIdChanged(currentProfileId);
}
}

View File

@ -168,6 +168,8 @@ public:
public slots:
void saveGlobal();
void sync();
void onSetAutoLogin(bool state);
void updateProfileData(Profile *profile);
signals:
// General
@ -190,7 +192,6 @@ signals:
void toxmeBioChanged(const QString& bio);
void toxmePrivChanged(bool priv);
void toxmePassChanged();
void currentProfileChanged(const QString& profile);
void currentProfileIdChanged(quint32 id);
void enableLoggingChanged(bool enabled);
void autoAwayTimeChanged(int minutes);

View File

@ -32,7 +32,7 @@
#include <QMessageBox>
#include <QToolButton>
LoginScreen::LoginScreen(QString initialProfile, QWidget* parent)
LoginScreen::LoginScreen(const QString& initialProfileName, QWidget* parent)
: QDialog(parent)
, ui(new Ui::LoginScreen)
, quitShortcut{QKeySequence(Qt::CTRL + Qt::Key_Q), this}
@ -72,6 +72,15 @@ LoginScreen::~LoginScreen()
delete ui;
}
void LoginScreen::closeEvent(QCloseEvent* event)
{
// If we are in the bootstrap, returning -1 will give us something to exit with in main.cpp
this->setResult(-1);
// If we are in application exec, we can quit by closing it, instead.
qApp->quit();
}
/**
* @brief Resets the UI, clears all fields.
*/
@ -103,14 +112,15 @@ void LoginScreen::reset(QString initialProfile)
ui->loginPassword->setFocus();
}
ui->autoLoginCB->blockSignals(true);
ui->autoLoginCB->setChecked(Settings::getInstance().getAutoLogin());
ui->autoLoginCB->blockSignals(false);
void LoginScreen::onProfileLoadFailed() {
QMessageBox::critical(this, tr("Couldn't load this profile"), tr("Wrong password."));
ui->loginPassword->setFocus();
ui->loginPassword->selectAll();
}
Profile *LoginScreen::getProfile() const
void LoginScreen::onAutoLoginChanged(bool state)
{
return profile;
ui->autoLoginCB->setChecked(state);
}
bool LoginScreen::event(QEvent* event)
@ -129,11 +139,6 @@ bool LoginScreen::event(QEvent* event)
return QWidget::event(event);
}
void LoginScreen::closeEvent(QCloseEvent*)
{
emit closed();
}
void LoginScreen::onNewProfilePageClicked()
{
ui->stackedWidget->setCurrentIndex(0);
@ -174,16 +179,7 @@ void LoginScreen::onCreateNewProfile()
return;
}
profile = Profile::createProfile(name, pass);
if (!profile) {
// Unknown error
QMessageBox::critical(this, tr("Couldn't create a new profile"),
tr("Unknown error: Couldn't create a new profile.\nIf you "
"encountered this error, please report it."));
done(-1);
return;
}
done(0);
emit createNewProfile(name, pass);
}
void LoginScreen::onLoginUsernameSelected(const QString& name)
@ -227,20 +223,7 @@ void LoginScreen::onLogin()
return;
}
profile = Profile::loadProfile(name, pass);
if (!profile) {
if (!ProfileLocker::isLockable(name)) {
QMessageBox::critical(this, tr("Couldn't load this profile"),
tr("Profile already in use. Close other clients."));
return;
} else {
QMessageBox::critical(this, tr("Couldn't load this profile"), tr("Wrong password."));
ui->loginPassword->setFocus();
ui->loginPassword->selectAll();
return;
}
}
done(0);
emit loadProfile(name, pass);
}
void LoginScreen::onPasswordEdited()

View File

@ -36,20 +36,23 @@ class LoginScreen : public QDialog
Q_OBJECT
public:
LoginScreen(QString selectedProfile = QString(), QWidget* parent = nullptr);
LoginScreen(const QString& initialProfileName = QString(), QWidget* parent = nullptr);
~LoginScreen();
void reset(QString selectedProfile = QString());
Profile* getProfile() const;
bool event(QEvent* event) final override;
signals:
void windowStateChanged(Qt::WindowStates states);
void closed();
void createNewProfile(QString name, const QString& pass);
void loadProfile(QString name, const QString& pass);
protected:
virtual void closeEvent(QCloseEvent* event) final override;
public slots:
void onProfileLoaded();
void onProfileLoadFailed();
private slots:
void onAutoLoginToggled(int state);
void onLoginUsernameSelected(const QString& name);
@ -63,6 +66,7 @@ private slots:
void onImportProfile();
private:
void reset(const QString& initialProfileName = QString());
void retranslateUi();
void showCapsIndicator();
void hideCapsIndicator();
@ -71,7 +75,6 @@ private:
private:
Ui::LoginScreen* ui;
QShortcut quitShortcut;
Profile* profile{nullptr};
};
#endif // LOGINSCREEN_H