From f02f4397907feb5c45f8d768fc298a66ecc47c74 Mon Sep 17 00:00:00 2001 From: Anika Raemer Date: Sun, 26 Sep 2021 21:49:21 +0200 Subject: [PATCH] added config --- LenaPi/MusicPlayer.qml | 3 +- LenaPi/Navigation.qml | 1 + LenaPi/controllers/NavigationController.cpp | 5 ++ LenaPi/controllers/NavigationController.h | 34 +++++++++++++ LenaPi/main.cpp | 53 ++++++++++++++------- LenaPi/models/UiStateModel.cpp | 49 +++++++++++++++++++ LenaPi/models/UiStateModel.h | 40 ++++++++++++++++ 7 files changed, 168 insertions(+), 17 deletions(-) diff --git a/LenaPi/MusicPlayer.qml b/LenaPi/MusicPlayer.qml index dae3f55..a34d213 100644 --- a/LenaPi/MusicPlayer.qml +++ b/LenaPi/MusicPlayer.qml @@ -23,7 +23,7 @@ Item{ anchors.top: parent.top anchors.margins: visible ? container.margins : 0 - visible: container.height > 500 + visible: container.height > 500 && uiStateModel.pShowQuitAppButton diameter: visible ? defaultDiameter : 0 imageSource: "qrc:/icon_close" @@ -56,6 +56,7 @@ Item{ VolumeSlider{ id: volumeSlider + visible: uiStateModel.pShowVolumeControls anchors{ right: parent.right top: closeAppButton.bottom diff --git a/LenaPi/Navigation.qml b/LenaPi/Navigation.qml index f33382d..5251493 100644 --- a/LenaPi/Navigation.qml +++ b/LenaPi/Navigation.qml @@ -23,6 +23,7 @@ Item { anchors.right: parent.right anchors.top: parent.top anchors.margins: container.margins + visible: uiStateModel.pShowQuitAppButton imageSource: "qrc:/icon_close" onClicked: { Qt.quit(); diff --git a/LenaPi/controllers/NavigationController.cpp b/LenaPi/controllers/NavigationController.cpp index 726fcfc..1eb5c59 100644 --- a/LenaPi/controllers/NavigationController.cpp +++ b/LenaPi/controllers/NavigationController.cpp @@ -31,6 +31,11 @@ void NavigationController::init(const QString &rootPath) mNavList->setModelItems(mRootItem->getChildren()); } +void NavigationController::setUiProfile(const QString &profileString) +{ + mUiState->setProfile(profileString); +} + void NavigationController::setContext(QQmlContext *context) { mContext = context; diff --git a/LenaPi/controllers/NavigationController.h b/LenaPi/controllers/NavigationController.h index 7ed2497..8761160 100644 --- a/LenaPi/controllers/NavigationController.h +++ b/LenaPi/controllers/NavigationController.h @@ -9,19 +9,50 @@ class NavigationListModel; class UiStateModel; class MusicController; +/** + * @brief Main controller controlling ui state, navigation and music player. + */ class NavigationController : public QObject { Q_OBJECT public: explicit NavigationController(QObject *parent = nullptr); + /** + * @brief Setup navigation model parsing all directories under rootPath + * @param rootPath path to root directory containing music + */ void init(const QString & rootPath); + /** + * @brief Set ui profile + * @param profileString String defining profile + * @see UiStateModel::setProfile(const QString& profileString) + */ + void setUiProfile(const QString& profileString); + /** + * @brief setContext set QML Context and context properties + * @param context QmlContext + * @see setContextProperties + */ void setContext(QQmlContext* context); private: + /** + * @brief Register models in context + */ void setContextProperties(); + /** + * @brief Add a directory and its subdirectories to navigation + * @param path Path to directory + * @param parentItem Parent directory + */ void add(const QString & path, NavigationItemModel* parentItem); + /** + * @brief Check whether directory contains either a subdirectory or flac or mp3 music files + * @param path path to directory + * @return true if directory is valid + */ bool checkContent(const QString& path); NavigationItemModel* mRootItem; @@ -35,6 +66,9 @@ private: QQmlContext* mContext = nullptr; private slots: + /** + * @brief Either show subdirectories or music player depending on current directory type + */ void onNavigationRequest(); }; diff --git a/LenaPi/main.cpp b/LenaPi/main.cpp index 6394660..dd66e89 100644 --- a/LenaPi/main.cpp +++ b/LenaPi/main.cpp @@ -1,34 +1,56 @@ #include #include #include +#include +#include +#include #include "controllers/NavigationController.h" #include "MouseEventSpy.h" #include "EnergySaver.h" int main(int argc, char *argv[]) { - /* - * @todo Add command line parser to specify a custom config file - * https://doc.qt.io/qt-5/qcommandlineparser.html - */ + QGuiApplication app(argc, argv); QQmlApplicationEngine engine; - /* Read Settings */ - QSettings settings("me", "LenaPi"); - const auto rootPath = settings.value("rootPath", "/home/ar/source/lenaMusic/").toString(); // path to music files - const auto profile = settings.value("profile", "RasPiTouch").toString(); // known modes are "RasPiTouch" and "Desktop" - const auto isEnergySavingEnabled = settings.value("enableEnergySaver", true).toBool(); // enable/disable energy saver - const auto energySaverTimeout = settings.value("timeout", 60).toInt(); //timeout in seconds - const auto shutdownScript = settings.value("shutdownScript", "/usr/local/sbin/do_shutdown.sh").toString(); - - /* @todo Hand over profile to UiStateModel via NavigationController - * Add properties to UiStateModel for showing volume controls and close button. - * Set those properties according to profile and use them to hide/show elements in qml + /* Add command line parser to specify a custom config file + * https://doc.qt.io/qt-5/qcommandlineparser.html */ + QCommandLineParser parser; + parser.setApplicationDescription("Lena's music app"); + // Define a custom config file using -c or --config + QCommandLineOption configOption(QStringList() << "c" << "config", "Optional: Define custom config file"); + parser.addOption(configOption); + + // process commandline arguments + parser.process(app); + + QSettings* settings = nullptr; + if(!parser.value(configOption).isEmpty()){ + // config was handed over via commandline argument. Use this config if file exists. + QString configFilePath = parser.value(configOption); + QFileInfo configInfo(configFilePath); + if(configInfo.exists()){ + settings = new QSettings(configFilePath, QSettings::Format::NativeFormat); + } + } + if(!settings){ + // default config + settings = new QSettings(QSettings::Scope::UserScope, "MaleyanaSoft", "LenaPi"); + } + /* Read Settings */ + + const auto rootPath = settings->value("rootPath", "/home/ar/source/lenaMusic/").toString(); // path to music files + const auto profile = settings->value("profile", "RasPiTouch").toString(); // known profiles are "RasPiTouch" and "Desktop" + const auto isEnergySavingEnabled = settings->value("enableEnergySaver", true).toBool(); // enable/disable energy saver + const auto energySaverTimeout = settings->value("timeout", 60).toInt(); //timeout in seconds + const auto shutdownScript = settings->value("shutdownScript", "/usr/local/sbin/do_shutdown.sh").toString(); + NavigationController navController; navController.setContext(engine.rootContext()); navController.init(rootPath); + navController.setUiProfile(profile); if(isEnergySavingEnabled){ /* install MouseEventSpy and energy saver used for auto shut down of device @@ -43,6 +65,5 @@ int main(int argc, char *argv[]) // load GUI engine.load(QUrl("qrc:/main.qml")); - return app.exec(); } diff --git a/LenaPi/models/UiStateModel.cpp b/LenaPi/models/UiStateModel.cpp index ec44a07..98062ff 100644 --- a/LenaPi/models/UiStateModel.cpp +++ b/LenaPi/models/UiStateModel.cpp @@ -1,10 +1,30 @@ #include "UiStateModel.h" +#include UiStateModel::UiStateModel(QObject *parent) : QObject(parent) { + initProfiles(); showNavigation(); } +void UiStateModel::setProfile(UiStateModel::EProfile profile) +{ + mProfile = profile; + emit profileChanged(); +} + +bool UiStateModel::isShowQuitAppButton() const +{ + const auto & profileInfo = mProfileInfoMap[mProfile]; + return profileInfo.isShowQuitAppButton; +} + +bool UiStateModel::isShowVolumeControls() const +{ + const auto & profileInfo = mProfileInfoMap[mProfile]; + return profileInfo.isShowVolumeControls; +} + QUrl UiStateModel::getSource() const { return mSource; @@ -19,3 +39,32 @@ void UiStateModel::showNavigation(){ mSource = QUrl("Navigation.qml"); emit sourceChanged(); } + +void UiStateModel::initProfiles() +{ + // Profile_RasPiTouch + ProfileInfo rasPiTouchProfile; + rasPiTouchProfile.profileType = Profile_RasPiTouch; + rasPiTouchProfile.isShowQuitAppButton = false; + rasPiTouchProfile.isShowVolumeControls = false; + + mProfileInfoMap.insert(rasPiTouchProfile.profileType, rasPiTouchProfile); + + // Profile_Desktop + ProfileInfo desktopProfile; + desktopProfile.profileType = Profile_Desktop; + desktopProfile.isShowQuitAppButton = true; + desktopProfile.isShowVolumeControls = true; + + mProfileInfoMap.insert(desktopProfile.profileType, desktopProfile); +} + +UiStateModel::EProfile UiStateModel::getProfileFromString(const QString &profileString) +{ + if(profileString == "Desktop"){ + return Profile_Desktop; + } else if(profileString != "RasPiTouch"){ + std::cout << "WARNING: Unknown profile\t" << profileString.toStdString() << std::endl; + } + return Profile_RasPiTouch; +} diff --git a/LenaPi/models/UiStateModel.h b/LenaPi/models/UiStateModel.h index 0c7fd91..d7eff7c 100644 --- a/LenaPi/models/UiStateModel.h +++ b/LenaPi/models/UiStateModel.h @@ -3,6 +3,7 @@ #include #include +#include /** * @brief Handles state of UI by providing the qml source. @@ -15,9 +16,12 @@ class UiStateModel : public QObject Q_OBJECT Q_PROPERTY(QUrl pSource READ getSource NOTIFY sourceChanged) + Q_PROPERTY(bool pShowQuitAppButton READ isShowQuitAppButton NOTIFY profileChanged) + Q_PROPERTY(bool pShowVolumeControls READ isShowVolumeControls NOTIFY profileChanged) signals: void sourceChanged(); + void profileChanged(); public: /** @@ -37,15 +41,51 @@ public: */ Profile_Desktop }; + explicit UiStateModel(QObject *parent = nullptr); + /** + * @brief setProfile + * @param profileString String identifying profile as read from config. + * + * Known profile strings are "RasPiTouch" and "Desktop". + */ + void setProfile(const QString& profileString){ setProfile(getProfileFromString(profileString)); } + void setProfile(EProfile profile); + + bool isShowQuitAppButton() const; + bool isShowVolumeControls() const; + QUrl getSource() const; void showMusicPlayer(); void showNavigation(); private: + /** + * @brief Container defining ui state inforamtion for a certain profile + */ + struct ProfileInfo{ + EProfile profileType = Profile_RasPiTouch; + bool isShowQuitAppButton = false; + bool isShowVolumeControls = false; + }; + /** + * @brief Map containing ProfileInfo for each profile + */ + QHash mProfileInfoMap; + /** + * @brief Init ProfileInfo for all known profiles and init mProfileInfoMap + */ + void initProfiles(); + /** + * @brief Transform given profile string to enum valie + * @param profileString String identifying profile + * @return Matching profile. If given string does not match a known profile, Profile_RasPiTouch is used as default. + */ + static EProfile getProfileFromString(const QString& profileString); QUrl mSource; + EProfile mProfile = Profile_RasPiTouch; }; #endif // UISTATEMODEL_H