Skip to content
Snippets Groups Projects
Commit e1dcc04c authored by Burak Hançerli's avatar Burak Hançerli :headphones:
Browse files

QDS-10755 New user interface

parent e98d6239
No related branches found
No related tags found
1 merge request!15QDS-10755 New user interface
Pipeline #64180 passed
<?xml version="1.0"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.qt.qtdesignviewer"
android:installLocation="auto" android:versionCode="8" android:versionName="1.2">
android:installLocation="auto" android:versionCode="9" android:versionName="1.2">
<!-- %%INSERT_PERMISSIONS -->
<!-- %%INSERT_FEATURES -->
<supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:smallScreens="true"/>
......
......@@ -52,7 +52,7 @@
#define QSTRN QString::number
Backend::Backend(QObject *parent)
Backend::Backend(QObject *parent) : QObject(parent)
{
QDesktopServices::setUrlHandler("qtdesignviewer", this, "registerUser");
......@@ -227,14 +227,21 @@ void Backend::parseQmlprojectFile(const QString &fileName,
bool Backend::runProject(const QByteArray &projectData, const QString &projectName)
{
emit popupTextChanged("Unpacking project...");
emit popupProgressIndeterminateChanged(true);
QEventLoop().processEvents(QEventLoop::AllEvents, 1000);
const QString projectLocation = unpackProject(projectData);
const QString newProjectName = QString(projectName).remove(".qmlrc").remove("#");
printLog("Final project location: " + projectLocation);
printLog("Project name: " + projectName);
printLog("New project name: " + newProjectName);
QString mainQmlFilePath;
QStringList importPaths;
printLog("Looking for qmlproject file in " + projectLocation);
const QString qmlProjectFile = findFile(projectLocation, "*.qmlproject");
const QString qmlProjectFile = findFile(projectLocation, newProjectName + "*.qmlproject");
if (!qmlProjectFile.isEmpty()) {
printLog("Found qmlproject file: " + qmlProjectFile);
parseQmlprojectFile(qmlProjectFile, &mainQmlFilePath, &importPaths);
......@@ -243,14 +250,13 @@ bool Backend::runProject(const QByteArray &projectData, const QString &projectNa
mainQmlFilePath = findFile(projectLocation, "main.qml");
if (mainQmlFilePath.isEmpty()) {
printWarn("Not found: \"main.qml\". Looking for \"" + projectName + ".qml\"..");
mainQmlFilePath = findFile(projectLocation, projectName + ".qml");
printWarn("Not found: \"main.qml\". Looking for \"" + newProjectName + ".qml\"..");
mainQmlFilePath = findFile(projectLocation, newProjectName + ".qml");
}
}
if (mainQmlFilePath.isEmpty()) {
printErr("No \"*.qmlproject\", \"main.qml\" or \"" + projectName + ".qml\" found in \""
+ projectLocation + "\".");
printErr("No \"*.qmlproject\", \"main.qml\" or \"" + newProjectName + ".qml\" found in \"" + projectLocation + "\".");
return false;
}
......@@ -287,25 +293,34 @@ bool Backend::runProject(const QByteArray &projectData, const QString &projectNa
}
});
emit popupTextChanged("Loading project...");
QEventLoop().processEvents(QEventLoop::AllEvents, 1000);
printLog("Loading mainQmlUrl: " + mainQmlUrl.toString());
m_qmlComponent.loadUrl(mainQmlUrl);
m_qmlComponent.reset(new QQmlComponent(&m_qmlEngine));
m_qmlComponent->loadUrl(mainQmlUrl);
printLog("Waiting for qmlComponent to load");
while (m_qmlComponent.isLoading())
while (m_qmlComponent->isLoading())
QCoreApplication::processEvents();
printLog("Checking if m_qmlComponent is ready");
if (!m_qmlComponent.isReady()) {
printErr("m_qmlComponent is not ready. Reason: " + m_qmlComponent.errorString());
if (!m_qmlComponent->isReady())
{
printErr("m_qmlComponent is not ready. Reason: " + m_qmlComponent->errorString());
return false;
}
printLog("Creating top level object");
QObject *topLevel = m_qmlComponent.create();
if (!topLevel && m_qmlComponent.isError()) {
printErr("Error while creating Qml m_qmlComponent:" + m_qmlComponent.errorString());
QObject *topLevel = m_qmlComponent->create();
if (!topLevel && m_qmlComponent->isError())
{
printErr("Error while creating Qml m_qmlComponent:" + m_qmlComponent->errorString());
return false;
}
emit popupTextChanged("Setting up the quickWindow...");
QEventLoop().processEvents(QEventLoop::AllEvents, 1000);
printLog("Setting up the quickWindow");
m_quickWindow.reset(qobject_cast<QQuickWindow *>(topLevel));
if (m_quickWindow) {
......@@ -323,7 +338,7 @@ bool Backend::runProject(const QByteArray &projectData, const QString &projectNa
printLog("Initializing QQuickView");
QQuickView *view = new QQuickView(&m_qmlEngine, nullptr);
m_quickWindow.reset(view);
view->setContent(mainQmlUrl, &m_qmlComponent, contentItem);
view->setContent(mainQmlUrl, m_qmlComponent.data(), contentItem);
view->setResizeMode(QQuickView::SizeViewToRootObject);
m_quickWindow->setBaseSize(QSize(contentItem->width(), contentItem->height()));
}
......@@ -377,28 +392,32 @@ void Backend::orientateWindow(Qt::ScreenOrientation orientation)
{
QQuickItem *contentItem = m_quickWindow->contentItem();
QQuickItem *childItem{contentItem->childItems().at(0)};
const QRect screenGeometry = QGuiApplication::primaryScreen()->geometry();
QQuickItem *grandChildItem{childItem->childItems().at(0)};
QQuickItem *targetItem = childItem;
printLog("Adapting orientation. Initial sizing:");
printLog("-- Screen size: " + QSTRN(screenGeometry.height()) + " x "
+ QSTRN(screenGeometry.width()));
const QRect screenGeometry = QGuiApplication::primaryScreen()->geometry();
const QString orientationString = (orientation == Qt::LandscapeOrientation ? "landscape"
: "portrait");
printLog("Adapting orientation to " + orientationString + " mode");
printLog("Initial sizing:");
printLog("-- Screen size: " + QSTRN(screenGeometry.height()) + " x " + QSTRN(screenGeometry.width()));
printLog("-- Quick window size: " + QSTRN(m_quickWindow->height()) + " x "
+ QSTRN(m_quickWindow->width()));
printLog("-- Child size: " + QSTRN(childItem->height()) + " x " + QSTRN(childItem->width()));
printLog("-- Child pos: " + QSTRN(childItem->x()) + ", " + QSTRN(childItem->y()));
printLog("-- Child scale: " + QSTRN(childItem->scale()));
printLog("-- Child size: " + QSTRN(targetItem->height()) + " x " + QSTRN(targetItem->width()));
printLog("-- Child pos: " + QSTRN(targetItem->x()) + ", " + QSTRN(targetItem->y()));
printLog("-- Child scale: " + QSTRN(targetItem->scale()));
printLog("Calculating the new size and scale...");
const QSizeF newContentSize = childItem->size().scaled(screenGeometry.size().toSizeF(),
const QSizeF newContentSize = targetItem->size().scaled(screenGeometry.size().toSizeF(),
Qt::AspectRatioMode::KeepAspectRatio);
const qreal newScale = newContentSize.height() / childItem->size().height();
const qreal newX = (childItem->width() - screenGeometry.width()) / -2.0f;
const qreal newY = (childItem->height() - screenGeometry.height()) / -2.0f;
const qreal newScale = newContentSize.height() / targetItem->size().height();
const qreal newX = (targetItem->width() - screenGeometry.width()) / -2.0f;
const qreal newY = (targetItem->height() - screenGeometry.height()) / -2.0f;
childItem->setScale(newScale);
childItem->setPosition(QPointF(newX, newY));
targetItem->setScale(newScale);
targetItem->setPosition(QPointF(newX, newY));
printLog("-- Calculated item height: " + QSTRN(newContentSize.height()));
printLog("-- Calculated item width: " + QSTRN(newContentSize.width()));
......@@ -406,11 +425,11 @@ void Backend::orientateWindow(Qt::ScreenOrientation orientation)
printLog("-- Calculated item pos..: " + QSTRN(newX) + "," + QSTRN(newY));
printLog("Final Sizing:");
printLog("-- Child height: " + QSTRN(childItem->height()));
printLog("-- Child width: " + QSTRN(childItem->width()));
printLog("-- Child scale: " + QSTRN(childItem->scale()));
printLog("-- Child pos-x: " + QSTRN(childItem->x()));
printLog("-- Child pos-y: " + QSTRN(childItem->y()));
printLog("-- Child height: " + QSTRN(targetItem->height()));
printLog("-- Child width: " + QSTRN(targetItem->width()));
printLog("-- Child scale: " + QSTRN(targetItem->scale()));
printLog("-- Child pos-x: " + QSTRN(targetItem->x()));
printLog("-- Child pos-y: " + QSTRN(targetItem->y()));
}
void Backend::showAppWindow()
......@@ -420,12 +439,16 @@ void Backend::showAppWindow()
orientateWindow(screen->orientation());
printLog("Initializing and showing the QML app window");
// m_quickWindow->showMaximized();
m_quickWindow->show();
}
void Backend::downloadAndRun(const QString &url)
{
emit popupTextChanged("Downloading project...");
emit popupProgressIndeterminateChanged(false);
emit popupOpen();
printLog("=========================");
printLog("Fetching a new project...");
......@@ -438,14 +461,17 @@ void Backend::downloadAndRun(const QString &url)
auto reply = fetchResource(projectUrl);
if (reply->error() != QNetworkReply::NoError) {
printErr("Could not fetch project");
emit popupClose();
return;
}
if (!runProject(reply->readAll(), QFileInfo(url).baseName())) {
printErr("Could not run project");
emit popupClose();
return;
}
emit popupClose();
showAppWindow();
}
......@@ -474,6 +500,8 @@ void Backend::updateUserProjectList()
.toObject()
.value("packages")
.toArray();
m_projectList.clear();
printLog("List of available projects fetched:");
for (const auto &project : projectList) {
const QString projectName{project.toObject().value("appName").toString()};
......
......@@ -31,6 +31,7 @@
#include <QQmlEngine>
#include <QQuickView>
#include <QQuickWindow>
#include <QWidget>
#define printErr(x) printError(x, __FILE_NAME__, __LINE__)
......@@ -60,8 +61,8 @@ private:
// Qml related members
QQmlEngine m_qmlEngine;
QQmlComponent m_qmlComponent{&m_qmlEngine};
QScopedPointer<QQuickWindow> m_quickWindow;
QSharedPointer<QQmlComponent> m_qmlComponent;
QSharedPointer<QQuickWindow> m_quickWindow;
// Other members
QNetworkAccessManager m_nam;
......@@ -89,6 +90,10 @@ signals:
void buildInfoChanged();
void downloadProgressChanged();
void projectListChanged();
void popupProgressIndeterminateChanged(bool indeterminate);
void popupTextChanged(QString text);
void popupOpen();
void popupClose();
public slots:
void downloadAndRun(const QString &url);
......
......@@ -37,9 +37,9 @@ int main(int argc, char *argv[])
QApplication::setApplicationName(QStringLiteral("Qt Design Viewer"));
QApplication::setApplicationVersion(QString("Built on %1 %2").arg(__DATE__, __TIME__));
QQuickView view;
Backend backend;
QQuickView view;
view.engine()->rootContext()->setContextProperty("backend", &backend);
view.setSource(QUrl(QStringLiteral("qrc:/main.qml")));
view.setResizeMode(QQuickView::SizeRootObjectToView);
......
import QtQuick
import QtQuick.Controls 6.4
import QtQuick.Layouts
Item {
id: header
ColumnLayout {
anchors.fill: parent
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Item {
id: item2
width: 200
height: 200
Layout.preferredHeight: 10
Layout.fillWidth: true
}
Label {
id: label
text: qsTr("Android Design Viewer")
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
id: label1
text: qsTr("Technology Preview")
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
id: label2
text: backend.buildInfo
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
horizontalAlignment: "AlignHCenter"
}
Item {
id: item1
Layout.fillHeight: true
Layout.fillWidth: true
}
}
}
import QtQuick
import QtQuick.Window 2.2
import QtQuick.Controls 6.5
import QtQuick.Layouts
Item {
id: examplesPage
ColumnLayout {
anchors.fill: parent
Button {
id: button3
text: qsTr("Cluster Tutorial")
Layout.fillWidth: true
onClicked: backend.downloadAndRun("https://designviewer.qt.io/#ClusterTutorial.qmlrc")
}
Button {
id: button5
text: qsTr("Coffee Machine")
Layout.fillWidth: true
onClicked: backend.downloadAndRun("https://designviewer.qt.io/#CoffeeMachine.qmlrc")
}
Button {
id: button
text: qsTr("E-Bike Design")
Layout.fillWidth: true
onClicked: backend.downloadAndRun("https://designviewer.qt.io/#EBikeDesign.qmlrc")
}
Button {
id: button2
text: qsTr("Side Menu")
Layout.fillWidth: true
onClicked: backend.downloadAndRun("https://designviewer.qt.io/#SideMenu.qmlrc")
}
Button {
id: button1
text: qsTr("Webinar Demo")
Layout.fillWidth: true
onClicked: backend.downloadAndRun("https://designviewer.qt.io/#WebinarDemo.qmlrc")
}
Button {
id: button4
text: qsTr("Material Bundle")
Layout.fillWidth: true
onClicked: backend.downloadAndRun("https://designviewer.qt.io/#MaterialBundle.qmlrc")
}
Item {
id: item1
width: 200
height: 200
Layout.fillHeight: true
Layout.fillWidth: true
}
}
}
import QtQuick
import QtQuick.Controls 6.4
import QtQuick.Layouts
Item {
id: homePage
//width: 400
//height: 740
ColumnLayout {
anchors.fill: parent
Item {
id: item2
Layout.preferredWidth: 10
Layout.preferredHeight: 10
Layout.fillWidth: true
Layout.fillHeight: true
}
ComboBox {
id: projectList
Layout.fillWidth: true
onCurrentIndexChanged: {
urlTextField.text = "https://designviewer.qt.io/qmlprojects/"
+ backend.userHash + "/"
+ textAt(currentIndex)
+ ".qmlrc"
displayText = textAt(currentIndex)
}
onModelChanged: {
if (model.count > 0) {
currentIndex = 0
}
}
model: backend.projectList
down: false
displayText: "Select project..."
currentIndex: -1
Layout.preferredHeight: 50
}
ColumnLayout {
id: column
Layout.fillWidth: true
TextField {
id: urlTextField
horizontalAlignment: Text.AlignHCenter
placeholderText: qsTr("Enter URL")
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
RowLayout {
id: rowLayout
anchors.left: parent.left
anchors.right: parent.right
Button {
id: downloadButton
text: qsTr("Download and Run")
onClicked: backend.downloadAndRun(urlTextField.text)
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
}
}
Item {
id: item1
Layout.fillHeight: true
Layout.fillWidth: true
Layout.preferredHeight: 10
Layout.preferredWidth: 10
}
}
}
import QtQuick
import QtQuick.Controls 6.4
import QtQuick.Window 2.2
Rectangle {
id: log
width: 348
height: 501
visible: true
color: "#EAEAEA"
ScrollView {
id: scrollArea
visible: true
anchors.fill: parent
topPadding: 13.1
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
Connections {
target: backend
function onLogsChanged() {
logTextArea.text = backend.logs
scrollArea.ScrollBar.vertical.position = 1.0 - scrollArea.ScrollBar.vertical.size
}
}
TextArea {
clip: false
id: logTextArea
wrapMode: TextEdit.Wrap
anchors.fill: parent
text: backend.logs
rightInset: 20
readOnly: true
anchors.topMargin: 5
placeholderText: qsTr("Application Logs")
}
}
}
import QtQuick 6.4
import QtQuick.Controls 6.4
import QtQuick.Controls.Material
import QtQuick.Controls.Material as M
import QtQuick.Layouts
import QtQuick.Window 2.2
//import QtQuick.Window 2.2
Rectangle {
id: root
width: 400
height: 800
color: "#EAEAEA"
state: "vertical"
Material.theme: Material.Light
Material.accent: Material.Blue
Material.primary: Material.Blue
M.Material.theme: M.Material.Light
M.Material.accent: M.Material.Blue
M.Material.primary: M.Material.Blue
ColumnLayout {
id: bar
y: 50
anchors.bottom: column.top
anchors.bottomMargin: 24
Image {
id: qdsicon1
width: 204
height: 173
anchors.top: parent.top
source: "content/images/dvicon.png"
anchors.horizontalCenter: parent.horizontalCenter
fillMode: Image.PreserveAspectFit
Text {
id: qdvLabel
text: qsTr("Qt Design Viewer for Android")
anchors.top: parent.bottom
font.pixelSize: 12
anchors.topMargin: -22
anchors.horizontalCenter: parent.horizontalCenter
}
}
Popup {
id: popup
anchors.centerIn: parent
width: 300
height: 100
modal: true
focus: true
closePolicy: Popup.CloseOnEscape
ColumnLayout {
anchors.fill: parent
Text {
id: popupText
text: backend.popupText
}
Item {
id: name
}
ProgressBar {
id: progressBar
Layout.minimumWidth: 380
to: 100
id: popupProgressBar
Layout.fillWidth: true
value: backend.downloadProgress
to: 100
indeterminate: backend.popupProgressIndeterminate
}
}
ColumnLayout {
id: column
height: 113
Connections {
target: backend
function onPopupOpen() {
popup.open()
}
function onPopupClose() {
popup.close()
}
function onPopupTextChanged(text) {
popupText.text = text
}
function onPopupProgressIndeterminateChanged(status) {
popupProgressBar.indeterminate = status
}
}
}
StackLayout {
id: stackLayout
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.bottomMargin: 12
anchors.rightMargin: 22
anchors.leftMargin: 22
TextField {
id: urlTextField
horizontalAlignment: Text.AlignHCenter
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
anchors.bottom: navFooter.top
anchors.bottomMargin: 10
anchors.top: qdsicon1.bottom
anchors.rightMargin: 20
anchors.leftMargin: 20
anchors.topMargin: 10
HomePage {
id: homePage
Layout.fillWidth: true
placeholderText: qsTr("Enter URL")
}
RowLayout{
id: rowLayout
anchors.left: parent.left
anchors.right: parent.right
Button {
id: downloadButton
ExamplesPage {
id: examplesPage
Layout.fillWidth: true
}
Logs {
id: logsPage
Layout.fillWidth: true
text: qsTr("Download and Run")
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
onClicked: backend.downloadAndRun(urlTextField.text)
}
AboutHeader {
id: headerPage
Layout.fillWidth: true
}
}
Item {
id: header
width: 351
height: gridLayout.height
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
id: navFooter
y: 703
height: 97
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.rightMargin: 0
anchors.leftMargin: 0
anchors.bottomMargin: 0
Layout.fillHeight: true
Layout.fillWidth: true
GridLayout {
id: gridLayout
anchors.horizontalCenter: parent.horizontalCenter
rows: root.height > 420 ? 2 : 1
columns: root.height > 420 ? 1 : 2
Rectangle {
id: rectangle
color: "#cecece"
anchors.fill: parent
Image {
id: qdsicon
x: 47
y: -48
width: 204
height: 202
source: "content/images/dvicon.png"
fillMode: Image.PreserveAspectFit
RowLayout {
id: row
anchors.fill: parent
anchors.bottomMargin: 31
anchors.rightMargin: 10
anchors.leftMargin: 10
spacing: 5
TabButton {
id: home
text: qsTr("Home")
Layout.fillWidth: true
checked: true
checkable: true
autoExclusive: true
Connections {
target: home
onClicked: stackLayout.currentIndex = 0
}
}
ColumnLayout {
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Label {
id: label
text: qsTr("Android Design Viewer")
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
TabButton {
id: examples
text: qsTr("Examples")
Layout.fillWidth: true
checkable: true
autoExclusive: true
Label {
id: label1
text: qsTr("Technology Preview")
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Connections {
target: examples
onClicked: stackLayout.currentIndex = 1
}
}
Label {
id: label2
text: backend.buildInfo
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
horizontalAlignment: "AlignHCenter"
TabButton {
id: logs
text: qsTr("Logs")
Layout.fillWidth: true
checkable: true
autoExclusive: true
Connections {
target: logs
onClicked: stackLayout.currentIndex = 2
}
}
TabButton {
id: about
text: qsTr("About")
Layout.fillWidth: true
checkable: true
autoExclusive: true
Connections {
target: about
onClicked: stackLayout.currentIndex = 3
}
}
ComboBox {
id: projectList
height: 50
anchors.left: parent.left
anchors.right: parent.right
anchors.top: header.bottom
down: false
anchors.topMargin: 15
anchors.rightMargin: 22
anchors.leftMargin: 22
displayText: "Select project..."
model: backend.projectList
currentIndex: -1
onCurrentIndexChanged: {
urlTextField.text = "https://designviewer.qt.io/qmlprojects/"
+ backend.userHash + "/"
+ textAt(currentIndex)
+ ".qmlrc"
displayText = textAt(currentIndex)
}
}
Rectangle {
id: log
visible: true
color: "#EAEAEA"
anchors.left: parent.left
anchors.right: parent.right
anchors.top: projectList.bottom
anchors.bottom: bar.top
anchors.bottomMargin: 24
anchors.leftMargin: 22
ScrollView {
id: scrollArea
visible: true
anchors.fill: parent
topPadding: 13.1
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
Connections {
target: backend
function onLogsChanged() {
logTextArea.text = backend.logs
scrollArea.ScrollBar.vertical.position = 1.0 - scrollArea.ScrollBar.vertical.size
}
states: [
State {
name: "vertical"
when: root.width <= 400
},
State {
name: "horizontal"
when: root.width > 400
PropertyChanges {
target: qdsicon1
width: 132
height: 83
}
TextArea {
clip: false
id: logTextArea
wrapMode: TextEdit.Wrap
anchors.fill: parent
text: backend.logs
rightInset: 20
readOnly: true
anchors.topMargin: 5
placeholderText: qsTr("Application Logs")
PropertyChanges {
target: qdvLabel
anchors.topMargin: -8
}
PropertyChanges {
target: stackLayout
anchors.topMargin: 20
}
}
]
......
; This file can be edited to change the style of the application
; Read "Qt Quick Controls 2 Configuration File" for details:
; http://doc.qt.io/qt-5/qtquickcontrols2-configuration.html
[Controls]
Style=Basic
Style=Material
......@@ -2,5 +2,9 @@
<qresource prefix="/">
<file>content/images/dvicon.png</file>
<file>main.qml</file>
<file>HomePage.qml</file>
<file>Logs.qml</file>
<file>ExamplesPage.qml</file>
<file>AboutHeader.qml</file>
</qresource>
</RCC>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment