Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • alcroito/qt-ui-viewer
  • design-studio/design-viewer/qt-ui-viewer
2 results
Show changes
Showing
with 291 additions and 122 deletions
icons/macOS/uv_document.appiconset/icon_512x512@2x.png

68.1 KiB

File deleted
find_package(
Qt6
COMPONENTS Core Widgets Quick Gui Qml Multimedia MultimediaWidgets Concurrent Network WebSockets
COMPONENTS
Core Widgets Quick Gui Qml Multimedia MultimediaWidgets Concurrent Network WebSockets
TextToSpeech Location Sensors WebView Positioning
REQUIRED
)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core Network WebSockets)
find_package(
QT NAMES Qt6 Qt5 REQUIRED
COMPONENTS
Core Network WebSockets TextToSpeech Location Sensors WebView Positioning)
# In shared Qt builds, the qml plugins don't have dependencies on their backing libraries, and
# thus the backing library packages are not automatically looked up.
# The StandaloneTests directory contains Config files that find_package all installed Qt packages.
# Abuse that, and include all of them to make all the backing libraries available as imported
# targets.
find_package(Qt6 COMPONENTS BuildInternals)
if(Qt6BuildInternals_DIR)
set(standalone_tests_dir "${Qt6BuildInternals_DIR}/StandaloneTests")
if(EXISTS "${standalone_tests_dir}")
# Glob the config files in there.
file(GLOB_RECURSE standalone_tests_files "${standalone_tests_dir}/*TestsConfig.cmake")
# Include each one of them.
foreach(standalone_tests_file IN LISTS standalone_tests_files)
include("${standalone_tests_file}")
endforeach()
endif()
endif()
set(imports "")
# Get all imported targets.
get_property(imported_targets DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY IMPORTED_TARGETS)
# Horrible hack for shared qt builds, to ensure we bundle all known shared library qml plugins.
# Do that by finding all qml modules, their plugins, the location of the plugins, then finding the
# path to the qmldir files of the plugins, extract the module name, and adding it as an import
# statement into a dynamically generated qml file.
foreach(imported_target IN LISTS imported_targets)
# Get all qml module targets, they would have the _qt_qml_module_installed_plugin_target
# property set.
get_target_property(qml_plugin_target "${imported_target}"
_qt_qml_module_installed_plugin_target)
if(qml_plugin_target)
message(STATUS
"Imported target: ${imported_target} -> ${qml_plugin_target}")
# Get location of the plugin file.
get_target_property(imported_location_default "${qml_plugin_target}" IMPORTED_LOCATION)
get_target_property(imported_location_release "${qml_plugin_target}" IMPORTED_LOCATION_RELEASE)
get_target_property(imported_location_min_size "${qml_plugin_target}" IMPORTED_LOCATION_MINSIZEREL)
get_target_property(imported_location_min_size_rel "${qml_plugin_target}" IMPORTED_LOCATION_RELWITHDEBINFO)
if(imported_location_default)
set(imported_location "${imported_location_default}")
elseif(imported_location_release)
set(imported_location "${imported_location_release}")
elseif(imported_location_min_size)
set(imported_location "${imported_location_min_size}")
elseif(imported_location_min_size_rel)
set(imported_location "${imported_location_min_size_rel}")
else()
message(WARNING "No imported location found for ${qml_plugin_target}.")
continue()
endif()
# Get parent dir of the plugin file.
get_filename_component(imported_location_dir "${imported_location}" DIRECTORY)
# Build path to qmldir in the same directory. We assume the qmldir is always next
# to the plugin file. That's at least usually the case for Qt qml plugins.
set(qmldir_path "${imported_location_dir}/qmldir")
if(NOT EXISTS "${qmldir_path}")
message(WARNING "No qmldir file found for ${qml_plugin_target}.")
continue()
endif()
# Read qmldir file contents.
file(READ "${qmldir_path}" qmldir_content)
if(qmldir_content STREQUAL "")
message(WARNING "Empty qmldir for ${qml_plugin_target}.")
continue()
endif()
# Find the module name in the qmldir file
string(REGEX MATCH "module ([^\n]+)" module_match "${qmldir_content}")
if(CMAKE_MATCH_1)
# Add the module name as an import to the imports list
list(APPEND imports "import ${CMAKE_MATCH_1}")
endif()
endif()
endforeach()
set(imports_file_path "${CMAKE_CURRENT_BINARY_DIR}/dynamic_imports.qml")
# Needed to stop __qt_get_relative_resource_path_for_file from erroring out.
set_source_files_properties("${imports_file_path}"
PROPERTIES QT_RESOURCE_ALIAS "dynamic_imports.qml")
if(imports)
list(REMOVE_DUPLICATES imports)
string(REPLACE ";" "\n" imports "${imports}")
endif()
# Use file(GENERATE) to prevent touching the file if the contents hasn't changed.
set(dummy_valid_content "ApplicationWindow {
visible: true
width: 640
height: 480
}")
file(GENERATE OUTPUT "${imports_file_path}" CONTENT "${imports}
${dummy_valid_content}
")
qt_add_executable(${PROJECT_NAME}
backend/importdummy.qml
backend/main.cpp
backend/logger.h
backend/backend.cpp backend/backend.h
......@@ -27,6 +138,7 @@ qt_add_qml_module(${PROJECT_NAME}
URI AndroidUI
VERSION 1.0
QML_FILES
"${imports_file_path}"
Constants.qml
HomePage.qml
Main.qml
......@@ -43,7 +155,7 @@ qt_target_qml_sources(${PROJECT_NAME}
"/"
RESOURCES
fonts/QtOneIconFont.ttf
images/appicon.png
images/appicon.svg
)
target_link_libraries(${PROJECT_NAME} PRIVATE
......@@ -52,6 +164,8 @@ target_link_libraries(${PROJECT_NAME} PRIVATE
Qt6::Qml Qt6::GuiPrivate
Qt6::Multimedia Qt6::MultimediaWidgets
Qt6::Concurrent Qt6::Network Qt6::WebSockets
Qt6::TextToSpeech Qt6::Location Qt6::Sensors
Qt6::WebView Qt6::Positioning
ZXing::ZXing
)
......@@ -69,9 +183,6 @@ target_link_libraries(qtuiviewerlib PRIVATE
Qt6::Qml
Qt6::Gui
Qt6::GuiPrivate
Qt6::Multimedia
Qt6::MultimediaWidgets
Qt6::Concurrent
Qt6::WebSockets
)
......@@ -79,16 +190,16 @@ target_include_directories(qtuiviewerlib PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
)
set_target_properties(${PROJECT_NAME} PROPERTIES QT_ANDROID_PACKAGE_NAME "io.qt.qtdesignviewer")
set_property(TARGET ${PROJECT_NAME}
APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/android
APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/android
)
set_property(TARGET ${PROJECT_NAME} PROPERTY QT_ANDROID_EXTRA_LIBS
${ANDROID_OPENSSL_PATH}/libcrypto_3.so
${ANDROID_OPENSSL_PATH}/libssl_3.so
set_property(TARGET ${PROJECT_NAME}
APPEND PROPERTY QT_ANDROID_EXTRA_LIBS
${ANDROID_OPENSSL_PATH}/libcrypto_3.so
${ANDROID_OPENSSL_PATH}/libssl_3.so
)
# this needs to be increased with every new release
set(GOOGLE_PLAY_APP_VERSION 31)
# CMAKE_VAR_GIT_VERSION (coming from the top-level CMakeLists.txt) and GOOGLE_PLAY_APP_VERSION replaced in the following file
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/android/AndroidManifest.xml.in ${CMAKE_CURRENT_SOURCE_DIR}/android/AndroidManifest.xml)
......@@ -53,7 +53,7 @@ Flickable {
Image {
id: qdsLogo
source: "/images/appicon.png"
source: "/images/appicon.svg"
fillMode: Image.PreserveAspectFit
Layout.preferredWidth: 64
Layout.preferredHeight: 64
......@@ -101,7 +101,7 @@ Flickable {
}
Repeater {
model: [qsTr("Open Qt Design Studio"), qsTr("Click Play > Manage Run Targets"), qsTr("In Manage Run Targets window click Add run target button.")]
model: [qsTr("Open up the Qt Design Studio, and a project"), qsTr("Click on the dropdown menu of the Play button in the header"), qsTr("Select Open Device Manager from the menu"), qsTr("In the Device Manager window click on Set Device IP and type in the IP address found from below")]
delegate: RowLayout {
Layout.fillWidth: true
......@@ -137,118 +137,47 @@ Flickable {
spacing: 10
Rectangle {
Label {
Layout.fillWidth: true
Layout.preferredHeight: optionLayout1.height
color: Constants.boxBackgroundColor
radius: Material.MediumScale
border {
width: 1
color: Constants.boxBorderColor
}
ColumnLayout {
id: optionLayout1
width: parent.width
spacing: 20
Label {
Layout.fillWidth: true
Layout.topMargin: 20
horizontalAlignment: Qt.AlignHCenter
text: qsTr("Option 1")
font.pixelSize: Constants.lgTextSize
font.bold: true
wrapMode: Text.WordWrap
}
Label {
Layout.fillWidth: true
Layout.leftMargin: 20
Layout.rightMargin: 20
horizontalAlignment: Qt.AlignHCenter
text: qsTr("Click to scan the QR code in Qt Design Studio")
font.pixelSize: Constants.mdTextSize
wrapMode: Text.WordWrap
}
QrButton {
Layout.alignment: Qt.AlignHCenter
Layout.bottomMargin: 20
onClicked: backend.scanQrCode()
}
}
text: qsTr("This device can be reached at the following IP addresses:")
font.pixelSize: Constants.lgTextSize
font.bold: true
wrapMode: Text.WordWrap
}
Rectangle {
Label {
id: ipAddress
Layout.fillWidth: true
Layout.preferredHeight: optionLayout2.height
color: Constants.boxBackgroundColor
radius: Material.MediumScale
border {
width: 1
color: Constants.boxBorderColor
}
ColumnLayout {
id: optionLayout2
width: parent.width
spacing: 20
Label {
Layout.fillWidth: true
Layout.topMargin: 20
text: qsTr("xxx.xxx.xxx.xxx")
font.pixelSize: Constants.lgTextSize
font.bold: false
wrapMode: Text.WordWrap
horizontalAlignment: Qt.AlignHCenter
text: qsTr("Option 2")
font.pixelSize: Constants.lgTextSize
font.bold: true
function updateIpAddresses() {
ipAddress.text = '';
var val = backend.getIpAddresses();
wrapMode: Text.WordWrap
}
if(val.length === 0)
ipAddress.text = qsTr("Not connected to any network.");
TextField {
id: ipAddress
Layout.fillWidth: true
Layout.leftMargin: 20
Layout.rightMargin: 20
Layout.alignment: Qt.AlignHCenter
placeholderText: qsTr("IP Address")
text: backend.lastDesignStudioIp()
validator: RegularExpressionValidator {
regularExpression: /^(\d{1,3}\.){3}\d{1,3}$/
}
for(var i = 0; i < val.length; i++)
ipAddress.text += val[i].interface + ': ' + val[i].ip + '\n';
}
Connections {
target: backend
Timer {
id: timer
interval: 1000
running: true
repeat: true
function onConnectedChanged(isConnected, ip) {
ipAddress.text = ip;
}
}
onTriggered: {
ipAddress.updateIpAddresses();
}
}
Button {
id: downloadUserProject
Layout.fillWidth: true
Layout.leftMargin: 20
Layout.rightMargin: 20
Layout.bottomMargin: 20
Layout.alignment: Qt.AlignHCenter
text: qsTr("Connect Design Studio")
enabled: true
onClicked: backend.connectDesignStudio(ipAddress.text)
}
Component.onCompleted: {
ipAddress.updateIpAddresses();
timer.start();
}
}
}
......
......@@ -61,7 +61,6 @@ Rectangle {
Connections {
target: backend
function onConnectedChanged(isConnected) {
console.log("Connected changed to", isConnected)
root.connected = isConnected
}
}
......@@ -107,4 +106,70 @@ Rectangle {
}
}
}
Popup {
id: popup
width: 250
height: 75
modal: true
visible: false
anchors.centerIn: parent
Rectangle {
anchors.fill: parent
color: "white"
Text {
id: popupText
anchors.centerIn: parent
}
}
ProgressBar {
id: progressBar
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
from: 0
to: 100
height: 2
visible: true
indeterminate: true
}
Timer {
id: timer
repeat: false
running: popup.visible
onTriggered: {
popup.visible = false
}
}
Connections {
target: backend
function onPopupOpen() {
popup.visible = true
}
function onPopupClose() {
popup.visible = false
}
function onPopupChangeText(text, timeout) {
popupText.text = text
timer.interval = timeout
timer.running = timeout > 0
}
function onPopupChangeProgress(percentage){
progressBar.value = percentage
}
function onPopupProgressIndeterminateChanged(indeterminate) {
progressBar.indeterminate = indeterminate
}
}
}
}
......@@ -29,11 +29,20 @@ Flickable {
Layout.fillWidth: true
horizontalPadding: 20
text: qsTr("Auto-scale")
subText: qsTr("Scales the project to fit to current display and orientation")
subText: qsTr("Tries to scale the project to fit to current display and orientation. May not work with all projects.")
checked: backend.autoScaleProject() ? Qt.Checked : Qt.Unchecked
onToggled: backend.setAutoScaleProject(checked)
}
SwitchSettingsItem {
Layout.fillWidth: true
horizontalPadding: 20
text: qsTr("Keep screen on")
subText: qsTr("Prevents the device from going to sleep while the app is running")
checked: backend.keepScreenOn() ? Qt.Checked : Qt.Unchecked
onToggled: backend.setKeepScreenOn(checked)
}
SettingsItem {
Layout.fillWidth: true
horizontalPadding: 20
......
<?xml version="1.0"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.qt.qtdesignviewer"
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:installLocation="auto" android:versionCode="@GOOGLE_PLAY_APP_VERSION@"
android:versionName="@CMAKE_VAR_GIT_VERSION@">
<!-- %%INSERT_PERMISSIONS -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- %%INSERT_FEATURES -->
<supports-screens android:anyDensity="true" android:largeScreens="true"
android:normalScreens="true" android:smallScreens="true" />
<application android:icon="@mipmap/app_icon"
<application android:icon="@mipmap/ic_launcher"
android:name="org.qtproject.qt.android.bindings.QtApplication"
android:extractNativeLibs="true" android:hardwareAccelerated="true"
android:label="Qt UI Viewer" android:requestLegacyExternalStorage="true"
......@@ -16,7 +17,7 @@
android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density"
android:label="Qt UI Viewer" android:launchMode="singleTask"
android:screenOrientation="unspecified" android:exported="true"
android:windowSoftInputMode="adjustResize">
android:windowSoftInputMode="adjustResize" android:keepScreenOn="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
......
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<group android:scaleX="0.99"
android:scaleY="0.99"
android:translateX="0.54"
android:translateY="0.54">
<path
android:pathData="M0,13.5V108H94.5L108,94.5V0H13.5L0,13.5Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="104.99"
android:startY="-26.62"
android:endX="11.55"
android:endY="126.08"
android:type="linear">
<item android:offset="0.14" android:color="#FF014B57"/>
<item android:offset="1" android:color="#FF0F7080"/>
</gradient>
</aapt:attr>
</path>
</group>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<group android:scaleX="0.66"
android:scaleY="0.66"
android:translateX="17.37"
android:translateY="17.04">
<group>
<clip-path
android:pathData="M0.25,0.13h107.75v107.75h-107.75z"/>
<path
android:pathData="M28.84,62.54C28.84,67.29 31.25,69.66 36.08,69.66C40.91,69.66 43.33,67.29 43.33,62.54V35.42H51.59V62.36C51.59,67.35 50.29,71.02 47.69,73.37C45.14,75.69 41.27,76.84 36.08,76.84C30.89,76.84 27,75.69 24.41,73.37C21.85,71.02 20.58,67.35 20.58,62.36V35.42H28.84V62.54ZM82.13,35.42H90.81L81.35,76.13H66.09L56.63,35.42H65.31L72.38,68.94H75.07L82.13,35.42Z"
android:fillColor="#2CDE85"/>
</group>
</group>
</vector>
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>
\ No newline at end of file
src/android/res/mipmap-hdpi/app_icon.png

4.36 KiB

src/android/res/mipmap-hdpi/ic_launcher.webp

2.04 KiB

src/android/res/mipmap-hdpi/ic_launcher_round.webp

3.5 KiB

src/android/res/mipmap-ldpi/app_icon.png

798 B

src/android/res/mipmap-mdpi/app_icon.png

1.72 KiB

src/android/res/mipmap-mdpi/ic_launcher.webp

1.4 KiB

src/android/res/mipmap-mdpi/ic_launcher_round.webp

2.29 KiB

src/android/res/mipmap-xhdpi/app_icon.png

6.22 KiB

src/android/res/mipmap-xhdpi/ic_launcher.webp

2.62 KiB