Handle set of new configuration parameters

This commit is contained in:
Christophe Deschamps 2024-09-05 06:28:09 +00:00
parent 4f5d6cabfa
commit 13d2fefcd1
9 changed files with 345 additions and 35 deletions

View file

@ -85,10 +85,168 @@
DEFINE_ABSTRACT_OBJECT(App)
#ifdef Q_OS_LINUX
const QString AutoStartDirectory(QDir::homePath().append(QStringLiteral("/.config/autostart/")));
const QString ApplicationsDirectory(QDir::homePath().append(QStringLiteral("/.local/share/applications/")));
const QString IconsDirectory(QDir::homePath().append(QStringLiteral("/.local/share/icons/hicolor/scalable/apps/")));
#elif defined(Q_OS_MACOS)
const QString OsascriptExecutable(QStringLiteral("osascript"));
#else
const QString
AutoStartSettingsFilePath(QStringLiteral("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"));
#endif
// -----------------------------------------------------------------------------
// Autostart
// -----------------------------------------------------------------------------
#ifdef Q_OS_LINUX
bool App::autoStartEnabled() {
const QString confPath(AutoStartDirectory + EXECUTABLE_NAME ".desktop");
QFile file(confPath);
if (!QDir(AutoStartDirectory).exists() || !file.exists()) return false;
if (!file.open(QFile::ReadOnly)) {
qWarning() << "Unable to open autostart file in read only: `" << confPath << "`.";
return false;
}
// Check if installation is done via Flatpak, AppImage, or classic package
// in order to check if there is a correct exec path for autostart
QString exec = getApplicationPath();
QTextStream in(&file);
QString autoStartConf = in.readAll();
int index = -1;
// check if the Exec part of the autostart ini file not corresponding to our executable (old desktop entry with
// wrong version in filename)
if (autoStartConf.indexOf(QString("Exec=" + exec + " ")) <
0) { // On autostart, there is the option --iconified so there is one space.
// replace file
setAutoStart(true);
}
return true;
}
#elif defined(Q_OS_MACOS)
static inline QString getMacOsBundlePath() {
QDir dir(QCoreApplication::applicationDirPath());
if (dir.dirName() != QLatin1String("MacOS")) return QString();
dir.cdUp();
dir.cdUp();
QString path(dir.path());
if (path.length() > 0 && path.right(1) == "/") path.chop(1);
return path;
}
static inline QString getMacOsBundleName() {
return QFileInfo(getMacOsBundlePath()).baseName();
}
bool App::autoStartEnabled() {
const QByteArray expectedWord(getMacOsBundleName().toUtf8());
if (expectedWord.isEmpty()) {
qInfo() << QStringLiteral("Application is not installed. Autostart unavailable.");
return false;
}
QProcess process;
process.start(OsascriptExecutable,
{"-e", "tell application \"System Events\" to get the name of every login item"});
if (!process.waitForFinished()) {
qWarning() << QStringLiteral("Unable to execute properly: `%1` (%2).")
.arg(OsascriptExecutable)
.arg(process.errorString());
return false;
}
// TODO: Move in utils?
const QByteArray buf(process.readAll());
for (const char *p = buf.data(), *word = p, *end = p + buf.length(); p <= end; ++p) {
switch (*p) {
case ' ':
case '\r':
case '\n':
case '\t':
case '\0':
if (word != p) {
if (!strncmp(word, expectedWord, size_t(p - word))) return true;
word = p + 1;
}
default:
break;
}
}
return false;
}
#else
bool App::autoStartEnabled() {
return QSettings(AutoStartSettingsFilePath, QSettings::NativeFormat).value(EXECUTABLE_NAME).isValid();
}
#endif // ifdef Q_OS_LINUX
#ifdef Q_OS_LINUX
void App::setAutoStart(bool enabled) {
if (enabled == mAutoStart) return;
QDir dir(AutoStartDirectory);
if (!dir.exists() && !dir.mkpath(AutoStartDirectory)) {
qWarning() << QStringLiteral("Unable to build autostart dir path: `%1`.").arg(AutoStartDirectory);
return;
}
const QString confPath(AutoStartDirectory + EXECUTABLE_NAME ".desktop");
if (generateDesktopFile(confPath, !enabled, true)) {
mAutoStart = enabled;
}
}
#elif defined(Q_OS_MACOS)
void App::setAutoStart(bool enabled) {
if (enabled == mAutoStart) return;
if (getMacOsBundlePath().isEmpty()) {
qWarning() << QStringLiteral("Application is not installed. Unable to change autostart state.");
return;
}
if (enabled)
QProcess::execute(OsascriptExecutable,
{"-e", "tell application \"System Events\" to make login item at end with properties"
"{ path: \"" +
getMacOsBundlePath() + "\", hidden: false }"});
else
QProcess::execute(OsascriptExecutable, {"-e", "tell application \"System Events\" to delete login item \"" +
getMacOsBundleName() + "\""});
mAutoStart = enabled;
}
#else
void App::setAutoStart(bool enabled) {
if (enabled == mAutoStart) return;
QSettings settings(AutoStartSettingsFilePath, QSettings::NativeFormat);
if (enabled) settings.setValue(EXECUTABLE_NAME, QDir::toNativeSeparators(applicationFilePath()));
else settings.remove(EXECUTABLE_NAME);
mAutoStart = enabled;
}
#endif // ifdef Q_OS_LINUX
// -----------------------------------------------------------------------------
// End Autostart
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
App::App(int &argc, char *argv[])
: SingleApplication(argc, argv, true, Mode::User | Mode::ExcludeAppPath | Mode::ExcludeAppVersion) {
// Do not use APPLICATION_NAME here.
@ -121,6 +279,8 @@ App::App(int &argc, char *argv[])
.arg(applicationVersion())
.arg(Utils::getOsProduct())
.arg(qVersion());
mAutoStart = autoStartEnabled();
}
App::~App() {
@ -317,6 +477,10 @@ void App::initCore() {
}
},
Qt::QueuedConnection);
QObject::connect(mSettings.get(), &Settings::autoStartChanged, [this]() {
mustBeInMainThread(log().arg(Q_FUNC_INFO));
setAutoStart(mSettings->getAutoStart());
});
mEngine->load(url);
});
// coreModel.reset();
@ -665,3 +829,7 @@ bool App::event(QEvent *event) {
}
#endif
//-----------------------------------------------------------
// AutoStart
//-----------------------------------------------------------

View file

@ -103,6 +103,7 @@ public:
void initCore();
void initCppInterfaces();
void restart();
bool autoStartEnabled();
void onLoggerInitialized();
void sendCommand();
@ -134,6 +135,7 @@ signals:
private:
void createCommandParser();
void setAutoStart(bool enabled);
QCommandLineParser *mParser = nullptr;
Thread *mLinphoneThread = nullptr;
@ -143,6 +145,7 @@ private:
QSharedPointer<Settings> mSettings;
QSharedPointer<SafeConnection<App, CoreModel>> mCoreModelConnection;
QSharedPointer<SafeConnection<App, CliModel>> mCliModelConnection;
bool mAutoStart = false;
DECLARE_ABSTRACT_OBJECT
};

View file

@ -87,6 +87,10 @@ Settings::Settings(QObject *parent) : QObject(parent) {
INIT_CORE_MEMBER(OnlyDisplaySipUriUsername, mSettingsModel)
INIT_CORE_MEMBER(DarkModeAllowed, mSettingsModel)
INIT_CORE_MEMBER(MaxAccount, mSettingsModel)
INIT_CORE_MEMBER(AssistantGoDirectlyToThirdPartySipAccountLogin, mSettingsModel)
INIT_CORE_MEMBER(AssistantThirdPartySipAccountDomain, mSettingsModel)
INIT_CORE_MEMBER(AssistantThirdPartySipAccountTransport, mSettingsModel)
INIT_CORE_MEMBER(AutoStart, mSettingsModel)
}
Settings::~Settings() {
@ -294,6 +298,15 @@ void Settings::setSelf(QSharedPointer<Settings> me) {
DarkModeAllowed)
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, Settings, SettingsModel, mSettingsModel, int, maxAccount,
MaxAccount)
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, Settings, SettingsModel, mSettingsModel, bool,
assistantGoDirectlyToThirdPartySipAccountLogin,
AssistantGoDirectlyToThirdPartySipAccountLogin)
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, Settings, SettingsModel, mSettingsModel, QString,
assistantThirdPartySipAccountDomain, AssistantThirdPartySipAccountDomain)
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, Settings, SettingsModel, mSettingsModel, QString,
assistantThirdPartySipAccountTransport, AssistantThirdPartySipAccountTransport)
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, Settings, SettingsModel, mSettingsModel, bool, autoStart,
AutoStart)
auto coreModelConnection = QSharedPointer<SafeConnection<Settings, CoreModel>>(
new SafeConnection<Settings, CoreModel>(me, CoreModel::getInstance()), &QObject::deleteLater);

View file

@ -151,6 +151,13 @@ public:
DECLARE_CORE_GETSET(bool, onlyDisplaySipUriUsername, OnlyDisplaySipUriUsername)
DECLARE_CORE_GETSET(bool, darkModeAllowed, DarkModeAllowed)
DECLARE_CORE_GETSET(int, maxAccount, MaxAccount)
DECLARE_CORE_GETSET(bool,
assistantGoDirectlyToThirdPartySipAccountLogin,
AssistantGoDirectlyToThirdPartySipAccountLogin)
DECLARE_CORE_GETSET(QString, assistantThirdPartySipAccountDomain, AssistantThirdPartySipAccountDomain)
DECLARE_CORE_GETSET(QString, assistantThirdPartySipAccountTransport, AssistantThirdPartySipAccountTransport)
DECLARE_CORE_GETSET(bool, autoStart, AutoStart)
bool getAutoStart() { return mAutoStart; };
signals:

View file

@ -40,6 +40,23 @@ SettingsModel::SettingsModel(QObject *parent) : QObject(parent) {
if (mConfig->hasEntry(UiSection, "do_not_disturb") == 1) {
enableDnd(dndEnabled());
}
QObject::connect(
CoreModel::getInstance().get(), &CoreModel::globalStateChanged, this,
[this](const std::shared_ptr<linphone::Core> &core, linphone::GlobalState gstate, const std::string &message) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
if (gstate == linphone::GlobalState::On) { // reached when misc|config-uri is set in config and app starts
// and after config is fetched.
notifyConfigReady();
}
});
QObject::connect(CoreModel::getInstance().get(), &CoreModel::configuringStatus, this,
[this](const std::shared_ptr<linphone::Core> &core, linphone::ConfiguringState status,
const std::string &message) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
if (status == linphone::ConfiguringState::Successful) {
notifyConfigReady();
}
});
}
SettingsModel::~SettingsModel() {
@ -460,38 +477,91 @@ bool SettingsModel::getShowChats() const {
return mConfig->getBool(UiSection, "disable_chat_feature", false);
}*/
void SettingsModel::notifyConfigReady(){
DEFINE_NOTIFY_CONFIG_READY(assistantGoDirectlyToThirdPartySipAccountLogin,
AssistantGoDirectlyToThirdPartySipAccountLogin)
DEFINE_NOTIFY_CONFIG_READY(assistantThirdPartySipAccountDomain, AssistantThirdPartySipAccountDomain)
DEFINE_NOTIFY_CONFIG_READY(assistantThirdPartySipAccountTransport, AssistantThirdPartySipAccountTransport)
DEFINE_NOTIFY_CONFIG_READY(autoStart, AutoStart)
}
DEFINE_GETSET_CONFIG(SettingsModel, bool, Bool, disableChatFeature, DisableChatFeature, "disable_chat_feature", false)
DEFINE_GETSET_CONFIG(
SettingsModel, bool, Bool, disableMeetingsFeature, DisableMeetingsFeature, "disable_meetings_feature", false)
DEFINE_GETSET_CONFIG(
SettingsModel, bool, Bool, disableBroadcastFeature, DisableBroadcastFeature, "disable_broadcast_feature", false)
SettingsModel, bool, Bool, disableMeetingsFeature, DisableMeetingsFeature, "disable_meetings_feature", false)
DEFINE_GETSET_CONFIG(SettingsModel,
bool,
Bool,
disableBroadcastFeature,
DisableBroadcastFeature,
"disable_broadcast_feature",
false)
DEFINE_GETSET_CONFIG(SettingsModel, bool, Bool, hideSettings, HideSettings, "hide_settings", false)
DEFINE_GETSET_CONFIG(
SettingsModel, bool, Bool, hideAccountSettings, HideAccountSettings, "hide_account_settings", false)
DEFINE_GETSET_CONFIG(
SettingsModel, bool, Bool, disableCallRecordings, DisableCallRecordings, "disable_call_recordings_feature", false)
DEFINE_GETSET_CONFIG(SettingsModel, bool, Bool, hideAccountSettings, HideAccountSettings, "hide_account_settings", false)
DEFINE_GETSET_CONFIG(SettingsModel,
bool,
Bool,
assistantHideCreateAccount,
AssistantHideCreateAccount,
"assistant_hide_create_account",
false)
DEFINE_GETSET_CONFIG(
SettingsModel, bool, Bool, assistantDisableQrCode, AssistantDisableQrCode, "assistant_disable_qr_code", true)
bool,
Bool,
disableCallRecordings,
DisableCallRecordings,
"disable_call_recordings_feature",
false)
DEFINE_GETSET_CONFIG(SettingsModel,
bool,
Bool,
assistantHideThirdPartyAccount,
AssistantHideThirdPartyAccount,
"assistant_hide_third_party_account",
false)
bool,
Bool,
assistantHideCreateAccount,
AssistantHideCreateAccount,
"assistant_hide_create_account",
false)
DEFINE_GETSET_CONFIG(SettingsModel,
bool,
Bool,
onlyDisplaySipUriUsername,
OnlyDisplaySipUriUsername,
"only_display_sip_uri_username",
false)
DEFINE_GETSET_CONFIG(SettingsModel, bool, Bool, darkModeAllowed, DarkModeAllowed, "dark_mode_allowed", false)
bool,
Bool,
assistantDisableQrCode,
AssistantDisableQrCode,
"assistant_disable_qr_code",
true)
DEFINE_GETSET_CONFIG(SettingsModel,
bool,
Bool,
assistantHideThirdPartyAccount,
AssistantHideThirdPartyAccount,
"assistant_hide_third_party_account",
false)
DEFINE_GETSET_CONFIG(SettingsModel,
bool,
Bool,
onlyDisplaySipUriUsername,
OnlyDisplaySipUriUsername,
"only_display_sip_uri_username",
false)
DEFINE_GETSET_CONFIG(SettingsModel,
bool,
Bool,
darkModeAllowed,
DarkModeAllowed,
"dark_mode_allowed",
false)
DEFINE_GETSET_CONFIG(SettingsModel, int, Int, maxAccount, MaxAccount, "max_account", 0)
DEFINE_GETSET_CONFIG(SettingsModel,
bool,
Bool,
assistantGoDirectlyToThirdPartySipAccountLogin,
AssistantGoDirectlyToThirdPartySipAccountLogin,
"assistant_go_directly_to_third_party_sip_account_login",
false)
DEFINE_GETSET_CONFIG_STRING(SettingsModel,
assistantThirdPartySipAccountDomain,
AssistantThirdPartySipAccountDomain,
"assistant_third_party_sip_account_domain",
"")
DEFINE_GETSET_CONFIG_STRING(SettingsModel,
assistantThirdPartySipAccountTransport,
AssistantThirdPartySipAccountTransport,
"assistant_third_party_sip_account_transport",
"TLS")
DEFINE_GETSET_CONFIG(SettingsModel,
bool,
Bool,
autoStart,
AutoStart,
"auto_start",
false)

View file

@ -136,6 +136,10 @@ public:
DECLARE_GETSET(bool, onlyDisplaySipUriUsername, OnlyDisplaySipUriUsername)
DECLARE_GETSET(bool, darkModeAllowed, DarkModeAllowed)
DECLARE_GETSET(int, maxAccount, MaxAccount)
DECLARE_GETSET(bool, assistantGoDirectlyToThirdPartySipAccountLogin, AssistantGoDirectlyToThirdPartySipAccountLogin)
DECLARE_GETSET(QString, assistantThirdPartySipAccountDomain, AssistantThirdPartySipAccountDomain)
DECLARE_GETSET(QString, assistantThirdPartySipAccountTransport, AssistantThirdPartySipAccountTransport)
DECLARE_GETSET(bool, autoStart, AutoStart)
signals:
@ -171,6 +175,7 @@ signals:
void dndChanged(bool value);
private:
void notifyConfigReady();
MediastreamerUtils::SimpleCaptureGraph *mSimpleCaptureGraph = nullptr;
int mCaptureGraphListenerCount = 0;
DECLARE_ABSTRACT_OBJECT

View file

@ -79,8 +79,10 @@ public:
[this](type data) { safe->invokeToModel([this, data]() { model->set##X(data); }); }); \
safe->makeConnectToModel(&ModelClass::x##Changed, [this](type data) { \
safe->invokeToCore([this, data]() { \
m##X = data; \
emit x##Changed(); \
if (m##X != data) { \
m##X = data; \
emit x##Changed(); \
} \
}); \
});
@ -96,6 +98,21 @@ public:
} \
}
#define DEFINE_GETSET_CONFIG_STRING(Class, x, X, key, def) \
QString Class::get##X() const { \
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); \
return Utils::coreStringToAppString(mConfig->getString(UiSection, key, def)); \
} \
void Class::set##X(QString data) { \
if (get##X() != data) { \
mConfig->setString(UiSection, key, Utils::appStringToCoreString(data)); \
emit x##Changed(data); \
} \
}
#define DEFINE_NOTIFY_CONFIG_READY(x, X) \
emit x##Changed(get##X());
class AbstractObject {
public:
virtual QString getClassName() const = 0;

View file

@ -44,8 +44,23 @@ AppWindow {
function initStackViewItem() {
if (accountProxy.haveAccount) mainWindowStackView.replace(mainPage, StackView.Immediate)
else if (SettingsCpp.getFirstLaunch()) mainWindowStackView.replace(welcomePage, StackView.Immediate)
else if (SettingsCpp.assistantGoDirectlyToThirdPartySipAccountLogin) mainWindowStackView.replace(sipLoginPage, StackView.Immediate)
else mainWindowStackView.replace(loginPage, StackView.Immediate)
}
function goToLogin() {
if (SettingsCpp.assistantGoDirectlyToThirdPartySipAccountLogin)
mainWindowStackView.replace(sipLoginPage)
else
mainWindowStackView.replace(loginPage)
}
Connections {
target: SettingsCpp
function onAssistantGoDirectlyToThirdPartySipAccountLoginChanged() {
initStackViewItem()
}
}
AccountProxy {
id: accountProxy
@ -69,7 +84,7 @@ AppWindow {
id: welcomePage
WelcomePage {
onStartButtonPressed: {
mainWindowStackView.replace(loginPage)// Replacing the first item will destroy the old.
goToLogin() // Replacing the first item will destroy the old.
SettingsCpp.setFirstLaunch(false)
}
}
@ -100,7 +115,7 @@ AppWindow {
Component {
id: registerPage
RegisterPage {
onReturnToLogin: mainWindowStackView.replace(loginPage)
onReturnToLogin: goToLogin()
onBrowserValidationRequested: mainWindow.showLoadingPopup(qsTr("Veuillez valider le captcha sur la page web"), true)
Connections {
target: RegisterPageCpp
@ -125,7 +140,7 @@ AppWindow {
Connections {
target: RegisterPageCpp
function onLinkingNewAccountWithCodeSucceed() {
mainWindowStackView.replace(loginPage)
goToLogin()
mainWindow.showInformationPopup(qsTr("Compte créé"), qsTr("Le compte a été créé avec succès. Vous pouvez maintenant vous connecter"), true)
}
function onLinkingNewAccountWithCodeFailed(errorMessage) {
@ -150,7 +165,7 @@ AppWindow {
Component {
id: mainPage
MainLayout {
onAddAccountRequest: mainWindowStackView.replace(loginPage)
onAddAccountRequest: goToLogin()
onAccountRemoved: {
initStackViewItem()
}

View file

@ -4,6 +4,7 @@ import QtQuick.Controls as Control
import Linphone
import ConstantsCpp
import SettingsCpp
import 'qrc:/Linphone/view/Tool/utils.js' as Utils
LoginLayout {
id: mainItem
@ -30,6 +31,7 @@ LoginLayout {
console.debug("[SIPLoginPage] User: return")
mainItem.goBack()
}
visible: !SettingsCpp.assistantGoDirectlyToThirdPartySipAccountLogin
}
Image {
fillMode: Image.PreserveAspectFit
@ -210,10 +212,17 @@ LoginLayout {
contentItem: TextField {
id: domainEdit
isError: domain.errorTextVisible
initialText: SettingsCpp.assistantThirdPartySipAccountDomain
Layout.preferredWidth: 360 * DefaultStyle.dp
KeyNavigation.up: passwordEdit
KeyNavigation.down: displayName
}
Connections {
target: SettingsCpp
function onAssistantThirdPartySipAccountDomainChanged() {
domain.resetText()
}
}
}
FormItemLayout {
label: qsTr("Nom d'affichage")
@ -238,6 +247,9 @@ LoginLayout {
{text: "TLS", value: LinphoneEnums.TransportType.Tls},
{text: "DTLS", value: LinphoneEnums.TransportType.Dtls}
]
currentIndex: Utils.findIndex(model, function (entry) {
return entry === SettingsCpp.assistantThirdPartySipAccountTransport.toUpperCase()
})
}
}
}
@ -333,7 +345,7 @@ LoginLayout {
centerContent: [
Control.StackView {
id: rootStackView
initialItem: firstItem
initialItem: SettingsCpp.assistantGoDirectlyToThirdPartySipAccountLogin ? secondItem : firstItem
anchors.top: parent.top
anchors.left: parent.left
anchors.bottom: parent.bottom