Update to Qt6, introduce first cmake based build
Port android to Qt 6
This commit is contained in:
parent
853b1b7b15
commit
5d6844efb2
8
.gitmodules
vendored
8
.gitmodules
vendored
@ -1,11 +1,13 @@
|
||||
[submodule "QtZeroConf"]
|
||||
path = QtZeroConf
|
||||
url = https://github.com/mzanetti/QtZeroConf.git
|
||||
url = https://github.com/nymea/QtZeroConf.git
|
||||
branch = main
|
||||
[submodule "nymea-remoteproxy"]
|
||||
path = nymea-remoteproxy
|
||||
url = https://github.com/guh/nymea-remoteproxy.git
|
||||
url = https://github.com/nymea/nymea-remoteproxy.git
|
||||
branch = qt6-cmake
|
||||
[submodule "android_openssl"]
|
||||
path = 3rdParty/android/android_openssl
|
||||
url = https://github.com/KDAB/android_openssl.git
|
||||
branch = 1.0.x
|
||||
branch = master
|
||||
shallow = true
|
||||
|
||||
19
AGENTS.md
Normal file
19
AGENTS.md
Normal file
@ -0,0 +1,19 @@
|
||||
# Repository Guidelines
|
||||
|
||||
## Project Structure & Module Organization
|
||||
`nymea-app/` holds the QtQuick entry point plus top-level QML, and `libnymea-app/` supplies shared C++ helpers, models, and logging categories. Feature bundles reside in `experiences/`, which should stay self-contained with QML, assets, and translations. Vendored code lives in `3rdParty/` and `QtZeroConf/`. Tests sit inside `tests/testrunner/` (unit) and `tests/integration/` (scenario). Packaging and store metadata are in `packaging/`, `snap/`, `debian/`, and `fastlane/`; edit them only when coordinating a release.
|
||||
|
||||
## Build, Test, and Development Commands
|
||||
After cloning, run `git submodule update --init --recursive`. Configure with `cmake -S . -B build -DNYMEA_ENABLE_ZEROCONF=ON` and build via `cmake --build build --target nymea-app -j$(nproc)`. Execute the suite with `cmake --build build --target test` or `ctest --test-dir build --output-on-failure`. Qt Creator users can rely on `qmake nymea-app.pro CONFIG+=withtests && make`. Re-run `messages.sh` whenever you touch translations.
|
||||
|
||||
## Coding Style & Naming Conventions
|
||||
Use Qt’s 4-space indentation, braces on new lines, and PascalCase for types (`DashboardModel`) with lowerCamelCase members (`defaultStyle`). Order includes as Qt, nymea, then local headers, and prefer `NYMEA_LOGGING_CATEGORY` over raw `qDebug`. In QML, match filenames to the exported component, avoid wildcard imports, and keep property names lowerCamelCase.
|
||||
|
||||
## Testing Guidelines
|
||||
Add Qt Test cases under `tests/testrunner/` following the module path (e.g., `tests/testrunner/dashboard/tst_dashboard.cpp`) and use descriptive names such as `shouldConnectOnValidCredentials`. Integration flows belong to `tests/integration/` and may drive nymead or device simulators. Every functional PR needs at least one automated test plus a screenshot for UI changes. Run `ctest --test-dir build -V` before requesting review and document any skipped cases.
|
||||
|
||||
## Commit & Pull Request Guidelines
|
||||
Commits should have concise, imperative subjects like “Fix Android packaging target configuration” plus a short body covering motivation, toggles, and tests. Pull requests must describe the issue solved, summarize design choices, link related issues, and attach test evidence (command snippets, screenshots, or APK links). Tag reviewers responsible for touched areas and keep changes scoped to a single feature or bugfix.
|
||||
|
||||
## Security & Configuration Tips
|
||||
Store secrets in local environment files, never in git. Update `config.h.in` or `config.pri` when adding switches and document the defaults in the PR. Android builds download OpenSSL during configuration, so ensure CI nodes have first-run network access or cache the package internally. Call out any new runtime permissions so reviewers can test them explicitly.
|
||||
94
CMakeLists.txt
Normal file
94
CMakeLists.txt
Normal file
@ -0,0 +1,94 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/version.txt" NYMEA_VERSION_LINES)
|
||||
list(LENGTH NYMEA_VERSION_LINES NYMEA_VERSION_COUNT)
|
||||
if(NOT NYMEA_VERSION_COUNT GREATER_EQUAL 1)
|
||||
message(FATAL_ERROR "version.txt must contain at least the application version")
|
||||
endif()
|
||||
list(GET NYMEA_VERSION_LINES 0 NYMEA_APP_VERSION)
|
||||
if(NOT NYMEA_VERSION_COUNT GREATER_EQUAL 2)
|
||||
set(NYMEA_APP_REVISION "0")
|
||||
else()
|
||||
list(GET NYMEA_VERSION_LINES 1 NYMEA_APP_REVISION)
|
||||
endif()
|
||||
|
||||
project(nymea-app VERSION ${NYMEA_APP_VERSION} LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
set(APPLICATION_NAME "nymea-app" CACHE STRING "Application name")
|
||||
set(ORGANISATION_NAME "nymea" CACHE STRING "Organisation name")
|
||||
|
||||
option(NYMEA_ENABLE_ZEROCONF "Enable ZeroConf support" OFF)
|
||||
option(NYMEA_USE_MATERIAL_ICONS "Use the Material icon set instead of Suru" OFF)
|
||||
option(NYMEA_ENABLE_FIREBASE "Enable Firebase Cloud Messaging integration" ON)
|
||||
set(NYMEA_OVERLAY_PATH "" CACHE PATH "Optional overlay directory for branding")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS
|
||||
Core
|
||||
Gui
|
||||
Network
|
||||
Qml
|
||||
Quick
|
||||
QuickControls2
|
||||
Svg
|
||||
WebSockets
|
||||
Bluetooth
|
||||
Charts
|
||||
Nfc
|
||||
)
|
||||
|
||||
find_package(OpenSSL QUIET)
|
||||
|
||||
if(ANDROID)
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
android_openssl
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP true
|
||||
URL https://github.com/KDAB/android_openssl/archive/refs/heads/master.zip
|
||||
)
|
||||
FetchContent_MakeAvailable(android_openssl)
|
||||
include(${android_openssl_SOURCE_DIR}/android_openssl.cmake)
|
||||
|
||||
set(NYMEA_ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_SOURCE_DIR}/packaging/android" CACHE PATH "Android packaging directory")
|
||||
|
||||
set(_nymea_app_root_property "nymeaAppRoot=${CMAKE_SOURCE_DIR}")
|
||||
if(NYMEA_ENABLE_FIREBASE)
|
||||
set(_nymea_firebase_property "useFirebase=true")
|
||||
else()
|
||||
set(_nymea_firebase_property "useFirebase=false")
|
||||
endif()
|
||||
|
||||
file(WRITE "${NYMEA_ANDROID_PACKAGE_SOURCE_DIR}/nymeaapp.properties" "${_nymea_app_root_property}\n${_nymea_firebase_property}\n")
|
||||
configure_file(
|
||||
"${CMAKE_SOURCE_DIR}/version.txt"
|
||||
"${NYMEA_ANDROID_PACKAGE_SOURCE_DIR}/version.txt"
|
||||
COPYONLY
|
||||
)
|
||||
|
||||
add_link_options("-Wl,-z,max-page-size=16384")
|
||||
endif()
|
||||
|
||||
# Make config.h available to all targets
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_BINARY_DIR}/config.h @ONLY)
|
||||
|
||||
# Common warning flags
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
add_compile_options(-Wall)
|
||||
if(UNIX AND NOT APPLE)
|
||||
add_compile_options(-Wno-deprecated-declarations -Wno-deprecated-copy)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(APP_VERSION ${NYMEA_APP_VERSION})
|
||||
set(APP_REVISION ${NYMEA_APP_REVISION})
|
||||
|
||||
add_subdirectory(libnymea-app)
|
||||
add_subdirectory(experiences)
|
||||
add_subdirectory(nymea-app)
|
||||
701
CMakeLists.txt.user
Normal file
701
CMakeLists.txt.user
Normal file
@ -0,0 +1,701 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<!-- Written by QtCreator 18.0.0, 2025-11-16T21:19:14. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>EnvironmentId</variable>
|
||||
<value type="QByteArray">{3a02a921-eea1-43cd-a37d-2b4e59d6151d}</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.ActiveTarget</variable>
|
||||
<value type="qlonglong">0</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.EditorSettings</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="bool" key="EditorConfiguration.AutoDetect">true</value>
|
||||
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
|
||||
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
|
||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
|
||||
<value type="QString" key="language">Cpp</value>
|
||||
<valuemap type="QVariantMap" key="value">
|
||||
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
|
||||
<value type="QString" key="language">QmlJS</value>
|
||||
<valuemap type="QVariantMap" key="value">
|
||||
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="EditorConfiguration.CodeStyle.Count">2</value>
|
||||
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
|
||||
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
|
||||
<value type="int" key="EditorConfiguration.IndentSize">4</value>
|
||||
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
|
||||
<value type="int" key="EditorConfiguration.LineEndingBehavior">0</value>
|
||||
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
|
||||
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
|
||||
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
|
||||
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
|
||||
<value type="int" key="EditorConfiguration.PreferAfterWhitespaceComments">0</value>
|
||||
<value type="bool" key="EditorConfiguration.PreferSingleLineComments">false</value>
|
||||
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
|
||||
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
|
||||
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">2</value>
|
||||
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
|
||||
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
|
||||
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
|
||||
<value type="int" key="EditorConfiguration.TabSize">8</value>
|
||||
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
|
||||
<value type="bool" key="EditorConfiguration.UseIndenter">false</value>
|
||||
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
|
||||
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
|
||||
<value type="QString" key="EditorConfiguration.ignoreFileTypes">*.md, *.MD, Makefile</value>
|
||||
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
|
||||
<value type="bool" key="EditorConfiguration.skipTrailingWhitespace">true</value>
|
||||
<value type="bool" key="EditorConfiguration.tintMarginArea">true</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.PluginSettings</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<valuemap type="QVariantMap" key="AutoTest.ActiveFrameworks">
|
||||
<value type="bool" key="AutoTest.Framework.Boost">true</value>
|
||||
<value type="bool" key="AutoTest.Framework.CTest">false</value>
|
||||
<value type="bool" key="AutoTest.Framework.Catch">true</value>
|
||||
<value type="bool" key="AutoTest.Framework.GTest">true</value>
|
||||
<value type="bool" key="AutoTest.Framework.QtQuickTest">true</value>
|
||||
<value type="bool" key="AutoTest.Framework.QtTest">true</value>
|
||||
</valuemap>
|
||||
<value type="bool" key="AutoTest.ApplyFilter">false</value>
|
||||
<valuemap type="QVariantMap" key="AutoTest.CheckStates"/>
|
||||
<valuelist type="QVariantList" key="AutoTest.PathFilters"/>
|
||||
<value type="int" key="AutoTest.RunAfterBuild">0</value>
|
||||
<value type="bool" key="AutoTest.UseGlobal">true</value>
|
||||
<valuemap type="QVariantMap" key="ClangTools">
|
||||
<value type="bool" key="ClangTools.AnalyzeOpenFiles">true</value>
|
||||
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
|
||||
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
|
||||
<value type="int" key="ClangTools.ParallelJobs">10</value>
|
||||
<value type="bool" key="ClangTools.PreferConfigFile">true</value>
|
||||
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
|
||||
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
|
||||
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
|
||||
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
|
||||
</valuemap>
|
||||
<value type="int" key="RcSync">0</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Target.0</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="QString" key="DeviceType">Android.Device.Type</value>
|
||||
<value type="bool" key="HasPerBcDcs">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Android Qt 6.8.4 Clang armeabi-v7a</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Android Qt 6.8.4 Clang armeabi-v7a</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{4ea481fa-d782-4c19-8a79-381a58bbab97}</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
||||
<value type="QString" key="CMake.Build.Type">Debug</value>
|
||||
<value type="int" key="CMake.Configure.BaseEnvironment">2</value>
|
||||
<value type="bool" key="CMake.Configure.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMake.Configure.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="CMake.Initial.Parameters">-DQT_HOST_PATH:PATH=%{Qt:QT_HOST_PREFIX}
|
||||
-DANDROID_PLATFORM:STRING=android-23
|
||||
-DANDROID_SDK_ROOT:PATH=/usr/local/android
|
||||
-DQT_USE_TARGET_ANDROID_BUILD_DIR:BOOL=ON
|
||||
-DANDROID_USE_LEGACY_TOOLCHAIN_FILE:BOOL=OFF
|
||||
-DCMAKE_BUILD_TYPE:STRING=Debug
|
||||
-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake
|
||||
-DQT_NO_GLOBAL_APK_TARGET_PART_OF_ALL:BOOL=ON
|
||||
-DANDROID_ABI:STRING=armeabi-v7a
|
||||
-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}
|
||||
-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable}
|
||||
-DQT_MAINTENANCE_TOOL:FILEPATH=/home/timon/Qt/MaintenanceTool
|
||||
-DANDROID_NDK:PATH=/usr/local/android/ndk/26.1.10909125
|
||||
-DCMAKE_COLOR_DIAGNOSTICS:BOOL=ON
|
||||
-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C}
|
||||
-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
|
||||
-DCMAKE_FIND_ROOT_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
|
||||
-DCMAKE_GENERATOR:STRING=Ninja
|
||||
-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx}
|
||||
-DANDROID_STL:STRING=c++_shared
|
||||
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=/usr/local/android/ndk/26.1.10909125/build/cmake/android.toolchain.cmake</value>
|
||||
<value type="int" key="EnableQmlDebugging">0</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/timon/nymea/development/qt6-cmake/nymea-app/build/Android_Qt_6_8_4_Clang_armeabi_v7a-Debug</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString">all</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
|
||||
<value type="QString" key="BuildTargetSdk">android-36</value>
|
||||
<value type="QString" key="BuildToolsVersion"></value>
|
||||
<value type="QString" key="KeystoreLocation"></value>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build Android APK</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QmakeProjectManager.AndroidBuildApkStep</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString">clean</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Debug</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.AndroidDeployQtStep</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.AndroidDeployConfiguration2</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.DeployConfigurationCount">2</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings">
|
||||
<value type="bool" key="AndroidBuildTargetDirSupport">true</value>
|
||||
<valuelist type="QVariantList" key="AndroidDeviceAbis">
|
||||
<value type="QString">arm64-v8a</value>
|
||||
<value type="QString">armeabi-v7a</value>
|
||||
<value type="QString">armeabi</value>
|
||||
</valuelist>
|
||||
<value type="QString" key="AndroidDeviceSerialNumber">0A301JEC211655</value>
|
||||
<value type="int" key="AndroidVersion.ApiLevel">33</value>
|
||||
<valuelist type="QVariantList" key="ApplicationmanagerPackageTargets"/>
|
||||
<value type="bool" key="UseAndroidBuildTargetDir">true</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<valuelist type="QVariantList" key="Android.PostStartShellCmdListKey">
|
||||
<value type="QString"></value>
|
||||
</valuelist>
|
||||
<valuelist type="QVariantList" key="Android.PreStartShellCmdListKey">
|
||||
<value type="QString"></value>
|
||||
</valuelist>
|
||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">0</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
||||
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">nymea-app</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.AndroidRunConfiguration:</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">nymea-app</value>
|
||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">true</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.UniqueId"></value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.AndroidDeployQtStep</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.AndroidDeployConfiguration2</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.DeployConfigurationCount">2</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<valuelist type="QVariantList" key="Android.PostStartShellCmdListKey">
|
||||
<value type="QString"></value>
|
||||
</valuelist>
|
||||
<valuelist type="QVariantList" key="Android.PreStartShellCmdListKey">
|
||||
<value type="QString"></value>
|
||||
</valuelist>
|
||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">0</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
||||
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">nymea-app</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.AndroidRunConfiguration:</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">nymea-app</value>
|
||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">true</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.UniqueId"></value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Target.1</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="QString" key="DeviceType">Desktop</value>
|
||||
<value type="bool" key="HasPerBcDcs">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop Qt 6.8.4</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop Qt 6.8.4</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">qt.qt6.684.linux_gcc_64_kit</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
||||
<value type="QString" key="CMake.Build.Type">Debug</value>
|
||||
<value type="int" key="CMake.Configure.BaseEnvironment">2</value>
|
||||
<value type="bool" key="CMake.Configure.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMake.Configure.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="CMake.Initial.Parameters">-DCMAKE_BUILD_TYPE:STRING=Debug
|
||||
-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake
|
||||
-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}
|
||||
-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable}
|
||||
-DQT_MAINTENANCE_TOOL:FILEPATH=/home/timon/Qt/MaintenanceTool
|
||||
-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C}
|
||||
-DCMAKE_COLOR_DIAGNOSTICS:BOOL=ON
|
||||
-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
|
||||
-DCMAKE_GENERATOR:STRING=Ninja
|
||||
-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx}</value>
|
||||
<value type="int" key="EnableQmlDebugging">0</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/timon/nymea/development/qt6-cmake/nymea-app/build/Desktop_Qt_6_8_4-Debug</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString">all</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString">clean</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Debug</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString"></value>
|
||||
</valuelist>
|
||||
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ApplicationManagerPlugin.Deploy.CMakePackageStep</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
|
||||
<value type="QString" key="ApplicationManagerPlugin.Deploy.InstallPackageStep.Arguments">install-package --acknowledge</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Install Application Manager package</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ApplicationManagerPlugin.Deploy.InstallPackageStep</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.RunConfiguration.LastDeployedFiles"/>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.RunConfiguration.LastDeployedHosts"/>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.RunConfiguration.LastDeployedRemotePaths"/>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.RunConfiguration.LastDeployedSysroots"/>
|
||||
<valuelist type="QVariantList" key="RemoteLinux.LastDeployedLocalTimes"/>
|
||||
<valuelist type="QVariantList" key="RemoteLinux.LastDeployedRemoteTimes"/>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ApplicationManagerPlugin.Deploy.Configuration</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.DeployConfigurationCount">2</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
||||
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">nymea-app</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">nymea-app</value>
|
||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">true</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.UniqueId"></value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseTerminal">false</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString"></value>
|
||||
</valuelist>
|
||||
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ApplicationManagerPlugin.Deploy.CMakePackageStep</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
|
||||
<value type="QString" key="ApplicationManagerPlugin.Deploy.InstallPackageStep.Arguments">install-package --acknowledge</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Install Application Manager package</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ApplicationManagerPlugin.Deploy.InstallPackageStep</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.RunConfiguration.LastDeployedFiles"/>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.RunConfiguration.LastDeployedHosts"/>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.RunConfiguration.LastDeployedRemotePaths"/>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.RunConfiguration.LastDeployedSysroots"/>
|
||||
<valuelist type="QVariantList" key="RemoteLinux.LastDeployedLocalTimes"/>
|
||||
<valuelist type="QVariantList" key="RemoteLinux.LastDeployedRemoteTimes"/>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ApplicationManagerPlugin.Deploy.Configuration</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.DeployConfigurationCount">2</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
||||
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">nymea-app</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">nymea-app</value>
|
||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">true</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.UniqueId"></value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseTerminal">false</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Target.2</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="QString" key="DeviceType">Android.Device.Type</value>
|
||||
<value type="bool" key="HasPerBcDcs">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Android Qt 6.8.4 Clang armeabi-v7a</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Android Qt 6.8.4 Clang armeabi-v7a</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{d6a68c9e-38a8-48ba-9f70-7050ff8c051f}</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
||||
<value type="QString" key="CMake.Build.Type">Debug</value>
|
||||
<value type="int" key="CMake.Configure.BaseEnvironment">2</value>
|
||||
<value type="bool" key="CMake.Configure.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMake.Configure.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="CMake.Initial.Parameters">-DANDROID_STL:STRING=c++_shared
|
||||
-DQT_NO_GLOBAL_APK_TARGET_PART_OF_ALL:BOOL=ON
|
||||
-DQT_HOST_PATH:PATH=%{Qt:QT_HOST_PREFIX}
|
||||
-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}
|
||||
-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
|
||||
-DANDROID_ABI:STRING=armeabi-v7a
|
||||
-DCMAKE_BUILD_TYPE:STRING=Debug
|
||||
-DANDROID_NDK:PATH=/usr/local/android/ndk/29.0.14033849
|
||||
-DQT_USE_TARGET_ANDROID_BUILD_DIR:BOOL=ON
|
||||
-DANDROID_USE_LEGACY_TOOLCHAIN_FILE:BOOL=OFF
|
||||
-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake
|
||||
-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C}
|
||||
-DCMAKE_FIND_ROOT_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
|
||||
-DANDROID_SDK_ROOT:PATH=/usr/local/android
|
||||
-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable}
|
||||
-DANDROID_PLATFORM:STRING=android-23
|
||||
-DQT_MAINTENANCE_TOOL:FILEPATH=/home/timon/Qt/MaintenanceTool
|
||||
-DCMAKE_GENERATOR:STRING=Ninja
|
||||
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=/usr/local/android/ndk/29.0.14033849/build/cmake/android.toolchain.cmake
|
||||
-DCMAKE_COLOR_DIAGNOSTICS:BOOL=ON
|
||||
-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx}</value>
|
||||
<value type="int" key="EnableQmlDebugging">0</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/timon/nymea/development/qt6-cmake/nymea-app/build/Android_Qt_6_8_4_Clang_armeabi_v7a-Debug</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString">all</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
|
||||
<value type="QString" key="BuildTargetSdk">android-36</value>
|
||||
<value type="QString" key="BuildToolsVersion"></value>
|
||||
<value type="QString" key="KeystoreLocation"></value>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build Android APK</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QmakeProjectManager.AndroidBuildApkStep</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString">clean</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Debug</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.AndroidDeployQtStep</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.AndroidDeployConfiguration2</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<valuelist type="QVariantList" key="Android.PostStartShellCmdListKey">
|
||||
<value type="QString"></value>
|
||||
</valuelist>
|
||||
<valuelist type="QVariantList" key="Android.PreStartShellCmdListKey">
|
||||
<value type="QString"></value>
|
||||
</valuelist>
|
||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">0</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
||||
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">nymea-app</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.AndroidRunConfiguration:</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">nymea-app</value>
|
||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.AndroidDeployQtStep</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.AndroidDeployConfiguration2</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<valuelist type="QVariantList" key="Android.PostStartShellCmdListKey">
|
||||
<value type="QString"></value>
|
||||
</valuelist>
|
||||
<valuelist type="QVariantList" key="Android.PreStartShellCmdListKey">
|
||||
<value type="QString"></value>
|
||||
</valuelist>
|
||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">0</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
||||
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">nymea-app</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.AndroidRunConfiguration:</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">nymea-app</value>
|
||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.TargetCount</variable>
|
||||
<value type="qlonglong">3</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>Version</variable>
|
||||
<value type="int">22</value>
|
||||
</data>
|
||||
</qtcreator>
|
||||
@ -1 +1 @@
|
||||
Subproject commit 2b9b3c7c74f05e83c4052fbb1629b22568f36b64
|
||||
Subproject commit 6e70786eef77303b5d630ce4acc7c49e03a58992
|
||||
28
README.md
28
README.md
@ -5,7 +5,7 @@ QtQuick nymea client application
|
||||
# building
|
||||
|
||||
Required packages:
|
||||
It is recommended to install a complete Qt installation. Minimum required Qt Version *5.7.0*.
|
||||
It is recommended to install a complete Qt installation. Minimum required Qt version is Qt 6.
|
||||
|
||||
No extra modules are required for a basic desktop build.
|
||||
|
||||
@ -14,14 +14,19 @@ After cloning the repository, run
|
||||
$ git submodule init
|
||||
$ git submodule update
|
||||
|
||||
To build a binary run
|
||||
To build a binary with CMake run
|
||||
|
||||
$ mkdir builddir
|
||||
$ cd builddir
|
||||
$ qmake path/to/source/dir
|
||||
$ make
|
||||
$ cmake -S . -B build
|
||||
$ cmake --build build
|
||||
|
||||
Or open `nymea-app.pro` in QtCreator and click the **"Play"** button.
|
||||
The build can be customised with the following cache variables:
|
||||
|
||||
- `-DNYMEA_ENABLE_ZEROCONF=ON` enables ZeroConf support when the QtZeroConf and
|
||||
Avahi dependencies are available.
|
||||
- `-DNYMEA_USE_MATERIAL_ICONS=ON` switches the icon theme to the Material icon set.
|
||||
|
||||
Legacy qmake builds are still available by opening `nymea-app.pro` in QtCreator
|
||||
and building the project there.
|
||||
|
||||
Optional configuration flags to be passed to qmake:
|
||||
|
||||
@ -30,8 +35,13 @@ Optional configuration flags to be passed to qmake:
|
||||
> Enables building the testrunner target
|
||||
|
||||
## Android
|
||||
As Qt can't bundle a build of openssl for android, you need to place a copy to
|
||||
`/opt/android-ssl/`
|
||||
When targeting Android, the build will download the KDAB
|
||||
[`android_openssl`](https://github.com/KDAB/android_openssl) package at
|
||||
configure time and automatically bundle the provided `libssl` and `libcrypto`
|
||||
shared libraries inside the APK. An active internet connection is therefore
|
||||
required the first time you configure an Android build directory. Other
|
||||
platforms will build without explicitly linking to OpenSSL if the development
|
||||
package is not installed.
|
||||
|
||||
## Windows
|
||||
|
||||
|
||||
@ -1,56 +0,0 @@
|
||||
TEMPLATE = lib
|
||||
TARGET = service
|
||||
CONFIG += dll
|
||||
QT += core androidextras
|
||||
QT += network qml quick quickcontrols2 svg websockets bluetooth charts nfc
|
||||
|
||||
include(../shared.pri)
|
||||
include(../3rdParty/android/android_openssl/openssl.pri)
|
||||
|
||||
|
||||
INCLUDEPATH += $$top_srcdir/libnymea-app/
|
||||
|
||||
# https://bugreports.qt.io/browse/QTBUG-83165
|
||||
LIBS += -L$${top_builddir}/libnymea-app/$${ANDROID_TARGET_ARCH}
|
||||
|
||||
LIBS += -L$$top_builddir/libnymea-app/ -lnymea-app
|
||||
PRE_TARGETDEPS += ../libnymea-app
|
||||
|
||||
RESOURCES += controlviews/controlviews.qrc \
|
||||
../nymea-app/resources.qrc \
|
||||
../nymea-app/images.qrc \
|
||||
../nymea-app/styles.qrc
|
||||
|
||||
INCLUDEPATH += ../nymea-app/
|
||||
|
||||
SOURCES += \
|
||||
controlviews/devicecontrolapplication.cpp \
|
||||
nymeaappservice/nymeaappservice.cpp \
|
||||
nymeaappservice/androidbinder.cpp \
|
||||
../nymea-app/stylecontroller.cpp \
|
||||
../nymea-app/platformhelper.cpp \
|
||||
../nymea-app/nfchelper.cpp \
|
||||
../nymea-app/nfcthingactionwriter.cpp \
|
||||
../nymea-app/platformintegration/android/platformhelperandroid.cpp \
|
||||
service_main.cpp
|
||||
|
||||
HEADERS += \
|
||||
controlviews/devicecontrolapplication.h \
|
||||
nymeaappservice/nymeaappservice.h \
|
||||
nymeaappservice/androidbinder.h \
|
||||
../nymea-app/stylecontroller.h \
|
||||
../nymea-app/platformhelper.h \
|
||||
../nymea-app/nfchelper.h \
|
||||
../nymea-app/nfcthingactionwriter.h \
|
||||
../nymea-app/platformintegration/android/platformhelperandroid.h \
|
||||
|
||||
DISTFILES += \
|
||||
java/io/guh/nymeaapp/Action.java \
|
||||
java/io/guh/nymeaapp/NymeaAppControlService.java \
|
||||
java/io/guh/nymeaapp/NymeaAppService.java \
|
||||
java/io/guh/nymeaapp/NymeaAppControlsActivity.java \
|
||||
java/io/guh/nymeaapp/NymeaAppServiceConnection.java \
|
||||
java/io/guh/nymeaapp/Thing.java \
|
||||
java/io/guh/nymeaapp/State.java \
|
||||
java/io/guh/nymeaapp/NymeaHost.java \
|
||||
controlviews/Main.qml
|
||||
@ -1,66 +0,0 @@
|
||||
import QtQuick 2.8
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Controls.Material 2.1
|
||||
import QtQuick.Layouts 1.2
|
||||
import Qt.labs.settings 1.0
|
||||
import Nymea 1.0
|
||||
import "qrc:/ui/devicepages/"
|
||||
|
||||
ApplicationWindow {
|
||||
id: app
|
||||
visible: true
|
||||
visibility: ApplicationWindow.FullScreen
|
||||
color: Material.background
|
||||
title: Configuration.appName
|
||||
|
||||
Material.theme: NymeaUtils.isDark(Style.backgroundColor) ? Material.Dark : Material.Light
|
||||
Material.background: Style.backgroundColor
|
||||
Material.accent: Style.accentColor
|
||||
Material.foreground: Style.foregroundColor
|
||||
|
||||
font.pixelSize: mediumFont
|
||||
font.weight: Font.Normal
|
||||
font.capitalization: Font.MixedCase
|
||||
font.family: Style.fontFamily
|
||||
|
||||
property int margins: 16
|
||||
property int bigMargins: 20
|
||||
|
||||
property int extraSmallFont: 10
|
||||
property int smallFont: 13
|
||||
property int mediumFont: 16
|
||||
property int largeFont: 20
|
||||
|
||||
property int smallIconSize: 16
|
||||
property int iconSize: 24
|
||||
property int bigIconSize: 40
|
||||
property int hugeIconSize: 64
|
||||
|
||||
property int delegateHeight: 60
|
||||
|
||||
readonly property bool landscape: app.width > app.height
|
||||
|
||||
ThingsProxy {
|
||||
id: thingProxy
|
||||
engine: _engine
|
||||
filterThingId: controlledThingId
|
||||
}
|
||||
|
||||
property Thing controlledThing: engine.thingManager.fetchingData ? null : engine.thingManager.things.getThing(controlledThingId)
|
||||
|
||||
onControlledThingChanged: {
|
||||
loader.setSource("qrc:/ui/devicepages/" + NymeaUtils.interfaceListToDevicePage(controlledThing.thingClass.interfaces), {thing: controlledThing, header: null})
|
||||
PlatformHelper.hideSplashScreen();
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: loader
|
||||
anchors.fill: parent
|
||||
anchors.bottomMargin: app.margins // For some reason the bottom edge seems a bit off in the overlay
|
||||
}
|
||||
|
||||
onClosing: {
|
||||
print("************* Control View closing")
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,5 +0,0 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>Main.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@ -1,234 +0,0 @@
|
||||
#include "devicecontrolapplication.h"
|
||||
|
||||
#include "engine.h"
|
||||
#include "connection/discovery/nymeadiscovery.h"
|
||||
#include "connection/nymeahosts.h"
|
||||
#include "libnymea-app-core.h"
|
||||
#include "../nymea-app/stylecontroller.h"
|
||||
#include "../nymea-app/platformhelper.h"
|
||||
#include "../nymea-app/nfchelper.h"
|
||||
#include "../nymea-app/nfcthingactionwriter.h"
|
||||
#include "../nymea-app/platformintegration/android/platformhelperandroid.h"
|
||||
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QtDebug>
|
||||
#include <QtQml>
|
||||
#include <QtAndroid>
|
||||
#include <QAndroidJniObject>
|
||||
#include <QAndroidIntent>
|
||||
#include <QNdefNfcUriRecord>
|
||||
|
||||
QObject *platformHelperProvider(QQmlEngine *engine, QJSEngine *scriptEngine)
|
||||
{
|
||||
Q_UNUSED(engine)
|
||||
Q_UNUSED(scriptEngine)
|
||||
return new PlatformHelperAndroid();
|
||||
}
|
||||
|
||||
DeviceControlApplication::DeviceControlApplication(int argc, char *argv[]) : QApplication(argc, argv)
|
||||
{
|
||||
setApplicationName("nymea-app");
|
||||
setOrganizationName("nymea");
|
||||
|
||||
QSettings settings;
|
||||
|
||||
m_discovery = new NymeaDiscovery(this);
|
||||
|
||||
m_engine = new Engine(this);
|
||||
|
||||
m_qmlEngine = new QQmlApplicationEngine(this);
|
||||
|
||||
Nymea::Core::registerQmlTypes();
|
||||
|
||||
qmlRegisterSingletonType<PlatformHelper>("Nymea", 1, 0, "PlatformHelper", platformHelperProvider);
|
||||
qmlRegisterSingletonType(QUrl("qrc:///ui/utils/NymeaUtils.qml"), "Nymea", 1, 0, "NymeaUtils" );
|
||||
qmlRegisterType<NfcThingActionWriter>("Nymea", 1, 0, "NfcThingActionWriter");
|
||||
qmlRegisterSingletonType<NfcHelper>("Nymea", 1, 0, "NfcHelper", NfcHelper::nfcHelperProvider);
|
||||
|
||||
StyleController *styleController = new StyleController("light", this);
|
||||
|
||||
QQmlFileSelector *styleSelector = new QQmlFileSelector(m_qmlEngine);
|
||||
styleSelector->setExtraSelectors({styleController->currentStyle()});
|
||||
|
||||
foreach (const QFileInfo &fi, QDir(":/ui/fonts/").entryInfoList()) {
|
||||
QFontDatabase::addApplicationFont(fi.absoluteFilePath());
|
||||
}
|
||||
foreach (const QFileInfo &fi, QDir(":/styles/" + styleController->currentStyle() + "/fonts/").entryInfoList()) {
|
||||
qDebug() << "Adding style font:" << fi.absoluteFilePath();
|
||||
QFontDatabase::addApplicationFont(fi.absoluteFilePath());
|
||||
}
|
||||
|
||||
qmlRegisterSingletonType(QUrl("qrc:///styles/" + styleController->currentStyle() + "/Style.qml"), "Nymea", 1, 0, "Style" );
|
||||
|
||||
m_qmlEngine->rootContext()->setContextProperty("styleController", styleController);
|
||||
m_qmlEngine->rootContext()->setContextProperty("engine", m_engine);
|
||||
m_qmlEngine->rootContext()->setContextProperty("_engine", m_engine);
|
||||
m_qmlEngine->rootContext()->setContextProperty("controlledThingId", ""); // Unknown at this point
|
||||
|
||||
m_qmlEngine->load(QUrl(QLatin1String("qrc:/Main.qml")));
|
||||
|
||||
jboolean startedByNfc = QtAndroid::androidActivity().callMethod<jboolean>("startedByNfc", "()Z");
|
||||
if (startedByNfc) {
|
||||
qDebug() << "**** Started by NFC";
|
||||
qDebug() << "Registering NFC handler and waiting for message.";
|
||||
|
||||
QNearFieldManager *manager = new QNearFieldManager(this);
|
||||
manager->registerNdefMessageHandler(this, SLOT(handleNdefMessage(QNdefMessage,QNearFieldTarget*)));
|
||||
|
||||
} else {
|
||||
qDebug() << "*** Started by other intent";
|
||||
qDebug() << "Expecing nymeaId and thingId in intent extras.";
|
||||
QString nymeaId = QtAndroid::androidActivity().callObjectMethod<jstring>("nymeaId").toString();
|
||||
QString thingId = QtAndroid::androidActivity().callObjectMethod<jstring>("thingId").toString();
|
||||
|
||||
connectToNymea(nymeaId);
|
||||
m_qmlEngine->rootContext()->setContextProperty("controlledThingId", thingId);
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceControlApplication::handleNdefMessage(QNdefMessage message, QNearFieldTarget *target)
|
||||
{
|
||||
Q_UNUSED(target)
|
||||
qDebug() << "************* NFC message!" << message.toByteArray();
|
||||
if (message.count() < 1) {
|
||||
qWarning() << "NFC message doesn't contain any records...";
|
||||
return;
|
||||
}
|
||||
// NOTE: At this point we're only supporting one NDEF record per message
|
||||
QNdefRecord record = message.first();
|
||||
QNdefNfcUriRecord uriRecord(record);
|
||||
|
||||
QUrl url = uriRecord.uri();
|
||||
if (url.scheme() != "nymea") {
|
||||
qWarning() << "NDEF URI record scheme is not \"nymea://\"";
|
||||
return;
|
||||
}
|
||||
|
||||
QUuid nymeaId = QUuid(url.host());
|
||||
if (nymeaId.isNull()) {
|
||||
qWarning() << "Invalid nymea UUID in NDEF record.";
|
||||
return;
|
||||
}
|
||||
|
||||
QUuid thingId = QUuid(QUrlQuery(url).queryItemValue("t"));
|
||||
if (thingId.isNull()) {
|
||||
qWarning() << "Invalid thing in NDEF record";
|
||||
return;
|
||||
}
|
||||
|
||||
m_pendingNfcAction = url;
|
||||
|
||||
connectToNymea(nymeaId);
|
||||
m_qmlEngine->rootContext()->setContextProperty("controlledThingId", thingId);
|
||||
|
||||
connect(m_engine->thingManager(), &ThingManager::fetchingDataChanged, [this](){
|
||||
if (m_engine->jsonRpcClient()->connected() && !m_engine->thingManager()->fetchingData()) {
|
||||
qDebug() << "Ready to process commands";
|
||||
runNfcAction();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void DeviceControlApplication::connectToNymea(const QUuid &nymeaId)
|
||||
{
|
||||
NymeaHost *host = m_discovery->nymeaHosts()->find(nymeaId);
|
||||
if (!host) {
|
||||
qWarning() << "No such nymea host:" << nymeaId;
|
||||
// TODO: We could wait here until the discovery finds it... But it really should be cached already...
|
||||
exit(1);
|
||||
}
|
||||
qDebug() << "Connecting to:" << host->name();
|
||||
m_engine->jsonRpcClient()->connectToHost(host);
|
||||
}
|
||||
|
||||
void DeviceControlApplication::runNfcAction()
|
||||
{
|
||||
if (!m_pendingNfcAction.isEmpty()) {
|
||||
qDebug() << "NFC action:" << m_pendingNfcAction;
|
||||
}
|
||||
QUrl url = m_pendingNfcAction;
|
||||
m_pendingNfcAction.clear();
|
||||
|
||||
if (url.scheme() != "nymea") {
|
||||
qWarning() << "NDEF URI record scheme is not \"nymea://\" in" << url.toString();
|
||||
return;
|
||||
}
|
||||
|
||||
QUuid nymeaId = QUuid(url.host());
|
||||
if (nymeaId.isNull()) {
|
||||
qWarning() << "Invalid nymea UUID" << url.host() << "in NDEF record" << url.toString();
|
||||
return;
|
||||
}
|
||||
|
||||
QUuid thingId = QUuid(QUrlQuery(url).queryItemValue("t"));
|
||||
Thing *thing = m_engine->thingManager()->things()->getThing(thingId);
|
||||
if (!thing) {
|
||||
qDebug() << "Thing" << thingId.toString() << "from" << url.toString() << "doesn't exist on nymea host" << nymeaId.toString();
|
||||
return;
|
||||
}
|
||||
|
||||
QList<QPair<QString, QString>> queryItems = QUrlQuery(url.query()).queryItems();
|
||||
for (int i = 0; i < queryItems.count(); i++) {
|
||||
QString entryName = queryItems.at(i).first;
|
||||
if (entryName == "t") {
|
||||
continue;
|
||||
}
|
||||
if (!entryName.startsWith("a")) {
|
||||
qDebug() << "Only actions are supported. Skipping query item" << entryName;
|
||||
continue;
|
||||
}
|
||||
|
||||
QString actionString = queryItems.at(i).second;
|
||||
QStringList parts = actionString.split("#");
|
||||
if (parts.count() == 0) {
|
||||
qDebug() << "Invalid action definition:" << actionString;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parts.count() > 2) {
|
||||
// The parameters might contain a #, let's merge them again
|
||||
parts[1] = parts.mid(1).join('#');
|
||||
}
|
||||
|
||||
QString actionTypeName = parts.at(0);
|
||||
ActionType *actionType = thing->thingClass()->actionTypes()->findByName(actionTypeName);
|
||||
if (!actionType) {
|
||||
qWarning() << "Invalid action name" << actionType << "in url:" << url.toString();
|
||||
continue;
|
||||
}
|
||||
|
||||
QHash<QString, QVariant> paramsInUri;
|
||||
if (parts.count() > 1) {
|
||||
QString paramsString = parts.at(1);
|
||||
foreach (const QString ¶mString, paramsString.split("+")) {
|
||||
QStringList parts = paramString.split(":");
|
||||
if (parts.count() != 2) {
|
||||
qWarning() << "Invalid param format" << paramString << "in url:" << url.toString();
|
||||
continue;
|
||||
}
|
||||
paramsInUri.insert(parts.at(0), parts.at(1));
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << "Parameters in NFC uri:" << paramsInUri;
|
||||
|
||||
QVariantList params;
|
||||
for (int j = 0; j < actionType->paramTypes()->rowCount(); j++) {
|
||||
ParamType *paramType = actionType->paramTypes()->get(j);
|
||||
QVariantMap param;
|
||||
param.insert("paramTypeId", paramType->id());
|
||||
if (paramsInUri.contains(paramType->name())) {
|
||||
param.insert("value", paramsInUri.value(paramType->name()));
|
||||
} else {
|
||||
param.insert("value", paramType->defaultValue());
|
||||
}
|
||||
params.append(param);
|
||||
}
|
||||
|
||||
qDebug() << "Action parameters:" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson());
|
||||
|
||||
m_engine->thingManager()->executeAction(thingId, actionType->id(), params);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,37 +0,0 @@
|
||||
#ifndef DEVICECONTROLAPPLICATION_H
|
||||
#define DEVICECONTROLAPPLICATION_H
|
||||
|
||||
#include <QApplication>
|
||||
#include <QNearFieldManager>
|
||||
#include <QNdefMessage>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QNdefMessage>
|
||||
|
||||
#include "types/ruleactions.h"
|
||||
#include "connection/discovery/nymeadiscovery.h"
|
||||
#include "engine.h"
|
||||
|
||||
class DeviceControlApplication : public QApplication
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DeviceControlApplication(int argc, char *argv[]);
|
||||
|
||||
private slots:
|
||||
void handleNdefMessage(QNdefMessage message,QNearFieldTarget* target);
|
||||
|
||||
void connectToNymea(const QUuid &nymeaId);
|
||||
|
||||
void runNfcAction();
|
||||
|
||||
private:
|
||||
NymeaDiscovery *m_discovery = nullptr;
|
||||
Engine *m_engine = nullptr;
|
||||
QQmlApplicationEngine *m_qmlEngine = nullptr;
|
||||
|
||||
QUrl m_pendingNfcAction;
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // DEVICECONTROLAPPLICATION_H
|
||||
@ -1,9 +0,0 @@
|
||||
package io.guh.nymeaapp;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class Action {
|
||||
public UUID typeId;
|
||||
public String name;
|
||||
public String displayName;
|
||||
}
|
||||
@ -1,289 +0,0 @@
|
||||
package io.guh.nymeaapp;
|
||||
|
||||
import android.util.Log;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.ComponentName;
|
||||
import android.app.PendingIntent;
|
||||
import android.net.Uri;
|
||||
import android.content.Context;
|
||||
import android.service.controls.ControlsProviderService;
|
||||
import android.service.controls.actions.*;
|
||||
import android.service.controls.Control;
|
||||
import android.service.controls.DeviceTypes;
|
||||
import android.service.controls.templates.*;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import android.os.Parcel;
|
||||
|
||||
import java.util.concurrent.Flow.Publisher;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.UUID;
|
||||
import java.util.HashMap;
|
||||
import io.reactivex.Flowable;
|
||||
import io.reactivex.processors.ReplayProcessor;
|
||||
import org.reactivestreams.FlowAdapters;
|
||||
import org.json.*;
|
||||
|
||||
// Android device controls service
|
||||
|
||||
// This service is instantiated by the android device controls on demand. It will
|
||||
// connect to the NymeaAppService and interact with nymea through that.
|
||||
|
||||
public class NymeaAppControlService extends ControlsProviderService {
|
||||
private String TAG = "nymea-app: NymeaAppControlService";
|
||||
private NymeaAppServiceConnection m_serviceConnection;
|
||||
|
||||
// For publishing all available
|
||||
private ReplayProcessor m_publisherForAll;
|
||||
private ArrayList<UUID> m_pendingForAll = new ArrayList<UUID>(); // pending nymea ids to query
|
||||
|
||||
private ReplayProcessor m_updatePublisher;
|
||||
private List m_activeControlIds;
|
||||
|
||||
|
||||
private void ensureServiceConnection() {
|
||||
if (m_serviceConnection == null) {
|
||||
m_serviceConnection = new NymeaAppServiceConnection(getBaseContext()) {
|
||||
@Override public void onConnectedChanged(boolean connected) {
|
||||
Log.d(TAG, "Connected to NymeaAppService. Known hosts: " + m_serviceConnection.getHosts().size());
|
||||
if (connected && m_publisherForAll != null) {
|
||||
Log.d(TAG, "Processing all");
|
||||
processAll();
|
||||
}
|
||||
}
|
||||
@Override public void onReadyChanged(UUID nymeaId, boolean ready) {
|
||||
Log.d(TAG, "Nymea instance " + nymeaId.toString() + " ready state changed: " + Boolean.toString(ready));
|
||||
if (ready) {
|
||||
process(nymeaId);
|
||||
}
|
||||
}
|
||||
@Override public void onUpdate(UUID nymeaId, UUID thingId) {
|
||||
if (m_updatePublisher != null && m_activeControlIds.contains(thingId.toString())) {
|
||||
// Log.d(TAG, "Updating publisher for thing: " + thingId);
|
||||
m_updatePublisher.onNext(thingToControl(nymeaId, thingId));
|
||||
// m_updatePublisher.onComplete();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
Intent serviceIntent = new Intent(this, NymeaAppService.class);
|
||||
bindService(serviceIntent, m_serviceConnection, Context.BIND_AUTO_CREATE);
|
||||
}
|
||||
|
||||
private void processAll() {
|
||||
ensureServiceConnection();
|
||||
if (m_serviceConnection.connected()) {
|
||||
// Need to add all the pending before processing
|
||||
if (m_publisherForAll != null) {
|
||||
for (UUID nymeaId: m_serviceConnection.getHosts().keySet()) {
|
||||
m_pendingForAll.add(nymeaId);
|
||||
}
|
||||
}
|
||||
for (UUID nymeaId: m_serviceConnection.getHosts().keySet()) {
|
||||
if (m_serviceConnection.getHosts().get(nymeaId).isReady) {
|
||||
process(nymeaId);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "Not connected to NymeaAppService yet...");
|
||||
}
|
||||
}
|
||||
|
||||
private void process(UUID nymeaId) {
|
||||
Log.d(TAG, "Processing...");
|
||||
ensureServiceConnection();
|
||||
if (!m_serviceConnection.connected()) {
|
||||
Log.d(TAG, "NymeaAppService not connected to nymea instance " + nymeaId + " yet.");
|
||||
return;
|
||||
}
|
||||
if (!m_serviceConnection.getHosts().keySet().contains(nymeaId)) {
|
||||
Log.d(TAG, "Service connection is not ready yet...");
|
||||
return;
|
||||
}
|
||||
|
||||
for (Thing thing : m_serviceConnection.getHosts().get(nymeaId).things.values()) {
|
||||
Log.d(TAG, "Processing thing: " + thing.name);
|
||||
|
||||
if (m_publisherForAll != null) {
|
||||
Log.d(TAG, "Adding stateless");
|
||||
m_publisherForAll.onNext(thingToControl(nymeaId, thing.id));
|
||||
}
|
||||
|
||||
if (m_updatePublisher != null) {
|
||||
if (m_activeControlIds.contains(thing.id.toString())) {
|
||||
Log.d(TAG, "Adding stateful");
|
||||
m_updatePublisher.onNext(thingToControl(nymeaId, thing.id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_pendingForAll.contains(nymeaId)) {
|
||||
m_pendingForAll.remove(nymeaId);
|
||||
}
|
||||
|
||||
// The publisher for all needs to be completed when done
|
||||
if (m_publisherForAll != null && m_pendingForAll.isEmpty()) {
|
||||
Log.d(TAG, "Completing all publisher");
|
||||
m_publisherForAll.onComplete();
|
||||
}
|
||||
|
||||
Log.d(TAG, "Done processing");
|
||||
// We never close the update publisher as we need that one to send updates
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Publisher createPublisherForAllAvailable() {
|
||||
Log.d(TAG, "Creating publishers for all");
|
||||
m_publisherForAll = ReplayProcessor.create();
|
||||
processAll();
|
||||
return FlowAdapters.toFlowPublisher(m_publisherForAll);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Publisher createPublisherFor(List controlIds) {
|
||||
Log.d(TAG, "Creating publishers for " + Integer.toString(controlIds.size()));
|
||||
m_updatePublisher = ReplayProcessor.create();
|
||||
m_activeControlIds = controlIds;
|
||||
processAll();
|
||||
return FlowAdapters.toFlowPublisher(m_updatePublisher);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performControlAction(String controlId, ControlAction action, Consumer consumer) {
|
||||
Log.d(TAG, "Performing control action: " + controlId);
|
||||
|
||||
UUID nymeaId = m_serviceConnection.hostForThing(UUID.fromString(controlId));
|
||||
if (nymeaId == null) {
|
||||
Log.d(TAG, "Nymea host not found for thing id: " + controlId);
|
||||
consumer.accept(ControlAction.RESPONSE_FAIL);
|
||||
return;
|
||||
}
|
||||
Thing thing = m_serviceConnection.getThing(UUID.fromString(controlId));
|
||||
if (thing == null) {
|
||||
Log.d(TAG, "Thing not found for id: " + controlId);
|
||||
consumer.accept(ControlAction.RESPONSE_FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
UUID actionTypeId;
|
||||
String param;
|
||||
if (thing.interfaces.contains("dimmablelight") && action instanceof FloatAction) {
|
||||
actionTypeId = thing.stateByName("brightness").typeId;
|
||||
FloatAction fAction = (FloatAction) action;
|
||||
param = String.valueOf(Math.round(fAction.getNewValue()));
|
||||
} else if (thing.interfaces.contains("power") && action instanceof BooleanAction) {
|
||||
actionTypeId = thing.stateByName("power").typeId;
|
||||
BooleanAction bAction = (BooleanAction) action;
|
||||
param = bAction.getNewState() == true ? "true" : "false";
|
||||
} else if (thing.interfaces.contains("closable") && action instanceof BooleanAction) {
|
||||
BooleanAction bAction = (BooleanAction) action;
|
||||
if (bAction.getNewState()) {
|
||||
Log.d(TAG, "executing open");
|
||||
actionTypeId = thing.actionByName("open").typeId;
|
||||
} else {
|
||||
Log.d(TAG, "executing close");
|
||||
actionTypeId = thing.actionByName("close").typeId;
|
||||
}
|
||||
param = "";
|
||||
} else if (thing.interfaces.contains("volumecontroller") && thing.stateByName("volume") != null) {
|
||||
actionTypeId = thing.stateByName("volume").typeId;
|
||||
FloatAction fAction = (FloatAction) action;
|
||||
param = String.valueOf(Math.round(fAction.getNewValue()));
|
||||
} else {
|
||||
Log.d(TAG, "Unhandled action for: " + thing.name);
|
||||
consumer.accept(ControlAction.RESPONSE_FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
m_serviceConnection.executeAction(nymeaId, thing.id, actionTypeId, param);
|
||||
consumer.accept(ControlAction.RESPONSE_OK);
|
||||
|
||||
}
|
||||
|
||||
private HashMap<UUID, Integer> m_intents = new HashMap<UUID, Integer>();
|
||||
|
||||
private Control thingToControl(UUID nymeaId, UUID thingId) {
|
||||
// Log.d(TAG, "Creating control for thing: " + thing.name + " id: " + thing.id);
|
||||
|
||||
NymeaHost nymeaHost = m_serviceConnection.getHosts().get(nymeaId);
|
||||
Thing thing = nymeaHost.things.get(thingId);
|
||||
|
||||
// NOTE: intentId 1 doesn't work for some reason I don't understand yet...
|
||||
// so let's make sure we never add "1" to it by always added 100
|
||||
int intentId = m_intents.size() + 100;
|
||||
PendingIntent pi;
|
||||
if (m_intents.containsKey(thing.id)) {
|
||||
intentId = m_intents.get(thing.id);
|
||||
} else {
|
||||
m_intents.put(thing.id, intentId);
|
||||
}
|
||||
|
||||
Context context = getBaseContext();
|
||||
Intent intent = new Intent(context, NymeaAppControlsActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
|
||||
intent.putExtra("nymeaId", nymeaId.toString());
|
||||
intent.putExtra("thingId", thing.id.toString());
|
||||
pi = PendingIntent.getActivity(context, intentId, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
|
||||
Log.d(TAG, "Created pendingintent for " + thing.name + " with id " + intentId + " and extra " + thing.id);
|
||||
|
||||
Control.StatefulBuilder builder = new Control.StatefulBuilder(thing.id.toString(), pi)
|
||||
.setTitle(thing.name)
|
||||
.setSubtitle(thing.className)
|
||||
.setStructure(nymeaHost.name);
|
||||
|
||||
if (thing.interfaces.contains("impulsebasedgaragedoor")) {
|
||||
builder.setDeviceType(DeviceTypes.TYPE_GARAGE);
|
||||
builder.setControlTemplate(new StatelessTemplate(thing.id.toString()));
|
||||
} else if (thing.interfaces.contains("statefulgaragedoor")) {
|
||||
builder.setDeviceType(DeviceTypes.TYPE_GARAGE);
|
||||
State stateState = thing.stateByName("state");
|
||||
ControlButton controlButton = new ControlButton(stateState.value.equals("open"), stateState.displayName);
|
||||
builder.setControlTemplate(new ToggleTemplate(thing.id.toString(), controlButton));
|
||||
|
||||
// } else if (thing.interfaces.contains("extendedstatefulgaragedoor")) {
|
||||
// builder.setDeviceTyoe(DeviceTypes.TYPE_GARAGE);
|
||||
|
||||
} else if (thing.interfaces.contains("light")) {
|
||||
builder.setDeviceType(DeviceTypes.TYPE_LIGHT);
|
||||
State powerState = thing.stateByName("power");
|
||||
ControlButton controlButton = new ControlButton(powerState.value.equals("true"), powerState.displayName);
|
||||
|
||||
if (thing.interfaces.contains("dimmablelight")) {
|
||||
State brightnessState = thing.stateByName("brightness");
|
||||
RangeTemplate rangeTemplate = new RangeTemplate(thing.id.toString(), 0, 100, Float.parseFloat(brightnessState.value), 1, brightnessState.displayName);
|
||||
builder.setControlTemplate(new ToggleRangeTemplate(thing.id.toString(), controlButton, rangeTemplate));
|
||||
} else {
|
||||
builder.setControlTemplate(new ToggleTemplate(thing.id.toString(), controlButton));
|
||||
}
|
||||
} else if (thing.interfaces.contains("powersocket")) {
|
||||
builder.setDeviceType(DeviceTypes.TYPE_OUTLET);
|
||||
State powerState = thing.stateByName("power");
|
||||
ControlButton controlButton = new ControlButton(powerState.value.equals("true"), powerState.displayName);
|
||||
builder.setControlTemplate(new ToggleTemplate(thing.id.toString(), controlButton));
|
||||
} else if (thing.interfaces.contains("mediaplayer")) {
|
||||
if (thing.stateByName("playerType").value == "video") {
|
||||
builder.setDeviceType(DeviceTypes.TYPE_TV);
|
||||
} else {
|
||||
// FIXME: There doesn't seem to be a speaker DeviceType!?!
|
||||
builder.setDeviceType(DeviceTypes.TYPE_TV);
|
||||
}
|
||||
if (thing.interfaces.contains("volumecontroller")) {
|
||||
State volumeState = thing.stateByName("volume");
|
||||
if (volumeState != null) {
|
||||
RangeTemplate rangeTemplate = new RangeTemplate(thing.id.toString(), 0, 100, Float.parseFloat(volumeState.value), 1, volumeState.displayName);
|
||||
builder.setControlTemplate(rangeTemplate);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
builder.setDeviceType(DeviceTypes.TYPE_GENERIC_ON_OFF);
|
||||
}
|
||||
builder.setStatus(Control.STATUS_OK);
|
||||
|
||||
// Log.d(TAG, "Created control for thing: " + thing.name + " id: " + thing.id);
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
@ -1,55 +0,0 @@
|
||||
package io.guh.nymeaapp;
|
||||
import android.util.Log;
|
||||
import android.content.Intent;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.os.Build;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.provider.Settings.Secure;
|
||||
import android.os.Vibrator;
|
||||
import android.os.Process;
|
||||
import android.nfc.NfcAdapter;
|
||||
import android.nfc.NdefMessage;
|
||||
import android.os.Parcelable;
|
||||
|
||||
// An activity spawned by android device controls on demand.
|
||||
|
||||
public class NymeaAppControlsActivity extends org.qtproject.qt5.android.bindings.QtActivity
|
||||
{
|
||||
private static final String TAG = "nymea-app: NymeaAppControlActivity";
|
||||
|
||||
|
||||
@Override public void onPause() {
|
||||
Log.d(TAG, "Pausing...");
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
@Override public void onResume() {
|
||||
super.onResume();
|
||||
Log.d(TAG, "Resuming...");
|
||||
}
|
||||
|
||||
@Override public void onDestroy() {
|
||||
Log.d(TAG, "Destroying...");
|
||||
}
|
||||
|
||||
public boolean startedByNfc() {
|
||||
return NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction());
|
||||
}
|
||||
|
||||
public String nymeaId()
|
||||
{
|
||||
return getIntent().getStringExtra("nymeaId");
|
||||
}
|
||||
|
||||
public String thingId()
|
||||
{
|
||||
return getIntent().getStringExtra("thingId");
|
||||
}
|
||||
|
||||
public void vibrate(int duration)
|
||||
{
|
||||
Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
|
||||
v.vibrate(duration);
|
||||
}
|
||||
}
|
||||
@ -1,50 +0,0 @@
|
||||
package io.guh.nymeaapp;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
|
||||
import org.qtproject.qt5.android.bindings.QtService;
|
||||
|
||||
// Background service establishing a connection to nymea and providing data on android specific interfaces
|
||||
// such as IBinder and BroadcastListener
|
||||
|
||||
// This service loads the service_main Qt entry point and does most of its work in C++/Qt
|
||||
|
||||
public class NymeaAppService extends QtService
|
||||
{
|
||||
public static final String NYMEA_APP_BROADCAST = "io.guh.nymeaapp.NymeaAppService.broadcast";
|
||||
|
||||
private static final String TAG = "nymea-app: NymeaAppService";
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
Log.i(TAG, "Creating Service");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
Log.i(TAG, "Destroying Service");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
int ret = super.onStartCommand(intent, flags, startId);
|
||||
|
||||
// Do some work
|
||||
|
||||
Log.d(TAG, "*************** Service started");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void sendBroadcast(String payload) {
|
||||
Intent sendToUiIntent = new Intent();
|
||||
sendToUiIntent.setAction(NYMEA_APP_BROADCAST);
|
||||
sendToUiIntent.putExtra("data", payload);
|
||||
// Log.d(TAG, "Service sending broadcast");
|
||||
sendBroadcast(sendToUiIntent);
|
||||
}
|
||||
}
|
||||
@ -1,283 +0,0 @@
|
||||
package io.guh.nymeaapp;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.UUID;
|
||||
import java.util.HashMap;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import android.os.IBinder;
|
||||
import android.os.Parcel;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
|
||||
import android.service.controls.Control;
|
||||
import android.service.controls.DeviceTypes;
|
||||
|
||||
import io.reactivex.processors.ReplayProcessor;
|
||||
|
||||
import org.json.*;
|
||||
|
||||
// Helper class to establish a connection to the NymeaAppService and interact
|
||||
// with that using IBinder and ServiceBroadcastListener
|
||||
|
||||
public class NymeaAppServiceConnection implements ServiceConnection {
|
||||
private static final String TAG = "nymea-app: NymeaAppServiceConnection";
|
||||
private IBinder m_service;
|
||||
private Context m_context;
|
||||
|
||||
private boolean m_connected = false;
|
||||
private HashMap<UUID, NymeaHost> m_nymeaHosts = new HashMap<UUID, NymeaHost>();
|
||||
|
||||
public NymeaAppServiceConnection(Context context) {
|
||||
super();
|
||||
m_context = context;
|
||||
}
|
||||
|
||||
final public boolean connected() {
|
||||
return m_connected;
|
||||
}
|
||||
public void onConnectedChanged(boolean connected) {};
|
||||
|
||||
final public boolean isReady(UUID nymeaId) {
|
||||
return m_nymeaHosts.get(nymeaId).isReady;
|
||||
}
|
||||
public void onReadyChanged(UUID nymeaId, boolean ready) {}
|
||||
|
||||
public final HashMap<UUID, NymeaHost> getHosts() {
|
||||
return m_nymeaHosts;
|
||||
}
|
||||
|
||||
final public Thing getThing(UUID thingId) {
|
||||
for (HashMap.Entry<UUID, NymeaHost> entry : m_nymeaHosts.entrySet()) {
|
||||
Thing thing = entry.getValue().things.get(thingId);
|
||||
if (thing != null) {
|
||||
return thing;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
final public UUID hostForThing(UUID thingId) {
|
||||
for (HashMap.Entry<UUID, NymeaHost> entry : m_nymeaHosts.entrySet()) {
|
||||
Thing thing = entry.getValue().things.get(thingId);
|
||||
if (thing != null) {
|
||||
return entry.getKey();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void onError() {}
|
||||
public void onUpdate(UUID nymeaId, UUID thingId) {}
|
||||
|
||||
final public void executeAction(UUID nymeaId, UUID thingId, UUID actionTypeId, String paramValue) {
|
||||
try {
|
||||
JSONObject params = new JSONObject();
|
||||
params.put("nymeaId", nymeaId.toString());
|
||||
params.put("thingId", thingId.toString());
|
||||
params.put("actionTypeId", actionTypeId.toString());
|
||||
JSONArray actionParams = new JSONArray();
|
||||
JSONObject param = new JSONObject();
|
||||
param.put("paramTypeId", actionTypeId.toString());
|
||||
param.put("value", paramValue);
|
||||
actionParams.put(param);
|
||||
params.put("params", actionParams);
|
||||
Parcel parcel = createRequest("ExecuteAction", params);
|
||||
Parcel retParcel = Parcel.obtain();
|
||||
m_service.transact(1, parcel, retParcel, 0);
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, "Error calling executeAction on NymeaAppService");
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void onServiceConnected(ComponentName className, IBinder service) {
|
||||
Log.d(TAG, "Connected to NymeaAppService");
|
||||
m_service = service;
|
||||
|
||||
registerServiceBroadcastReceiver();
|
||||
|
||||
try {
|
||||
Parcel parcel = createRequest("GetInstances");
|
||||
Parcel retParcel = Parcel.obtain();
|
||||
|
||||
m_service.transact(1, parcel, retParcel, 0);
|
||||
|
||||
JSONObject reply = new JSONObject(retParcel.readString());
|
||||
Log.d(TAG, "Instaces received: " + reply.toString());
|
||||
JSONArray instances = reply.getJSONArray("instances");
|
||||
for (int i = 0; i < instances.length(); i++) {
|
||||
JSONObject instanceMap = instances.getJSONObject(i);
|
||||
NymeaHost nymeaHost = new NymeaHost();
|
||||
nymeaHost.id = UUID.fromString(instanceMap.getString("id"));
|
||||
nymeaHost.name = instanceMap.getString("name");
|
||||
nymeaHost.isReady = instanceMap.getBoolean("isReady");
|
||||
m_nymeaHosts.put(nymeaHost.id, nymeaHost);
|
||||
if (nymeaHost.isReady) {
|
||||
fetchThings(nymeaHost.id);
|
||||
}
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
Log.d(TAG, "Error while processing JSON in communication with NymeaAppService: " + e.toString());
|
||||
onError();
|
||||
return;
|
||||
} catch (RemoteException e) {
|
||||
Log.d(TAG, "Error communicating with NymeaAppService: " + e.toString());
|
||||
onError();
|
||||
return;
|
||||
}
|
||||
|
||||
m_connected = true;
|
||||
onConnectedChanged(m_connected);
|
||||
}
|
||||
|
||||
@Override public void onServiceDisconnected(ComponentName arg0) {
|
||||
m_service = null;
|
||||
for (int i = 0; i < m_nymeaHosts.size(); i++) {
|
||||
m_nymeaHosts.get(i).isReady = false;
|
||||
}
|
||||
m_connected = false;
|
||||
onConnectedChanged(m_connected);
|
||||
}
|
||||
|
||||
public void registerServiceBroadcastReceiver() {
|
||||
IntentFilter intentFilter = new IntentFilter();
|
||||
intentFilter.addAction(NymeaAppService.NYMEA_APP_BROADCAST);
|
||||
m_context.registerReceiver(serviceMessageReceiver, intentFilter);
|
||||
Log.d(TAG, "Registered broadcast receiver");
|
||||
}
|
||||
|
||||
private BroadcastReceiver serviceMessageReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (NymeaAppService.NYMEA_APP_BROADCAST.equals(intent.getAction())) {
|
||||
String payload = intent.getStringExtra("data");
|
||||
try {
|
||||
processBroadcast(payload);
|
||||
} catch(JSONException e) {
|
||||
Log.d(TAG, "Error parsing broadcast JSON: " + e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private void processBroadcast(String payload) throws JSONException
|
||||
{
|
||||
JSONObject data = new JSONObject(payload);
|
||||
JSONObject params = data.getJSONObject("params");
|
||||
// Log.d(TAG, "Broadcast received from NymeaAppService: " + data.getString("notification"));
|
||||
Log.d(TAG, params.toString());
|
||||
|
||||
if (data.getString("notification").equals("ThingStateChanged")) {
|
||||
UUID nymeaId = UUID.fromString(params.getString("nymeaId"));
|
||||
UUID thingId = UUID.fromString(params.getString("thingId"));
|
||||
UUID stateTypeId = UUID.fromString(params.getString("stateTypeId"));
|
||||
String value = params.getString("value");
|
||||
// Log.d(TAG, "Thing state changed: " + thingId + " stateTypeId: " + stateTypeId + " value: " + value);
|
||||
|
||||
Thing thing = getThing(thingId);
|
||||
if (thing != null) {
|
||||
thing.stateById(stateTypeId).value = value;
|
||||
onUpdate(nymeaId, thingId);
|
||||
} else {
|
||||
Log.d(TAG, "Got a state change notification for a thing we don't know!");
|
||||
}
|
||||
}
|
||||
|
||||
if (data.getString("notification").equals("ReadyStateChanged")) {
|
||||
UUID nymeaId = UUID.fromString(params.getString("nymeaId"));
|
||||
NymeaHost host = m_nymeaHosts.get(nymeaId);
|
||||
host.isReady = params.getBoolean("isReady");
|
||||
if (host.isReady) {
|
||||
Log.d(TAG, "Host is ready. Fetching things...");
|
||||
fetchThings(nymeaId);
|
||||
} else {
|
||||
Log.d(TAG, "Host is not ready yet...");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fetchThings(UUID nymeaId) {
|
||||
Log.d(TAG, "Fetching things");
|
||||
String thingsList;
|
||||
try {
|
||||
JSONObject params = new JSONObject();
|
||||
params.put("nymeaId", nymeaId.toString());
|
||||
Parcel parcel = createRequest("GetThings", params);
|
||||
Parcel retParcel = Parcel.obtain();
|
||||
m_service.transact(1, parcel, retParcel, 0);
|
||||
thingsList = retParcel.readString();
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, "Error fetching things from NymeaAppService: " + e.toString());
|
||||
onError();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
JSONObject result = new JSONObject(thingsList);
|
||||
for (int i = 0; i < result.getJSONArray("things").length(); i++) {
|
||||
JSONObject entry = result.getJSONArray("things").getJSONObject(i);
|
||||
Thing thing = new Thing();
|
||||
thing.id = UUID.fromString(entry.getString("id"));
|
||||
thing.name = entry.getString("name");
|
||||
thing.className = entry.getString("className");
|
||||
JSONArray ifaces = entry.getJSONArray("interfaces");
|
||||
for (int j = 0; j < ifaces.length(); j++) {
|
||||
thing.interfaces.add(ifaces.get(j));
|
||||
}
|
||||
JSONArray states = entry.getJSONArray("states");
|
||||
for (int j = 0; j < states.length(); j++) {
|
||||
JSONObject stateMap = states.getJSONObject(j);
|
||||
State s = new State();
|
||||
s.typeId = UUID.fromString(stateMap.getString("stateTypeId"));
|
||||
s.name = stateMap.getString("name");
|
||||
s.displayName = stateMap.getString("displayName");
|
||||
s.value = stateMap.getString("value");
|
||||
thing.states.add(s);
|
||||
}
|
||||
JSONArray actions = entry.getJSONArray("actions");
|
||||
for (int j = 0; j < actions.length(); j++) {
|
||||
JSONObject actionMap = actions.getJSONObject(j);
|
||||
Action a = new Action();
|
||||
a.typeId = UUID.fromString(actionMap.getString("actionTypeId"));
|
||||
a.name = actionMap.getString("name");
|
||||
a.displayName = actionMap.getString("displayName");
|
||||
thing.actions.add(a);
|
||||
}
|
||||
m_nymeaHosts.get(nymeaId).things.put(thing.id, thing);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, "Error parsing JSON from NymeaAppService: " + e.toString());
|
||||
Log.d(TAG, thingsList);
|
||||
m_service = null;
|
||||
onError();
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Things fetched: " + m_nymeaHosts.get(nymeaId).things.size());
|
||||
m_nymeaHosts.get(nymeaId).isReady = true;
|
||||
onReadyChanged(nymeaId, true);
|
||||
}
|
||||
|
||||
private Parcel createRequest(String method) throws JSONException {
|
||||
return createRequest(method, null);
|
||||
}
|
||||
private Parcel createRequest(String method, JSONObject params) throws JSONException {
|
||||
Parcel ret = Parcel.obtain();
|
||||
JSONObject payload = new JSONObject();
|
||||
payload.put("method", method);
|
||||
if (params != null) {
|
||||
payload.put("params", params);
|
||||
}
|
||||
Log.d(TAG, "Parcel payload: " + payload.toString());
|
||||
ret.writeString(payload.toString());
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
package io.guh.nymeaapp;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.UUID;
|
||||
|
||||
public class NymeaHost {
|
||||
|
||||
UUID id;
|
||||
boolean isReady = false;
|
||||
String name = "";
|
||||
HashMap<UUID, Thing> things = new HashMap<UUID, Thing>();
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
package io.guh.nymeaapp;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class State {
|
||||
public UUID typeId;
|
||||
public String name;
|
||||
public String displayName;
|
||||
public String value;
|
||||
}
|
||||
@ -1,56 +0,0 @@
|
||||
package io.guh.nymeaapp;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.UUID;
|
||||
|
||||
|
||||
public class Thing {
|
||||
static final public String TAG = "nymea-app: Thing";
|
||||
public UUID id;
|
||||
public String name;
|
||||
public String className;
|
||||
public List interfaces = new ArrayList<State>();
|
||||
|
||||
public ArrayList<State> states = new ArrayList<State>();
|
||||
public ArrayList<Action> actions = new ArrayList<Action>();
|
||||
|
||||
public State stateByName(String name) {
|
||||
for (int i = 0; i < states.size(); i++) {
|
||||
if (states.get(i).name.equals(name)) {
|
||||
return states.get(i);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public State stateById(UUID stateTypeId) {
|
||||
for (int i = 0; i < states.size(); i++) {
|
||||
if (states.get(i).typeId.equals(stateTypeId)) {
|
||||
return states.get(i);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Action actionByName(String name) {
|
||||
for (int i = 0; i < actions.size(); i++) {
|
||||
Log.d(TAG, "Thing has action: " + actions.get(i).name);
|
||||
if (actions.get(i).name.equals(name)) {
|
||||
return actions.get(i);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Action actionById(UUID actionTypeId) {
|
||||
for (int i = 0; i < actions.size(); i++) {
|
||||
if (actions.get(i).typeId.equals(actionTypeId)) {
|
||||
return actions.get(i);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -1,115 +0,0 @@
|
||||
#include "androidbinder.h"
|
||||
#include "engine.h"
|
||||
#include "types/thing.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QAndroidParcel>
|
||||
#include <QAndroidJniObject>
|
||||
#include <QJsonDocument>
|
||||
#include <QtAndroid>
|
||||
|
||||
AndroidBinder::AndroidBinder(NymeaAppService *service):
|
||||
m_service(service)
|
||||
{
|
||||
}
|
||||
|
||||
bool AndroidBinder::onTransact(int code, const QAndroidParcel &data, const QAndroidParcel &reply, QAndroidBinder::CallType flags)
|
||||
{
|
||||
qDebug() << "onTransact: code " << code << ", flags " << int(flags);
|
||||
|
||||
// QString payload = data.readData();
|
||||
QString payload = data.handle().callObjectMethod<jstring>("readString").toString();
|
||||
|
||||
QJsonParseError error;
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(payload.toUtf8(), &error);
|
||||
if (error.error != QJsonParseError::NoError) {
|
||||
qWarning() << "Error parsing JSON from parcel:" << error.errorString();
|
||||
qWarning() << payload;
|
||||
return false;
|
||||
}
|
||||
QVariantMap request = jsonDoc.toVariant().toMap();
|
||||
|
||||
if (request.value("method").toString() == "GetInstances") {
|
||||
QVariantMap params;
|
||||
QVariantList instances;
|
||||
foreach (const QUuid &nymeaId, m_service->engines().keys()) {
|
||||
Engine *engine = m_service->engines().value(nymeaId);
|
||||
QVariantMap instance;
|
||||
instance.insert("id", nymeaId);
|
||||
instance.insert("isReady", engine->jsonRpcClient()->connected() && !engine->thingManager()->fetchingData());
|
||||
instance.insert("name", engine->jsonRpcClient()->currentHost()->name());
|
||||
instances.append(instance);
|
||||
}
|
||||
params.insert("instances", instances);
|
||||
sendReply(reply, params);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (request.value("method").toString() == "GetThings") {
|
||||
QUuid nymeaId = request.value("params").toMap().value("nymeaId").toUuid();
|
||||
Engine *engine = m_service->engines().value(nymeaId);
|
||||
if (!engine) {
|
||||
qWarning() << "Android client requested things for an invalid nymea instance:" << nymeaId;
|
||||
return false;
|
||||
}
|
||||
QVariantList thingsList;
|
||||
for (int i = 0; i < engine->thingManager()->things()->rowCount(); i++) {
|
||||
Thing *thing = engine->thingManager()->things()->get(i);
|
||||
QVariantMap thingMap;
|
||||
thingMap.insert("id", thing->id());
|
||||
thingMap.insert("name", thing->name());
|
||||
thingMap.insert("className", thing->thingClass()->displayName());
|
||||
thingMap.insert("interfaces", thing->thingClass()->interfaces());
|
||||
QVariantList states;
|
||||
for (int j = 0; j < thing->states()->rowCount(); j++) {
|
||||
State *state = thing->states()->get(j);
|
||||
QVariantMap stateMap;
|
||||
stateMap.insert("stateTypeId", state->stateTypeId());
|
||||
stateMap.insert("name", thing->thingClass()->stateTypes()->getStateType(state->stateTypeId())->name());
|
||||
stateMap.insert("displayName", thing->thingClass()->stateTypes()->getStateType(state->stateTypeId())->displayName());
|
||||
stateMap.insert("value", state->value());
|
||||
states.append(stateMap);
|
||||
}
|
||||
thingMap.insert("states", states);
|
||||
QVariantList actions;
|
||||
for (int j = 0; j < thing->thingClass()->actionTypes()->rowCount(); j++) {
|
||||
ActionType *actionType = thing->thingClass()->actionTypes()->get(j);
|
||||
QVariantMap actionMap;
|
||||
actionMap.insert("actionTypeId", actionType->id());
|
||||
actionMap.insert("name", actionType->name());
|
||||
actionMap.insert("displayName", actionType->displayName());
|
||||
actions.append(actionMap);
|
||||
}
|
||||
thingMap.insert("actions", actions);
|
||||
thingsList.append(thingMap);
|
||||
}
|
||||
QVariantMap params;
|
||||
params.insert("things", thingsList);
|
||||
sendReply(reply, params);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (request.value("method").toString() == "ExecuteAction") {
|
||||
qDebug() << "ExecuteAction";
|
||||
QUuid nymeaId = request.value("params").toMap().value("nymeaId").toUuid();
|
||||
Engine *engine = m_service->engines().value(nymeaId);
|
||||
if (!engine) {
|
||||
qWarning() << "Android client requested executeAction for an invalid nymea instance:" << nymeaId;
|
||||
return false;
|
||||
}
|
||||
QUuid thingId = request.value("params").toMap().value("thingId").toUuid();
|
||||
QUuid actionTypeId = request.value("params").toMap().value("actionTypeId").toUuid();
|
||||
QVariantList params = request.value("params").toMap().value("params").toList();
|
||||
|
||||
qDebug() << "**** executeAction:" << thingId << actionTypeId << params;
|
||||
engine->thingManager()->executeAction(thingId, actionTypeId, params);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void AndroidBinder::sendReply(const QAndroidParcel &reply, const QVariantMap ¶ms)
|
||||
{
|
||||
QString payload = QJsonDocument::fromVariant(params).toJson();
|
||||
reply.handle().callMethod<void>("writeString", "(Ljava/lang/String;)V", QAndroidJniObject::fromString(payload).object<jstring>());
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
#ifndef ANDROIDBINDER_H
|
||||
#define ANDROIDBINDER_H
|
||||
|
||||
#include <QAndroidBinder>
|
||||
|
||||
#include "nymeaappservice.h"
|
||||
#include "engine.h"
|
||||
|
||||
class AndroidBinder : public QAndroidBinder
|
||||
{
|
||||
public:
|
||||
explicit AndroidBinder(NymeaAppService *service);
|
||||
|
||||
bool onTransact(int code, const QAndroidParcel &data, const QAndroidParcel &reply, QAndroidBinder::CallType flags) override;
|
||||
|
||||
private:
|
||||
void sendReply(const QAndroidParcel &reply, const QVariantMap ¶ms);
|
||||
|
||||
private:
|
||||
NymeaAppService *m_service = nullptr;
|
||||
};
|
||||
|
||||
#endif // ANDROIDBINDER_H
|
||||
@ -1,83 +0,0 @@
|
||||
#include "nymeaappservice.h"
|
||||
#include "androidbinder.h"
|
||||
|
||||
#include <QtAndroid>
|
||||
#include <QDebug>
|
||||
#include <QSettings>
|
||||
#include <QJsonDocument>
|
||||
|
||||
#include "connection/discovery/nymeadiscovery.h"
|
||||
#include "connection/nymeahosts.h"
|
||||
|
||||
NymeaAppService::NymeaAppService(int argc, char **argv):
|
||||
QAndroidService(argc, argv, [=](const QAndroidIntent &) {
|
||||
return new AndroidBinder{this};
|
||||
})
|
||||
{
|
||||
setApplicationName("nymea-app");
|
||||
setOrganizationName("nymea");
|
||||
|
||||
QSettings settings;
|
||||
|
||||
NymeaDiscovery *discovery = new NymeaDiscovery(this);
|
||||
|
||||
settings.beginGroup("ConfiguredHosts");
|
||||
foreach (const QString &childGroup, settings.childGroups()) {
|
||||
settings.beginGroup(childGroup);
|
||||
QUuid lastConnected = settings.value("uuid").toUuid();
|
||||
QString cachedName = settings.value("cachedName").toString();
|
||||
settings.endGroup();
|
||||
|
||||
if (lastConnected.isNull()) {
|
||||
continue;
|
||||
}
|
||||
NymeaHost *host = discovery->nymeaHosts()->find(lastConnected);
|
||||
if (!host) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Engine *engine = new Engine(this);
|
||||
engine->jsonRpcClient()->connectToHost(host);
|
||||
m_engines.insert(host->uuid(), engine);
|
||||
|
||||
|
||||
QObject::connect(engine->thingManager(), &ThingManager::thingStateChanged, [=](const QUuid &thingId, const QUuid &stateTypeId, const QVariant &value){
|
||||
QVariantMap params;
|
||||
params.insert("nymeaId", engine->jsonRpcClient()->currentHost()->uuid());
|
||||
params.insert("thingId", thingId);
|
||||
params.insert("stateTypeId", stateTypeId);
|
||||
params.insert("value", value);
|
||||
sendNotification("ThingStateChanged", params);
|
||||
});
|
||||
|
||||
connect(engine->thingManager(), &ThingManager::fetchingDataChanged, [=]() {
|
||||
qDebug() << "Fetching data changed";
|
||||
QVariantMap params;
|
||||
params.insert("nymeaId", engine->jsonRpcClient()->currentHost()->uuid());
|
||||
params.insert("isReady", !engine->thingManager()->fetchingData());
|
||||
qDebug() << "Nymea host is ready" << engine->jsonRpcClient()->currentHost()->uuid();
|
||||
sendNotification("ReadyStateChanged", params);
|
||||
});
|
||||
}
|
||||
settings.endGroup();
|
||||
|
||||
qDebug() << "NymeaAppService started.";
|
||||
|
||||
}
|
||||
|
||||
QHash<QUuid, Engine *> NymeaAppService::engines() const
|
||||
{
|
||||
return m_engines;
|
||||
}
|
||||
|
||||
void NymeaAppService::sendNotification(const QString ¬ification, const QVariantMap ¶ms)
|
||||
{
|
||||
QVariantMap data;
|
||||
data.insert("notification", notification);
|
||||
data.insert("params", params);
|
||||
QString payload = QJsonDocument::fromVariant(data).toJson();
|
||||
QtAndroid::androidService().callMethod<void>("sendBroadcast",
|
||||
"(Ljava/lang/String;)V",
|
||||
QAndroidJniObject::fromString(payload).object<jstring>());
|
||||
|
||||
}
|
||||
@ -1,27 +0,0 @@
|
||||
#ifndef NYMEAAPPSERVICE_H
|
||||
#define NYMEAAPPSERVICE_H
|
||||
|
||||
#include <QAndroidService>
|
||||
#include <QNearFieldManager>
|
||||
#include <QNdefMessage>
|
||||
|
||||
#include "engine.h"
|
||||
|
||||
class NymeaAppService : public QAndroidService
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit NymeaAppService(int argc, char** argv);
|
||||
|
||||
QHash<QUuid, Engine*> engines() const;
|
||||
|
||||
private:
|
||||
void sendNotification(const QString ¬ification, const QVariantMap ¶ms);
|
||||
|
||||
|
||||
private:
|
||||
QHash<QUuid, Engine*> m_engines;
|
||||
|
||||
};
|
||||
|
||||
#endif // NYMEAAPPSERVICE_H
|
||||
@ -1,37 +0,0 @@
|
||||
#include <QDebug>
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include "nymeaappservice/nymeaappservice.h"
|
||||
#include "controlviews/devicecontrolapplication.h"
|
||||
|
||||
#include <QCommandLineParser>
|
||||
#include <QLoggingCategory>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
qWarning() << "Service starting from a separate .so file";
|
||||
|
||||
QLoggingCategory::setFilterRules("qt.remoteobjects.debug=true\n");
|
||||
|
||||
QStringList args;
|
||||
for (int i = 0; i < argc; i++) {
|
||||
args.append(QByteArray(argv[i]));
|
||||
qDebug() << "nymea-app: Added command line arg" << args.last();
|
||||
}
|
||||
QCommandLineParser parser;
|
||||
QCommandLineOption controlActivityOption("controlActivity");
|
||||
parser.addOption(controlActivityOption);
|
||||
parser.parse(args);
|
||||
|
||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
|
||||
QCoreApplication *app;
|
||||
if (parser.isSet(controlActivityOption)) {
|
||||
qDebug() << "nymea-app: Starting Device Control Activity";
|
||||
app = new DeviceControlApplication(argc, argv);
|
||||
} else {
|
||||
qDebug() << "nymea-app: Starting NymeaAppService background service";
|
||||
app = new NymeaAppService(argc, argv);
|
||||
}
|
||||
return app->exec();
|
||||
}
|
||||
71
config.h.in.qmake
Normal file
71
config.h.in.qmake
Normal file
@ -0,0 +1,71 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by
|
||||
* copyright law, and remains the property of nymea GmbH. All rights, including
|
||||
* reproduction, publication, editing and translation, are reserved. The use of
|
||||
* this project is subject to the terms of a license agreement to be concluded
|
||||
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
|
||||
* under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under the
|
||||
* terms of the GNU General Public License as published by the Free Software
|
||||
* Foundation, GNU version 3. This project is distributed in the hope that it
|
||||
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this project. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under
|
||||
* contact@nymea.io or see our FAQ/Licensing Information on
|
||||
* https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef VERSION_H
|
||||
#define VERSION_H
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by
|
||||
* copyright law, and remains the property of nymea GmbH. All rights, including
|
||||
* reproduction, publication, editing and translation, are reserved. The use of
|
||||
* this project is subject to the terms of a license agreement to be concluded
|
||||
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
|
||||
* under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under the
|
||||
* terms of the GNU General Public License as published by the Free Software
|
||||
* Foundation, GNU version 3. This project is distributed in the hope that it
|
||||
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this project. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under
|
||||
* contact@nymea.io or see our FAQ/Licensing Information on
|
||||
* https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef VERSION_H
|
||||
#define VERSION_H
|
||||
|
||||
#define APP_VERSION '"$$APP_VERSION"'
|
||||
#define APPLICATION_NAME '"$$APPLICATION_NAME"'
|
||||
#define ORGANISATION_NAME '"$$ORGANISATION_NAME"'
|
||||
|
||||
#endif
|
||||
1
experiences/CMakeLists.txt
Normal file
1
experiences/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
||||
add_subdirectory(airconditioning)
|
||||
31
experiences/airconditioning/CMakeLists.txt
Normal file
31
experiences/airconditioning/CMakeLists.txt
Normal file
@ -0,0 +1,31 @@
|
||||
file(GLOB AIRCONDITIONING_SOURCES CONFIGURE_DEPENDS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
|
||||
)
|
||||
file(GLOB AIRCONDITIONING_HEADERS CONFIGURE_DEPENDS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/*.h
|
||||
)
|
||||
|
||||
add_library(nymea-app-airconditioning STATIC
|
||||
${AIRCONDITIONING_SOURCES}
|
||||
${AIRCONDITIONING_HEADERS}
|
||||
)
|
||||
set_target_properties(nymea-app-airconditioning PROPERTIES OUTPUT_NAME "nymea-app-airconditioning")
|
||||
|
||||
target_include_directories(nymea-app-airconditioning
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_SOURCE_DIR}/libnymea-app
|
||||
${CMAKE_BINARY_DIR}
|
||||
)
|
||||
|
||||
target_link_libraries(nymea-app-airconditioning
|
||||
PUBLIC
|
||||
nymea-app-core
|
||||
Qt6::Core
|
||||
Qt6::Network
|
||||
Qt6::WebSockets
|
||||
Qt6::Bluetooth
|
||||
Qt6::Charts
|
||||
Qt6::Quick
|
||||
Qt6::Qml
|
||||
)
|
||||
@ -10,8 +10,8 @@ include(../../shared.pri)
|
||||
LIBS += -L$${top_builddir}/libnymea-app/ -lnymea-app
|
||||
|
||||
android: {
|
||||
LIBS += -L$${top_builddir}/libnymea-app/$${ANDROID_TARGET_ARCH}
|
||||
PRE_TARGETDEPS += $$top_builddir/libnymea-app/$${ANDROID_TARGET_ARCH}/libnymea-app.a
|
||||
LIBS += -L$${top_builddir}/libnymea-app/$${ANDROID_TARGET_ARCH}
|
||||
PRE_TARGETDEPS += $$top_builddir/libnymea-app/$${ANDROID_TARGET_ARCH}/libnymea-app_$${ANDROID_TARGET_ARCH}.a
|
||||
}
|
||||
|
||||
INCLUDEPATH += $${top_srcdir}/libnymea-app/
|
||||
|
||||
@ -25,8 +25,6 @@
|
||||
#include "airconditioningmanager.h"
|
||||
#include "zoneinfo.h"
|
||||
|
||||
#include "engine.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QMetaEnum>
|
||||
|
||||
|
||||
@ -28,8 +28,7 @@
|
||||
#include <QObject>
|
||||
|
||||
#include "zoneinfo.h"
|
||||
|
||||
class Engine;
|
||||
#include "engine.h"
|
||||
|
||||
class AirConditioningManager : public QObject
|
||||
{
|
||||
|
||||
116
libnymea-app/CMakeLists.txt
Normal file
116
libnymea-app/CMakeLists.txt
Normal file
@ -0,0 +1,116 @@
|
||||
set(LIBNYMEA_APP_SOURCES)
|
||||
file(GLOB_RECURSE LIBNYMEA_APP_SOURCES CONFIGURE_DEPENDS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
|
||||
)
|
||||
file(GLOB_RECURSE LIBNYMEA_APP_HEADERS CONFIGURE_DEPENDS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/*.h
|
||||
)
|
||||
|
||||
set(NYMEA_REMOTEPROXYCLIENT_MODULE
|
||||
${CMAKE_SOURCE_DIR}/nymea-remoteproxy/cmake/nymea-remoteproxyclient-sources.cmake
|
||||
)
|
||||
|
||||
set(REMOTE_PROXYCLIENT_SOURCES)
|
||||
set(REMOTE_PROXYCLIENT_HEADERS)
|
||||
set(REMOTE_PROXYCLIENT_INCLUDE_DIRS)
|
||||
|
||||
if(EXISTS ${NYMEA_REMOTEPROXYCLIENT_MODULE})
|
||||
include(${NYMEA_REMOTEPROXYCLIENT_MODULE})
|
||||
|
||||
if(COMMAND nymea_remoteproxyclient_sources)
|
||||
nymea_remoteproxyclient_sources(
|
||||
REMOTE_PROXYCLIENT_SOURCES
|
||||
REMOTE_PROXYCLIENT_HEADERS
|
||||
REMOTE_PROXYCLIENT_INCLUDE_DIRS
|
||||
)
|
||||
endif()
|
||||
|
||||
if(DEFINED NYMEA_REMOTEPROXYCLIENT_SOURCES)
|
||||
list(APPEND REMOTE_PROXYCLIENT_SOURCES ${NYMEA_REMOTEPROXYCLIENT_SOURCES})
|
||||
endif()
|
||||
if(DEFINED NYMEA_REMOTEPROXYCLIENT_HEADERS)
|
||||
list(APPEND REMOTE_PROXYCLIENT_HEADERS ${NYMEA_REMOTEPROXYCLIENT_HEADERS})
|
||||
endif()
|
||||
if(DEFINED NYMEA_REMOTEPROXYCLIENT_INCLUDE_DIRS)
|
||||
list(APPEND REMOTE_PROXYCLIENT_INCLUDE_DIRS ${NYMEA_REMOTEPROXYCLIENT_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
if(NOT REMOTE_PROXYCLIENT_SOURCES AND NOT REMOTE_PROXYCLIENT_HEADERS)
|
||||
message(FATAL_ERROR
|
||||
"nymea-remoteproxyclient module did not populate its source lists. "
|
||||
"Please ensure nymea-remoteproxy is checked out at the required revision."
|
||||
)
|
||||
endif()
|
||||
else()
|
||||
message(FATAL_ERROR
|
||||
"nymea-remoteproxyclient CMake module not found. Did you initialize the nymea-remoteproxy submodule?"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(NOT REMOTE_PROXYCLIENT_INCLUDE_DIRS)
|
||||
set(_nymea_remoteproxyclient_root
|
||||
${CMAKE_SOURCE_DIR}/nymea-remoteproxy/libnymea-remoteproxyclient
|
||||
)
|
||||
if(EXISTS ${_nymea_remoteproxyclient_root})
|
||||
list(APPEND REMOTE_PROXYCLIENT_INCLUDE_DIRS ${_nymea_remoteproxyclient_root})
|
||||
endif()
|
||||
unset(_nymea_remoteproxyclient_root)
|
||||
endif()
|
||||
|
||||
if(NOT REMOTE_PROXYCLIENT_INCLUDE_DIRS)
|
||||
message(FATAL_ERROR
|
||||
"nymea-remoteproxyclient include directories were not provided by the module. "
|
||||
"Please ensure the nymea-remoteproxy submodule is checked out at the required revision."
|
||||
)
|
||||
endif()
|
||||
|
||||
set(NYMEA_APP_CORE_INCLUDE_DIRS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_BINARY_DIR}
|
||||
)
|
||||
|
||||
list(APPEND NYMEA_APP_CORE_INCLUDE_DIRS ${REMOTE_PROXYCLIENT_INCLUDE_DIRS})
|
||||
|
||||
if(EXISTS ${CMAKE_SOURCE_DIR}/QtZeroConf)
|
||||
list(APPEND NYMEA_APP_CORE_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/QtZeroConf)
|
||||
endif()
|
||||
|
||||
add_library(nymea-app-core STATIC
|
||||
${LIBNYMEA_APP_SOURCES}
|
||||
${LIBNYMEA_APP_HEADERS}
|
||||
${REMOTE_PROXYCLIENT_SOURCES}
|
||||
${REMOTE_PROXYCLIENT_HEADERS}
|
||||
)
|
||||
set_target_properties(nymea-app-core PROPERTIES OUTPUT_NAME "nymea-app")
|
||||
|
||||
list(REMOVE_DUPLICATES NYMEA_APP_CORE_INCLUDE_DIRS)
|
||||
target_include_directories(nymea-app-core PUBLIC ${NYMEA_APP_CORE_INCLUDE_DIRS})
|
||||
|
||||
target_link_libraries(nymea-app-core
|
||||
PUBLIC
|
||||
Qt6::Core
|
||||
Qt6::Network
|
||||
Qt6::WebSockets
|
||||
Qt6::Bluetooth
|
||||
Qt6::Charts
|
||||
Qt6::Quick
|
||||
Qt6::Qml
|
||||
)
|
||||
|
||||
if(TARGET OpenSSL::SSL AND TARGET OpenSSL::Crypto)
|
||||
target_link_libraries(nymea-app-core PUBLIC OpenSSL::SSL OpenSSL::Crypto)
|
||||
else()
|
||||
message(WARNING "OpenSSL development libraries not found; continuing without explicit OpenSSL linkage.")
|
||||
endif()
|
||||
|
||||
if(NYMEA_ENABLE_ZEROCONF)
|
||||
target_compile_definitions(nymea-app-core PUBLIC WITH_ZEROCONF QZEROCONF_STATIC)
|
||||
find_library(QTZEROCONF_LIBRARY NAMES QtZeroConf HINTS ${CMAKE_SOURCE_DIR}/QtZeroConf)
|
||||
if(NOT QTZEROCONF_LIBRARY AND TARGET Qt6::QtZeroConf)
|
||||
target_link_libraries(nymea-app-core PUBLIC Qt6::QtZeroConf)
|
||||
elseif(QTZEROCONF_LIBRARY)
|
||||
target_link_libraries(nymea-app-core PUBLIC ${QTZEROCONF_LIBRARY})
|
||||
else()
|
||||
message(FATAL_ERROR "ZeroConf support requested but QtZeroConf library was not found")
|
||||
endif()
|
||||
endif()
|
||||
@ -52,15 +52,17 @@ public:
|
||||
void addPolicy(MqttPolicy *policy);
|
||||
void removePolicy(MqttPolicy *policy);
|
||||
|
||||
Q_INVOKABLE MqttPolicy* getPolicy(const QString &clientId) const;
|
||||
Q_INVOKABLE MqttPolicy* get(int index) const;
|
||||
Q_INVOKABLE MqttPolicy *getPolicy(const QString &clientId) const;
|
||||
Q_INVOKABLE MqttPolicy *get(int index) const;
|
||||
|
||||
void clear();
|
||||
|
||||
signals:
|
||||
void countChanged();
|
||||
|
||||
private:
|
||||
QList<MqttPolicy*> m_list;
|
||||
QList<MqttPolicy *> m_list;
|
||||
|
||||
};
|
||||
|
||||
#endif // MQTTPOLICIES_H
|
||||
|
||||
@ -133,7 +133,7 @@ signals:
|
||||
void serverNameChanged();
|
||||
|
||||
private:
|
||||
JsonRpcClient* m_client = nullptr;
|
||||
JsonRpcClient *m_client = nullptr;
|
||||
|
||||
bool m_fetchingData = false;
|
||||
bool m_debugServerEnabled = false;
|
||||
|
||||
@ -56,7 +56,7 @@ public:
|
||||
bool sslEnabled() const;
|
||||
void setSslEnabled(bool sslEnabled);
|
||||
|
||||
Q_INVOKABLE virtual ServerConfiguration* clone() const;
|
||||
Q_INVOKABLE virtual ServerConfiguration *clone() const;
|
||||
|
||||
signals:
|
||||
void addressChanged();
|
||||
|
||||
@ -57,8 +57,8 @@ public:
|
||||
|
||||
void clear();
|
||||
|
||||
Q_INVOKABLE ServerConfiguration* get(int index) const;
|
||||
Q_INVOKABLE ServerConfiguration* getConfiguration(const QString &id) const;
|
||||
Q_INVOKABLE ServerConfiguration *get(int index) const;
|
||||
Q_INVOKABLE ServerConfiguration *getConfiguration(const QString &id) const;
|
||||
|
||||
signals:
|
||||
void countChanged();
|
||||
|
||||
@ -24,9 +24,6 @@
|
||||
|
||||
#include "bluetoothservicediscovery.h"
|
||||
|
||||
#include "../nymeahosts.h"
|
||||
#include "../nymeahost.h"
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
#include "logging.h"
|
||||
@ -127,17 +124,6 @@ void BluetoothServiceDiscovery::onServiceDiscovered(const QBluetoothServiceInfo
|
||||
|
||||
if (serviceInfo.serviceClassUuids().first() == QBluetoothUuid(QUuid("997936b5-d2cd-4c57-b41b-c6048320cd2b"))) {
|
||||
qCDebug(dcBluetoothDiscovery()) << "BluetoothServiceDiscovery: Found nymea rfcom service!";
|
||||
|
||||
// NymeaHost* host = m_nymeaHosts->find(serviceInfo.device().address());
|
||||
// if (!host) {
|
||||
// host = new DiscoveryDevice(DiscoveryDevice::DeviceTypeBluetooth, this);
|
||||
// qDebug() << "BluetoothServiceDiscovery: Adding new bluetooth host to model";
|
||||
// host->setName(QString("%1 (%2)").arg(serviceInfo.serviceName()).arg(serviceInfo.device().name()));
|
||||
//// device->setBluetoothAddress(serviceInfo.device().address());
|
||||
// PortConfig pc;
|
||||
|
||||
// m_nymeaHosts->addHost(device);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@ -157,7 +143,6 @@ void BluetoothServiceDiscovery::onServiceDiscoveryFinished()
|
||||
return;
|
||||
}
|
||||
|
||||
// qDebug() << "BluetoothServiceDiscovery: Restart service discovery";
|
||||
discover();
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,7 +36,6 @@ class UpnpDiscovery;
|
||||
class ZeroconfDiscovery;
|
||||
class BluetoothServiceDiscovery;
|
||||
|
||||
|
||||
class NymeaDiscovery : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@ -116,8 +116,13 @@ void UpnpDiscovery::updateInterfaces()
|
||||
}
|
||||
qCInfo(dcUPnP()) << "Discovering on" << netAddressEntry.ip() << port;
|
||||
m_sockets.insert(netAddressEntry.ip(), socket);
|
||||
connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error(QAbstractSocket::SocketError)));
|
||||
|
||||
connect(socket, &QUdpSocket::readyRead, this, &UpnpDiscovery::readData);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5 , 15, 0)
|
||||
connect(socket, &QUdpSocket::errorOccurred, this, &UpnpDiscovery::error);
|
||||
#else
|
||||
connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error(QAbstractSocket::SocketError)));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -45,23 +45,23 @@ ZeroconfDiscovery::ZeroconfDiscovery(NymeaHosts *nymeaHosts, QObject *parent) :
|
||||
connect(m_zeroconfJsonRPC, &QZeroConf::serviceUpdated, this, &ZeroconfDiscovery::serviceEntryAdded);
|
||||
connect(m_zeroconfJsonRPC, &QZeroConf::serviceRemoved, this, &ZeroconfDiscovery::serviceEntryRemoved);
|
||||
|
||||
if (m_zeroconfJsonRPC->isValid()) {
|
||||
// if (m_zeroconfJsonRPC->isValid()) {
|
||||
m_zeroconfJsonRPC->startBrowser("_jsonrpc._tcp", QAbstractSocket::IPv4Protocol);
|
||||
qCInfo(dcZeroConf()) << "Created service browser for _jsonrpc._tcp:" << m_zeroconfJsonRPC->browserExists();
|
||||
} else {
|
||||
qCWarning(dcZeroConf()) << "Failed to initialize service broeser for _jsonprc._tcp";
|
||||
}
|
||||
// } else {
|
||||
// qCWarning(dcZeroConf()) << "Failed to initialize service broeser for _jsonprc._tcp";
|
||||
// }
|
||||
|
||||
m_zeroconfWebSocket = new QZeroConf(this);
|
||||
connect(m_zeroconfWebSocket, &QZeroConf::serviceAdded, this, &ZeroconfDiscovery::serviceEntryAdded);
|
||||
connect(m_zeroconfWebSocket, &QZeroConf::serviceUpdated, this, &ZeroconfDiscovery::serviceEntryAdded);
|
||||
connect(m_zeroconfWebSocket, &QZeroConf::serviceRemoved, this, &ZeroconfDiscovery::serviceEntryRemoved);
|
||||
if (m_zeroconfWebSocket->isValid()) {
|
||||
// if (m_zeroconfWebSocket->isValid()) {
|
||||
m_zeroconfWebSocket->startBrowser("_ws._tcp", QAbstractSocket::IPv4Protocol);
|
||||
qCInfo(dcZeroConf()) << "Created service browser for _ws._tcp:" << m_zeroconfWebSocket->browserExists();
|
||||
} else {
|
||||
qCWarning(dcZeroConf()) << "Failed to initialize service browserr for _ws._tcp";
|
||||
}
|
||||
// } else {
|
||||
// qCWarning(dcZeroConf()) << "Failed to initialize service browserr for _ws._tcp";
|
||||
// }
|
||||
|
||||
#else
|
||||
qCInfo(dcZeroConf()) << "Zeroconf support not compiled in. Zeroconf will not be available.";
|
||||
|
||||
@ -38,6 +38,25 @@ NetworkReachabilityMonitor::NetworkReachabilityMonitor(QObject *parent)
|
||||
setupIOS();
|
||||
#endif
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
|
||||
m_networkInformation = QNetworkInformation::instance();
|
||||
|
||||
qCDebug(dcNymeaConnection()) << "Network infromation supported features:" << m_networkInformation->supportedFeatures();
|
||||
qCDebug(dcNymeaConnection()) << "Network reachability:" << m_networkInformation->reachability();
|
||||
qCDebug(dcNymeaConnection()) << "Network trasport medium changed:" << m_networkInformation->transportMedium();
|
||||
|
||||
QObject::connect(m_networkInformation, &QNetworkInformation::reachabilityChanged, this, [this](QNetworkInformation::Reachability reachability){
|
||||
qCDebug(dcNymeaConnection()) << "Network reachability changed:" << reachability;
|
||||
updateActiveBearers();
|
||||
});
|
||||
|
||||
QObject::connect(m_networkInformation, &QNetworkInformation::transportMediumChanged, this, [this](QNetworkInformation::TransportMedium type){
|
||||
qCDebug(dcNymeaConnection()) << "Network trasport medium changed:" << type;
|
||||
updateActiveBearers();
|
||||
});
|
||||
|
||||
#else
|
||||
m_networkConfigManager = new QNetworkConfigurationManager(this);
|
||||
|
||||
QObject::connect(m_networkConfigManager, &QNetworkConfigurationManager::configurationAdded, this, [this](const QNetworkConfiguration &config){
|
||||
@ -50,6 +69,7 @@ NetworkReachabilityMonitor::NetworkReachabilityMonitor(QObject *parent)
|
||||
qCDebug(dcNymeaConnection()) << "Network configuration removed:" << config.name() << config.bearerTypeName() << config.purpose();
|
||||
updateActiveBearers();
|
||||
});
|
||||
#endif
|
||||
|
||||
QGuiApplication *app = static_cast<QGuiApplication*>(QGuiApplication::instance());
|
||||
QObject::connect(app, &QGuiApplication::applicationStateChanged, this, [this](Qt::ApplicationState state) {
|
||||
@ -58,7 +78,6 @@ NetworkReachabilityMonitor::NetworkReachabilityMonitor(QObject *parent)
|
||||
});
|
||||
|
||||
updateActiveBearers();
|
||||
|
||||
}
|
||||
|
||||
NetworkReachabilityMonitor::~NetworkReachabilityMonitor()
|
||||
@ -80,6 +99,16 @@ void NetworkReachabilityMonitor::updateActiveBearers()
|
||||
#endif
|
||||
|
||||
NymeaConnection::BearerTypes availableBearerTypes;
|
||||
|
||||
// Note: some features are availabe since Qt 6.3.0, but the minimal Qt6 version is 6.6.0,
|
||||
// so we don't want so have an unhanlded gap and let the compiler warn about incompatibility
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
if (m_networkInformation->reachability() == QNetworkInformation::Reachability::Disconnected) {
|
||||
qCDebug(dcNymeaConnection()) << "No reachable network transport medium available.";
|
||||
} else {
|
||||
availableBearerTypes.setFlag(qBearerTypeToNymeaBearerType(m_networkInformation->transportMedium()));
|
||||
}
|
||||
#else
|
||||
QList<QNetworkConfiguration> configs = m_networkConfigManager->allConfigurations(QNetworkConfiguration::Active);
|
||||
qCDebug(dcNymeaConnection()) << "Network configuations:" << configs.count();
|
||||
foreach (const QNetworkConfiguration &config, configs) {
|
||||
@ -97,6 +126,7 @@ void NetworkReachabilityMonitor::updateActiveBearers()
|
||||
qCDebug(dcNymeaConnection()) << "Updating network manager";
|
||||
m_networkConfigManager->updateConfigurations();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_availableBearerTypes != availableBearerTypes) {
|
||||
qCInfo(dcNymeaConnection()) << "Available Bearer Types changed to:" << availableBearerTypes;
|
||||
@ -109,6 +139,27 @@ void NetworkReachabilityMonitor::updateActiveBearers()
|
||||
emit availableBearerTypesUpdated();
|
||||
}
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
NymeaConnection::BearerType NetworkReachabilityMonitor::qBearerTypeToNymeaBearerType(QNetworkInformation::TransportMedium type)
|
||||
{
|
||||
switch (type) {
|
||||
case QNetworkInformation::TransportMedium::Unknown:
|
||||
// Unable to determine the connection type. Assume it's something we can establish any connection type on
|
||||
return NymeaConnection::BearerTypeAll;
|
||||
case QNetworkInformation::TransportMedium::Ethernet:
|
||||
return NymeaConnection::BearerTypeEthernet;
|
||||
case QNetworkInformation::TransportMedium::Cellular:
|
||||
return NymeaConnection::BearerTypeMobileData;
|
||||
case QNetworkInformation::TransportMedium::WiFi:
|
||||
return NymeaConnection::BearerTypeWiFi;
|
||||
case QNetworkInformation::TransportMedium::Bluetooth:
|
||||
// Note: Do not confuse this with the Bluetooth transport... For Qt, this means IP over BT, not RFCOMM as we do it.
|
||||
return NymeaConnection::BearerTypeBluetooth;
|
||||
}
|
||||
|
||||
return NymeaConnection::BearerTypeAll;
|
||||
}
|
||||
#else
|
||||
NymeaConnection::BearerType NetworkReachabilityMonitor::qBearerTypeToNymeaBearerType(QNetworkConfiguration::BearerType type)
|
||||
{
|
||||
switch (type) {
|
||||
@ -130,9 +181,11 @@ NymeaConnection::BearerType NetworkReachabilityMonitor::qBearerTypeToNymeaBearer
|
||||
case QNetworkConfiguration::Bearer4G:
|
||||
return NymeaConnection::BearerTypeMobileData;
|
||||
case QNetworkConfiguration::BearerBluetooth:
|
||||
// Note: Do not confuse this with the Bluetooth transport... For Qt, this means IP over BT, not RFCOMM as we do it.
|
||||
// Note: Do not confuse this with the Bluetooth transport... For Qt, this means IP over BT, not RFCOMM as we do it.
|
||||
return NymeaConnection::BearerTypeNone;
|
||||
}
|
||||
return NymeaConnection::BearerTypeAll;
|
||||
|
||||
return NymeaConnection::BearerTypeAll;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -26,14 +26,19 @@
|
||||
#define NETWORKREACHABILITYMONITOR_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QNetworkConfigurationManager>
|
||||
|
||||
#include "nymeaconnection.h"
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
#include <QNetworkConfigurationManager>
|
||||
#else
|
||||
#include <QNetworkInformation>
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#import <SystemConfiguration/SystemConfiguration.h>
|
||||
#endif
|
||||
|
||||
#include "nymeaconnection.h"
|
||||
|
||||
class NetworkReachabilityMonitor : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -52,10 +57,16 @@ private slots:
|
||||
void updateActiveBearers();
|
||||
|
||||
private:
|
||||
QNetworkConfigurationManager *m_networkConfigManager = nullptr;
|
||||
NymeaConnection::BearerTypes m_availableBearerTypes = NymeaConnection::BearerTypeNone;
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
|
||||
QNetworkInformation *m_networkInformation = nullptr;
|
||||
static NymeaConnection::BearerType qBearerTypeToNymeaBearerType(QNetworkInformation::TransportMedium type);
|
||||
#else
|
||||
QNetworkConfigurationManager *m_networkConfigManager = nullptr;
|
||||
static NymeaConnection::BearerType qBearerTypeToNymeaBearerType(QNetworkConfiguration::BearerType type);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
void setupIOS();
|
||||
|
||||
@ -45,18 +45,21 @@ NYMEA_LOGGING_CATEGORY(dcNymeaConnection, "NymeaConnection")
|
||||
|
||||
NymeaConnection::NymeaConnection(QObject *parent) : QObject(parent)
|
||||
{
|
||||
// m_networkConfigManager = new QNetworkConfigurationManager(this);
|
||||
m_networkReachabilityMonitor = new NetworkReachabilityMonitor(this);
|
||||
connect(m_networkReachabilityMonitor, &NetworkReachabilityMonitor::availableBearerTypesChanged, this, &NymeaConnection::availableBearerTypesChanged);
|
||||
connect(m_networkReachabilityMonitor, &NetworkReachabilityMonitor::availableBearerTypesUpdated, this, &NymeaConnection::onAvailableBearerTypesUpdated);
|
||||
|
||||
// QObject::connect(m_networkConfigManager, &QNetworkConfigurationManager::configurationAdded, this, [this](const QNetworkConfiguration &config){
|
||||
// Q_UNUSED(config)
|
||||
// qCDebug(dcNymeaConnection()) << "Network configuration added:" << config.name() << config.bearerTypeName() << config.purpose();
|
||||
// updateActiveBearers();
|
||||
// });
|
||||
// QObject::connect(m_networkConfigManager, &QNetworkConfigurationManager::configurationRemoved, this, [this](const QNetworkConfiguration &config){
|
||||
// Q_UNUSED(config)
|
||||
// qCDebug(dcNymeaConnection()) << "Network configuration removed:" << config.name() << config.bearerTypeName() << config.purpose();
|
||||
// updateActiveBearers();
|
||||
// });
|
||||
#ifdef Q_OS_IOS
|
||||
connect(m_networkReachabilityMonitor, &NetworkReachabilityMonitor::availableBearerTypesChanged, this, [this](){
|
||||
if (m_currentTransport) {
|
||||
qCInfo(dcNymeaConnection()) << "Available bearer types changed:" << m_networkReachabilityMonitor->availableBearerTypes() << "currently used:" << m_usedBearerType;
|
||||
if (!m_networkReachabilityMonitor->availableBearerTypes().testFlag(m_usedBearerType)) {
|
||||
qCInfo(dcNymeaConnection()) << "Used bearer type" << m_usedBearerType << "isn't available any more. Reconnecting.";
|
||||
m_currentTransport->disconnect();
|
||||
}
|
||||
}
|
||||
});
|
||||
#endif
|
||||
|
||||
QGuiApplication *app = static_cast<QGuiApplication*>(QGuiApplication::instance());
|
||||
QObject::connect(app, &QGuiApplication::applicationStateChanged, this, [app, this](Qt::ApplicationState state) {
|
||||
@ -313,18 +316,18 @@ void NymeaConnection::onConnected()
|
||||
newTransport->deleteLater();
|
||||
|
||||
|
||||
// Connection *existingConnection = m_transportCandidates.value(m_currentTransport);
|
||||
// Connection *alternativeConnection = m_transportCandidates.value(newTransport);
|
||||
// if (alternativeConnection->priority() > existingConnection->priority()) {
|
||||
// qDebug() << "New connection has higher priority! Roaming from" << existingConnection->url() << existingConnection->priority() << "to" << alternativeConnection->url() << alternativeConnection->priority();
|
||||
// m_transportCandidates.remove(m_currentTransport);
|
||||
// m_currentTransport->deleteLater();
|
||||
// m_currentTransport = newTransport;
|
||||
// } else {
|
||||
// qDebug() << "Connection" << alternativeConnection->url() << alternativeConnection->priority() << "has lower priority than existing" << existingConnection->url() << existingConnection->priority();
|
||||
// m_transportCandidates.remove(newTransport);
|
||||
// newTransport->deleteLater();
|
||||
// }
|
||||
// Connection *existingConnection = m_transportCandidates.value(m_currentTransport);
|
||||
// Connection *alternativeConnection = m_transportCandidates.value(newTransport);
|
||||
// if (alternativeConnection->priority() > existingConnection->priority()) {
|
||||
// qDebug() << "New connection has higher priority! Roaming from" << existingConnection->url() << existingConnection->priority() << "to" << alternativeConnection->url() << alternativeConnection->priority();
|
||||
// m_transportCandidates.remove(m_currentTransport);
|
||||
// m_currentTransport->deleteLater();
|
||||
// m_currentTransport = newTransport;
|
||||
// } else {
|
||||
// qDebug() << "Connection" << alternativeConnection->url() << alternativeConnection->priority() << "has lower priority than existing" << existingConnection->url() << existingConnection->priority();
|
||||
// m_transportCandidates.remove(newTransport);
|
||||
// newTransport->deleteLater();
|
||||
// }
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -386,7 +389,7 @@ void NymeaConnection::onDataAvailable(const QByteArray &data)
|
||||
{
|
||||
NymeaTransportInterface *t = static_cast<NymeaTransportInterface*>(sender());
|
||||
if (t == m_currentTransport) {
|
||||
// qCDebug(dcNymeaConnection()) << "Data available";
|
||||
// qCDebug(dcNymeaConnection()) << "Data available";
|
||||
emit dataAvailable(data);
|
||||
} else {
|
||||
qCDebug(dcNymeaConnection()) << "Received data from a transport that is not the current one:" << t->url();
|
||||
@ -395,39 +398,6 @@ void NymeaConnection::onDataAvailable(const QByteArray &data)
|
||||
|
||||
void NymeaConnection::onAvailableBearerTypesUpdated()
|
||||
{
|
||||
NymeaConnection::BearerTypes availableBearerTypes;
|
||||
// QList<QNetworkConfiguration> configs = m_networkConfigManager->allConfigurations(QNetworkConfiguration::Active);
|
||||
// qCDebug(dcNymeaConnection()) << "Network configuations:" << configs.count();
|
||||
// foreach (const QNetworkConfiguration &config, configs) {
|
||||
// qCDebug(dcNymeaConnection()) << "Active network config:" << config.name() << config.bearerTypeFamily() << config.bearerTypeName();
|
||||
|
||||
// // NOTE: iOS doesn't correctly report bearer types. It'll be Unknown all the time. Let's hardcode it to WiFi for that...
|
||||
//#if defined(Q_OS_IOS)
|
||||
availableBearerTypes.setFlag(NymeaConnection::BearerTypeWiFi);
|
||||
//#else
|
||||
// availableBearerTypes.setFlag(qBearerTypeToNymeaBearerType(config.bearerType()));
|
||||
//#endif
|
||||
// }
|
||||
// if (availableBearerTypes == NymeaConnection::BearerTypeNone) {
|
||||
// // This is just debug info... On some platform bearer management seems a bit broken, so let's get some infos right away...
|
||||
// qCDebug(dcNymeaConnection()) << "No active bearer available. Inactive bearers are:";
|
||||
// QList<QNetworkConfiguration> configs = m_networkConfigManager->allConfigurations();
|
||||
// foreach (const QNetworkConfiguration &config, configs) {
|
||||
// qCDebug(dcNymeaConnection()) << "Inactive network config:" << config.name() << config.bearerTypeFamily() << config.bearerTypeName();
|
||||
// }
|
||||
|
||||
// qCDebug(dcNymeaConnection()) << "Updating network manager";
|
||||
// m_networkConfigManager->updateConfigurations();
|
||||
// }
|
||||
|
||||
if (m_availableBearerTypes != availableBearerTypes) {
|
||||
qCInfo(dcNymeaConnection()) << "Available Bearer Types changed to:" << availableBearerTypes;
|
||||
m_availableBearerTypes = availableBearerTypes;
|
||||
emit availableBearerTypesChanged();
|
||||
} else {
|
||||
qCDebug(dcNymeaConnection()) << "Available Bearer Types:" << availableBearerTypes;
|
||||
}
|
||||
|
||||
if (!m_currentHost) {
|
||||
// No host set... Nothing to do...
|
||||
qCInfo(dcNymeaConnection()) << "No current host... Nothing to do...";
|
||||
@ -446,7 +416,7 @@ void NymeaConnection::onAvailableBearerTypesUpdated()
|
||||
if (!m_currentTransport) {
|
||||
// There's a host but no connection. Try connecting now...
|
||||
qCInfo(dcNymeaConnection()) << "There's a host but no connection. Trying to connect now...";
|
||||
connectInternal(m_currentHost);
|
||||
//connectInternal(m_currentHost);
|
||||
}
|
||||
}
|
||||
|
||||
@ -493,7 +463,7 @@ void NymeaConnection::connectInternal(NymeaHost *host)
|
||||
connectInternal(loopbackConnection);
|
||||
|
||||
} else if (m_networkReachabilityMonitor->availableBearerTypes().testFlag(NymeaConnection::BearerTypeWiFi)
|
||||
|| m_networkReachabilityMonitor->availableBearerTypes().testFlag(NymeaConnection::BearerTypeEthernet)) {
|
||||
|| m_networkReachabilityMonitor->availableBearerTypes().testFlag(NymeaConnection::BearerTypeEthernet)) {
|
||||
Connection* lanConnection = host->connections()->bestMatch(Connection::BearerTypeLan | Connection::BearerTypeWan);
|
||||
if (lanConnection) {
|
||||
qCDebug(dcNymeaConnection()) << "Best candidate LAN/WAN connection:" << lanConnection->url();
|
||||
@ -554,44 +524,17 @@ bool NymeaConnection::connectInternal(Connection *connection)
|
||||
return newTransport->connect(connection->url());
|
||||
}
|
||||
|
||||
//NymeaConnection::BearerType NymeaConnection::qBearerTypeToNymeaBearerType(QNetworkConfiguration::BearerType type) const
|
||||
//{
|
||||
// switch (type) {
|
||||
// case QNetworkConfiguration::BearerUnknown:
|
||||
// // Unable to determine the connection type. Assume it's something we can establish any connection type on
|
||||
// return BearerTypeAll;
|
||||
// case QNetworkConfiguration::BearerEthernet:
|
||||
// return BearerTypeEthernet;
|
||||
// case QNetworkConfiguration::BearerWLAN:
|
||||
// return BearerTypeWiFi;
|
||||
// case QNetworkConfiguration::Bearer2G:
|
||||
// case QNetworkConfiguration::BearerCDMA2000:
|
||||
// case QNetworkConfiguration::BearerWCDMA:
|
||||
// case QNetworkConfiguration::BearerHSPA:
|
||||
// case QNetworkConfiguration::BearerWiMAX:
|
||||
// case QNetworkConfiguration::BearerEVDO:
|
||||
// case QNetworkConfiguration::BearerLTE:
|
||||
// case QNetworkConfiguration::Bearer3G:
|
||||
// case QNetworkConfiguration::Bearer4G:
|
||||
// return BearerTypeMobileData;
|
||||
// case QNetworkConfiguration::BearerBluetooth:
|
||||
// // Note: Do not confuse this with the Bluetooth transport... For Qt, this means IP over BT, not RFCOMM as we do it.
|
||||
// return BearerTypeNone;
|
||||
// }
|
||||
// return BearerTypeAll;
|
||||
//}
|
||||
|
||||
bool NymeaConnection::isConnectionBearerAvailable(Connection::BearerType connectionBearerType) const
|
||||
{
|
||||
switch (connectionBearerType) {
|
||||
case Connection::BearerTypeLan:
|
||||
return availableBearerTypes().testFlag(BearerTypeEthernet)
|
||||
|| availableBearerTypes().testFlag(BearerTypeWiFi);
|
||||
|| availableBearerTypes().testFlag(BearerTypeWiFi);
|
||||
case Connection::BearerTypeWan:
|
||||
case Connection::BearerTypeCloud:
|
||||
return availableBearerTypes().testFlag(BearerTypeEthernet)
|
||||
|| availableBearerTypes().testFlag(BearerTypeWiFi)
|
||||
|| availableBearerTypes().testFlag(BearerTypeMobileData);
|
||||
|| availableBearerTypes().testFlag(BearerTypeWiFi)
|
||||
|| availableBearerTypes().testFlag(BearerTypeMobileData);
|
||||
case Connection::BearerTypeBluetooth:
|
||||
return availableBearerTypes().testFlag(BearerTypeBluetooth);
|
||||
case Connection::BearerTypeUnknown:
|
||||
|
||||
@ -30,9 +30,14 @@
|
||||
#include <QSslError>
|
||||
#include <QAbstractSocket>
|
||||
#include <QUrl>
|
||||
//#include <QNetworkConfigurationManager>
|
||||
#include <QTimer>
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
#include <QNetworkConfigurationManager>
|
||||
#else
|
||||
#include <QNetworkInformation>
|
||||
#endif
|
||||
|
||||
#include "nymeahost.h"
|
||||
|
||||
class NymeaTransportInterface;
|
||||
@ -125,8 +130,7 @@ private:
|
||||
|
||||
private:
|
||||
ConnectionStatus m_connectionStatus = ConnectionStatusUnconnected;
|
||||
// QNetworkConfigurationManager *m_networkConfigManager = nullptr;
|
||||
NymeaConnection::BearerTypes m_availableBearerTypes = BearerTypeNone;
|
||||
NetworkReachabilityMonitor *m_networkReachabilityMonitor = nullptr;
|
||||
|
||||
QHash<QString, NymeaTransportInterfaceFactory *> m_transportFactories;
|
||||
QHash<NymeaTransportInterface *, Connection *> m_transportCandidates;
|
||||
|
||||
@ -23,9 +23,8 @@
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "nymeahosts.h"
|
||||
#include "connection/discovery/nymeadiscovery.h"
|
||||
#include "nymeahost.h"
|
||||
#include "jsonrpc/jsonrpcclient.h"
|
||||
|
||||
#include <QUuid>
|
||||
|
||||
NymeaHosts::NymeaHosts(QObject *parent) :
|
||||
|
||||
@ -29,8 +29,11 @@
|
||||
#include <QList>
|
||||
#include <QBluetoothAddress>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include "nymeahost.h"
|
||||
|
||||
class JsonRpcClient;
|
||||
class NymeaDiscovery;
|
||||
|
||||
class NymeaHosts : public QAbstractListModel
|
||||
{
|
||||
@ -74,49 +77,49 @@ private:
|
||||
QList<NymeaHost *> m_hosts;
|
||||
};
|
||||
|
||||
class NymeaHostsFilterModel: public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
|
||||
Q_PROPERTY(NymeaDiscovery* discovery READ discovery WRITE setDiscovery NOTIFY discoveryChanged)
|
||||
Q_PROPERTY(JsonRpcClient* jsonRpcClient READ jsonRpcClient WRITE setJsonRpcClient NOTIFY jsonRpcClientChanged)
|
||||
Q_PROPERTY(bool showUnreachableBearers READ showUnreachableBearers WRITE setShowUnreachableBearers NOTIFY showUnreachableBearersChanged)
|
||||
Q_PROPERTY(bool showUnreachableHosts READ showUnreachableHosts WRITE setShowUnreachableHosts NOTIFY showUnreachableHostsChanged)
|
||||
// class NymeaHostsFilterModel: public QSortFilterProxyModel
|
||||
// {
|
||||
// Q_OBJECT
|
||||
// Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
|
||||
// Q_PROPERTY(NymeaDiscovery* discovery READ discovery WRITE setDiscovery NOTIFY discoveryChanged)
|
||||
// Q_PROPERTY(JsonRpcClient* jsonRpcClient READ jsonRpcClient WRITE setJsonRpcClient NOTIFY jsonRpcClientChanged)
|
||||
// Q_PROPERTY(bool showUnreachableBearers READ showUnreachableBearers WRITE setShowUnreachableBearers NOTIFY showUnreachableBearersChanged)
|
||||
// Q_PROPERTY(bool showUnreachableHosts READ showUnreachableHosts WRITE setShowUnreachableHosts NOTIFY showUnreachableHostsChanged)
|
||||
|
||||
public:
|
||||
NymeaHostsFilterModel(QObject *parent = nullptr);
|
||||
// public:
|
||||
// NymeaHostsFilterModel(QObject *parent = nullptr);
|
||||
|
||||
NymeaDiscovery *discovery() const;
|
||||
void setDiscovery(NymeaDiscovery *discovery);
|
||||
// NymeaDiscovery *discovery() const;
|
||||
// void setDiscovery(NymeaDiscovery *discovery);
|
||||
|
||||
JsonRpcClient *jsonRpcClient() const;
|
||||
void setJsonRpcClient(JsonRpcClient* jsonRpcClient);
|
||||
// JsonRpcClient *jsonRpcClient() const;
|
||||
// void setJsonRpcClient(JsonRpcClient* jsonRpcClient);
|
||||
|
||||
bool showUnreachableBearers() const;
|
||||
void setShowUnreachableBearers(bool showUnreachableBearers);
|
||||
// bool showUnreachableBearers() const;
|
||||
// void setShowUnreachableBearers(bool showUnreachableBearers);
|
||||
|
||||
bool showUnreachableHosts() const;
|
||||
void setShowUnreachableHosts(bool showUnreachableHosts);
|
||||
// bool showUnreachableHosts() const;
|
||||
// void setShowUnreachableHosts(bool showUnreachableHosts);
|
||||
|
||||
Q_INVOKABLE NymeaHost* get(int index) const;
|
||||
// Q_INVOKABLE NymeaHost *get(int index) const;
|
||||
|
||||
signals:
|
||||
void countChanged();
|
||||
void discoveryChanged();
|
||||
void jsonRpcClientChanged();
|
||||
void showUnreachableBearersChanged();
|
||||
void showUnreachableHostsChanged();
|
||||
// signals:
|
||||
// void countChanged();
|
||||
// void discoveryChanged();
|
||||
// void jsonRpcClientChanged();
|
||||
// void showUnreachableBearersChanged();
|
||||
// void showUnreachableHostsChanged();
|
||||
|
||||
protected:
|
||||
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
|
||||
// protected:
|
||||
// bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
|
||||
|
||||
private:
|
||||
NymeaDiscovery *m_nymeaDiscovery = nullptr;
|
||||
JsonRpcClient *m_jsonRpcClient = nullptr;
|
||||
// private:
|
||||
// NymeaDiscovery *m_nymeaDiscovery = nullptr;
|
||||
// JsonRpcClient *m_jsonRpcClient = nullptr;
|
||||
|
||||
bool m_showUneachableBearers = false;
|
||||
bool m_showUneachableHosts = false;
|
||||
// bool m_showUneachableBearers = false;
|
||||
// bool m_showUneachableHosts = false;
|
||||
|
||||
};
|
||||
// };
|
||||
|
||||
#endif // NYMEAHOSTS_H
|
||||
|
||||
@ -59,7 +59,7 @@ bool TunnelProxyTransport::connect(const QUrl &url)
|
||||
serverUrl.setScheme(url.scheme() == "tunnels" ? "ssl" : "tcp");
|
||||
serverUrl.setHost(url.host());
|
||||
serverUrl.setPort(url.port());
|
||||
QUuid serverUuid = QUrlQuery(url).queryItemValue("uuid");
|
||||
QUuid serverUuid(QUrlQuery(url).queryItemValue("uuid"));
|
||||
|
||||
return m_remoteConnection->connectServer(serverUrl, serverUuid);
|
||||
}
|
||||
|
||||
@ -48,21 +48,6 @@ Engine::Engine(QObject *parent) :
|
||||
|
||||
connect(m_thingManager, &ThingManager::fetchingDataChanged, this, &Engine::onThingManagerFetchingChanged);
|
||||
|
||||
connect(m_jsonRpcClient, &JsonRpcClient::connectedChanged, this, [this]() {
|
||||
qDebug() << "JSONRpc connected changed:" << m_jsonRpcClient->connected() << "AWS status:" << AWSClient::instance()->awsDevices()->rowCount();
|
||||
if (m_jsonRpcClient->connected() && m_jsonRpcClient->cloudConnectionState() == JsonRpcClient::CloudConnectionStateConnected) {
|
||||
if (AWSClient::instance()->awsDevices()->getDevice(m_jsonRpcClient->serverUuid().toString()) == nullptr) {
|
||||
m_jsonRpcClient->setupRemoteAccess(AWSClient::instance()->idToken(), AWSClient::instance()->userId());
|
||||
}
|
||||
}
|
||||
});
|
||||
connect(m_jsonRpcClient, &JsonRpcClient::cloudConnectionStateChanged, this, [this](){
|
||||
if (m_jsonRpcClient->connected() && m_jsonRpcClient->cloudConnectionState() == JsonRpcClient::CloudConnectionStateConnected) {
|
||||
if (AWSClient::instance()->awsDevices()->getDevice(m_jsonRpcClient->serverUuid().toString()) == nullptr) {
|
||||
m_jsonRpcClient->setupRemoteAccess(AWSClient::instance()->idToken(), AWSClient::instance()->userId());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ThingManager *Engine::thingManager() const
|
||||
@ -105,22 +90,6 @@ SystemController *Engine::systemController() const
|
||||
return m_systemController;
|
||||
}
|
||||
|
||||
void Engine::deployCertificate()
|
||||
{
|
||||
if (!m_jsonRpcClient->connected()) {
|
||||
qWarning() << "JSONRPC not connected. Cannot deploy certificate";
|
||||
return;
|
||||
}
|
||||
if (!AWSClient::instance()->isLoggedIn()) {
|
||||
qWarning() << "Not logged in at AWS. Cannot deploy certificate";
|
||||
return;
|
||||
}
|
||||
AWSClient::instance()->fetchCertificate(m_jsonRpcClient->serverUuid().toString(), [this](const QByteArray &rootCA, const QByteArray &certificate, const QByteArray &publicKey, const QByteArray &privateKey, const QString &endpoint){
|
||||
qDebug() << "Certificate received" << certificate << publicKey << privateKey;
|
||||
m_jsonRpcClient->deployCertificate(rootCA, certificate, publicKey, privateKey, endpoint);
|
||||
});
|
||||
}
|
||||
|
||||
void Engine::onConnectedChanged()
|
||||
{
|
||||
qDebug() << "Engine: connected changed:" << m_jsonRpcClient->connected();
|
||||
|
||||
@ -154,10 +154,10 @@ void InterfacesModel::syncInterfaces()
|
||||
}
|
||||
}
|
||||
|
||||
qWarning() << "syncing for interfaces:" << m_shownInterfaces;
|
||||
// qWarning() << "syncing for interfaces:" << m_shownInterfaces;
|
||||
QStringList interfacesInSource;
|
||||
foreach (ThingClass *dc, thingClasses) {
|
||||
// qWarning() << "thing" <<dc->name() << "has interfaces" << dc->interfaces();
|
||||
// qWarning() << "thing" <<dc->name() << "has interfaces" << dc->interfaces();
|
||||
|
||||
bool isInShownIfaces = false;
|
||||
foreach (const QString &interface, dc->interfaces()) {
|
||||
@ -168,7 +168,7 @@ void InterfacesModel::syncInterfaces()
|
||||
if (!interfacesInSource.contains(interface)) {
|
||||
interfacesInSource.append(interface);
|
||||
}
|
||||
// qWarning() << "yes" << interface;
|
||||
// qWarning() << "yes" << interface;
|
||||
isInShownIfaces = true;
|
||||
}
|
||||
if (m_showUncategorized && !isInShownIfaces && !interfacesInSource.contains("uncategorized")) {
|
||||
|
||||
@ -307,7 +307,7 @@ QString JsonRpcClient::jsonRpcVersion() const
|
||||
|
||||
QUuid JsonRpcClient::serverUuid() const
|
||||
{
|
||||
return m_connection && m_connection->currentHost() ? m_connection->currentHost()->uuid().toString() : "";
|
||||
return m_connection && m_connection->currentHost() ? m_connection->currentHost()->uuid() : QUuid();
|
||||
}
|
||||
|
||||
QString JsonRpcClient::serverName() const
|
||||
|
||||
@ -11,7 +11,6 @@
|
||||
|
||||
include(../nymea-remoteproxy/libnymea-remoteproxyclient/libnymea-remoteproxyclient.pri)
|
||||
|
||||
|
||||
QT -= gui
|
||||
QT += network websockets bluetooth charts quick
|
||||
|
||||
|
||||
@ -46,12 +46,12 @@ void BoolSeriesAdapter::setLogsModel(LogsModel *logsModel)
|
||||
|
||||
}
|
||||
|
||||
QtCharts::QXYSeries *BoolSeriesAdapter::xySeries() const
|
||||
QXYSeries *BoolSeriesAdapter::xySeries() const
|
||||
{
|
||||
return m_series;
|
||||
}
|
||||
|
||||
void BoolSeriesAdapter::setXySeries(QtCharts::QXYSeries *series)
|
||||
void BoolSeriesAdapter::setXySeries(QXYSeries *series)
|
||||
{
|
||||
if (m_series != series) {
|
||||
m_series = series;
|
||||
|
||||
@ -34,7 +34,7 @@ class BoolSeriesAdapter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(LogsModel* logsModel READ logsModel WRITE setLogsModel NOTIFY logsModelChanged)
|
||||
Q_PROPERTY(QtCharts::QXYSeries* xySeries READ xySeries WRITE setXySeries NOTIFY xySeriesChanged)
|
||||
Q_PROPERTY(QXYSeries* xySeries READ xySeries WRITE setXySeries NOTIFY xySeriesChanged)
|
||||
|
||||
Q_PROPERTY(bool inverted READ inverted WRITE setInverted NOTIFY invertedChanged)
|
||||
|
||||
@ -44,8 +44,8 @@ public:
|
||||
LogsModel* logsModel() const;
|
||||
void setLogsModel(LogsModel *logsModel);
|
||||
|
||||
QtCharts::QXYSeries* xySeries() const;
|
||||
void setXySeries(QtCharts::QXYSeries *series);
|
||||
QXYSeries* xySeries() const;
|
||||
void setXySeries(QXYSeries *series);
|
||||
|
||||
bool inverted() const;
|
||||
void setInverted(bool inverted);
|
||||
@ -65,7 +65,7 @@ private:
|
||||
|
||||
private:
|
||||
LogsModel* m_model = nullptr;
|
||||
QtCharts::QXYSeries* m_series = nullptr;
|
||||
QXYSeries* m_series = nullptr;
|
||||
bool m_inverted = false;
|
||||
|
||||
};
|
||||
|
||||
@ -460,7 +460,7 @@ void NewLogsModel::logsReply(int commandId, const QVariantMap &data)
|
||||
} else {
|
||||
if (!entries.isEmpty()) {
|
||||
beginInsertRows(QModelIndex(), m_list.count(), m_list.count() + entries.count() - 1);
|
||||
qSort(entries.begin(), entries.end(), [](NewLogEntry *left, NewLogEntry *right){
|
||||
std::sort(entries.begin(), entries.end(), [](NewLogEntry *left, NewLogEntry *right){
|
||||
return left->timestamp() > right->timestamp();
|
||||
});
|
||||
m_list.append(entries);
|
||||
|
||||
@ -25,11 +25,12 @@
|
||||
#ifndef NEWLOGSMODEL_H
|
||||
#define NEWLOGSMODEL_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QObject>
|
||||
#include <QQmlParserStatus>
|
||||
#include "newlogentry.h"
|
||||
#include <QAbstractListModel>
|
||||
|
||||
class Engine;
|
||||
#include "engine.h"
|
||||
#include "newlogentry.h"
|
||||
|
||||
class NewLogsModel : public QAbstractListModel, public QQmlParserStatus
|
||||
{
|
||||
|
||||
@ -3,8 +3,8 @@
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include "connection/discovery/nymeadiscovery.h"
|
||||
#include "jsonrpc/jsonrpcclient.h"
|
||||
#include "connection/discovery/nymeadiscovery.h"
|
||||
|
||||
class NymeaHostsFilterModel: public QSortFilterProxyModel
|
||||
{
|
||||
|
||||
@ -85,7 +85,7 @@ void PluginConfigManager::getPluginConfigResponse(int /*commandId*/, const QVari
|
||||
QVariantList pluginParams = params.value("configuration").toList();
|
||||
foreach (const QVariant ¶mVariant, pluginParams) {
|
||||
Param* param = new Param();
|
||||
param->setParamTypeId(paramVariant.toMap().value("paramTypeId").toString());
|
||||
param->setParamTypeId(paramVariant.toMap().value("paramTypeId").toUuid());
|
||||
param->setValue(paramVariant.toMap().value("value"));
|
||||
m_params->addParam(param);
|
||||
}
|
||||
|
||||
@ -237,16 +237,16 @@ void CodeCompletion::update()
|
||||
qDebug() << "stateName block info" << info.name << info.properties;
|
||||
QString thingId;
|
||||
Interfaces ifaces;
|
||||
StateTypes *stateTypes = nullptr;
|
||||
//StateTypes *stateTypes = nullptr;
|
||||
if (info.properties.contains("thingId")) {
|
||||
thingId = info.properties.value("thingId");
|
||||
|
||||
qDebug() << "selected thingId" << thingId;
|
||||
Thing *thing = m_engine->thingManager()->things()->getThing(thingId);
|
||||
Thing *thing = m_engine->thingManager()->things()->getThing(QUuid(thingId));
|
||||
if (!thing) {
|
||||
return;
|
||||
}
|
||||
stateTypes = thing->thingClass()->stateTypes();
|
||||
//stateTypes = thing->thingClass()->stateTypes();
|
||||
|
||||
} else if (info.properties.contains("interfaceName")) {
|
||||
QString interfaceName = info.properties.value("interfaceName");
|
||||
@ -254,7 +254,7 @@ void CodeCompletion::update()
|
||||
if (!iface) {
|
||||
return;
|
||||
}
|
||||
stateTypes = iface->stateTypes();
|
||||
//stateTypes = iface->stateTypes();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -24,9 +24,7 @@
|
||||
|
||||
#include "serverdebugmanager.h"
|
||||
|
||||
#include "engine.h"
|
||||
#include "logging.h"
|
||||
#include "serverloggingcategories.h"
|
||||
|
||||
NYMEA_LOGGING_CATEGORY(dcServerDebug, "ServerDebug")
|
||||
|
||||
|
||||
@ -27,17 +27,16 @@
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "serverloggingcategory.h"
|
||||
#include "engine.h"
|
||||
#include "serverloggingcategories.h"
|
||||
|
||||
class Engine;
|
||||
class JsonRpcClient;
|
||||
class ServerLoggingCategories;
|
||||
|
||||
class ServerDebugManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(Engine* engine READ engine WRITE setEngine NOTIFY engineChanged)
|
||||
Q_PROPERTY(bool fetchingData READ fetchingData NOTIFY fetchingDataChanged)
|
||||
Q_PROPERTY(Engine* engine READ engine WRITE setEngine NOTIFY engineChanged FINAL)
|
||||
Q_PROPERTY(bool fetchingData READ fetchingData NOTIFY fetchingDataChanged FINAL)
|
||||
Q_PROPERTY(ServerLoggingCategories *categories READ categories CONSTANT FINAL)
|
||||
|
||||
public:
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
#include "zigbeenode.h"
|
||||
|
||||
#include <QMetaEnum>
|
||||
#include <QRegularExpression>
|
||||
|
||||
ZigbeeNode::ZigbeeNode(const QUuid &networkUuid, const QString &ieeeAddress, QObject *parent) :
|
||||
QObject(parent),
|
||||
@ -666,7 +667,7 @@ QString ZigbeeCluster::clusterName() const
|
||||
QMetaEnum clusterEnum = QMetaEnum::fromType<ZigbeeClusterId>();
|
||||
QString name = clusterEnum.valueToKey(m_clusterId);
|
||||
name.remove("ZigbeeClusterId");
|
||||
QRegExp re1 = QRegExp("([A-Z])([a-z]*)");
|
||||
QRegularExpression re1 = QRegularExpression("([A-Z])([a-z]*)");
|
||||
name.replace(re1, ";\\1\\2");
|
||||
QStringList parts = name.split(";");
|
||||
QString clusterName = parts.join(" ").trimmed();
|
||||
|
||||
@ -27,12 +27,9 @@
|
||||
#include <QJsonDocument>
|
||||
#include <QMetaEnum>
|
||||
|
||||
#include "types/serialports.h"
|
||||
#include "types/serialport.h"
|
||||
#include "zwavenetwork.h"
|
||||
#include "zwavenode.h"
|
||||
|
||||
#include "engine.h"
|
||||
|
||||
#include "logging.h"
|
||||
NYMEA_LOGGING_CATEGORY(dcZWave, "ZWave")
|
||||
|
||||
|
||||
@ -28,22 +28,21 @@
|
||||
#include <QObject>
|
||||
#include <QHash>
|
||||
|
||||
class Engine;
|
||||
#include "engine.h"
|
||||
#include "zwavenetwork.h"
|
||||
#include "types/serialports.h"
|
||||
|
||||
class JsonRpcClient;
|
||||
class SerialPorts;
|
||||
class ZWaveNetwork;
|
||||
class ZWaveNetworks;
|
||||
class ZWaveNode;
|
||||
|
||||
class ZWaveManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(Engine* engine READ engine WRITE setEngine NOTIFY engineChanged)
|
||||
Q_PROPERTY(bool fetchingData READ fetchingData NOTIFY fetchingDataChanged)
|
||||
Q_PROPERTY(bool zwaveAvailable READ zwaveAvailable NOTIFY zwaveAvailableChanged)
|
||||
Q_PROPERTY(Engine *engine READ engine WRITE setEngine NOTIFY engineChanged FINAL)
|
||||
Q_PROPERTY(bool fetchingData READ fetchingData NOTIFY fetchingDataChanged FINAL)
|
||||
Q_PROPERTY(bool zwaveAvailable READ zwaveAvailable NOTIFY zwaveAvailableChanged FINAL)
|
||||
|
||||
Q_PROPERTY(SerialPorts *serialPorts READ serialPorts CONSTANT)
|
||||
Q_PROPERTY(ZWaveNetworks *networks READ networks CONSTANT)
|
||||
Q_PROPERTY(SerialPorts *serialPorts READ serialPorts CONSTANT FINAL)
|
||||
Q_PROPERTY(ZWaveNetworks *networks READ networks CONSTANT FINAL)
|
||||
|
||||
public:
|
||||
enum ZWaveError {
|
||||
@ -111,7 +110,7 @@ private:
|
||||
Q_INVOKABLE void notificationReceived(const QVariantMap &data);
|
||||
|
||||
private:
|
||||
Engine* m_engine = nullptr;
|
||||
Engine *m_engine = nullptr;
|
||||
bool m_fetchingData = false;
|
||||
bool m_zwaveAvailable = false;
|
||||
SerialPorts *m_serialPorts = nullptr;
|
||||
|
||||
@ -29,23 +29,22 @@
|
||||
#include <QUuid>
|
||||
#include <QAbstractListModel>
|
||||
|
||||
class ZWaveNode;
|
||||
class ZWaveNodes;
|
||||
#include "zwavenode.h"
|
||||
|
||||
class ZWaveNetwork : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QUuid networkUuid READ networkUuid CONSTANT)
|
||||
Q_PROPERTY(QString serialPort READ serialPort CONSTANT)
|
||||
Q_PROPERTY(quint32 homeId READ homeId NOTIFY homeIdChanged)
|
||||
Q_PROPERTY(bool isZWavePlus READ isZWavePlus NOTIFY isZWavePlusChanged)
|
||||
Q_PROPERTY(bool isPrimaryController READ isPrimaryController NOTIFY isPrimaryControllerChanged)
|
||||
Q_PROPERTY(bool isStaticUpdateController READ isStaticUpdateController NOTIFY isStaticUpdateControllerChanged)
|
||||
Q_PROPERTY(bool isBridgeController READ isBridgeController NOTIFY isBridgeControllerChanged)
|
||||
Q_PROPERTY(bool waitingForNodeAddition READ waitingForNodeAddition NOTIFY waitingForNodeAdditionChanged)
|
||||
Q_PROPERTY(bool waitingForNodeRemoval READ waitingForNodeRemoval NOTIFY waitingForNodeRemovalChanged)
|
||||
Q_PROPERTY(ZWaveNetworkState networkState READ networkState NOTIFY networkStateChanged)
|
||||
Q_PROPERTY(ZWaveNodes* nodes READ nodes CONSTANT)
|
||||
Q_PROPERTY(QUuid networkUuid READ networkUuid CONSTANT FINAL)
|
||||
Q_PROPERTY(QString serialPort READ serialPort CONSTANT FINAL)
|
||||
Q_PROPERTY(quint32 homeId READ homeId NOTIFY homeIdChanged FINAL)
|
||||
Q_PROPERTY(bool isZWavePlus READ isZWavePlus NOTIFY isZWavePlusChanged FINAL)
|
||||
Q_PROPERTY(bool isPrimaryController READ isPrimaryController NOTIFY isPrimaryControllerChanged FINAL)
|
||||
Q_PROPERTY(bool isStaticUpdateController READ isStaticUpdateController NOTIFY isStaticUpdateControllerChanged FINAL)
|
||||
Q_PROPERTY(bool isBridgeController READ isBridgeController NOTIFY isBridgeControllerChanged FINAL)
|
||||
Q_PROPERTY(bool waitingForNodeAddition READ waitingForNodeAddition NOTIFY waitingForNodeAdditionChanged FINAL)
|
||||
Q_PROPERTY(bool waitingForNodeRemoval READ waitingForNodeRemoval NOTIFY waitingForNodeRemovalChanged FINAL)
|
||||
Q_PROPERTY(ZWaveNetworkState networkState READ networkState NOTIFY networkStateChanged FINAL)
|
||||
Q_PROPERTY(ZWaveNodes* nodes READ nodes CONSTANT FINAL)
|
||||
|
||||
public:
|
||||
enum ZWaveNetworkState {
|
||||
@ -55,6 +54,7 @@ public:
|
||||
ZWaveNetworkStateError
|
||||
};
|
||||
Q_ENUM(ZWaveNetworkState)
|
||||
|
||||
explicit ZWaveNetwork(const QUuid &networkUuid, const QString &serialPort, QObject *parent = nullptr);
|
||||
|
||||
QUuid networkUuid() const;
|
||||
@ -119,6 +119,7 @@ class ZWaveNetworks: public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
|
||||
|
||||
public:
|
||||
enum Roles {
|
||||
RoleUuid,
|
||||
@ -141,14 +142,14 @@ public:
|
||||
void addNetwork(ZWaveNetwork *network);
|
||||
void removeNetwork(const QUuid &networkUuid);
|
||||
|
||||
Q_INVOKABLE ZWaveNetwork* get(int index) const;
|
||||
Q_INVOKABLE ZWaveNetwork* getNetwork(const QUuid &networkUuid);
|
||||
Q_INVOKABLE ZWaveNetwork *get(int index) const;
|
||||
Q_INVOKABLE ZWaveNetwork *getNetwork(const QUuid &networkUuid);
|
||||
|
||||
signals:
|
||||
void countChanged();
|
||||
|
||||
private:
|
||||
QList<ZWaveNetwork*> m_list;
|
||||
QList<ZWaveNetwork *> m_list;
|
||||
};
|
||||
|
||||
#endif // ZWAVENETWORK_H
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
|
||||
#include "zwavenode.h"
|
||||
#include <QMetaEnum>
|
||||
#include <QRegularExpression>
|
||||
|
||||
ZWaveNode::ZWaveNode(const QUuid &networkUuid, quint8 id, QObject *parent):
|
||||
QObject{parent},
|
||||
@ -59,7 +60,7 @@ void ZWaveNode::setNodeType(ZWaveNodeType nodeType)
|
||||
QString ZWaveNode::nodeTypeString() const
|
||||
{
|
||||
QMetaEnum metaEnum = QMetaEnum::fromType<ZWaveNode::ZWaveNodeType>();
|
||||
return QString(metaEnum.valueToKey(m_nodeType)).remove(QRegExp("^ZWaveNodeType"));
|
||||
return QString(metaEnum.valueToKey(m_nodeType)).remove(QRegularExpression("^ZWaveNodeType"));
|
||||
}
|
||||
|
||||
ZWaveNode::ZWaveNodeRole ZWaveNode::role() const
|
||||
@ -78,7 +79,7 @@ void ZWaveNode::setRole(ZWaveNodeRole role)
|
||||
QString ZWaveNode::roleString() const
|
||||
{
|
||||
QMetaEnum metaEnum = QMetaEnum::fromType<ZWaveNode::ZWaveNodeRole>();
|
||||
return QString(metaEnum.valueToKey(m_role)).remove(QRegExp("^ZWaveNodeRole"));
|
||||
return QString(metaEnum.valueToKey(m_role)).remove(QRegularExpression("^ZWaveNodeRole"));
|
||||
}
|
||||
|
||||
ZWaveNode::ZWaveDeviceType ZWaveNode::deviceType() const
|
||||
@ -94,7 +95,7 @@ void ZWaveNode::setDeviceType(ZWaveDeviceType deviceType)
|
||||
QString ZWaveNode::deviceTypeString() const
|
||||
{
|
||||
QMetaEnum metaEnum = QMetaEnum::fromType<ZWaveNode::ZWaveDeviceType>();
|
||||
return QString(metaEnum.valueToKey(m_deviceType)).remove(QRegExp("^ZWaveDeviceType"));
|
||||
return QString(metaEnum.valueToKey(m_deviceType)).remove(QRegularExpression("^ZWaveDeviceType"));
|
||||
}
|
||||
|
||||
quint16 ZWaveNode::manufacturerId() const
|
||||
|
||||
@ -81,9 +81,6 @@ linux:!android: {
|
||||
|
||||
android: {
|
||||
message("Android package source dir $${ANDROID_PACKAGE_SOURCE_DIR}")
|
||||
SUBDIRS += androidservice
|
||||
androidservice.depends = libnymea-app
|
||||
|
||||
NYMEA_APP_ROOT_PROPERTY="nymeaAppRoot=$${top_srcdir}"
|
||||
no-firebase: FIREBASE_PROPERTY="useFirebase=false"
|
||||
else: FIREBASE_PROPERTY="useFirebase=true"
|
||||
|
||||
153
nymea-app/CMakeLists.txt
Normal file
153
nymea-app/CMakeLists.txt
Normal file
@ -0,0 +1,153 @@
|
||||
set(NYMEA_APP_SOURCES
|
||||
main.cpp
|
||||
configuredhostsmodel.cpp
|
||||
dashboard/dashboarditem.cpp
|
||||
dashboard/dashboardmodel.cpp
|
||||
mouseobserver.cpp
|
||||
nfchelper.cpp
|
||||
nfcthingactionwriter.cpp
|
||||
platformintegration/platformpermissions.cpp
|
||||
stylecontroller.cpp
|
||||
pushnotifications.cpp
|
||||
platformhelper.cpp
|
||||
platformintegration/generic/screenhelper.cpp
|
||||
utils/privacypolicyhelper.cpp
|
||||
utils/qhashqml.cpp
|
||||
)
|
||||
|
||||
set(NYMEA_APP_HEADERS
|
||||
configuredhostsmodel.h
|
||||
dashboard/dashboarditem.h
|
||||
dashboard/dashboardmodel.h
|
||||
mouseobserver.h
|
||||
nfchelper.h
|
||||
nfcthingactionwriter.h
|
||||
platformintegration/generic/screenhelper.h
|
||||
platformintegration/platformpermissions.h
|
||||
stylecontroller.h
|
||||
pushnotifications.h
|
||||
platformhelper.h
|
||||
ruletemplates/messages.h
|
||||
utils/privacypolicyhelper.h
|
||||
utils/qhashqml.h
|
||||
)
|
||||
|
||||
if(UNIX AND NOT APPLE AND NOT ANDROID)
|
||||
list(APPEND NYMEA_APP_SOURCES
|
||||
platformintegration/generic/platformhelpergeneric.cpp
|
||||
)
|
||||
list(APPEND NYMEA_APP_HEADERS
|
||||
platformintegration/generic/platformhelpergeneric.h
|
||||
)
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
list(APPEND NYMEA_APP_SOURCES
|
||||
platformintegration/android/platformhelperandroid.cpp
|
||||
platformintegration/android/platformpermissionsandroid.cpp
|
||||
)
|
||||
list(APPEND NYMEA_APP_HEADERS
|
||||
platformintegration/android/platformhelperandroid.h
|
||||
platformintegration/android/platformpermissionsandroid.h
|
||||
)
|
||||
endif()
|
||||
|
||||
set(NYMEA_APP_RESOURCES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/resources.qrc
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ruletemplates.qrc
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/images.qrc
|
||||
)
|
||||
|
||||
if(NYMEA_OVERLAY_PATH)
|
||||
message(WARNING "Overlay support is not implemented in the CMake build yet; NYMEA_OVERLAY_PATH will be ignored.")
|
||||
else()
|
||||
list(APPEND NYMEA_APP_RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/styles.qrc)
|
||||
endif()
|
||||
|
||||
if(NYMEA_USE_MATERIAL_ICONS)
|
||||
list(APPEND NYMEA_APP_RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/ui/icons/material/icons.qrc)
|
||||
else()
|
||||
list(APPEND NYMEA_APP_RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/ui/icons/suru/icons.qrc)
|
||||
endif()
|
||||
|
||||
qt_add_executable(nymea-app
|
||||
MANUAL_FINALIZATION
|
||||
${NYMEA_APP_SOURCES}
|
||||
${NYMEA_APP_HEADERS}
|
||||
${NYMEA_APP_RESOURCES}
|
||||
)
|
||||
|
||||
target_include_directories(nymea-app
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_SOURCE_DIR}/libnymea-app
|
||||
${CMAKE_SOURCE_DIR}/experiences/airconditioning
|
||||
${CMAKE_BINARY_DIR}
|
||||
)
|
||||
|
||||
target_link_libraries(nymea-app
|
||||
PRIVATE
|
||||
nymea-app-core
|
||||
nymea-app-airconditioning
|
||||
Qt6::Gui
|
||||
Qt6::Network
|
||||
Qt6::Qml
|
||||
Qt6::Quick
|
||||
Qt6::QuickControls2
|
||||
Qt6::Svg
|
||||
Qt6::WebSockets
|
||||
Qt6::Bluetooth
|
||||
Qt6::Charts
|
||||
Qt6::Nfc
|
||||
)
|
||||
|
||||
if(TARGET Qt6::WebView)
|
||||
target_link_libraries(nymea-app PRIVATE Qt6::WebView)
|
||||
target_compile_definitions(nymea-app PRIVATE HAVE_WEBVIEW)
|
||||
endif()
|
||||
|
||||
find_package(Qt6 COMPONENTS GuiPrivate QUIET)
|
||||
if(TARGET Qt6::GuiPrivate)
|
||||
target_link_libraries(nymea-app PRIVATE Qt6::GuiPrivate)
|
||||
else()
|
||||
message(WARNING "Qt6::GuiPrivate not found; continuing without private GUI APIs.")
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE AND NYMEA_ENABLE_ZEROCONF)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(AVAHI REQUIRED IMPORTED_TARGET avahi-client avahi-common)
|
||||
target_link_libraries(nymea-app PRIVATE PkgConfig::AVAHI)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_compile_definitions(nymea-app PRIVATE NOMINMAX)
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
if(DEFINED NYMEA_ANDROID_PACKAGE_SOURCE_DIR)
|
||||
set_property(TARGET nymea-app PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR "${NYMEA_ANDROID_PACKAGE_SOURCE_DIR}")
|
||||
endif()
|
||||
|
||||
set_property(TARGET nymea-app PROPERTY QT_ANDROID_MIN_SDK_VERSION 23)
|
||||
set_property(TARGET nymea-app PROPERTY QT_ANDROID_TARGET_SDK_VERSION 35)
|
||||
|
||||
if(NYMEA_ENABLE_FIREBASE)
|
||||
target_compile_definitions(nymea-app PRIVATE WITH_FIREBASE)
|
||||
target_include_directories(nymea-app PRIVATE ${CMAKE_SOURCE_DIR}/3rdParty/android/firebase_cpp_sdk/include)
|
||||
|
||||
if(CMAKE_ANDROID_ARCH_ABI)
|
||||
set(_firebase_lib_dir "${CMAKE_SOURCE_DIR}/3rdParty/android/firebase_cpp_sdk/libs/android/${CMAKE_ANDROID_ARCH_ABI}/c++")
|
||||
target_link_libraries(nymea-app PRIVATE
|
||||
"${_firebase_lib_dir}/libfirebase_messaging.a"
|
||||
"${_firebase_lib_dir}/libfirebase_app.a"
|
||||
)
|
||||
else()
|
||||
message(WARNING "CMAKE_ANDROID_ARCH_ABI is not defined; Firebase static libraries could not be linked.")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Firebase support disabled via NYMEA_ENABLE_FIREBASE option.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
qt_finalize_executable(nymea-app)
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
#include <QDir>
|
||||
#include <QSettings>
|
||||
#include <QStandardPaths>
|
||||
#include <QRegularExpression>
|
||||
|
||||
#include <QLoggingCategory>
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcApplication)
|
||||
@ -154,8 +155,8 @@ void ConfiguredHostsModel::removeHost(int index)
|
||||
settings.remove("");
|
||||
settings.endGroup();
|
||||
|
||||
QDir dir(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/sslcerts/");
|
||||
QFile certFile(dir.absoluteFilePath(hostUuidString.remove(QRegExp("[{}]")) + ".pem"));
|
||||
QDir dir(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/sslcerts/");
|
||||
QFile certFile(dir.absoluteFilePath(hostUuidString.remove(QRegularExpression("[{}]")) + ".pem"));
|
||||
if (certFile.exists()) {
|
||||
if (!certFile.remove()) {
|
||||
qCWarning(dcApplication()) << "Failed to remove certificate file" << certFile.fileName() << certFile.errorString();
|
||||
|
||||
@ -39,6 +39,10 @@
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
#include <QNetworkInformation>
|
||||
#endif
|
||||
|
||||
#include "libnymea-app-core.h"
|
||||
#include "libnymea-app-airconditioning.h"
|
||||
|
||||
@ -53,8 +57,9 @@
|
||||
#include "dashboard/dashboarditem.h"
|
||||
#include "mouseobserver.h"
|
||||
#include "configuredhostsmodel.h"
|
||||
#include "../config.h"
|
||||
#include "utils/qhashqml.h"
|
||||
#include "utils/privacypolicyhelper.h"
|
||||
#include "config.h"
|
||||
|
||||
#include "logging.h"
|
||||
|
||||
@ -71,10 +76,7 @@ int main(int argc, char *argv[])
|
||||
#ifdef Q_OS_OSX
|
||||
qputenv("QT_WEBVIEW_PLUGIN", "native");
|
||||
#endif
|
||||
|
||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
QApplication application(argc, argv);
|
||||
|
||||
application.setApplicationName(APPLICATION_NAME);
|
||||
application.setOrganizationName(ORGANISATION_NAME);
|
||||
|
||||
@ -114,8 +116,11 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
QTranslator qtTranslator;
|
||||
qtTranslator.load("qt_" + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath));
|
||||
QTranslator qtTranslator;
|
||||
if (!qtTranslator.load("qt_" + QLocale::system().name(), QLibraryInfo::path(QLibraryInfo::TranslationsPath))) {
|
||||
qCWarning(dcApplication()) << "Unable to load translations from" << QLibraryInfo::path(QLibraryInfo::TranslationsPath);
|
||||
}
|
||||
|
||||
application.installTranslator(&qtTranslator);
|
||||
|
||||
QStringList loadedTranslations;
|
||||
@ -169,6 +174,21 @@ int main(int argc, char *argv[])
|
||||
QFontDatabase::addApplicationFont(fi.absoluteFilePath());
|
||||
}
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
// Note: QNetworkInformation should always first be loaded in the same thread as the QCoreApplication object
|
||||
qCInfo(dcApplication()) << "Available network information backends" << QNetworkInformation::instance()->availableBackends();
|
||||
|
||||
if (QNetworkInformation::instance()->loadDefaultBackend()) {
|
||||
qCInfo(dcApplication()) << "Loaded default network information backend" << QNetworkInformation::instance()->backendName();
|
||||
qCInfo(dcApplication()) << "Network infromation supported features:" << QNetworkInformation::instance()->supportedFeatures();
|
||||
qCInfo(dcApplication()) << "Network reachability:" << QNetworkInformation::instance()->reachability();
|
||||
qCInfo(dcApplication()) << "Network trasport medium changed:" << QNetworkInformation::instance()->transportMedium();
|
||||
|
||||
} else {
|
||||
qCWarning(dcApplication()) << "Unable to load default network information backend." << QNetworkInformation::instance()->availableBackends();
|
||||
}
|
||||
#endif
|
||||
|
||||
qmlRegisterSingletonType(QUrl("qrc:///styles/" + styleController.currentStyle() + "/Style.qml"), "Nymea", 1, 0, "Style" );
|
||||
qmlRegisterType(QUrl("qrc:///styles/" + styleController.currentStyle() + "/Background.qml"), "Nymea", 1, 0, "Background" );
|
||||
qmlRegisterSingletonType(QUrl("qrc:///ui/Configuration.qml"), "Nymea", 1, 0, "Configuration");
|
||||
|
||||
@ -15,8 +15,7 @@ qtHaveModule(webview) {
|
||||
INCLUDEPATH += $$top_srcdir/libnymea-app \
|
||||
$$top_srcdir/experiences/airconditioning
|
||||
|
||||
LIBS += -L$$top_builddir/libnymea-app/ -lnymea-app \
|
||||
-L$$top_builddir/experiences/airconditioning -lnymea-app-airconditioning
|
||||
linux:!android: LIBS += -L$$top_builddir/libnymea-app/ -lnymea-app -L$$top_builddir/experiences/airconditioning -lnymea-app-airconditioning
|
||||
|
||||
win32:Debug:LIBS += -L$$top_builddir/libnymea-app/debug \
|
||||
-L$$top_builddir/experiences/airconditioning/debug
|
||||
@ -92,19 +91,17 @@ android {
|
||||
ANDROID_MIN_SDK_VERSION = 21
|
||||
ANDROID_TARGET_SDK_VERSION = 35
|
||||
|
||||
QT += androidextras
|
||||
HEADERS += platformintegration/android/platformhelperandroid.h \
|
||||
platformintegration/android/platformpermissionsandroid.h \
|
||||
|
||||
SOURCES += platformintegration/android/platformhelperandroid.cpp \
|
||||
platformintegration/android/platformpermissionsandroid.cpp \
|
||||
|
||||
# https://bugreports.qt.io/browse/QTBUG-83165
|
||||
CORE_LIBS += -L$${top_builddir}/libnymea-app/$${ANDROID_TARGET_ARCH}
|
||||
AIRCONDITIONING_LIBS += -L$${top_builddir}/experiences/airconditioning/$${ANDROID_TARGET_ARCH}
|
||||
|
||||
LIBS += $${CORE_LIBS} $${AIRCONDITIONING_LIBS}
|
||||
message("CORE_LIBS: $${CORE_LIBS}")
|
||||
LIBS += $${CORE_LIBS} -lnymea-app_$${ANDROID_TARGET_ARCH} \
|
||||
$${AIRCONDITIONING_LIBS} -lnymea-app-airconditioning_$${ANDROID_TARGET_ARCH}
|
||||
|
||||
versioninfo.files = ../version.txt
|
||||
versioninfo.path = /
|
||||
@ -113,9 +110,9 @@ android {
|
||||
DISTFILES += \
|
||||
$$ANDROID_PACKAGE_SOURCE_DIR/AndroidManifest.xml \
|
||||
$$ANDROID_PACKAGE_SOURCE_DIR/google-services.json \
|
||||
$$ANDROID_PACKAGE_SOURCE_DIR/gradle/wrapper/gradle-wrapper.jar \
|
||||
$$ANDROID_PACKAGE_SOURCE_DIR/gradlew \
|
||||
$$ANDROID_PACKAGE_SOURCE_DIR/res/values/libs.xml \
|
||||
$$ANDROID_PACKAGE_SOURCE_DIR/res/values/styles.xml \
|
||||
$$ANDROID_PACKAGE_SOURCE_DIR/build.gradle \
|
||||
$$ANDROID_PACKAGE_SOURCE_DIR/gradle/wrapper/gradle-wrapper.properties \
|
||||
$$ANDROID_PACKAGE_SOURCE_DIR/gradlew.bat \
|
||||
|
||||
@ -32,7 +32,6 @@
|
||||
#include <QJsonDocument>
|
||||
|
||||
#if defined Q_OS_ANDROID
|
||||
#include <QtAndroidExtras/QtAndroid>
|
||||
#include "platformintegration/android/platformhelperandroid.h"
|
||||
#elif defined Q_OS_IOS
|
||||
#include "platformintegration/ios/platformhelperios.h"
|
||||
@ -70,7 +69,7 @@ void PlatformHelper::notificationActionReceived(const QString &nymeaData)
|
||||
QUrlQuery query(map.value("data").toString());
|
||||
QVariantMap dataMap;
|
||||
for (int i = 0; i < query.queryItems().count(); i++) {
|
||||
const QPair<QString, QString> &item = query.queryItems().at(i);
|
||||
QPair<QString, QString> item = query.queryItems().at(i);
|
||||
dataMap.insert(item.first, item.second);
|
||||
}
|
||||
map.insert("dataMap", dataMap);
|
||||
|
||||
@ -20,8 +20,15 @@ import androidx.core.content.FileProvider;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowCompat;
|
||||
import android.view.WindowInsets;
|
||||
import android.graphics.Insets;
|
||||
|
||||
public class NymeaAppActivity extends org.qtproject.qt5.android.bindings.QtActivity
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
|
||||
import org.qtproject.qt.android.bindings.QtActivity;
|
||||
|
||||
public class NymeaAppActivity extends QtActivity
|
||||
{
|
||||
private static final String TAG = "nymea-app: NymeaAppActivity";
|
||||
private static Context context = null;
|
||||
@ -42,6 +49,7 @@ public class NymeaAppActivity extends org.qtproject.qt5.android.bindings.QtActiv
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
Log.w(TAG, "Create activity");
|
||||
super.onCreate(savedInstanceState);
|
||||
// Move th app to the background (Edge to edge is forced since SDK 35)
|
||||
//WindowCompat.setDecorFitsSystemWindows(getWindow(), true);
|
||||
@ -143,12 +151,62 @@ public class NymeaAppActivity extends org.qtproject.qt5.android.bindings.QtActiv
|
||||
|
||||
public int topPadding() {
|
||||
WindowInsets windowInsets = getWindow().getDecorView().getRootWindowInsets();
|
||||
return windowInsets.getInsets(WindowInsets.Type.statusBars() | WindowInsets.Type.displayCutout()).top;
|
||||
|
||||
if (windowInsets == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
Insets insets = windowInsets.getInsets(WindowInsets.Type.statusBars() | WindowInsets.Type.displayCutout());
|
||||
return insets != null ? insets.top : 0;
|
||||
}
|
||||
|
||||
return windowInsets.getStableInsetTop();
|
||||
}
|
||||
|
||||
public int bottomPadding() {
|
||||
WindowInsets windowInsets = getWindow().getDecorView().getRootWindowInsets();
|
||||
return windowInsets.getInsets(WindowInsets.Type.navigationBars() | WindowInsets.Type.displayCutout()).bottom;
|
||||
if (windowInsets == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
Insets insets = windowInsets.getInsets(WindowInsets.Type.navigationBars() | WindowInsets.Type.displayCutout());
|
||||
return insets != null ? insets.bottom : 0;
|
||||
}
|
||||
|
||||
return windowInsets.getStableInsetBottom();
|
||||
}
|
||||
|
||||
private void logStaticInitClassesMetadata() {
|
||||
try {
|
||||
ApplicationInfo appInfo = getPackageManager().getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA);
|
||||
if (appInfo.metaData == null || !appInfo.metaData.containsKey("android.app.static_init_classes")) {
|
||||
Log.w(TAG, "No android.app.static_init_classes meta-data present in the manifest");
|
||||
return;
|
||||
}
|
||||
|
||||
Object value = appInfo.metaData.get("android.app.static_init_classes");
|
||||
if (!(value instanceof Integer)) {
|
||||
Log.w(TAG, "android.app.static_init_classes meta-data is not a resource reference: " + value);
|
||||
return;
|
||||
}
|
||||
|
||||
int resId = (Integer) value;
|
||||
if (resId == 0) {
|
||||
Log.e(TAG, "android.app.static_init_classes meta-data resolves to resource id 0");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
String resName = getResources().getResourceName(resId);
|
||||
String resValue = getResources().getString(resId);
|
||||
Log.i(TAG, "android.app.static_init_classes -> " + resName + " = " + resValue);
|
||||
} catch (Resources.NotFoundException notFoundException) {
|
||||
Log.e(TAG, "android.app.static_init_classes references missing resource 0x" + Integer.toHexString(resId), notFoundException);
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException exception) {
|
||||
Log.e(TAG, "Failed to inspect android.app.static_init_classes meta-data", exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,10 +26,9 @@
|
||||
|
||||
#include <QDebug>
|
||||
#include <QScreen>
|
||||
#include <QtAndroid>
|
||||
#include <QAndroidIntent>
|
||||
#include <QtCore/private/qandroidextras_p.h>
|
||||
#include <QApplication>
|
||||
#include <QAndroidJniObject>
|
||||
#include <QJniObject>
|
||||
|
||||
// WindowManager.LayoutParams
|
||||
#define FLAG_TRANSLUCENT_STATUS 0x04000000
|
||||
@ -64,20 +63,27 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/)
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
|
||||
static QAndroidJniObject getAndroidWindow()
|
||||
{
|
||||
QAndroidJniObject window = QtAndroid::androidActivity().callObjectMethod("getWindow", "()Landroid/view/Window;");
|
||||
return window;
|
||||
}
|
||||
// static QJniObject getAndroidWindow()
|
||||
// {
|
||||
// QJniObject window;
|
||||
// QJniObject activity = QNativeInterface::QAndroidApplication::context();
|
||||
// if(activity.isValid()) {
|
||||
// activity.callMethod<void>("setRequestedOrientation", "(I)V", 0);
|
||||
// window = activity.callObjectMethod("getWindow", "()Landroid/view/Window;");
|
||||
// }
|
||||
|
||||
// // QJniObject window = QNativeInterface::QAndroidApplication::context().callMethod<jobject>("getWindow", "()Landroid/view/Window;");
|
||||
// return window;
|
||||
// }
|
||||
|
||||
PlatformHelperAndroid::PlatformHelperAndroid(QObject *parent) : PlatformHelper(parent)
|
||||
{
|
||||
m_instance = this;
|
||||
|
||||
QString notificationData = QtAndroid::androidActivity().callObjectMethod("notificationData", "()Ljava/lang/String;").toString();
|
||||
if (!notificationData.isNull()) {
|
||||
notificationActionReceived(notificationData);
|
||||
}
|
||||
// QString notificationData = QNativeInterface::QAndroidApplication::context().callMethod<jstring>("notificationData", "()Ljava/lang/String;").toString();
|
||||
// if (!notificationData.isNull()) {
|
||||
// notificationActionReceived(notificationData);
|
||||
// }
|
||||
|
||||
connect(qApp, &QApplication::applicationStateChanged, this, [this](Qt::ApplicationState state){
|
||||
qCritical() << "----> Application state changed" << state;
|
||||
@ -92,7 +98,7 @@ void PlatformHelperAndroid::hideSplashScreen()
|
||||
// Android's splash will flicker when fading out twice
|
||||
static bool alreadyHiding = false;
|
||||
if (!alreadyHiding) {
|
||||
QtAndroid::hideSplashScreen(250);
|
||||
//QtAndroid::hideSplashScreen(250);
|
||||
alreadyHiding = true;
|
||||
}
|
||||
}
|
||||
@ -105,23 +111,23 @@ QString PlatformHelperAndroid::machineHostname() const
|
||||
|
||||
QString PlatformHelperAndroid::deviceSerial() const
|
||||
{
|
||||
QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;");
|
||||
QJniObject activity = QJniObject::callStaticObjectMethod("org/qtproject/qt/android/QtNative", "activity", "()Landroid/app/Activity;");
|
||||
return activity.callObjectMethod<jstring>("deviceSerial").toString();
|
||||
}
|
||||
|
||||
QString PlatformHelperAndroid::device() const
|
||||
{
|
||||
return QAndroidJniObject::callStaticObjectMethod<jstring>("io/guh/nymeaapp/NymeaAppActivity","device").toString();
|
||||
return QJniObject::callStaticObjectMethod<jstring>("io/guh/nymeaapp/NymeaAppActivity", "device").toString();
|
||||
}
|
||||
|
||||
QString PlatformHelperAndroid::deviceModel() const
|
||||
{
|
||||
return QAndroidJniObject::callStaticObjectMethod<jstring>("io/guh/nymeaapp/NymeaAppActivity","deviceModel").toString();
|
||||
return QJniObject::callStaticObjectMethod<jstring>("io/guh/nymeaapp/NymeaAppActivity", "deviceModel").toString();
|
||||
}
|
||||
|
||||
QString PlatformHelperAndroid::deviceManufacturer() const
|
||||
{
|
||||
return QAndroidJniObject::callStaticObjectMethod<jstring>("io/guh/nymeaapp/NymeaAppActivity","deviceManufacturer").toString();
|
||||
return QJniObject::callStaticObjectMethod<jstring>("io/guh/nymeaapp/NymeaAppActivity", "deviceManufacturer").toString();
|
||||
}
|
||||
|
||||
void PlatformHelperAndroid::vibrate(PlatformHelper::HapticsFeedback feedbackType)
|
||||
@ -139,7 +145,20 @@ void PlatformHelperAndroid::vibrate(PlatformHelper::HapticsFeedback feedbackType
|
||||
break;
|
||||
}
|
||||
|
||||
QtAndroid::androidActivity().callMethod<void>("vibrate","(I)V", duration);
|
||||
QJniObject context = QNativeInterface::QAndroidApplication::context();
|
||||
if (!context.isValid()) {
|
||||
qDebug() << "Could not get Android context.";
|
||||
return;
|
||||
}
|
||||
|
||||
QJniObject vibrator = context.callMethod<jobject>("getSystemService", "Landroid/content/Context;Ljava/lang/String;", QJniObject::fromString("vibrator").object());
|
||||
if (!vibrator.isValid()) {
|
||||
qDebug() << "Could not get vibrator service.";
|
||||
return;
|
||||
}
|
||||
|
||||
// Call the vibrate method
|
||||
vibrator.callMethod<void>("vibrate", "(J)V", duration);
|
||||
}
|
||||
|
||||
//void PlatformHelperAndroid::syncThings()
|
||||
@ -147,7 +166,7 @@ void PlatformHelperAndroid::vibrate(PlatformHelper::HapticsFeedback feedbackType
|
||||
|
||||
// QAndroidIntent serviceIntent(QtAndroid::androidActivity().object(),
|
||||
// "io/guh/nymeaapp/NymeaAppService");
|
||||
// QAndroidJniObject result = QtAndroid::androidActivity().callObjectMethod(
|
||||
// QJniObject result = QtAndroid::androidActivity().callObjectMethod(
|
||||
// "startService",
|
||||
// "(Landroid/content/Intent;)Landroid/content/ComponentName;",
|
||||
// serviceIntent.handle().object());
|
||||
@ -163,7 +182,7 @@ void PlatformHelperAndroid::vibrate(PlatformHelper::HapticsFeedback feedbackType
|
||||
//// m_serviceConnection->handle().callMethod<void>("syncThings", "(Ljava/lang/String;)V", "bla");
|
||||
|
||||
|
||||
//// QAndroidJniObject result = QtAndroid::androidActivity().callObjectMethod(
|
||||
//// QJniObject result = QtAndroid::androidActivity().callObjectMethod(
|
||||
//// "syncThings",
|
||||
//// "(Landroid/content/Intent;)Landroid/content/ComponentName;",
|
||||
//// m_serviceConnection->handle().object());
|
||||
@ -173,113 +192,120 @@ void PlatformHelperAndroid::setTopPanelColor(const QColor &color)
|
||||
{
|
||||
PlatformHelper::setTopPanelColor(color);
|
||||
|
||||
if (QtAndroid::androidSdkVersion() < 21)
|
||||
return;
|
||||
// if (QtAndroid::androidSdkVersion() < 21)
|
||||
// return;
|
||||
|
||||
QtAndroid::runOnAndroidThread([=]() {
|
||||
QAndroidJniObject window = getAndroidWindow();
|
||||
window.callMethod<void>("addFlags", "(I)V", FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
|
||||
window.callMethod<void>("clearFlags", "(I)V", FLAG_TRANSLUCENT_STATUS);
|
||||
window.callMethod<void>("setStatusBarColor", "(I)V", color.rgba());
|
||||
});
|
||||
// QtAndroid::runOnAndroidThread([=]() {
|
||||
// QJniObject window = getAndroidWindow();
|
||||
// window.callMethod<void>("addFlags", "(I)V", FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
|
||||
// window.callMethod<void>("clearFlags", "(I)V", FLAG_TRANSLUCENT_STATUS);
|
||||
// window.callMethod<void>("setStatusBarColor", "(I)V", color.rgba());
|
||||
// });
|
||||
|
||||
if (((color.red() * 299 + color.green() * 587 + color.blue() * 114) / 1000) > 123) {
|
||||
setTopPanelTheme(Light);
|
||||
} else {
|
||||
setTopPanelTheme(Dark);
|
||||
}
|
||||
// if (((color.red() * 299 + color.green() * 587 + color.blue() * 114) / 1000) > 123) {
|
||||
// setTopPanelTheme(Light);
|
||||
// } else {
|
||||
// setTopPanelTheme(Dark);
|
||||
// }
|
||||
}
|
||||
|
||||
void PlatformHelperAndroid::setBottomPanelColor(const QColor &color)
|
||||
{
|
||||
PlatformHelper::setBottomPanelColor(color);
|
||||
|
||||
if (QtAndroid::androidSdkVersion() < 21)
|
||||
return;
|
||||
// if (QtAndroid::androidSdkVersion() < 21)
|
||||
// return;
|
||||
|
||||
QtAndroid::runOnAndroidThread([=]() {
|
||||
QAndroidJniObject window = getAndroidWindow();
|
||||
window.callMethod<void>("clearFlags", "(I)V", FLAG_TRANSLUCENT_NAVIGATION);
|
||||
window.callMethod<void>("setNavigationBarColor", "(I)V", color.rgba());
|
||||
// QtAndroid::runOnAndroidThread([=]() {
|
||||
// QJniObject window = getAndroidWindow();
|
||||
// window.callMethod<void>("clearFlags", "(I)V", FLAG_TRANSLUCENT_NAVIGATION);
|
||||
// window.callMethod<void>("setNavigationBarColor", "(I)V", color.rgba());
|
||||
|
||||
if (((color.red() * 299 + color.green() * 587 + color.blue() * 114) / 1000) > 123) {
|
||||
setBottomPanelTheme(Light);
|
||||
} else {
|
||||
setBottomPanelTheme(Dark);
|
||||
}
|
||||
});
|
||||
// if (((color.red() * 299 + color.green() * 587 + color.blue() * 114) / 1000) > 123) {
|
||||
// setBottomPanelTheme(Light);
|
||||
// } else {
|
||||
// setBottomPanelTheme(Dark);
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
void PlatformHelperAndroid::setTopPanelTheme(PlatformHelperAndroid::Theme theme)
|
||||
{
|
||||
if (QtAndroid::androidSdkVersion() < 23)
|
||||
return;
|
||||
Q_UNUSED(theme)
|
||||
// if (QtAndroid::androidSdkVersion() < 23)
|
||||
// return;
|
||||
|
||||
QtAndroid::runOnAndroidThread([=]() {
|
||||
QAndroidJniObject window = getAndroidWindow();
|
||||
QAndroidJniObject view = window.callObjectMethod("getDecorView", "()Landroid/view/View;");
|
||||
int visibility = view.callMethod<int>("getSystemUiVisibility", "()I");
|
||||
if (theme == Theme::Light)
|
||||
visibility |= SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
|
||||
else
|
||||
visibility &= ~SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
|
||||
view.callMethod<void>("setSystemUiVisibility", "(I)V", visibility);
|
||||
});
|
||||
// QtAndroid::runOnAndroidThread([=]() {
|
||||
// QJniObject window = getAndroidWindow();
|
||||
// QJniObject view = window.callObjectMethod("getDecorView", "()Landroid/view/View;");
|
||||
// int visibility = view.callMethod<int>("getSystemUiVisibility", "()I");
|
||||
// if (theme == Theme::Light)
|
||||
// visibility |= SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
|
||||
// else
|
||||
// visibility &= ~SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
|
||||
// view.callMethod<void>("setSystemUiVisibility", "(I)V", visibility);
|
||||
// });
|
||||
}
|
||||
|
||||
void PlatformHelperAndroid::setBottomPanelTheme(Theme theme)
|
||||
{
|
||||
if (QtAndroid::androidSdkVersion() < 23)
|
||||
return;
|
||||
Q_UNUSED(theme)
|
||||
|
||||
QtAndroid::runOnAndroidThread([=]() {
|
||||
QAndroidJniObject window = getAndroidWindow();
|
||||
QAndroidJniObject view = window.callObjectMethod("getDecorView", "()Landroid/view/View;");
|
||||
int visibility = view.callMethod<int>("getSystemUiVisibility", "()I");
|
||||
if (theme == Theme::Light)
|
||||
visibility |= SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
|
||||
else
|
||||
visibility &= ~SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
|
||||
view.callMethod<void>("setSystemUiVisibility", "(I)V", visibility);
|
||||
});
|
||||
// if (QtAndroid::androidSdkVersion() < 23)
|
||||
// return;
|
||||
|
||||
// QtAndroid::runOnAndroidThread([=]() {
|
||||
// QJniObject window = getAndroidWindow();
|
||||
// QJniObject view = window.callObjectMethod("getDecorView", "()Landroid/view/View;");
|
||||
// int visibility = view.callMethod<int>("getSystemUiVisibility", "()I");
|
||||
// if (theme == Theme::Light)
|
||||
// visibility |= SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
|
||||
// else
|
||||
// visibility &= ~SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
|
||||
// view.callMethod<void>("setSystemUiVisibility", "(I)V", visibility);
|
||||
// });
|
||||
}
|
||||
|
||||
int PlatformHelperAndroid::topPadding() const
|
||||
{
|
||||
// Edge to edge has been forced since android SDK 35
|
||||
// We don't want to handle it in earlied versions.
|
||||
if (QtAndroid::androidSdkVersion() < 35)
|
||||
return 0;
|
||||
// if (QtAndroid::androidSdkVersion() < 35)
|
||||
// return 0;
|
||||
|
||||
return QtAndroid::androidActivity().callMethod<jint>("topPadding") / QApplication::primaryScreen()->devicePixelRatio();
|
||||
//return QNativeInterface::QAndroidApplication::context().callMethod<jint>("topPadding") / QApplication::primaryScreen()->devicePixelRatio();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PlatformHelperAndroid::bottomPadding() const
|
||||
{
|
||||
// Edge to edge has been forced since android SDK 35
|
||||
// We don't want to handle it in earlied versions.
|
||||
if (QtAndroid::androidSdkVersion() < 35)
|
||||
return 0;
|
||||
// if (QtAndroid::androidSdkVersion() < 35)
|
||||
// return 0;
|
||||
|
||||
return QtAndroid::androidActivity().callMethod<jint>("bottomPadding") / QApplication::primaryScreen()->devicePixelRatio();
|
||||
// return QNativeInterface::QAndroidApplication::context().callMethod<jint>("bottomPadding") / QApplication::primaryScreen()->devicePixelRatio();
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool PlatformHelperAndroid::darkModeEnabled() const
|
||||
{
|
||||
return QtAndroid::androidActivity().callMethod<jboolean>("darkModeEnabled");
|
||||
return QNativeInterface::QAndroidApplication::context().callMethod<jboolean>("darkModeEnabled");
|
||||
}
|
||||
|
||||
bool PlatformHelperAndroid::locationServicesEnabled() const
|
||||
{
|
||||
jboolean enabled = QtAndroid::androidActivity().callMethod<jboolean>("locationServicesEnabled", "()Z");
|
||||
return enabled;
|
||||
// jboolean enabled = QNativeInterface::QAndroidApplication::context().callMethod<jboolean>("locationServicesEnabled", "()Z");
|
||||
// return enabled;
|
||||
return true;
|
||||
}
|
||||
|
||||
void PlatformHelperAndroid::shareFile(const QString &fileName)
|
||||
{
|
||||
QtAndroid::androidActivity().callMethod<void>("shareFile", "(Ljava/lang/String;)V",
|
||||
QAndroidJniObject::fromString(fileName).object<jstring>()
|
||||
);
|
||||
Q_UNUSED(fileName)
|
||||
// QNativeInterface::QAndroidApplication::context().callMethod<void>("shareFile", "(Ljava/lang/String;)V",
|
||||
// QJniObject::fromString(fileName).object<jstring>()
|
||||
// );
|
||||
}
|
||||
|
||||
void PlatformHelperAndroid::darkModeEnabledChangedJNI()
|
||||
|
||||
@ -28,8 +28,9 @@
|
||||
#include "platformhelper.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QtAndroid>
|
||||
#include <QAndroidServiceConnection>
|
||||
#include <QJniObject>
|
||||
#include <QJniEnvironment>
|
||||
#include <QtCore/private/qandroidextras_p.h>
|
||||
|
||||
class PlatformHelperAndroid : public PlatformHelper
|
||||
{
|
||||
@ -67,8 +68,6 @@ public:
|
||||
static void notificationActionReceivedJNI(JNIEnv *env, jobject /*thiz*/, jstring data);
|
||||
static void locationServicesEnabledChangedJNI();
|
||||
|
||||
private:
|
||||
static void permissionRequestFinished(const QtAndroid::PermissionResultMap &);
|
||||
};
|
||||
|
||||
#endif // PLATFORMHELPERANDROID_H
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
|
||||
#include <QDebug>
|
||||
#include <QApplication>
|
||||
#include <QAndroidIntent>
|
||||
#include <QPermission>
|
||||
#include <QOperatingSystemVersion>
|
||||
|
||||
#include "logging.h"
|
||||
@ -53,94 +53,227 @@ PlatformPermissionsAndroid::PlatformPermissionsAndroid(QObject *parent)
|
||||
|
||||
}
|
||||
|
||||
void PlatformPermissionsAndroid::requestPermission(PlatformPermissions::Permission permission)
|
||||
{
|
||||
if (permissionMap().contains(permission)) {
|
||||
qCDebug(dcPlatformPermissions()) << "Requesting permissions:" << permissionMap().value(permission);
|
||||
QtAndroid::requestPermissions({permissionMap().value(permission)}, &permissionResultCallback);
|
||||
}
|
||||
}
|
||||
|
||||
void PlatformPermissionsAndroid::openPermissionSettings()
|
||||
{
|
||||
qCDebug(dcPlatformPermissions()) << "Opening permission dialog.";
|
||||
QAndroidJniObject packageName = QtAndroid::androidContext().callObjectMethod("getPackageName", "()Ljava/lang/String;");
|
||||
QString packageUri = "package:" + packageName.toString();
|
||||
QAndroidJniObject uri = QAndroidJniObject::callStaticObjectMethod("android/net/Uri", "parse", "(Ljava/lang/String;)Landroid/net/Uri;", QAndroidJniObject::fromString(packageUri).object());
|
||||
QAndroidIntent intent = QAndroidIntent("android.settings.APPLICATION_DETAILS_SETTINGS");
|
||||
intent.handle().callObjectMethod("setData", "(Landroid/net/Uri;)Landroid/content/Intent;", uri.object());
|
||||
intent.handle().callObjectMethod("addFlags", "(I)Landroid/content/Intent;", FLAG_ACTIVITY_NEW_TASK);
|
||||
QtAndroid::androidContext().callMethod<void>("startActivity", "(Landroid/content/Intent;)V", intent.handle().object());
|
||||
}
|
||||
|
||||
QHash<PlatformPermissions::Permission, QStringList> PlatformPermissionsAndroid::permissionMap() const
|
||||
{
|
||||
QOperatingSystemVersion osVersion = QOperatingSystemVersion::current();
|
||||
if (osVersion.majorVersion() <= 9) {
|
||||
return {
|
||||
{PlatformPermissions::PermissionBluetooth, {"android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION"}},
|
||||
{PlatformPermissions::PermissionLocation, {"android.permission.ACCESS_FINE_LOCATION"}},
|
||||
{PlatformPermissions::PermissionBackgroundLocation, {"android.permission.ACCESS_FINE_LOCATION"}}
|
||||
};
|
||||
}
|
||||
if (osVersion.majorVersion() <= 10) {
|
||||
return {
|
||||
{PlatformPermissions::PermissionBluetooth, {"android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION"}},
|
||||
{PlatformPermissions::PermissionLocation, {"android.permission.ACCESS_FINE_LOCATION"}},
|
||||
{PlatformPermissions::PermissionBackgroundLocation, {"android.permission.ACCESS_FINE_LOCATION", "android.permission.ACCESS_BACKGROUND_LOCATION"}}
|
||||
};
|
||||
}
|
||||
if (osVersion.majorVersion() <= 12) {
|
||||
return {
|
||||
// TODO: Once QtBluetooth does not request the COARSE_LOCATION and FINE_LOCATION for Bluetooth any more, remove it from here. The new Bluetooth permissions would be enough.
|
||||
{PlatformPermissions::PermissionBluetooth, {"android.permission.BLUETOOTH_SCAN", "android.permission.BLUETOOTH_CONNECT", "android.permission.BLUETOOTH_ADVERTISE", "android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION"}},
|
||||
{PlatformPermissions::PermissionLocation, {"android.permission.ACCESS_FINE_LOCATION"}},
|
||||
{PlatformPermissions::PermissionBackgroundLocation, {"android.permission.ACCESS_FINE_LOCATION", "android.permission.ACCESS_BACKGROUND_LOCATION"}}
|
||||
};
|
||||
}
|
||||
return {
|
||||
// TODO: Once QtBluetooth does not request the COARSE_LOCATION and FINE_LOCATION for Bluetooth any more, remove it from here. The new Bluetooth permissions would be enough.
|
||||
{PlatformPermissions::PermissionBluetooth, {"android.permission.BLUETOOTH_SCAN", "android.permission.BLUETOOTH_CONNECT", "android.permission.BLUETOOTH_ADVERTISE", "android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION"}},
|
||||
{PlatformPermissions::PermissionLocation, {"android.permission.ACCESS_FINE_LOCATION"}},
|
||||
{PlatformPermissions::PermissionBackgroundLocation, {"android.permission.ACCESS_FINE_LOCATION", "android.permission.ACCESS_BACKGROUND_LOCATION"}},
|
||||
{PlatformPermissions::PermissionNotifications, {"android.permission.POST_NOTIFICATIONS"}}
|
||||
};
|
||||
}
|
||||
|
||||
PlatformPermissions::PermissionStatus PlatformPermissionsAndroid::checkPermission(Permission permission) const
|
||||
PlatformPermissions::PermissionStatus PlatformPermissionsAndroid::checkPermission(Permission platformPermission) const
|
||||
{
|
||||
PermissionStatus status = PermissionStatusGranted;
|
||||
QStringList androidPermissions = permissionMap().value(permission);
|
||||
qCDebug(dcPlatformPermissions()) << "Checking permission" << permission << "(" << androidPermissions << ")";
|
||||
foreach (const QString androidPermission, androidPermissions) {
|
||||
if (QtAndroid::shouldShowRequestPermissionRationale(androidPermission) || m_requestedButDeniedPermissions.contains(androidPermission)) {
|
||||
qCDebug(dcPlatformPermissions()) << "Permission:" << androidPermission << "denied";
|
||||
status = PermissionStatusDenied;
|
||||
qCDebug(dcPlatformPermissions()) << "Checking permission" << platformPermission;
|
||||
|
||||
switch (platformPermission) {
|
||||
case PlatformPermissions::PermissionBluetooth: {
|
||||
QBluetoothPermission permission;
|
||||
|
||||
// Status prüfen
|
||||
auto status = qApp->checkPermission(permission);
|
||||
|
||||
switch (status) {
|
||||
case Qt::PermissionStatus::Granted:
|
||||
qCDebug(dcPlatformPermissions()) << "Bluetooth permission already granted.";
|
||||
break;
|
||||
case Qt::PermissionStatus::Denied:
|
||||
qCDebug(dcPlatformPermissions()) << "Bluetooth permission denied.";
|
||||
break;
|
||||
case Qt::PermissionStatus::Undetermined:
|
||||
qCDebug(dcPlatformPermissions()) << "Bluetooth permission not yet requested. Requesting...";
|
||||
qApp->requestPermission(permission, [](const QPermission &perm){
|
||||
if (perm.status() == Qt::PermissionStatus::Granted)
|
||||
qCDebug(dcPlatformPermissions()) << "Bluetooth permission granted after request.";
|
||||
else
|
||||
qCDebug(dcPlatformPermissions()) << "Bluetooth permission denied after request.";
|
||||
});
|
||||
break;
|
||||
}
|
||||
if (QtAndroid::checkPermission(androidPermission) == QtAndroid::PermissionResult::Denied) {
|
||||
qDebug(dcPlatformPermissions()) << "Permission:" << androidPermission << "not determined";
|
||||
if (status != PermissionStatusDenied) {
|
||||
status = PermissionStatusNotDetermined;
|
||||
}
|
||||
} else {
|
||||
qDebug(dcPlatformPermissions()) << "Permission:" << androidPermission << "granted";
|
||||
break;
|
||||
}
|
||||
case PlatformPermissions::PermissionLocalNetwork: {
|
||||
QLocationPermission permission;
|
||||
permission.setAccuracy(QLocationPermission::Precise);
|
||||
|
||||
// Status prüfen
|
||||
auto status = qApp->checkPermission(permission);
|
||||
|
||||
switch (status) {
|
||||
case Qt::PermissionStatus::Granted:
|
||||
qCDebug(dcPlatformPermissions()) << "Location permission already granted.";
|
||||
break;
|
||||
case Qt::PermissionStatus::Denied:
|
||||
qCDebug(dcPlatformPermissions()) << "Location permission denied.";
|
||||
break;
|
||||
case Qt::PermissionStatus::Undetermined:
|
||||
qCDebug(dcPlatformPermissions()) << "Location permission not yet requested. Requesting...";
|
||||
qApp->requestPermission(permission, [](const QPermission &perm){
|
||||
if (perm.status() == Qt::PermissionStatus::Granted)
|
||||
qCDebug(dcPlatformPermissions()) << "Location permission granted after request.";
|
||||
else
|
||||
qCDebug(dcPlatformPermissions()) << "Location permission denied after request.";
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
qCDebug(dcPlatformPermissions()) << "Permission status for:" << permission << ":" << status;
|
||||
case PlatformPermissions::PermissionNotifications: {
|
||||
break;
|
||||
}
|
||||
default:
|
||||
qCWarning(dcPlatformPermissions()) << "Requested status of platform permission" << platformPermission << "but is not implemented yet.";
|
||||
break;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
void PlatformPermissionsAndroid::permissionResultCallback(const QtAndroid::PermissionResultMap &results)
|
||||
void PlatformPermissionsAndroid::requestPermission(PlatformPermissions::Permission platformPermission)
|
||||
{
|
||||
foreach (const QString &androidPermission, results.keys()) {
|
||||
qCDebug(dcPlatformPermissions()) << "Permission result callback:" << androidPermission << (results.value(androidPermission) == QtAndroid::PermissionResult::Granted ? "Granted" : "Denied");
|
||||
if (results.value(androidPermission) == QtAndroid::PermissionResult::Denied) {
|
||||
s_instance->m_requestedButDeniedPermissions.append(androidPermission);
|
||||
}
|
||||
switch (platformPermission) {
|
||||
case PlatformPermissions::PermissionBluetooth:
|
||||
qCDebug(dcPlatformPermissions()) << "Requesting bluetooth permission";
|
||||
qApp->requestPermission(QLocationPermission{}, [platformPermission](const QPermission &permission) {
|
||||
if (permission.status() == Qt::PermissionStatus::Denied) {
|
||||
qCWarning(dcPlatformPermissions()) << "Bluetooth permission denied.";
|
||||
s_instance->m_requestedButDeniedPermissions.append(platformPermission);
|
||||
}
|
||||
|
||||
if (permission.status() == Qt::PermissionStatus::Granted)
|
||||
qCDebug(dcPlatformPermissions()) << "Bluetooth permission granted.";
|
||||
|
||||
emit s_instance->bluetoothPermissionChanged();
|
||||
});
|
||||
break;
|
||||
case PlatformPermissions::PermissionLocation: {
|
||||
QLocationPermission locationPermission;
|
||||
locationPermission.setAccuracy(QLocationPermission::Precise);
|
||||
qApp->requestPermission(locationPermission, [platformPermission](const QPermission &permission) {
|
||||
if (permission.status() == Qt::PermissionStatus::Denied) {
|
||||
qCWarning(dcPlatformPermissions()) << "Location permission denied.";
|
||||
s_instance->m_requestedButDeniedPermissions.append(platformPermission);
|
||||
}
|
||||
|
||||
if (permission.status() == Qt::PermissionStatus::Granted)
|
||||
qCDebug(dcPlatformPermissions()) << "Location permission granted.";
|
||||
|
||||
emit s_instance->locationPermissionChanged();
|
||||
});
|
||||
break;
|
||||
}
|
||||
emit s_instance->bluetoothPermissionChanged();
|
||||
case PlatformPermissions::PermissionLocalNetwork: {
|
||||
QFuture permission_request = QtAndroidPrivate::requestPermission("android.permission.POST_NOTIFICATIONS");
|
||||
switch(permission_request.result())
|
||||
{
|
||||
case QtAndroidPrivate::Undetermined:
|
||||
qWarning() << "Permission for posting notifications undetermined!";
|
||||
break;
|
||||
case QtAndroidPrivate::Authorized:
|
||||
qDebug() << "Permission for posting notifications authorized";
|
||||
break;
|
||||
case QtAndroidPrivate::Denied:
|
||||
qWarning() << "Permission for posting notifications denied!";
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
qCWarning(dcPlatformPermissions()) << "Requested platform permission" << platformPermission << "but is not implemented yet.";
|
||||
break;
|
||||
}
|
||||
|
||||
emit s_instance->locationPermissionChanged();
|
||||
emit s_instance->backgroundLocationPermissionChanged();
|
||||
emit s_instance->notificationsPermissionChanged();
|
||||
|
||||
// if (permissionMap().contains(permission)) {
|
||||
// qCDebug(dcPlatformPermissions()) << "Requesting permissions:" << permissionMap().value(permission);
|
||||
|
||||
|
||||
|
||||
// qApp->requestPermission(QCameraPermission{}, [](const QPermission &permission) {
|
||||
|
||||
|
||||
// if (permission.status() == Qt::PermissionStatus::Granted)
|
||||
// takePhoto();
|
||||
// });
|
||||
|
||||
// // QtAndroid::requestPermissions({permissionMap().value(permission)}, &permissionResultCallback);
|
||||
// }
|
||||
}
|
||||
|
||||
// void PlatformPermissionsAndroid::openPermissionSettings()
|
||||
// {
|
||||
// qCDebug(dcPlatformPermissions()) << "Opening permission dialog.";
|
||||
// QJniObject packageName = QtAndroid::androidContext().callObjectMethod("getPackageName", "()Ljava/lang/String;");
|
||||
// QString packageUri = "package:" + packageName.toString();
|
||||
// QJniObject uri = QJniObject::callStaticObjectMethod("android/net/Uri", "parse", "(Ljava/lang/String;)Landroid/net/Uri;", QJniObject::fromString(packageUri).object());
|
||||
// QAndroidIntent intent = QAndroidIntent("android.settings.APPLICATION_DETAILS_SETTINGS");
|
||||
// intent.handle().callObjectMethod("setData", "(Landroid/net/Uri;)Landroid/content/Intent;", uri.object());
|
||||
// intent.handle().callObjectMethod("addFlags", "(I)Landroid/content/Intent;", FLAG_ACTIVITY_NEW_TASK);
|
||||
// QtAndroid::androidContext().callMethod<void>("startActivity", "(Landroid/content/Intent;)V", intent.handle().object());
|
||||
// }
|
||||
|
||||
// QHash<PlatformPermissions::Permission, QStringList> PlatformPermissionsAndroid::permissionMap() const
|
||||
// {
|
||||
// QOperatingSystemVersion osVersion = QOperatingSystemVersion::current();
|
||||
// if (osVersion.majorVersion() <= 9) {
|
||||
// return {
|
||||
// {PlatformPermissions::PermissionBluetooth, {"android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION"}},
|
||||
// {PlatformPermissions::PermissionLocation, {"android.permission.ACCESS_FINE_LOCATION"}},
|
||||
// {PlatformPermissions::PermissionBackgroundLocation, {"android.permission.ACCESS_FINE_LOCATION"}}
|
||||
// };
|
||||
// }
|
||||
// if (osVersion.majorVersion() <= 10) {
|
||||
// return {
|
||||
// {PlatformPermissions::PermissionBluetooth, {"android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION"}},
|
||||
// {PlatformPermissions::PermissionLocation, {"android.permission.ACCESS_FINE_LOCATION"}},
|
||||
// {PlatformPermissions::PermissionBackgroundLocation, {"android.permission.ACCESS_FINE_LOCATION", "android.permission.ACCESS_BACKGROUND_LOCATION"}}
|
||||
// };
|
||||
// }
|
||||
// if (osVersion.majorVersion() <= 12) {
|
||||
// return {
|
||||
// // TODO: Once QtBluetooth does not request the COARSE_LOCATION and FINE_LOCATION for Bluetooth any more, remove it from here. The new Bluetooth permissions would be enough.
|
||||
// {PlatformPermissions::PermissionBluetooth, {"android.permission.BLUETOOTH_SCAN", "android.permission.BLUETOOTH_CONNECT", "android.permission.BLUETOOTH_ADVERTISE", "android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION"}},
|
||||
// {PlatformPermissions::PermissionLocation, {"android.permission.ACCESS_FINE_LOCATION"}},
|
||||
// {PlatformPermissions::PermissionBackgroundLocation, {"android.permission.ACCESS_FINE_LOCATION", "android.permission.ACCESS_BACKGROUND_LOCATION"}}
|
||||
// };
|
||||
// }
|
||||
// return {
|
||||
// // TODO: Once QtBluetooth does not request the COARSE_LOCATION and FINE_LOCATION for Bluetooth any more, remove it from here. The new Bluetooth permissions would be enough.
|
||||
// {PlatformPermissions::PermissionBluetooth, {"android.permission.BLUETOOTH_SCAN", "android.permission.BLUETOOTH_CONNECT", "android.permission.BLUETOOTH_ADVERTISE", "android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION"}},
|
||||
// {PlatformPermissions::PermissionLocation, {"android.permission.ACCESS_FINE_LOCATION"}},
|
||||
// {PlatformPermissions::PermissionBackgroundLocation, {"android.permission.ACCESS_FINE_LOCATION", "android.permission.ACCESS_BACKGROUND_LOCATION"}},
|
||||
// {PlatformPermissions::PermissionNotifications, {"android.permission.POST_NOTIFICATIONS"}}
|
||||
// };
|
||||
// }
|
||||
|
||||
// PlatformPermissions::PermissionStatus PlatformPermissionsAndroid::checkPermission(Permission permission) const
|
||||
// {
|
||||
// PermissionStatus status = PermissionStatusGranted;
|
||||
// QStringList androidPermissions = permissionMap().value(permission);
|
||||
// qCDebug(dcPlatformPermissions()) << "Checking permission" << permission << "(" << androidPermissions << ")";
|
||||
// foreach (const QString androidPermission, androidPermissions) {
|
||||
// if (QtAndroid::shouldShowRequestPermissionRationale(androidPermission) || m_requestedButDeniedPermissions.contains(androidPermission)) {
|
||||
// qCDebug(dcPlatformPermissions()) << "Permission:" << androidPermission << "denied";
|
||||
// status = PermissionStatusDenied;
|
||||
// }
|
||||
// if (QtAndroid::checkPermission(androidPermission) == QtAndroid::PermissionResult::Denied) {
|
||||
// qDebug(dcPlatformPermissions()) << "Permission:" << androidPermission << "not determined";
|
||||
// if (status != PermissionStatusDenied) {
|
||||
// status = PermissionStatusNotDetermined;
|
||||
// }
|
||||
// } else {
|
||||
// qDebug(dcPlatformPermissions()) << "Permission:" << androidPermission << "granted";
|
||||
// }
|
||||
// }
|
||||
// qCDebug(dcPlatformPermissions()) << "Permission status for:" << permission << ":" << status;
|
||||
// return status;
|
||||
// }
|
||||
|
||||
// void PlatformPermissionsAndroid::permissionResultCallback(const QtAndroid::PermissionResultMap &results)
|
||||
// {
|
||||
// foreach (const QString &androidPermission, results.keys()) {
|
||||
// qCDebug(dcPlatformPermissions()) << "Permission result callback:" << androidPermission << (results.value(androidPermission) == QtAndroid::PermissionResult::Granted ? "Granted" : "Denied");
|
||||
// if (results.value(androidPermission) == QtAndroid::PermissionResult::Denied) {
|
||||
// s_instance->m_requestedButDeniedPermissions.append(androidPermission);
|
||||
// }
|
||||
// }
|
||||
// emit s_instance->bluetoothPermissionChanged();
|
||||
// emit s_instance->locationPermissionChanged();
|
||||
// emit s_instance->backgroundLocationPermissionChanged();
|
||||
// emit s_instance->notificationsPermissionChanged();
|
||||
// }
|
||||
|
||||
|
||||
@ -26,8 +26,7 @@
|
||||
#define PLATFORMPERMISSIONSANDROID_H
|
||||
|
||||
#include "../platformpermissions.h"
|
||||
|
||||
#include <QtAndroidExtras/QtAndroid>
|
||||
#include <QtCore/private/qandroidextras_p.h>
|
||||
|
||||
class PlatformPermissionsAndroid : public PlatformPermissions
|
||||
{
|
||||
@ -35,20 +34,14 @@ class PlatformPermissionsAndroid : public PlatformPermissions
|
||||
public:
|
||||
explicit PlatformPermissionsAndroid(QObject *parent = nullptr);
|
||||
|
||||
PermissionStatus checkPermission(Permission permission) const override;
|
||||
|
||||
void requestPermission(Permission permission) override;
|
||||
void openPermissionSettings() override;
|
||||
|
||||
signals:
|
||||
PermissionStatus checkPermission(Permission platformPermission) const override;
|
||||
void requestPermission(Permission platformPermission) override;
|
||||
|
||||
private:
|
||||
QHash<PlatformPermissions::Permission, QStringList> permissionMap() const;
|
||||
|
||||
QStringList m_requestedButDeniedPermissions;
|
||||
|
||||
static PlatformPermissionsAndroid *s_instance;
|
||||
static void permissionResultCallback(const QtAndroid::PermissionResultMap &results);
|
||||
|
||||
QList<PlatformPermissions::Permission> m_requestedButDeniedPermissions;
|
||||
QList<PlatformPermissions::Permission> m_grantedPermission;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -26,11 +26,16 @@
|
||||
#include "platformhelper.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QCoreApplication>
|
||||
|
||||
#if defined Q_OS_ANDROID
|
||||
#include <QtAndroid>
|
||||
#include <QtAndroidExtras>
|
||||
#include <QAndroidJniObject>
|
||||
#include <QJniObject>
|
||||
#include <QJniEnvironment>
|
||||
|
||||
#include <QtCore/qjnienvironment.h> // QJniEnvironment
|
||||
#include <QtCore/qjniobject.h> // QJniObject
|
||||
#include <QtCore/qjnitypes.h> // QtJniTypes::Context / Activity
|
||||
#include <QtCore/qnativeinterface.h>
|
||||
static PushNotifications *m_client_pointer;
|
||||
#endif
|
||||
|
||||
@ -82,14 +87,50 @@ void PushNotifications::registerForPush()
|
||||
{
|
||||
#if defined Q_OS_ANDROID && defined WITH_FIREBASE
|
||||
qDebug() << "Checking for play services";
|
||||
jboolean playServicesAvailable = QAndroidJniObject::callStaticMethod<jboolean>("io.guh.nymeaapp.NymeaAppNotificationService", "checkPlayServices", "()Z");
|
||||
jboolean playServicesAvailable = QJniObject::callStaticMethod<jboolean>("io.guh.nymeaapp.NymeaAppNotificationService", "checkPlayServices", "()Z");
|
||||
if (playServicesAvailable) {
|
||||
|
||||
qDebug() << "Setting up firebase";
|
||||
m_client_pointer = this;
|
||||
m_firebaseApp = ::firebase::App::Create(::firebase::AppOptions(), QAndroidJniEnvironment(), QtAndroid::androidActivity().object());
|
||||
m_firebase_initializer.Initialize(m_firebaseApp, nullptr, [](::firebase::App * fapp, void *) {
|
||||
return ::firebase::messaging::Initialize( *fapp, (::firebase::messaging::Listener *)m_client_pointer);
|
||||
});
|
||||
|
||||
JNIEnv *jni = QJniEnvironment().jniEnv();
|
||||
QtJniTypes::Context ctx = QNativeInterface::QAndroidApplication::context();
|
||||
jobject contextObj = ctx.object<jobject>();
|
||||
|
||||
m_firebaseApp = firebase::App::Create(firebase::AppOptions(), jni, contextObj);
|
||||
|
||||
firebase::messaging::Initialize(*m_firebaseApp, this);
|
||||
firebase::messaging::SetListener(this);
|
||||
|
||||
// (Optional, Android 13+): Benachrichtigungs-Erlaubnis anfragen
|
||||
// firebase::messaging::RequestPermission();
|
||||
|
||||
|
||||
|
||||
// // Activity + JNIEnv besorgen
|
||||
// JNIEnv* env = QNativeInterface::QAndroidApplication::jniEnv();
|
||||
// jobject activity = QNativeInterface::QAndroidApplication::context();
|
||||
|
||||
// // Firebase App erstellen
|
||||
// m_firebaseApp = firebase::App::Create(firebase::AppOptions(), env, activity);
|
||||
|
||||
// // Messaging initialisieren und Listener setzen
|
||||
// auto initResult = firebase::messaging::Initialize(*m_firebaseApp);
|
||||
// if (initResult != firebase::kFutureStatusComplete) {
|
||||
// // optional: warten oder loggen
|
||||
// }
|
||||
// firebase::messaging::SetListener(this);
|
||||
|
||||
// // Optional: Token anfordern (wird i.d.R. via OnTokenReceived geliefert)
|
||||
// firebase::messaging::RequestPermission(); // Android 13+ für Notifications sinnvoll
|
||||
|
||||
|
||||
|
||||
|
||||
// m_firebaseApp = ::firebase::App::Create(::firebase::AppOptions(), QAndroidJniEnvironment(), QtAndroid::androidActivity().object());
|
||||
// m_firebase_initializer.Initialize(m_firebaseApp, nullptr, [](::firebase::App * fapp, void *) {
|
||||
// return ::firebase::messaging::Initialize( *fapp, (::firebase::messaging::Listener *)m_client_pointer);
|
||||
// });
|
||||
} else {
|
||||
qDebug() << "Google Play Services not available. Cannot connect to push client.";
|
||||
}
|
||||
|
||||
@ -323,5 +323,7 @@
|
||||
<file>ui/components/BackgroundFocusHandler.qml</file>
|
||||
<file>ui/components/LicenseInformationItem.qml</file>
|
||||
<file>ui/shaders/coloricon.frag.qsb</file>
|
||||
<file>ui/shaders/brightnesscircle.frag.qsb</file>
|
||||
<file>ui/shaders/colorizedimage.frag.qsb</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
@ -45,5 +45,6 @@
|
||||
<file>styles/lime/Background.qml</file>
|
||||
<file>styles/mellow/Background.qml</file>
|
||||
<file>styles/noir/Background.qml</file>
|
||||
<file>styles/dark/ItemDelegate.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
@ -22,8 +22,8 @@
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
import QtQuick 2.0
|
||||
import Nymea 1.0
|
||||
import QtQuick
|
||||
import Nymea
|
||||
|
||||
Rectangle {
|
||||
color: Style.backgroundColor
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
// Copyright (C) 2017 The Qt Company Ltd.
|
||||
* Copyright (C) 2013 - 2024, nymea GmbH
|
||||
* Copyright (C) 2024 - 2025, chargebyte austria GmbH
|
||||
*
|
||||
@ -22,90 +23,78 @@
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Templates 2.2 as T
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Controls.impl 2.2
|
||||
import QtQuick.Controls.Material 2.2
|
||||
import QtQuick.Controls.Material.impl 2.2
|
||||
import Nymea 1.0
|
||||
import QtQuick
|
||||
import QtQuick.Templates as T
|
||||
import QtQuick.Controls.impl
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Controls.Material.impl
|
||||
|
||||
T.Button {
|
||||
id: control
|
||||
|
||||
implicitWidth: Math.max(background ? background.implicitWidth : 0,
|
||||
contentItem.implicitWidth + leftPadding + rightPadding)
|
||||
implicitHeight: Math.max(background ? background.implicitHeight : 0,
|
||||
contentItem.implicitHeight + topPadding + bottomPadding)
|
||||
baselineOffset: contentItem.y + contentItem.baselineOffset
|
||||
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
|
||||
implicitContentWidth + leftPadding + rightPadding)
|
||||
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
|
||||
implicitContentHeight + topPadding + bottomPadding)
|
||||
|
||||
// external vertical padding is 6 (to increase touch area)
|
||||
padding: 12
|
||||
leftPadding: padding - 4
|
||||
rightPadding: padding - 4
|
||||
topInset: 6
|
||||
bottomInset: 6
|
||||
verticalPadding: Material.buttonVerticalPadding
|
||||
leftPadding: Material.buttonLeftPadding(flat, hasIcon && (display !== AbstractButton.TextOnly))
|
||||
rightPadding: Material.buttonRightPadding(flat, hasIcon && (display !== AbstractButton.TextOnly),
|
||||
(text !== "") && (display !== AbstractButton.IconOnly))
|
||||
spacing: 8
|
||||
|
||||
Material.elevation: flat ? control.down || control.hovered ? 2 : 0
|
||||
: control.down ? 8 : 2
|
||||
Material.background: flat ? "transparent" : undefined
|
||||
icon.width: 24
|
||||
icon.height: 24
|
||||
icon.color: !enabled ? Material.hintTextColor :
|
||||
(control.flat && control.highlighted) || (control.checked && !control.highlighted) ? Material.accentColor :
|
||||
highlighted ? Material.primaryHighlightedTextColor : Material.foreground
|
||||
|
||||
contentItem: Text {
|
||||
readonly property bool hasIcon: icon.name.length > 0 || icon.source.toString().length > 0
|
||||
|
||||
Material.elevation: control.down ? 8 : 2
|
||||
Material.roundedScale: Material.FullScale
|
||||
|
||||
contentItem: IconLabel {
|
||||
spacing: control.spacing
|
||||
mirrored: control.mirrored
|
||||
display: control.display
|
||||
|
||||
icon: control.icon
|
||||
text: control.text
|
||||
color: Style.foregroundColor
|
||||
font.bold: control.font.bold
|
||||
font.capitalization: Font.AllUppercase
|
||||
font.family: control.font.family
|
||||
font.hintingPreference: control.font.hintingPreference
|
||||
font.italic: control.font.italic
|
||||
font.letterSpacing: 2
|
||||
font.overline: control.font.overline
|
||||
font.pixelSize: app.smallFont
|
||||
font.weight: Font.Bold
|
||||
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideRight
|
||||
font: control.font
|
||||
color: !control.enabled ? control.Material.hintTextColor :
|
||||
(control.flat && control.highlighted) || (control.checked && !control.highlighted) ? control.Material.accentColor :
|
||||
control.highlighted ? control.Material.primaryHighlightedTextColor : control.Material.foreground
|
||||
}
|
||||
|
||||
// TODO: Add a proper ripple/ink effect for mouse/touch input and focus state
|
||||
background: Rectangle {
|
||||
implicitWidth: 64
|
||||
implicitHeight: Style.smallDelegateHeight
|
||||
implicitHeight: control.Material.buttonHeight
|
||||
|
||||
// external vertical padding is 6 (to increase touch area)
|
||||
y: 6
|
||||
width: parent.width
|
||||
height: parent.height - 12
|
||||
radius: Style.smallCornerRadius
|
||||
color: !control.enabled ? control.Material.buttonDisabledColor :
|
||||
control.highlighted ? control.Material.highlightedButtonColor : control.Material.accentColor
|
||||
|
||||
PaddedRectangle {
|
||||
y: parent.height - 4
|
||||
width: parent.width
|
||||
height: 4
|
||||
radius: 2
|
||||
topPadding: -2
|
||||
clip: true
|
||||
visible: control.checkable && (!control.highlighted || control.flat)
|
||||
color: control.checked && control.enabled ? control.Material.accentColor : control.Material.secondaryTextColor
|
||||
}
|
||||
radius: control.Material.roundedScale === Material.FullScale ? height / 2 : control.Material.roundedScale
|
||||
color: control.Material.buttonColor(control.Material.theme, control.Material.background,
|
||||
control.Material.accent, control.enabled, control.flat, control.highlighted, control.checked)
|
||||
|
||||
// The layer is disabled when the button color is transparent so you can do
|
||||
// Material.background: "transparent" and get a proper flat button without needing
|
||||
// to set Material.elevation as well
|
||||
layer.enabled: control.enabled && control.Material.buttonColor.a > 0
|
||||
layer.effect: ElevationEffect {
|
||||
layer.enabled: control.enabled && color.a > 0 && !control.flat
|
||||
layer.effect: RoundedElevationEffect {
|
||||
elevation: control.Material.elevation
|
||||
roundedScale: control.background.radius
|
||||
}
|
||||
|
||||
Ripple {
|
||||
clipRadius: 2
|
||||
clip: true
|
||||
clipRadius: parent.radius
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
pressed: control.pressed
|
||||
anchor: control
|
||||
active: control.down || control.visualFocus || control.hovered
|
||||
color: control.Material.rippleColor
|
||||
active: enabled && (control.down || control.visualFocus || control.hovered)
|
||||
color: control.flat && control.highlighted ? control.Material.highlightedRippleColor : control.Material.rippleColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,8 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Copyright (C) 2013 - 2024, nymea GmbH
|
||||
** Copyright (C) 2024 - 2025, chargebyte austria GmbH
|
||||
** Contact: http://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
|
||||
@ -36,34 +38,13 @@
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright (C) 2013 - 2024, nymea GmbH
|
||||
* Copyright (C) 2024 - 2025, chargebyte austria GmbH
|
||||
*
|
||||
* This file is part of nymea-app.
|
||||
*
|
||||
* nymea-app is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* nymea-app is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with nymea-app. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
import QtQuick
|
||||
import QtQuick.Templates as T
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Controls.Material.impl
|
||||
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Templates 2.2 as T
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Controls.Material 2.2
|
||||
import QtQuick.Controls.Material.impl 2.2
|
||||
import Nymea 1.0
|
||||
import Nymea
|
||||
|
||||
T.Dialog {
|
||||
id: control
|
||||
|
||||
57
nymea-app/styles/dark/ItemDelegate.qml
Normal file
57
nymea-app/styles/dark/ItemDelegate.qml
Normal file
@ -0,0 +1,57 @@
|
||||
// Copyright (C) 2017 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Templates as T
|
||||
import QtQuick.Controls.impl
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Controls.Material.impl
|
||||
|
||||
import Nymea
|
||||
|
||||
T.ItemDelegate {
|
||||
id: control
|
||||
|
||||
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
|
||||
implicitContentWidth + leftPadding + rightPadding)
|
||||
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
|
||||
implicitContentHeight + topPadding + bottomPadding,
|
||||
implicitIndicatorHeight + topPadding + bottomPadding)
|
||||
|
||||
padding: 16
|
||||
verticalPadding: 8
|
||||
spacing: 16
|
||||
|
||||
icon.width: 24
|
||||
icon.height: 24
|
||||
icon.color: enabled ? Material.foreground : Material.hintTextColor
|
||||
|
||||
contentItem: IconLabel {
|
||||
spacing: control.spacing
|
||||
mirrored: control.mirrored
|
||||
display: control.display
|
||||
alignment: control.display === IconLabel.IconOnly || control.display === IconLabel.TextUnderIcon ? Qt.AlignCenter : Qt.AlignLeft
|
||||
|
||||
icon: control.icon
|
||||
text: control.text
|
||||
font: control.font
|
||||
color: control.enabled ? control.Material.foreground : control.Material.hintTextColor
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
implicitHeight: control.Material.delegateHeight
|
||||
color: control.highlighted ? control.Material.listHighlightColor : "transparent"
|
||||
radius: Style.cornerRadius
|
||||
|
||||
Ripple {
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
|
||||
clip: true
|
||||
pressed: control.pressed
|
||||
anchor: control
|
||||
active: enabled && (control.down || control.visualFocus || control.hovered)
|
||||
color: control.Material.rippleColor
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -22,9 +22,9 @@
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
import QtQuick 2.0
|
||||
import QtQuick.Templates 2.2
|
||||
import QtQuick.Controls.Material 2.2
|
||||
import QtQuick
|
||||
import QtQuick.Templates
|
||||
import QtQuick.Controls.Material
|
||||
|
||||
Page {
|
||||
background: Background {}
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
pragma Singleton
|
||||
import QtQuick 2.0
|
||||
import QtQuick
|
||||
import "../../ui"
|
||||
|
||||
StyleBase {
|
||||
|
||||
@ -22,8 +22,8 @@
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
import QtQuick 2.0
|
||||
import Nymea 1.0
|
||||
import QtQuick
|
||||
import Nymea
|
||||
|
||||
Rectangle {
|
||||
gradient: Gradient {
|
||||
|
||||
@ -22,13 +22,13 @@
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
import QtQuick 2.9
|
||||
import QtQuick
|
||||
import QtQuick.Templates 2.2 as T
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Controls.impl 2.2
|
||||
import QtQuick.Controls.Material 2.2
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Controls.Material.impl 2.2
|
||||
import Nymea 1.0
|
||||
import Nymea
|
||||
|
||||
T.Button {
|
||||
id: control
|
||||
|
||||
@ -22,9 +22,9 @@
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
import QtQuick 2.0
|
||||
import QtQuick
|
||||
import QtQuick.Templates 2.2
|
||||
import QtQuick.Controls.Material 2.2
|
||||
import QtQuick.Controls.Material
|
||||
|
||||
Page {
|
||||
background: Background {}
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
pragma Singleton
|
||||
import QtQuick 2.0
|
||||
import QtQuick
|
||||
import "../../ui"
|
||||
|
||||
StyleBase {
|
||||
|
||||
@ -22,8 +22,9 @@
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
import QtQuick 2.0
|
||||
import Nymea 1.0
|
||||
import QtQuick
|
||||
import Nymea
|
||||
|
||||
import "qrc:/styles/light"
|
||||
|
||||
Rectangle {
|
||||
|
||||
@ -22,13 +22,13 @@
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
import QtQuick 2.9
|
||||
import QtQuick
|
||||
import QtQuick.Templates 2.2 as T
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Controls.impl 2.2
|
||||
import QtQuick.Controls.Material 2.2
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Controls.Material.impl 2.2
|
||||
import Nymea 1.0
|
||||
import Nymea
|
||||
|
||||
T.Button {
|
||||
id: control
|
||||
|
||||
@ -3,6 +3,8 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Copyright (C) 2013 - 2024, nymea GmbH
|
||||
** Copyright (C) 2024 - 2025, chargebyte austria GmbH
|
||||
** Contact: http://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
|
||||
@ -36,34 +38,12 @@
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright (C) 2013 - 2024, nymea GmbH
|
||||
* Copyright (C) 2024 - 2025, chargebyte austria GmbH
|
||||
*
|
||||
* This file is part of nymea-app.
|
||||
*
|
||||
* nymea-app is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* nymea-app is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with nymea-app. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Templates 2.2 as T
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Controls.Material 2.2
|
||||
import QtQuick.Controls.Material.impl 2.2
|
||||
import Nymea 1.0
|
||||
import QtQuick
|
||||
import QtQuick.Templates as T
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Controls.Material.impl
|
||||
import Nymea
|
||||
|
||||
T.Dialog {
|
||||
id: control
|
||||
|
||||
@ -22,9 +22,9 @@
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
import QtQuick 2.0
|
||||
import QtQuick
|
||||
import QtQuick.Templates 2.2
|
||||
import QtQuick.Controls.Material 2.2
|
||||
import QtQuick.Controls.Material
|
||||
|
||||
Page {
|
||||
background: Background {}
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
pragma Singleton
|
||||
import QtQuick 2.0
|
||||
import QtQuick
|
||||
import "../../ui"
|
||||
|
||||
StyleBase {
|
||||
|
||||
@ -22,8 +22,8 @@
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
import QtQuick 2.0
|
||||
import Nymea 1.0
|
||||
import QtQuick
|
||||
import Nymea
|
||||
|
||||
Rectangle {
|
||||
color: Style.backgroundColor
|
||||
|
||||
@ -22,11 +22,11 @@
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
import QtQuick 2.9
|
||||
import QtQuick
|
||||
import QtQuick.Templates 2.2 as T
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Controls.impl 2.2
|
||||
import QtQuick.Controls.Material 2.2
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Controls.Material.impl 2.2
|
||||
|
||||
T.Button {
|
||||
|
||||
@ -22,9 +22,9 @@
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
import QtQuick 2.0
|
||||
import QtQuick
|
||||
import QtQuick.Templates 2.2
|
||||
import QtQuick.Controls.Material 2.2
|
||||
import QtQuick.Controls.Material
|
||||
|
||||
Page {
|
||||
background: Background {}
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
pragma Singleton
|
||||
import QtQuick 2.0
|
||||
import QtQuick
|
||||
import "../../ui"
|
||||
|
||||
StyleBase {
|
||||
|
||||
@ -22,8 +22,8 @@
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
import QtQuick 2.0
|
||||
import Nymea 1.0
|
||||
import QtQuick
|
||||
import Nymea
|
||||
|
||||
Rectangle {
|
||||
color: Style.backgroundColor
|
||||
|
||||
@ -22,13 +22,13 @@
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
import QtQuick 2.9
|
||||
import QtQuick
|
||||
import QtQuick.Templates 2.2 as T
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Controls.impl 2.2
|
||||
import QtQuick.Controls.Material 2.2
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Controls.Material.impl 2.2
|
||||
import Nymea 1.0
|
||||
import Nymea
|
||||
|
||||
T.Button {
|
||||
id: control
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user