diff --git a/.gitignore b/.gitignore index ebd8b13..56accb7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.autosave -build-LenaPi* +build-LenaPi-Desktop-Debug +build-LenaPi-RasPi-Debug +build-LenaPi-RasPi-Release LenaPi/LenaPi.pro.user.4.8-pre1 -musik diff --git a/LenaPi/.qmake.stash b/LenaPi/.qmake.stash deleted file mode 100644 index 8046afc..0000000 --- a/LenaPi/.qmake.stash +++ /dev/null @@ -1,24 +0,0 @@ -QMAKE_CXX.QT_COMPILER_STDCXX = 201402L -QMAKE_CXX.QMAKE_GCC_MAJOR_VERSION = 10 -QMAKE_CXX.QMAKE_GCC_MINOR_VERSION = 2 -QMAKE_CXX.QMAKE_GCC_PATCH_VERSION = 1 -QMAKE_CXX.COMPILER_MACROS = \ - QT_COMPILER_STDCXX \ - QMAKE_GCC_MAJOR_VERSION \ - QMAKE_GCC_MINOR_VERSION \ - QMAKE_GCC_PATCH_VERSION -QMAKE_CXX.INCDIRS = \ - /usr/arm-linux-gnueabihf/include/c++/10 \ - /usr/arm-linux-gnueabihf/include/c++/10/arm-linux-gnueabihf \ - /usr/arm-linux-gnueabihf/include/c++/10/backward \ - /usr/lib/gcc-cross/arm-linux-gnueabihf/10/include \ - /usr/arm-linux-gnueabihf/include \ - /usr/include/arm-linux-gnueabihf \ - /usr/include -QMAKE_CXX.LIBDIRS = \ - /usr/lib/gcc-cross/arm-linux-gnueabihf/10 \ - /usr/arm-linux-gnueabihf/lib \ - /lib/arm-linux-gnueabihf \ - /lib \ - /usr/lib/arm-linux-gnueabihf \ - /usr/lib diff --git a/LenaPi/EnergySaver.cpp b/LenaPi/EnergySaver.cpp index da9db13..556dcbc 100644 --- a/LenaPi/EnergySaver.cpp +++ b/LenaPi/EnergySaver.cpp @@ -4,35 +4,16 @@ #include #include #include -EnergySaver::~EnergySaver() -{ -#ifdef ANDROID - releaseAndroidLock(); -#endif -} - -void EnergySaver::init() -{ - auto saver = instance(); - saver->mIsAutoShutDownEnabled = false; -#ifdef ANDROID - saver->initAdroidLocks(); -#endif -} void EnergySaver::init(int interval, const QString &shutdownScript) { - auto saver = instance(); - saver->mIsAutoShutDownEnabled = true; QFileInfo script(shutdownScript); if(script.exists()){ + auto saver = instance(); saver->setShutdownScript(shutdownScript); saver->initTimer(interval*1000); saver->restartTimer(); } -#ifdef ANDROID - saver->initAdroidLocks(); -#endif } @@ -40,32 +21,15 @@ void EnergySaver::init(int interval, const QString &shutdownScript) EnergySaver *EnergySaver::instance() { static EnergySaver* inst; - if (!inst) + if (inst == nullptr) { inst = new EnergySaver(); } return inst; } -void EnergySaver::deactivate() -{ - mIsActive = false; - mTimer.stop(); - setAndroidLock(); -} - -void EnergySaver::activate() -{ - mIsActive = true; - restartTimer(); - releaseAndroidLock(); -} - void EnergySaver::restartTimer() { - // Energy saver is currently deactivated -> Do NOT start timer - if(!mIsActive) return; - if(mTimer.isActive()){ mTimer.stop(); } @@ -85,59 +49,9 @@ void EnergySaver::setShutdownScript(const QString &shutdownScript) mShutdownScript = shutdownScript; } -void EnergySaver::initAdroidLocks() -{ -#ifdef ANDROID - QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;"); - if ( activity.isValid() ) - { - QAndroidJniObject serviceName = QAndroidJniObject::getStaticObjectField("android/content/Context","POWER_SERVICE"); - if ( serviceName.isValid() ) - { - QAndroidJniObject powerMgr = activity.callObjectMethod("getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;",serviceName.object()); - if ( powerMgr.isValid() ) - { - jint levelAndFlags = QAndroidJniObject::getStaticField("android/os/PowerManager","SCREEN_DIM_WAKE_LOCK"); - - QAndroidJniObject tag = QAndroidJniObject::fromString( "My Tag" ); - - m_wakeLock = powerMgr.callObjectMethod("newWakeLock", "(ILjava/lang/String;)Landroid/os/PowerManager$WakeLock;", levelAndFlags,tag.object()); - } - } - } -#endif -} - -void EnergySaver::setAndroidLock() -{ -#ifdef ANDROID - if ( m_wakeLock.isValid() ) - { - m_wakeLock.callMethod("acquire", "()V"); - qDebug() << "Locked device, can't go to standby anymore"; - } - else - { - assert( false ); - } -#endif -} - -void EnergySaver::releaseAndroidLock() -{ -#ifdef ANDROID - if ( m_wakeLock.isValid() ) - { - m_wakeLock.callMethod("release", "()V"); - qDebug() << "Unlocked device, can now go to standby"; - } -#endif -} - void EnergySaver::onTimeout() { - if(!mIsAutoShutDownEnabled) return; std::cout << "Shutting down."; #ifndef _DEBUG QProcess p; diff --git a/LenaPi/EnergySaver.h b/LenaPi/EnergySaver.h index fbfd503..3e14fe4 100644 --- a/LenaPi/EnergySaver.h +++ b/LenaPi/EnergySaver.h @@ -4,39 +4,27 @@ #include #include -#ifdef ANDROID -#include -#endif - /** * @brief Class handling energy saving options. * - * On Android devices, it locks the cpu shutdown while active. On other devices, it - * will shut down device on timeout if the options are set accordingly and a shutdown script - * is provided. + * Shut down device if no mouse input is detected and music player + * has not been active or a certain time interval. * - * In the context of the LenaPi application, it will prevent cpu shutdown on android devices while playing - * music. On other devices, it will shutdown the device if no music has been playing and no mouse input was - * detected for a certain time intervall. + * @todo For now this does only work for Lena's RasPi, where the + * shutdown script is positioned in a ceratin hardcoded path. + * Enable/disable energy saving option, timeout and path of + * shutdown script via config */ class EnergySaver : public QObject { Q_OBJECT protected: - using QObject::QObject; + explicit EnergySaver(QObject *parent = nullptr) : QObject(parent) {} public: - ~EnergySaver(); - /** - * @brief Create instance if necessary. The instance will have auto shutdown disabeld. - * - * Used to prevent sleep on android devices. - */ - static void init(); /** * @brief Create instance if necessary, configure it and start timer. - * @param enabledAutoShutdown Defines whether device will shutdown on inactivity using shutdownScript * @param interval Timer interval in seconds * @param shutdownScript Path to shutdown script file * @see EnergySaver::instance @@ -55,19 +43,7 @@ public: public slots: /** - * @brief Deactivate energy saver, e.g., as music is currently playing - * - * Sets locks on adroid devics and stops shutdown-timer. - */ - void deactivate(); - /** - * @brief Active energy saver - * - * Releases locks on android devices and restarts shutdown-timer if shutdown option is set. - */ - void activate(); - /** - * @brief Restart shutdown timer, e.g. because of music player activity + * @brief Restart shutdown timer, e.g. because of music player activiti */ void restartTimer(); @@ -78,31 +54,8 @@ private: */ void initTimer(int interval); void setShutdownScript(const QString& shutdownScript); - /** - * @brief Initializes locking or Android devices - */ - void initAdroidLocks(); - /** - * @brief Sets locks on Android devices to prevent sleep. - * - * Used to prevent cpu sleep as otherwise music will stop. - */ - void setAndroidLock(); - /** - * @brief Releases locks on Android devices to allow the device's cpu to go into sleep mode. - */ - void releaseAndroidLock(); QTimer mTimer; QString mShutdownScript; - bool mIsActive{false}; - bool mIsAutoShutDownEnabled{false}; - -#ifdef ANDROID - /** - * @brief Prevent energy saving for Android devices - */ - QAndroidJniObject m_wakeLock; -#endif private slots: /** @@ -110,7 +63,6 @@ private slots: */ void onTimeout(); - }; #endif // ENERGYSAVER_H diff --git a/LenaPi/LenaPi.pro b/LenaPi/LenaPi.pro index e603e36..5750661 100644 --- a/LenaPi/LenaPi.pro +++ b/LenaPi/LenaPi.pro @@ -1,20 +1,16 @@ TEMPLATE = app -linux:android { -QT += androidextras -ANDROID_PERMISSIONS += android.permission.WAKE_LOCK -ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android-files -QMAKE_CXXFLAGS += -DANDROID=1 -} -QT += qml quick multimedia + +QT += qml quick CONFIG += c++11 -LIBS += +LIBS += -lVLCQtCore -lVLCQtQml + SOURCES += main.cpp \ - controllers/MusicPlayer.cpp \ - controllers/StyleHandling.cpp \ models/NavigationListModel.cpp \ models/NavigationItemModel.cpp \ controllers/NavigationController.cpp \ models/UiStateModel.cpp \ + controllers/MusicController.cpp \ + models/MusicModel.cpp \ MouseEventSpy.cpp \ EnergySaver.cpp \ controllers/SettingsHandler.cpp @@ -45,18 +41,14 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target HEADERS += \ - controllers/MusicPlayer.h \ - controllers/StyleHandling.h \ - models/MusicPlayer.h \ models/NavigationListModel.h \ models/NavigationItemModel.h \ controllers/NavigationController.h \ models/UiStateModel.h \ + controllers/MusicController.h \ + models/MusicModel.h \ MouseEventSpy.h \ EnergySaver.h \ controllers/SettingsHandler.h INCLUDEPATH+=/usr/local/include - -DISTFILES += \ - android-files/AndroidManifest.xml diff --git a/LenaPi/LenaPi.pro.user b/LenaPi/LenaPi.pro.user index 73f8196..430c2b1 100644 --- a/LenaPi/LenaPi.pro.user +++ b/LenaPi/LenaPi.pro.user @@ -1,14 +1,14 @@ - + EnvironmentId - {baaf8c13-9b67-4e08-b264-88275a728682} + {76cb87c9-a04b-479b-87ff-1b3ddab073a7} ProjectExplorer.Project.ActiveTarget - 0 + 0 ProjectExplorer.Project.EditorSettings @@ -28,7 +28,7 @@ QmlJSGlobal - 2 + 2 UTF-8 false 4 @@ -37,7 +37,6 @@ true true 1 - false true false 0 @@ -46,703 +45,282 @@ 0 8 true - false 1 true true true - *.md, *.MD, Makefile false - true ProjectExplorer.Project.PluginSettings - - true - false - true - true - true - true - - - 0 - true true - Builtin.Questionable - - true - true - Builtin.DefaultTidyAndClazy - 4 - - - - true - ProjectExplorer.Project.Target.0 - GenericLinuxOsType - armhf/raspi 10.0.1.146 - armhf/raspi 10.0.1.146 - {9f02fab2-7f72-4b24-bbd8-dbe33e863260} - 1 - 0 - 0 + Desktop + Desktop + {f9938f31-357c-4785-aa6e-21a3feac2ebf} + 0 + 0 + 0 - 0 - /home/jmr/privat/src/LenaPi/build-LenaPi-Unnamed-Debug - /home/jmr/privat/src/LenaPi/build-LenaPi-Unnamed-Debug + /home/araemer/source/LenaPi/build-LenaPi-Desktop-Debug true + qmake + QtProjectManager.QMakeBuildStep + true + false - + false + false true + Make + Qt4ProjectManager.MakeStep + + false + + + false - 2 + 2 Build - Build + ProjectExplorer.BuildSteps.Build true + Make + Qt4ProjectManager.MakeStep + + true clean + + false - 1 + 1 Clean - Clean + ProjectExplorer.BuildSteps.Clean 2 false - - false - Debug + Debug + Qt4ProjectManager.Qt4BuildConfiguration 2 + true - /home/jmr/privat/src/LenaPi/build-LenaPi-Unnamed-Release - /home/jmr/privat/src/LenaPi/build-LenaPi-Unnamed-Release + /home/ar/source/LenaPi/build-LenaPi-Desktop-Release true + qmake + QtProjectManager.QMakeBuildStep + false + false - + false + false true + Make + Qt4ProjectManager.MakeStep + + false + + + false - 2 + 2 Build - Build + ProjectExplorer.BuildSteps.Build true + Make + Qt4ProjectManager.MakeStep + + true clean + + false - 1 + 1 Clean - Clean + ProjectExplorer.BuildSteps.Clean 2 false - - false - Release + Release + Qt4ProjectManager.Qt4BuildConfiguration 0 + true - 0 - /home/jmr/privat/src/LenaPi/build-LenaPi-Unnamed-Profile - /home/jmr/privat/src/LenaPi/build-LenaPi-Unnamed-Profile + /home/ar/source/LenaPi/build-LenaPi-Desktop-Profile true + qmake + QtProjectManager.QMakeBuildStep + true + false - + true + false true + Make + Qt4ProjectManager.MakeStep + + false + + + false - 2 + 2 Build - Build + ProjectExplorer.BuildSteps.Build true + Make + Qt4ProjectManager.MakeStep + + true clean + + false - 1 + 1 Clean - Clean + ProjectExplorer.BuildSteps.Clean 2 false - - false - Profile + Profile + Qt4ProjectManager.Qt4BuildConfiguration 0 - 0 + true - 3 + 3 - - true - RemoteLinux.CheckForFreeDiskSpaceStep - - - - - / - 5242880 - - - - - true - RemoteLinux.KillAppStep - - - - - - - - - true - RemoteLinux.RsyncDeployStep - - - - - - - -av - - 3 + 0 Deploy - Deploy + ProjectExplorer.BuildSteps.Deploy 1 - - false - DeployToGenericLinux - - 1 - - true - true - true - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - - - 2 - - ProjectExplorer.CustomExecutableRunConfiguration - - false - true - false - true - - - true - true - true - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - - - 1 - - RemoteLinux.CustomRunConfig - - 1 - false - true - false - true - :0.0 - - 2 - - - - ProjectExplorer.Project.Target.1 - - Android.Device.Type - Android Qt 5.15.2 (android) Clang Multi-Abi - Android Qt 5.15.2 (android) Clang Multi-Abi - {ec9ac26e-ce2e-4aaf-b544-ccaec5b0b918} - 1 - 0 - 0 - - 0 - /home/jmr/privat/src/LenaPi/build-LenaPi-Android_Qt_5_15_2_android_Clang_Multi_Abi-Debug - /home/jmr/privat/src/LenaPi/build-LenaPi-Android_Qt_5_15_2_android_Clang_Multi_Abi-Debug - - - true - QtProjectManager.QMakeBuildStep - false - - armeabi-v7a - - - - true - Qt4ProjectManager.MakeStep - - - true - Copy application data - Qt4ProjectManager.AndroidPackageInstallationStep - - - android-31 - - true - Build Android APK - QmakeProjectManager.AndroidBuildApkStep - false - - 4 - Build - Build - ProjectExplorer.BuildSteps.Build - - - - true - Qt4ProjectManager.MakeStep - clean - - 1 - Clean - Clean - ProjectExplorer.BuildSteps.Clean - - 2 - false - - false - - Debug - Qt4ProjectManager.Qt4BuildConfiguration - 2 - 0 - - - /home/jmr/privat/src/LenaPi/build-LenaPi-Android_Qt_5_15_2_android_Clang_Multi_Abi-Release - /home/jmr/privat/src/LenaPi/build-LenaPi-Android_Qt_5_15_2_android_Clang_Multi_Abi-Release - - - true - QtProjectManager.QMakeBuildStep - false - - armeabi-v7a - - - - true - Qt4ProjectManager.MakeStep - - - true - Copy application data - Qt4ProjectManager.AndroidPackageInstallationStep - - - android-31 - - true - Build Android APK - QmakeProjectManager.AndroidBuildApkStep - false - - 4 - Build - Build - ProjectExplorer.BuildSteps.Build - - - - true - Qt4ProjectManager.MakeStep - clean - - 1 - Clean - Clean - ProjectExplorer.BuildSteps.Clean - - 2 - false - - false - - Release - Qt4ProjectManager.Qt4BuildConfiguration - 0 - 0 - 0 - - - 0 - /home/jmr/privat/src/LenaPi/build-LenaPi-Android_Qt_5_15_2_android_Clang_Multi_Abi-Profile - /home/jmr/privat/src/LenaPi/build-LenaPi-Android_Qt_5_15_2_android_Clang_Multi_Abi-Profile - - - true - QtProjectManager.QMakeBuildStep - false - - - - true - Qt4ProjectManager.MakeStep - - - true - Copy application data - Qt4ProjectManager.AndroidPackageInstallationStep - - - android-31 - - true - Build Android APK - QmakeProjectManager.AndroidBuildApkStep - false - - 4 - Build - Build - ProjectExplorer.BuildSteps.Build - - - - true - Qt4ProjectManager.MakeStep - clean - - 1 - Clean - Clean - ProjectExplorer.BuildSteps.Clean - - 2 - false - - false - - Profile - Qt4ProjectManager.Qt4BuildConfiguration - 0 - 0 - 0 - 0 - - 3 - - - - true - <b>Deploy to Android device</b> - Qt4ProjectManager.AndroidDeployQtStep - - 1 - Deploy - Deploy - ProjectExplorer.BuildSteps.Deploy - - 1 - - false - Qt4ProjectManager.AndroidDeployConfiguration2 - - 1 - - - arm64-v8a - armeabi-v7a - armeabi - - 58009fc2 - 28 - - - dwarf - - cpu-cycles - - -F - true - true - true - - - - - - - - 0 - - Qt4ProjectManager.AndroidRunConfiguration:/home/jmr/privat/src/LenaPi/LenaPi/LenaPi.pro - /home/jmr/privat/src/LenaPi/LenaPi/LenaPi.pro - false - true - false - true - - 1 - - - - ProjectExplorer.Project.Target.2 - - Desktop - desktop - desktop - {73308c85-3272-4fe8-8c9f-0eb72285644f} - 1 - 0 - 0 - - 0 - /home/jmr/privat/src/LenaPi/build-LenaPi-desktop-Debug - /home/jmr/privat/src/LenaPi/build-LenaPi-desktop-Debug - - - true - QtProjectManager.QMakeBuildStep - false - - - - true - Qt4ProjectManager.MakeStep - - 2 - Build - Build - ProjectExplorer.BuildSteps.Build - - - - true - Qt4ProjectManager.MakeStep - clean - - 1 - Clean - Clean - ProjectExplorer.BuildSteps.Clean - - 2 - false - - false - - Debug - Qt4ProjectManager.Qt4BuildConfiguration - 2 - 0 - - - /home/jmr/privat/src/LenaPi/build-LenaPi-desktop-Release - /home/jmr/privat/src/LenaPi/build-LenaPi-desktop-Release - - - true - QtProjectManager.QMakeBuildStep - false - - - - true - Qt4ProjectManager.MakeStep - - 2 - Build - Build - ProjectExplorer.BuildSteps.Build - - - - true - Qt4ProjectManager.MakeStep - clean - - 1 - Clean - Clean - ProjectExplorer.BuildSteps.Clean - - 2 - false - - false - - Release - Qt4ProjectManager.Qt4BuildConfiguration - 0 - 0 - - - 0 - /home/jmr/privat/src/LenaPi/build-LenaPi-desktop-Profile - /home/jmr/privat/src/LenaPi/build-LenaPi-desktop-Profile - - - true - QtProjectManager.QMakeBuildStep - false - - - - true - Qt4ProjectManager.MakeStep - - 2 - Build - Build - ProjectExplorer.BuildSteps.Build - - - - true - Qt4ProjectManager.MakeStep - clean - - 1 - Clean - Clean - ProjectExplorer.BuildSteps.Clean - - 2 - false - - false - - Profile - Qt4ProjectManager.Qt4BuildConfiguration - 0 - 0 - 0 - - 3 - - - 0 - Deploy - Deploy - ProjectExplorer.BuildSteps.Deploy - - 1 - - false + Deploy locally + ProjectExplorer.DefaultDeployConfiguration - 1 + 1 + - dwarf - - cpu-cycles - - -F - true + false + false + 1000 + true + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 true - + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 2 - Qt4ProjectManager.Qt4RunConfiguration:/home/jmr/privat/src/LenaPi/LenaPi/LenaPi.pro - /home/jmr/privat/src/LenaPi/LenaPi/LenaPi.pro + LenaPi + LenaPi2 + Qt4ProjectManager.Qt4RunConfiguration:/home/ar/source/LenaPi/LenaPi/LenaPi.pro + LenaPi.pro + + 3768 false true true + false false true + + /home/araemer/source/LenaPi/build-LenaPi-Desktop-Debug - 1 + 1 ProjectExplorer.Project.TargetCount - 3 + 1 ProjectExplorer.Project.Updater.FileVersion - 22 + 20 Version - 22 + 20 diff --git a/LenaPi/MediaProgress.qml b/LenaPi/MediaProgress.qml index d87746d..5b6b441 100644 --- a/LenaPi/MediaProgress.qml +++ b/LenaPi/MediaProgress.qml @@ -1,52 +1,51 @@ import QtQuick 2.0 import QtQuick.Controls 1.4 -import QtQuick.Layouts 1.3 import QtQuick.Controls.Styles 1.4 -ColumnLayout { +Item { id: container property var model - spacing: StyleSpacings.tinySpacing + // manually set height + Component.onCompleted: height = childrenRect.height - RowLayout{ - Label{ - font.pointSize: 9 - color: "grey" - text: model.pMediaTitle - } - Item{ - // spacer - Layout.fillWidth: true - } + Label{ + anchors.left: progress.left + anchors.bottom: progress.top + font.pointSize: 9 + color: "grey" + text: model.pMediaTitle + } - Label{ - font.pointSize: 9 - color: "grey" - text: model.pTime + " / " + model.pMediaLength - } + Label{ + anchors.right: progress.right + anchors.bottom: progress.top + font.pointSize: 9 + color: "grey" + text: model.pTime + " / " + model.pMediaLength } ProgressBar{ id: progress - Layout.fillWidth: true + anchors.top: parent.top + anchors.left: parent.left value: model.pProgress style:ProgressBarStyle { background: Rectangle { - radius: StyleSizes.progressBackgroundRadius + radius: 5 color: "white" border.color: "grey" - border.width: StyleSizes.progressBackgroundBorderWidth + border.width: 1 implicitWidth: container.width - implicitHeight: StyleSizes.progressBackgroundDefaultHeight + implicitHeight: 10 } progress: Rectangle { color: "blue" border.color: "blue" - radius: StyleSizes.progressBackgroundRadius - implicitHeight: StyleSizes.progressBarDefaultHeight + radius: 5 + implicitHeight: 8 } } } diff --git a/LenaPi/MouseEventSpy.cpp b/LenaPi/MouseEventSpy.cpp index 95ade23..26eb916 100644 --- a/LenaPi/MouseEventSpy.cpp +++ b/LenaPi/MouseEventSpy.cpp @@ -12,7 +12,7 @@ void MouseEventSpy::init() MouseEventSpy* MouseEventSpy::instance() { static MouseEventSpy* inst; - if (!inst) + if (inst == nullptr) { inst = new MouseEventSpy(); QGuiApplication* app = qGuiApp; diff --git a/LenaPi/MusicPlayer.qml b/LenaPi/MusicPlayer.qml index 15cf60b..a34d213 100644 --- a/LenaPi/MusicPlayer.qml +++ b/LenaPi/MusicPlayer.qml @@ -5,7 +5,7 @@ import QtGraphicalEffects 1.0 Item{ id: container - property int margins: StyleMargins.defaultMargin + property int margins: 20 RoundImageButton{ id: backNavigation @@ -43,9 +43,9 @@ Item{ Image{ id: cover anchors.centerIn: parent - height: parent.height-StyleMargins.smallMargin + height: parent.height-10 width: height - source: musicModel.pCoverImageSource + source: musicModel.pCurrentItem.pImageSource fillMode: Image.PreserveAspectCrop layer.enabled: true layer.effect: OpacityMask{ @@ -64,9 +64,12 @@ Item{ margins: container.margins topMargin: closeAppButton.visible ? 2*container.margins : container.margins } - value: musicModel.volume + from: 34 // we cannot hear anything if lower than 35% + to: 100 + stepSize: 1 + value: musicModel.pAudioVolume onValueChanged: { - musicModel.volume = value; + musicModel.pAudioVolume = value; } } PlayerControlPannel { diff --git a/LenaPi/MyScrollView.qml b/LenaPi/MyScrollView.qml index 63245eb..4d3e6e8 100644 --- a/LenaPi/MyScrollView.qml +++ b/LenaPi/MyScrollView.qml @@ -6,24 +6,24 @@ ScrollView{ style: ScrollViewStyle{ transientScrollBars: true handle: Item { - implicitWidth: StyleSizes.scrollHandleWidth - implicitHeight: StyleSizes.scrollHandleHeight + implicitWidth: 16 + implicitHeight: 8 Rectangle { color: "blue" border.color: "black" radius: height/2 anchors.fill: parent - anchors.topMargin: StyleMargins.scrollHandleMargin - anchors.leftMargin: StyleMargins.scrollHandleMargin - anchors.rightMargin: StyleMargins.scrollHandleMargin - anchors.bottomMargin: StyleMargins.scrollHandleMargin + anchors.topMargin: 1 + anchors.leftMargin: 1 + anchors.rightMargin: 1 + anchors.bottomMargin: 1 } } scrollBarBackground: Rectangle{ color: "transparent" border.color: "grey" - border.width: StyleSizes.scrollHandleBorderWidth - height: StyleSizes.scrollHandleHeight + border.width: 1 + height: 8 radius: height/2 } decrementControl: Item{} diff --git a/LenaPi/Navigation.qml b/LenaPi/Navigation.qml index 8e6f283..5251493 100644 --- a/LenaPi/Navigation.qml +++ b/LenaPi/Navigation.qml @@ -1,12 +1,11 @@ import QtQuick 2.0 -import QtQuick.Controls 2.4 /** * @brief Navigation view containing list view displaying artists or genres and albums */ Item { id: container - property int margins: StyleMargins.defaultMargin + property int margins: 20 RoundImageButton{ id: back @@ -36,27 +35,21 @@ Item { anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter - height: StyleSizes.navigationListHeight + height: 210 color: "#99ffffff" - Label{ - text: debug.pDebugOutput - anchors.centerIn: parent - visible: text !== "" - } - ListView{ id: circleList anchors.left: parent.left anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter - anchors.margins: StyleMargins.defaultMargin + anchors.margins: 20 - height: parent.height - 2*StyleMargins.defaultMargin + height: parent.height - 40 model: navigationList.pModelItems - spacing: StyleSpacings.defaultSpacing + spacing: 20 orientation: ListView.Horizontal delegate: NavigationListDelegate{ id: delegate diff --git a/LenaPi/NavigationListDelegate.qml b/LenaPi/NavigationListDelegate.qml index aaff20a..94b8919 100644 --- a/LenaPi/NavigationListDelegate.qml +++ b/LenaPi/NavigationListDelegate.qml @@ -14,11 +14,11 @@ ItemDelegate{ property alias imageSource: contentImage.source - padding: StylePaddings.defaultPadding + padding: 5 background: Rectangle{ id: background - implicitWidth: StyleSizes.navigationDelegateDefaultSize + implicitWidth: 150 implicitHeight: implicitWidth radius: container.isCircleDelegate ? height/2 : 0 color: "blue" @@ -26,7 +26,7 @@ ItemDelegate{ id: contentImage source: "qrc:/default_image" anchors.fill: parent - anchors.margins: StyleMargins.tinyMargin + anchors.margins: 5 fillMode: Image.PreserveAspectCrop layer.enabled: true diff --git a/LenaPi/PlayerButtons.qml b/LenaPi/PlayerButtons.qml index 07caed0..8fe8b00 100644 --- a/LenaPi/PlayerButtons.qml +++ b/LenaPi/PlayerButtons.qml @@ -1,58 +1,62 @@ import QtQuick 2.0 -import QtQuick.Layouts 1.3 -RowLayout{ +Item { id: container property var model - property var spacing: StyleSpacings.defaultSpacing + property var spacing: 20 + Row{ + id: buttons + anchors.centerIn: parent + spacing: container.spacing - RoundImageButton{ - id: previous - Layout.alignment: Qt.AlignVCenter + RoundImageButton{ + id: previous + anchors.verticalCenter: parent.verticalCenter - diameter: StyleSizes.smallPlayerButtonSize //60 - imageSource: "qrc:/icon_previous" + diameter: 60 + imageSource: "qrc:/icon_previous" - enabled: model.pHasPrevious + enabled: model.pHasPrevious - onClicked:{ - model.playPrevious(); + onClicked:{ + model.playPrevious(); + } } - } - RoundImageButton{ - id: playPause - Layout.alignment: Qt.AlignVCenter - diameter: StyleSizes.largePlayerButtonSize - imageSource: model.pIsPlaying ? "qrc:/icon_pause" : "qrc:/icon_play" + RoundImageButton{ + id: playPause + anchors.verticalCenter: parent.verticalCenter + diameter: 80 + imageSource: model.pIsPlaying ? "qrc:/icon_pause" : "qrc:/icon_play" - onClicked:{ - model.playPause(); + onClicked:{ + model.playPause(); + } } - } - RoundImageButton{ - id: stop - Layout.alignment: Qt.AlignVCenter + RoundImageButton{ + id: stop + anchors.verticalCenter: parent.verticalCenter - diameter: StyleSizes.smallPlayerButtonSize - imageSource: "qrc:/icon_stop" + diameter: 60 + imageSource: "qrc:/icon_stop" - enabled: model.pIsPlaying + enabled: model.pIsPlaying - onClicked:{ - model.stopMusic(); + onClicked:{ + model.stopMusic(); + } } - } - RoundImageButton{ - id: next - Layout.alignment: Qt.AlignVCenter + RoundImageButton{ + id: next + anchors.verticalCenter: parent.verticalCenter - diameter: StyleSizes.smallPlayerButtonSize - imageSource: "qrc:/icon_next" + diameter: 60 + imageSource: "qrc:/icon_next" - enabled: model.pHasNext + enabled: model.pHasNext - onClicked:{ - model.playNext(); + onClicked:{ + model.playNext(); + } } - } + } //Row } diff --git a/LenaPi/PlayerControlPannel.qml b/LenaPi/PlayerControlPannel.qml index 9eb4ff2..e438945 100644 --- a/LenaPi/PlayerControlPannel.qml +++ b/LenaPi/PlayerControlPannel.qml @@ -1,5 +1,4 @@ import QtQuick 2.0 -import QtQuick.Layouts 1.3 Rectangle { id: container @@ -7,29 +6,28 @@ Rectangle { property int margins color: "#99ffffff" - height: content.height + 2* margins //StyleSizes.playerControlPanelHeight + height: 140 + MediaProgress{ + id: progress + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: container.margins - ColumnLayout{ - id: content - spacing: StyleSpacings.smallSpacing - anchors.margins: container.margins + model: container.model + // might require height for labels to be shown on RasPi (Qt 5.10) + //2019-04-04: defined in MediaProgress.qml -> test on rasPi + } + + PlayerButtons{ + id: buttons anchors.left: parent.left anchors.right: parent.right + anchors.top: progress.bottom + anchors.bottom: parent.bottom - MediaProgress{ - id: progress - - model: container.model - } - - PlayerButtons{ - id: buttons - Layout.alignment: Qt.AlignHCenter - Layout.fillWidth: true - Layout.fillHeight: true - model: container.model - spacing: StyleSpacings.defaultSpacing - } + model: container.model + spacing: 20 } } diff --git a/LenaPi/RoundImageButton.qml b/LenaPi/RoundImageButton.qml index e2453c3..5334465 100644 --- a/LenaPi/RoundImageButton.qml +++ b/LenaPi/RoundImageButton.qml @@ -8,7 +8,7 @@ Button { id: container property alias imageSource: image.source // default button diameter -> default width, readonly - readonly property int defaultDiameter: StyleSizes.roundButtonDefaultSize + readonly property int defaultDiameter: 65 // button diameter -> width property int diameter: defaultDiameter // diameter of content image -> width @@ -16,7 +16,7 @@ Button { background: Rectangle{ - border.width: StyleSizes.roundButtonBorderWidth + border.width: 2 border.color: "grey" color: "white" diff --git a/LenaPi/VolumeSlider.qml b/LenaPi/VolumeSlider.qml index 6b51aca..1ca6c9b 100644 --- a/LenaPi/VolumeSlider.qml +++ b/LenaPi/VolumeSlider.qml @@ -7,7 +7,7 @@ ColumnLayout { property alias to: slider.to property alias stepSize: slider.stepSize property alias value: slider.value - spacing: StyleSpacings.tinySpacing + spacing: 5 RoundImageButton{ id: increaseButton imageSource: "qrc:///icon_increase_volume" @@ -18,9 +18,9 @@ ColumnLayout { Layout.fillHeight: true Layout.alignment: Qt.AlignHCenter orientation: Qt.Vertical - from: 0 + from: 34 // we cannot hear anything if lower than 35% to: 100 - stepSize: 2 + stepSize: 1 value: 50 } RoundImageButton{ diff --git a/LenaPi/android-files/AndroidManifest.xml b/LenaPi/android-files/AndroidManifest.xml deleted file mode 100644 index e0c143a..0000000 --- a/LenaPi/android-files/AndroidManifest.xml +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/LenaPi/android-files/res/drawable-hdpi/icon.png b/LenaPi/android-files/res/drawable-hdpi/icon.png deleted file mode 100644 index b22cf59..0000000 Binary files a/LenaPi/android-files/res/drawable-hdpi/icon.png and /dev/null differ diff --git a/LenaPi/android-files/res/drawable-ldpi/icon.png b/LenaPi/android-files/res/drawable-ldpi/icon.png deleted file mode 100644 index 7c9ca0f..0000000 Binary files a/LenaPi/android-files/res/drawable-ldpi/icon.png and /dev/null differ diff --git a/LenaPi/android-files/res/drawable-mdpi/icon.png b/LenaPi/android-files/res/drawable-mdpi/icon.png deleted file mode 100644 index 57a20d1..0000000 Binary files a/LenaPi/android-files/res/drawable-mdpi/icon.png and /dev/null differ diff --git a/LenaPi/android-files/res/drawable-xhdpi/icon.png b/LenaPi/android-files/res/drawable-xhdpi/icon.png deleted file mode 100644 index 3ebfa96..0000000 Binary files a/LenaPi/android-files/res/drawable-xhdpi/icon.png and /dev/null differ diff --git a/LenaPi/android-files/res/drawable-xxhdpi/icon.png b/LenaPi/android-files/res/drawable-xxhdpi/icon.png deleted file mode 100644 index aaf15bf..0000000 Binary files a/LenaPi/android-files/res/drawable-xxhdpi/icon.png and /dev/null differ diff --git a/LenaPi/android-files/res/drawable-xxxhdpi/icon.png b/LenaPi/android-files/res/drawable-xxxhdpi/icon.png deleted file mode 100644 index c8cf6cb..0000000 Binary files a/LenaPi/android-files/res/drawable-xxxhdpi/icon.png and /dev/null differ diff --git a/LenaPi/controllers/MusicController.cpp b/LenaPi/controllers/MusicController.cpp new file mode 100644 index 0000000..4b51a00 --- /dev/null +++ b/LenaPi/controllers/MusicController.cpp @@ -0,0 +1,72 @@ +#include "MusicController.h" + +#include +#include +#include +#include "EnergySaver.h" + +MusicController::MusicController(QObject *parent) : QObject(parent) +{ + mVlc = new VlcInstance(VlcCommon::args(), this); + mModel = new MusicModel(mVlc, this); + mPlayer = new VlcMediaListPlayer(mVlc); + mVlcAudio = new VlcAudio(mPlayer->mediaPlayer()); + + connect(mModel, &MusicModel::navigateTo, this, &MusicController::onNavigationRequest); + + //connect(mModel, &MusicModel::play, mPlayer, &VlcMediaListPlayer::play); + connect(mModel, &MusicModel::play, [this](){ + mVlcAudio->setVolume(mModel->getAudioVolume()); + mPlayer->play(); + }); + connect(mModel, &MusicModel::stop, mPlayer, &VlcMediaListPlayer::stop); + connect(mModel, &MusicModel::previous, mPlayer, &VlcMediaListPlayer::previous); + connect(mModel, &MusicModel::next, mPlayer, &VlcMediaListPlayer::next); + connect(mModel, &MusicModel::pause, mPlayer->mediaPlayer(), &VlcMediaPlayer::pause); + connect(mModel, &MusicModel::audioVolumeChanged, mVlcAudio, &VlcAudio::setVolume); + + connect(mPlayer, SIGNAL(nextItemSet(VlcMedia*)), mModel, SLOT(onNextMediaSet(VlcMedia*))); + connect(mPlayer->mediaPlayer(), &VlcMediaPlayer::lengthChanged, mModel, &MusicModel::onLengthChanged); + connect(mPlayer->mediaPlayer(), &VlcMediaPlayer::timeChanged, mModel, &MusicModel::onTimeChanged); + + // hand over player signals to energy saver in order to determine player activity. + connect(mPlayer->mediaPlayer(), &VlcMediaPlayer::timeChanged, EnergySaver::instance(), &EnergySaver::restartTimer); +} + +MusicController::~MusicController() +{ + mPlayer->deleteLater(); + mVlcAudio->deleteLater(); +} + +void MusicController::initPlayer(NavigationItemModel *item) +{ + if(item != mModel->getCurrentItem()){ + mPlayer->stop(); + mModel->init(item); + } + if(!mIsMediaListSet){ + mPlayer->setMediaList(mModel->getMedia()); + mIsMediaListSet = true; + } +} + +void MusicController::setContext(QQmlContext *context) +{ + mContext = context; + setContextProperties(); +} + +void MusicController::setContextProperties() +{ + if(!mContext) return; + mContext->setContextProperty("musicModel", mModel); +} + +void MusicController::onNavigationRequest(NavigationItemModel *item) +{ + if(mModel->isPlaying()) { + mModel->playPause(); + } + emit navigateTo(item); +} diff --git a/LenaPi/controllers/MusicController.h b/LenaPi/controllers/MusicController.h new file mode 100644 index 0000000..4bdf01f --- /dev/null +++ b/LenaPi/controllers/MusicController.h @@ -0,0 +1,52 @@ +#ifndef MUSICCONTROLLER_H +#define MUSICCONTROLLER_H + +#include +#include +#include + +#include +#include +#include +#include + +class MusicModel; + +class MusicController : public QObject +{ + Q_OBJECT + +signals: + void navigateTo(NavigationItemModel* item); + +public: + MusicController(QObject *parent = Q_NULLPTR); + ~MusicController(); + + void initPlayer(NavigationItemModel* item); + + void setContext(QQmlContext* context); + +private: + void setContextProperties(); + + QQmlContext* mContext = Q_NULLPTR; + + MusicModel* mModel = Q_NULLPTR; + + VlcInstance* mVlc = Q_NULLPTR; + VlcMediaListPlayer* mPlayer = Q_NULLPTR; + VlcAudio* mVlcAudio = Q_NULLPTR; + + bool mIsMediaListSet = false; + + private slots: + /** + * @brief Stop player if necessary and forward signal navigatTo + * @param item target of navigation request + * @see navigateTo(NavigationItemModel* item); + */ + void onNavigationRequest(NavigationItemModel* item); +}; + +#endif // MUSICCONTROLLER_H diff --git a/LenaPi/controllers/MusicPlayer.cpp b/LenaPi/controllers/MusicPlayer.cpp deleted file mode 100644 index abbd9df..0000000 --- a/LenaPi/controllers/MusicPlayer.cpp +++ /dev/null @@ -1,165 +0,0 @@ -#include "MusicPlayer.h" -#include -#include -#include - - -MusicPlayer::MusicPlayer(QObject *parent) : QMediaPlayer(parent) -{ - // init audio - /// @todo remove magic number - setVolume(50); - // relay signal to qml - connect(this, &QMediaPlayer::stateChanged, this, &MusicPlayer::isPlayingChanged); - connect(this, &QMediaPlayer::currentMediaChanged, this, [this](const QMediaContent&){ - // notify qml to refresh enable state of next and previous button - emit hasNextChanged(); - emit hasPreviousChanged(); - }); - connect(this, &QMediaPlayer::positionChanged, this, [this](qint64){ - emit progressChanged(); - }); - connect(this, &QMediaPlayer::durationChanged, this, [this](qint64){ - emit progressChanged(); - emit mediaLengthChanged(); - }); -} - -void MusicPlayer::init(NavigationItemModel *item) -{ - if(mCurrentItem == item){ - return; - } - mCurrentItem = item; - emit coverImageSourceChanged(); - - clearPlaylist(); - - readMedia(mCurrentItem->getPath()); -} - -void MusicPlayer::navigateBack() -{ - emit navigateTo(mCurrentItem); -} - -void MusicPlayer::playPause() -{ - if(isPlaying()) - pause(); - else - play(); -} - -void MusicPlayer::stopMusic() -{ - if(isPlaying()){ - stop(); - resetPlaylistToFirstTrack(); - } -} - -void MusicPlayer::playNext() -{ - if(!hasNext()) return; // checks if playlist exists - playlist()->next(); -} - -void MusicPlayer::playPrevious() -{ - if(!hasPrevious()) return; // checks if playlist exists - playlist()->previous(); -} - -void MusicPlayer::resetPlaylistToFirstTrack() -{ - if(!playlist() && !playlist()->isEmpty()) return; - playlist()->setCurrentIndex(0); -} - -bool MusicPlayer::isPlaying() const -{ - return state() == State::PlayingState; -} - -bool MusicPlayer::hasNext() const -{ - if(!playlist()) return false; - const auto nextIndex = playlist()->nextIndex(); - /* player yields -1 as next index while playing last track - */ - return nextIndex >=0 && nextIndex < playlist()->mediaCount(); -} - -bool MusicPlayer::hasPrevious() const -{ - if(!playlist()) return false; - const auto previousIndex = playlist()->previousIndex(); - /* player inits with currentIndex -1 and hence previousIndex = last index - * until started. Yet, previousButton should initially be disabled. - */ - return previousIndex >= 0 && previousIndex < playlist()->currentIndex(); -} - -double MusicPlayer::getProgress() const -{ - if(duration() <= 0 || position() < 0){ - return 0.0; - } - return (double)position()/duration(); -} - -QString MusicPlayer::getMediaTitle() const -{ - return metaData("Title").toString(); -} - -QString MusicPlayer::getMediaDuration() const -{ - return millisecondsToString(duration()); -} - -QString MusicPlayer::getPosition() const -{ - return millisecondsToString(position()); -} - -void MusicPlayer::clearPlaylist() -{ - if(playlist()){ - playlist()->clear(); - } -} - -void MusicPlayer::readMedia(const QString& path) -{ - auto dir = QDir(path); - if(!dir.exists()) return; - - // create playlist if necessary - auto playList = playlist(); - if(!playList){ - playList = new QMediaPlaylist(this); - setPlaylist(playList); - } - - // add audio files to playlist - dir.setNameFilters(SettingsHandler::getAudioFileNameFilters()); - auto files = dir.entryInfoList(QDir::Files); - for(auto file:files){ - auto fileName = file.absoluteFilePath(); - auto fileUrl = QUrl::fromLocalFile(fileName); - playList->addMedia(QMediaContent(fileUrl)); - } -} - -QString MusicPlayer::millisecondsToString(int timeInMilliseconds) const -{ - int seconds = timeInMilliseconds/1000; // ms to secons - int minutes = seconds/60; //seconds to minutes - seconds %= 60; // seconds remaining after subtracting minutes - // format according to [M]M:ss - // at leading zero to seconds if necessary - QString secStr = (seconds < 10) ? "0"+QString::number(seconds) : QString::number(seconds); - return QString::number(minutes) + ":" + secStr; -} diff --git a/LenaPi/controllers/MusicPlayer.h b/LenaPi/controllers/MusicPlayer.h deleted file mode 100644 index 2b5e8c3..0000000 --- a/LenaPi/controllers/MusicPlayer.h +++ /dev/null @@ -1,143 +0,0 @@ -#ifndef MUSICPLAYER_H -#define MUSICPLAYER_H - -#include -#include -#include - -/** - * @brief MusicPlayer providing interface to QML and Navigation. - * - * Adds media from directory referenced by the current navigation item to - * playlist and provides interface to QML MusicPlayer. - */ -class MusicPlayer : public QMediaPlayer -{ - Q_OBJECT - - Q_PROPERTY(QUrl pCoverImageSource READ getCoverImageSource NOTIFY coverImageSourceChanged) - Q_PROPERTY(bool pHasNext READ hasNext NOTIFY hasNextChanged) - Q_PROPERTY(bool pHasPrevious READ hasPrevious NOTIFY hasPreviousChanged) - Q_PROPERTY(bool pIsPlaying READ isPlaying NOTIFY isPlayingChanged) - Q_PROPERTY(double pProgress READ getProgress NOTIFY progressChanged) - Q_PROPERTY(QString pMediaLength READ getMediaDuration NOTIFY mediaLengthChanged) - Q_PROPERTY(QString pTime READ getPosition NOTIFY progressChanged) - Q_PROPERTY(QString pMediaTitle READ getMediaTitle NOTIFY metaDataChanged) - -signals: - void navigateTo(NavigationItemModel *item); - void coverImageSourceChanged(); - void hasPreviousChanged(); - void hasNextChanged(); - void isPlayingChanged(); - void progressChanged(); - void mediaLengthChanged(); - -public: - MusicPlayer(QObject *parent = Q_NULLPTR); - ~MusicPlayer() =default; - - /** - * @brief Init playlist with media from directory referenced by item. - * @param item Navigation item representing a leaf - * @see void readMedia(const QString& path) - */ - void init(NavigationItemModel* item); - - /** - * @brief Get path to media cover image. - * @return Path to media cover image. - */ - inline const QString& getCoverImageSource() const {return mCurrentItem->getImageSource();} - /** - * @brief Indicates whether the media player is currently playing a track. - * @return true if media player is playing a track. - */ - bool isPlaying() const; - /** - * @brief Indicates whether there is a next item in the playlist. - * @return True if there is a next item in the playlist - * Does not wrap. - */ - bool hasNext() const; - /** - * @brief Indicates whether there is a previous item in the playlist. - * @return True if there is a previous item in the playlist - * Does not wrap. - */ - bool hasPrevious() const; - - /** - * @brief Get media progress as value in between 0 and 1 - * @return Media progress - * 0 corresponds to the beginning and 1 to the end of the current track. - */ - double getProgress() const; - - /** - * @brief Get current media title extracted from media meta data (id3 tags) - * @return Current media title - */ - QString getMediaTitle() const; - /** - * @brief Get duration of the current track - * @return Duration of the current track formatted as string - * @see QMediaPlayer::duration() - * @see millisecondsToString(int timeInMilliseconds) const - */ - QString getMediaDuration() const; - /** - * @brief Get current position within the track - * @return Postion within the track formatted as string - * @see QMediaPlayer::position() - * @see millisecondsToString(int timeInMilliseconds) const - */ - QString getPosition() const; - -public slots: - /** - * @brief Navigate back to navgation list - */ - void navigateBack(); - /** - * @brief Play or pause music depending on whether it is currently playing - */ - void playPause(); - /** - * @brief Stop music and reset track to first track in playlist - */ - void stopMusic(); - /** - * @brief Play next track in current playlist if available - */ - void playNext(); - /** - * @brief Replay previoustrack in current playlist if available - */ - void playPrevious(); - -private: - /** - * @brief Resets playlist to first track if playlist exists and is non-empty - */ - void resetPlaylistToFirstTrack(); - /** - * @brief Clear the current playlist - */ - void clearPlaylist(); - /** - * @brief Add all media from path to playlist - * @param path Path to media - */ - void readMedia(const QString& path); - /** - * @brief Format time in milliseconds acoording to [M]m:ss - * @param time Time in ms - * @return formateted string - */ - QString millisecondsToString(int timeInMilliseconds) const; - - NavigationItemModel* mCurrentItem = nullptr; -}; - -#endif // MUSICPLAYER_H diff --git a/LenaPi/controllers/NavigationController.cpp b/LenaPi/controllers/NavigationController.cpp index f3bb4ab..1eb5c59 100644 --- a/LenaPi/controllers/NavigationController.cpp +++ b/LenaPi/controllers/NavigationController.cpp @@ -1,41 +1,30 @@ #include "NavigationController.h" -#include #include #include -#include #include #include #include -#include +#include NavigationController::NavigationController(QObject *parent) : QObject(parent), mRootItem(new NavigationItemModel(this)), mNavList(new NavigationListModel(this)), mUiState(new UiStateModel(this)), - mMediaPlayer(new MusicPlayer(this)) + mMusicController(new MusicController(this)) { - connect(mMediaPlayer, &MusicPlayer::navigateTo, [this](NavigationItemModel* item) { + connect(mMusicController, &MusicController::navigateTo, [this](NavigationItemModel* item) { mUiState->showNavigation(); mNavList->navigateTo(item); }); - /* Connect player state to energy saver to prevent device shutdown while playing music. - */ - connect(mMediaPlayer, &MusicPlayer::isPlayingChanged, this, &NavigationController::startOrStopEnergySaverDependingOnPlayerState); -} - -void NavigationController::setDebugOutput(const QString& text) -{ - mDebugOutput = text; - emit debugOutputChanged(); } void NavigationController::init(const QString &rootPath) { auto rootDir = QDir(rootPath); if(!rootDir.exists()) return; - mRootPath = rootPath; + mRootPath = rootPath; add(mRootPath, mRootItem); @@ -51,6 +40,7 @@ void NavigationController::setContext(QQmlContext *context) { mContext = context; setContextProperties(); + mMusicController->setContext(mContext); } void NavigationController::setContextProperties() @@ -58,8 +48,6 @@ void NavigationController::setContextProperties() if(!mContext) return; mContext->setContextProperty("navigationList", mNavList); mContext->setContextProperty("uiStateModel", mUiState); - mContext->setContextProperty("musicModel", mMediaPlayer); - mContext->setContextProperty("debug", this); } void NavigationController::add(const QString &path, NavigationItemModel *parentItem) @@ -87,18 +75,18 @@ bool NavigationController::checkContent(const QString &path) { bool valid = false; auto dir =QDir(path); - // directory must either contain subdirectories or media files auto subDirsNames = dir.entryList(QDir::AllDirs); if(subDirsNames.length() > 0) { valid = true; } else { - dir.setNameFilters(SettingsHandler::getAudioFileNameFilters()); auto fileNames = dir.entryList(QDir::Files); int numAudio = 0; for(auto file:fileNames){ + if(file.endsWith(".flac") || file.endsWith(".mp3")){ numAudio++; + } } - valid = numAudio > 0; + if(numAudio > 0) valid = true; } return valid; } @@ -111,20 +99,7 @@ void NavigationController::onNavigationRequest() if(item->hasChildren()) mNavList->setModelItems(item->getChildren()); else { - mMediaPlayer->init(item); + mMusicController->initPlayer(item); mUiState->showMusicPlayer(); } } - -void NavigationController::startOrStopEnergySaverDependingOnPlayerState() -{ - auto* energySaver = EnergySaver::instance(); - assert(energySaver); - if(energySaver){ - if(mMediaPlayer->isPlaying()){ - energySaver->deactivate(); - } else { - energySaver->activate(); - } - } -} diff --git a/LenaPi/controllers/NavigationController.h b/LenaPi/controllers/NavigationController.h index 0459f3d..8761160 100644 --- a/LenaPi/controllers/NavigationController.h +++ b/LenaPi/controllers/NavigationController.h @@ -7,7 +7,7 @@ class NavigationItemModel; class NavigationListModel; class UiStateModel; -class MusicPlayer; +class MusicController; /** * @brief Main controller controlling ui state, navigation and music player. @@ -15,12 +15,6 @@ class MusicPlayer; class NavigationController : public QObject { Q_OBJECT - - Q_PROPERTY(QString pDebugOutput READ getDebugOutput NOTIFY debugOutputChanged) - -signals: - void debugOutputChanged(); - public: explicit NavigationController(QObject *parent = nullptr); @@ -43,8 +37,6 @@ public: */ void setContext(QQmlContext* context); - QString getDebugOutput() const { return mDebugOutput; } - private: /** * @brief Register models in context @@ -63,22 +55,14 @@ private: */ bool checkContent(const QString& path); - /** - * @brief Set Debug Output. Necessary as Android Debugger does not work yet - * @param text Output to show in ui - */ - void setDebugOutput(const QString& text); - NavigationItemModel* mRootItem; NavigationListModel* mNavList; UiStateModel* mUiState; - MusicPlayer* mMediaPlayer; + MusicController* mMusicController; QString mRootPath = "."; - QString mDebugOutput; - QQmlContext* mContext = nullptr; private slots: @@ -86,7 +70,6 @@ private slots: * @brief Either show subdirectories or music player depending on current directory type */ void onNavigationRequest(); - void startOrStopEnergySaverDependingOnPlayerState(); }; #endif // NAVIGATIONCONTROLLER_H diff --git a/LenaPi/controllers/SettingsHandler.cpp b/LenaPi/controllers/SettingsHandler.cpp index a0f6edb..9dd1373 100644 --- a/LenaPi/controllers/SettingsHandler.cpp +++ b/LenaPi/controllers/SettingsHandler.cpp @@ -1,5 +1,4 @@ #include "SettingsHandler.h" -#include constexpr const char* const rootPath = "rootPath"; constexpr const char* const profile = "profile"; @@ -60,20 +59,11 @@ QString SettingsHandler::getShutdownScript() const void SettingsHandler::initDefaults() { - mDefaults.insert(rootPath, QStandardPaths::MusicLocation); - mDefaults.insert(enableEnergySaver, false); + mDefaults.insert(rootPath, "/home/ar/source/lenaMusic/"); + mDefaults.insert(profile, "RasPiTouch"); + mDefaults.insert(enableEnergySaver, true); mDefaults.insert(timeout, 60); mDefaults.insert(shutdownScript, "/usr/local/sbin/do_shutdown.sh"); - mDefaults.insert(profile, "RasPiTouch"); - // @todo add profile Android? Or simply scale ui for RasPi - // mDefaults.insert(profile, "Android"); - -// Defaults for LenaPi -// mDefaults.insert(rootPath, "/home/ar/source/lenaMusic/"); -// mDefaults.insert(profile, "RasPiTouch"); -// mDefaults.insert(enableEnergySaver, true); -// mDefaults.insert(timeout, 60); -// mDefaults.insert(shutdownScript, "/usr/local/sbin/do_shutdown.sh"); } diff --git a/LenaPi/controllers/SettingsHandler.h b/LenaPi/controllers/SettingsHandler.h index 2b7cb8d..83b9868 100644 --- a/LenaPi/controllers/SettingsHandler.h +++ b/LenaPi/controllers/SettingsHandler.h @@ -17,12 +17,6 @@ public: static SettingsHandler* createSettingsHandlerAndFillWithDefaultsIfMissing(QSettings* settings); - /** - * @brief Provides a name filter for QDir that can be used to filter all audio files with valid formats. - * @return name filter for QDir - */ - static QStringList getAudioFileNameFilters() {return {"*.mp3", "*.flac"};} - inline void setSettings(QSettings* settings) { mSettings = settings;} inline QSettings* getSettings() const { return mSettings; } void fillWithDefaultIfMissing(); diff --git a/LenaPi/controllers/StyleHandling.cpp b/LenaPi/controllers/StyleHandling.cpp deleted file mode 100644 index 19d4419..0000000 --- a/LenaPi/controllers/StyleHandling.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include "StyleHandling.h" -#include -#include -#include - -StyleHandling::StyleHandling(QObject *parent) - : QObject{parent}, mStyleSizes(new QQmlPropertyMap(this)), - mMargins(new QQmlPropertyMap(this)), mSpacings(new QQmlPropertyMap(this)), mPaddings(new QQmlPropertyMap(this)) -{ - // nothing -} - -void StyleHandling::calculateAndSetRatio() -{ - qreal refHeight = 480; - qreal refWidth = 800; - // Scales to fullscreen. No rescaling when changing window size - QRect rect = QGuiApplication::primaryScreen()->geometry(); - qreal height = qMin(rect.width(),rect.height()); - qreal width = qMax(rect.width(), rect.height()); - - mRatio = qMin(height/refHeight, width/refWidth); - qDebug() << "mRation=" << mRatio<< "sizes="<insert(key, applyRatio(value)); -} - -int StyleHandling::applyRatio(int size) const -{ - return size*mRatio; -} - -void StyleHandling::init(QQmlContext *context) -{ - calculateAndSetRatio(); - initStyleSizes(); - initMargins(); - initSpacings(); - initPaddings(); - - context->setContextProperty("StyleSizes", mStyleSizes); - context->setContextProperty("StyleSpacings", mSpacings); - context->setContextProperty("StyleMargins", mMargins); - context->setContextProperty("StylePaddings", mPaddings); -} diff --git a/LenaPi/controllers/StyleHandling.h b/LenaPi/controllers/StyleHandling.h deleted file mode 100644 index 2128b05..0000000 --- a/LenaPi/controllers/StyleHandling.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef STYLEHANDLING_H -#define STYLEHANDLING_H - -#include -#include -#include - -/** - * @brief Contains all style sizes, margins and paddings used throughout the application - * - * Based on a reference screen size, maps for scaled margins, paddings and spacings are created and - * registered in the QML context. The values stored in the maps can then be used from QML. - * Map names: StyleSizes, StylePaddings, StyleSpacings, StyleMargins - * - * Always use values from these maps in QML! Never use magic numbers! They will NOT scale when - * the application is run on a different screen. - * - * See https://doc.qt.io/qt-5/scalability.html - * - * @todo scale fonts as well? - * @todo use dpi for scaling as app is very small on Android? - */ -class StyleHandling : public QObject -{ - Q_OBJECT -public: - explicit StyleHandling(QObject *parent = nullptr); - - /** - * @brief Calculates ratio, initializes all maps and registers them in QML context - * @param context Context to register Maps in - */ - void init(QQmlContext* context); - -private: - /** - * @brief Calculates ratio from reference screen size and size of the current primary screen and inits member mRatio - */ - void calculateAndSetRatio(); - /** - * @brief Initializes map containing all sizes (e.g., button or delegate sizes) - */ - void initStyleSizes(); - /** - * @brief Initializes map containing all spacings - */ - void initSpacings(); - /** - * @brief Initializes map containing all margins - */ - void initMargins(); - /** - * @brief Initializes map containing all paddings - */ - void initPaddings(); - /** - * @brief Scales the value with calculated ratio and inserts it into the given map under the given key - * @param map Map to insert key-value pair into - * @param key Key used in the map. This is the name used to retrieve the value in QML - * @param value Unscaled value - * @see mRatio - * - * In QML the value with the key "defaulSpacing" in the Map "StyleSpacings" is accessed by StyleSpacings.defaultSpacing - */ - void scaleAndInsert(QQmlPropertyMap* map, const QString& key, int value); - /** - * @brief Applys ratio to given size - * @param size Size to be scaled - * @return scaled size - * @see mRatio - */ - int applyRatio(int size) const; - - qreal mRatio = 1.0; - QQmlPropertyMap* mStyleSizes = nullptr; - QQmlPropertyMap* mMargins = nullptr; - QQmlPropertyMap* mSpacings = nullptr; - QQmlPropertyMap* mPaddings = nullptr; -}; - -#endif // STYLEHANDLING_H diff --git a/LenaPi/main.cpp b/LenaPi/main.cpp index b125dc7..e4633a4 100644 --- a/LenaPi/main.cpp +++ b/LenaPi/main.cpp @@ -4,20 +4,20 @@ #include #include #include -#include -#include -#include +#include "controllers/NavigationController.h" #include "MouseEventSpy.h" #include "EnergySaver.h" +#include "controllers/SettingsHandler.h" int main(int argc, char *argv[]) { + QGuiApplication app(argc, argv); QQmlApplicationEngine engine; - /**************************************************************************** - * Configure and parse commandline arguments - ****************************************************************************/ + /* 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 @@ -27,12 +27,6 @@ int main(int argc, char *argv[]) // process commandline arguments parser.process(app); - /**************************************************************************** - * Find and read settings - * If a config file is handed over via commandline arguments, it is preferred. - * Otherwise, the config in the standard location is used. If none exists yet, - * a default config is created. - ****************************************************************************/ QSettings* settings = nullptr; if(!parser.value(configOption).isEmpty()){ // config was handed over via commandline argument. Use this config if file exists. @@ -43,35 +37,20 @@ int main(int argc, char *argv[]) } } if(!settings){ - // create config from default location + // default config settings = new QSettings(QSettings::Scope::UserScope, "MaleyanaSoft", "LenaPi"); } - // Read Settings + /* Read Settings */ const auto settingsHandler = SettingsHandler::createSettingsHandlerAndFillWithDefaultsIfMissing(settings); - /**************************************************************************** - * init style - * Sets default sizes for ui elements. The element size is scaled according - * to the device's display size. - ****************************************************************************/ - StyleHandling styleHandler; - styleHandler.init(engine.rootContext()); - - /**************************************************************************** - * init main app - ****************************************************************************/ + // init main app NavigationController navController; navController.setContext(engine.rootContext()); navController.init(settingsHandler->getRootPath()); navController.setUiProfile(settingsHandler->getProfile()); - /**************************************************************************** - * init energy saver - * Prevents sleep on android devices and shuts down other device if inactive - * (no music or mouse events) for a certain time intervall - ****************************************************************************/ if(settingsHandler->isEnergySaverEnabled()){ /* install MouseEventSpy and energy saver used for auto shut down of device * if not used for a predefined time. @@ -80,13 +59,9 @@ int main(int argc, char *argv[]) EnergySaver::init(settingsHandler->getEnergySaverTimeout(), settingsHandler->getShutdownScript()); QObject::connect(MouseEventSpy::instance(), &MouseEventSpy::mouseEventDetected, EnergySaver::instance(), &EnergySaver::restartTimer); - } else { - EnergySaver::init(); } - /**************************************************************************** - * load view - ****************************************************************************/ + // load GUI engine.load(QUrl("qrc:/main.qml")); return app.exec(); diff --git a/LenaPi/main.qml b/LenaPi/main.qml index c796e43..7d26c1b 100644 --- a/LenaPi/main.qml +++ b/LenaPi/main.qml @@ -4,8 +4,8 @@ import QtQuick.Controls 2.4 Window { visible: true - // width: 800 - //height: 480 + width: 800 + height: 480 title: "LenaPi 1.2" Component.onCompleted: showMaximized(); diff --git a/LenaPi/models/MusicModel.cpp b/LenaPi/models/MusicModel.cpp new file mode 100644 index 0000000..9383ea4 --- /dev/null +++ b/LenaPi/models/MusicModel.cpp @@ -0,0 +1,218 @@ +#include "MusicModel.h" +#include +#include +#include + +MusicModel::MusicModel(VlcInstance* instance, QObject *parent) : QObject(parent), + mVlc(instance), mMedia(new VlcMediaList(instance)) +{ + /* nothing */ +} + +MusicModel::~MusicModel() +{ + // do not delete! will cause segmentation fault + //if(mMedia) + // mMedia->deleteLater(); +} + +void MusicModel::init(NavigationItemModel *item) +{ + if(mCurrentItem == item){ + return; + } + mCurrentItem = item; + emit currentItemChanged(); + + reset(); + clearMediaList(); + + readMedia(mCurrentItem->getPath()); + + setMediaTitle(mMedia->at(0)); +} + +void MusicModel::navigateBack() +{ + emit navigateTo(mCurrentItem); +} + +void MusicModel::playPause() +{ + mIsPlaying = !mIsPlaying; + emit isPlayingChanged(); + if(mIsPlaying) + emit play(); + else + emit pause(); +} + +void MusicModel::stopMusic() +{ + if(mIsPlaying){ + mIsPlaying = false; + emit isPlayingChanged(); + + reset(); + + emit stop(); + } +} + +void MusicModel::playNext() +{ + emit next(); + if(!mIsPlaying){ + mIsPlaying = true; + emit isPlayingChanged(); + } +} + +void MusicModel::playPrevious() +{ + emit previous(); + if(!mIsPlaying){ + mIsPlaying = true; + emit isPlayingChanged(); + } +} + +NavigationItemModel *MusicModel::getCurrentItem() +{ + return mCurrentItem; +} + +VlcMediaList *MusicModel::getMedia() +{ + return mMedia; +} + +bool MusicModel::isPlaying() const +{ + return mIsPlaying; +} + +bool MusicModel::hasNext() const +{ + return mHasNext; +} + +bool MusicModel::hasPrevious() const +{ + return mHasPrevious; +} + +void MusicModel::setAudioVolume(int newVolume) +{ + if(newVolume != mAudioVolume){ + if(newVolume > 100){ + mAudioVolume = 100; + } else if(newVolume < 0){ + mAudioVolume = 0; + } else { + mAudioVolume = newVolume; + } + emit audioVolumeChanged(mAudioVolume); + } +} + +double MusicModel::getProgress() const +{ + return mCurrentMediaItemProgress; +} + +QString MusicModel::getMediaTitle() const +{ + return mMediaTitle; +} + +QString MusicModel::getMediaLength() +{ + return timeToString(mCurrentMediaItemLength); +} + +QString MusicModel::getTime() +{ + return timeToString(mCurrentTime); +} + +void MusicModel::onNextMediaSet(VlcMedia *media) +{ + setMediaTitle(media); + + mHasNext = true; + mHasPrevious = true; + if(mMedia->at(0) == media){ + mHasPrevious = false; + } + if(mMedia->at(mMedia->count()-1) == media){ + mHasNext = false; + } + emit hasPreviousChanged(); + emit hasNextChanged(); +} + +void MusicModel::onTimeChanged(int time) +{ + mCurrentMediaItemProgress = (double) time / mCurrentMediaItemLength; + mCurrentTime = time; + emit progressChanged(); +} + +void MusicModel::onLengthChanged(int length) +{ + mCurrentMediaItemLength= length; + emit mediaLengthChanged(); +} + +void MusicModel::reset() +{ + mHasNext = false; + mHasPrevious = false; + emit hasNextChanged(); + emit hasPreviousChanged(); + + mCurrentMediaItemProgress = 0.0; + mCurrentTime = 0.0; + emit progressChanged(); + + mCurrentMediaItemLength = 0.0; + emit mediaLengthChanged(); +} + +void MusicModel::clearMediaList() +{ + while(mMedia->count() > 0){ + mMedia->removeMedia(0); + } +} + +void MusicModel::readMedia(const QString& path) +{ + auto dir = QDir(path); + if(!dir.exists()) return; + + auto fileNames = dir.entryList(QDir::Files); + for(auto file:fileNames){ + if(file.endsWith(".flac") || file.endsWith(".mp3")){ + mMedia->addMedia(new VlcMedia(dir.filePath(file), true, mVlc)); + } + } +} + +QString MusicModel::timeToString(int time) +{ + int sec = time/1000; + int min = sec/60; + sec = sec-min*60; + QString secStr = (sec < 10) ? "0"+QString::number(sec) : QString::number(sec); + return QString::number(min) + ":" + secStr; +} + +void MusicModel::setMediaTitle(VlcMedia *media) +{ + auto list = media->currentLocation().split("/"); + auto title = list.at(list.count() -1 ); + mMediaTitle = title.left(title.lastIndexOf(".")); + emit mediaTitleChanged(); +} diff --git a/LenaPi/models/MusicModel.h b/LenaPi/models/MusicModel.h new file mode 100644 index 0000000..764d79a --- /dev/null +++ b/LenaPi/models/MusicModel.h @@ -0,0 +1,100 @@ +#ifndef MUSICMODEL_H +#define MUSICMODEL_H + +#include + +#include +#include + +class MusicModel : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QObject* pCurrentItem READ getCurrentItem NOTIFY currentItemChanged) + Q_PROPERTY(bool pHasNext READ hasNext NOTIFY hasNextChanged) + Q_PROPERTY(bool pHasPrevious READ hasPrevious NOTIFY hasPreviousChanged) + Q_PROPERTY(bool pIsPlaying READ isPlaying NOTIFY isPlayingChanged) + Q_PROPERTY(double pProgress READ getProgress NOTIFY progressChanged) + Q_PROPERTY(QString pMediaLength READ getMediaLength NOTIFY mediaLengthChanged) + Q_PROPERTY(QString pTime READ getTime NOTIFY progressChanged) + Q_PROPERTY(QString pMediaTitle READ getMediaTitle NOTIFY mediaTitleChanged) + Q_PROPERTY(int pAudioVolume READ getAudioVolume WRITE setAudioVolume NOTIFY audioVolumeChanged) + +signals: + void navigateTo(NavigationItemModel *item); + void currentItemChanged(); + void play(); + void pause(); + void stop(); + void previous(); + void next(); + void hasPreviousChanged(); + void hasNextChanged(); + void isPlayingChanged(); + void progressChanged(); + void mediaLengthChanged(); + void mediaTitleChanged(); + void audioVolumeChanged(int newVolume); + +public: + MusicModel(VlcInstance* instance, QObject *parent = Q_NULLPTR); + ~MusicModel(); + + void init(NavigationItemModel* item); + + Q_INVOKABLE void navigateBack(); + Q_INVOKABLE void playPause(); + Q_INVOKABLE void stopMusic(); + Q_INVOKABLE void playNext(); + Q_INVOKABLE void playPrevious(); + + NavigationItemModel *getCurrentItem(); + + VlcMediaList *getMedia(); + + bool isPlaying() const; + bool hasNext() const; + bool hasPrevious() const; + + inline int getAudioVolume() const { return mAudioVolume; } + /** + * @brief Set audio volume. Information is transferred to VlcAudio + * @param newVolume value between 0 and 100 (audio level in percent) + * Ensures that volume is inbetween 0 and 100. If this range is exceeded, + * the volume is set to the lowest and highest allowed value, respectively. + */ + void setAudioVolume(int newVolume); + + double getProgress() const; + + QString getMediaTitle() const; + QString getMediaLength(); + QString getTime(); + +public slots: + void onNextMediaSet(VlcMedia* media); + void onTimeChanged(int time); + void onLengthChanged(int length); + +private: + void reset(); + void clearMediaList(); + void readMedia(const QString& path); + void setMediaTitle(VlcMedia* media); + QString timeToString(int time); + + + bool mIsPlaying = false; + bool mHasNext = false; + bool mHasPrevious = false; + int mCurrentMediaItemLength = 0; + int mCurrentTime = 0; + double mCurrentMediaItemProgress = 0; + int mAudioVolume{50}; + QString mMediaTitle = QString(""); + NavigationItemModel* mCurrentItem = Q_NULLPTR; + VlcMediaList* mMedia = Q_NULLPTR; + VlcInstance* mVlc = Q_NULLPTR; +}; + +#endif // MUSICMODEL_H diff --git a/LenaPi/models/NavigationItemModel.cpp b/LenaPi/models/NavigationItemModel.cpp index c4287b3..d540425 100644 --- a/LenaPi/models/NavigationItemModel.cpp +++ b/LenaPi/models/NavigationItemModel.cpp @@ -10,12 +10,12 @@ NavigationItemModel::NavigationItemModel(QObject *parent) : QObject(parent), qRegisterMetaType("NavigationItemModel*"); } -const QString& NavigationItemModel::getImageSource() const +QString NavigationItemModel::getImageSource() const { return mImageSource; } -const QString& NavigationItemModel::getPath() const +QString NavigationItemModel::getPath() const { return mPath; } diff --git a/LenaPi/models/NavigationItemModel.h b/LenaPi/models/NavigationItemModel.h index 0bd7133..afb17b2 100644 --- a/LenaPi/models/NavigationItemModel.h +++ b/LenaPi/models/NavigationItemModel.h @@ -36,13 +36,13 @@ public: * represented by this item. If no such image is found, a default image is displayed * on the delegate. */ - const QString &getImageSource() const; + QString getImageSource() const; /** * @brief Get path to folder represented by this navigation item. * @return Path to folder */ - const QString& getPath() const; + QString getPath() const; /** * @brief Set folder path and set image source displayed on delegate. * @param path Path to directory that is represented by this navigation item. diff --git a/LenaPi/models/UiStateModel.h b/LenaPi/models/UiStateModel.h index bcd352d..d7eff7c 100644 --- a/LenaPi/models/UiStateModel.h +++ b/LenaPi/models/UiStateModel.h @@ -4,7 +4,6 @@ #include #include #include -#include /** * @brief Handles state of UI by providing the qml source. diff --git a/LenaPi/resources/icon.jpeg b/LenaPi/resources/icon.jpeg deleted file mode 100644 index 42118e0..0000000 Binary files a/LenaPi/resources/icon.jpeg and /dev/null differ