diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..b34404630fcd76fb5bbb2afff02daece663dc259
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+.DS_Store
+ui/*.db
+ui/*.qtds
+ui/*.db-shm
+ui/*.db-wal
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ddcd1165f5ea40e00435612a906a06f9a1532084..1df7557afd97cd46a073e6f117b2cdd1169c862c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -31,7 +31,8 @@ endif()
 qt_add_executable(${PROJECT_NAME}
     src/main.cpp
     src/backend.cpp src/backend.h
-    resources/resources.qrc
+    ui/main.qml
+    ui/resources.qrc
 )
 
 target_link_libraries(${PROJECT_NAME} PRIVATE
@@ -48,15 +49,17 @@ set_property(TARGET ${PROJECT_NAME}
 APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/android
 )
 
-if(EXISTS ${ANDROID_OPENSSL_PATH})
-    message(STATUS "Found OpenSSL for Android. Path: ${ANDROID_OPENSSL_PATH}")
-    set_property(TARGET ${PROJECT_NAME} PROPERTY QT_ANDROID_EXTRA_LIBS
-        ${ANDROID_OPENSSL_PATH}/libcrypto_3.so
-        ${ANDROID_OPENSSL_PATH}/libssl_3.so)
-else()
+if(NOT EXISTS ${ANDROID_OPENSSL_PATH})
     message(WARNING "Cannot find OpenSSL for Android. Path: ${ANDROID_OPENSSL_PATH}")
+    message(FATAL_ERROR "Please set ANDROID_OPENSSL_PATH to the path of OpenSSL for Android.")
 endif()
 
+message(STATUS "Found OpenSSL for Android. Path: ${ANDROID_OPENSSL_PATH}")
+set_property(TARGET ${PROJECT_NAME} PROPERTY QT_ANDROID_EXTRA_LIBS
+    ${ANDROID_OPENSSL_PATH}/libcrypto_3.so
+    ${ANDROID_OPENSSL_PATH}/libssl_3.so)
+
 set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${CMAKE_INSTALL_PREFIX})
 
 qt6_import_qml_plugins(${PROJECT_NAME})
+
diff --git a/README.md b/README.md
index a149076a282c0b79ae05a3511dd3298c092ba672..10c34f863b6553edd5cd9385b8adfa59133db690 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,8 @@ Qt Design Viewer works with minimum Android 33.
 * cicd: GitLab pipeline files
 * resources: UI related files
 * android: Files needed for Android build system
-* src: Source files
+* src: Backend source files
+* ui: UI source files
 * qtquickdesigner-components: Required 3rd party QML components
 
 ## Building
@@ -42,6 +43,7 @@ cmake \
     -G Ninja \
     -DCMAKE_TOOLCHAIN_FILE=<qt-android-path>/lib/cmake/Qt6/qt.toolchain.cmake \
     -DCMAKE_INSTALL_PREFIX=<qt-android-path> \
+    -DCMAKE_PREFIX_PATH=<qt-android-path> \
     -DANDROID_SDK_ROOT=<android-sdk-path> \
     -DANDROID_NDK_ROOT=<android-sdk-path>/ndk/<ndk-version> \
     -DANDROID_OPENSSL_PATH=<openssl-path>
diff --git a/ui/CMakeLists.txt b/ui/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..5630ce6641c1d640673ed8cc9c56ba4c5fa9b6ab
--- /dev/null
+++ b/ui/CMakeLists.txt
@@ -0,0 +1,45 @@
+cmake_minimum_required(VERSION 3.21.1)
+
+option(LINK_INSIGHT "Link Qt Insight Tracker library" ON)
+option(BUILD_QDS_COMPONENTS "Build design studio components" ON)
+
+project(DesignViewerApp LANGUAGES CXX)
+
+set(CMAKE_AUTOMOC ON)
+
+find_package(Qt6 6.2 REQUIRED COMPONENTS Core Gui Qml Quick)
+
+if (Qt6_VERSION VERSION_GREATER_EQUAL 6.3)
+    qt_standard_project_setup()
+endif()
+
+qt_add_executable(DesignViewerApp src/main.cpp)
+
+qt_add_resources(DesignViewerApp "configuration"
+    PREFIX "/"
+    FILES
+        qtquickcontrols2.conf
+)
+
+target_link_libraries(DesignViewerApp PRIVATE
+    Qt6::Core
+    Qt6::Gui
+    Qt6::Qml
+    Qt6::Quick
+)
+
+if (BUILD_QDS_COMPONENTS)
+    include(${CMAKE_CURRENT_SOURCE_DIR}/qmlcomponents)
+endif()
+
+include(${CMAKE_CURRENT_SOURCE_DIR}/qmlmodules)
+
+if (LINK_INSIGHT)
+    include(${CMAKE_CURRENT_SOURCE_DIR}/insight)
+endif ()
+
+install(TARGETS DesignViewerApp
+    BUNDLE DESTINATION .
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+)
diff --git a/ui/DesignViewer.qmlproject b/ui/DesignViewer.qmlproject
new file mode 100644
index 0000000000000000000000000000000000000000..f9003808bbc92b473b959fd556ff0a7d00f33f4d
--- /dev/null
+++ b/ui/DesignViewer.qmlproject
@@ -0,0 +1,117 @@
+import QmlProject
+
+Project {
+    mainFile: "main.qml"
+
+    /* Include .qml, .js, and image files from current directory and subdirectories */
+    QmlFiles {
+        directory: "."
+    }
+
+    QmlFiles {
+        directory: "content"
+    }
+
+    QmlFiles {
+        directory: "imports"
+    }
+
+    JavaScriptFiles {
+        directory: "content"
+    }
+
+    JavaScriptFiles {
+        directory: "imports"
+    }
+
+    ImageFiles {
+        directory: "content"
+    }
+
+    ImageFiles {
+        directory: "asset_imports"
+    }
+
+    Files {
+        filter: "*.conf"
+        files: ["qtquickcontrols2.conf"]
+    }
+
+    Files {
+        filter: "qmldir"
+        directory: "."
+    }
+
+    Files {
+        filter: "*.ttf;*.otf"
+    }
+
+    Files {
+        filter: "*.wav;*.mp3"
+    }
+
+    Files {
+        filter: "*.mp4"
+    }
+
+    Files {
+        filter: "*.glsl;*.glslv;*.glslf;*.vsh;*.fsh;*.vert;*.frag"
+    }
+
+    Files {
+        filter: "*.qsb"
+    }
+
+    Files {
+        filter: "*.mesh"
+        directory: "asset_imports"
+    }
+
+    Files {
+        filter: "*.qml"
+        directory: "asset_imports"
+    }
+
+    Environment {
+        QT_QUICK_CONTROLS_CONF: "qtquickcontrols2.conf"
+        QT_AUTO_SCREEN_SCALE_FACTOR: "1"
+        QML_COMPAT_RESOLVE_URLS_ON_ASSIGNMENT: "1"
+        QT_LOGGING_RULES: "qt.qml.connections=false"
+        QT_ENABLE_HIGHDPI_SCALING: "0"
+        /* Useful for debugging
+       QSG_VISUALIZE=batches
+       QSG_VISUALIZE=clip
+       QSG_VISUALIZE=changes
+       QSG_VISUALIZE=overdraw
+       */
+    }
+
+    qt6Project: true
+
+    /* List of plugin directories passed to QML runtime */
+    importPaths: [ "imports", "asset_imports" ]
+
+    /* Required for deployment */
+    targetDirectory: "/opt/DesignViewer"
+
+    qdsVersion: "4.2"
+
+    quickVersion: "6.5"
+
+    /* If any modules the project imports require widgets (e.g. QtCharts), widgetApp must be true */
+    widgetApp: true
+
+    /* args: Specifies command line arguments for qsb tool to generate shaders.
+       files: Specifies target files for qsb tool. If path is included, it must be relative to this file.
+              Wildcard '*' can be used in the file name part of the path.
+              e.g. files: [ "content/shaders/*.vert", "*.frag" ]  */
+    ShaderTool {
+        args: "-s --glsl \"100 es,120,150\" --hlsl 50 --msl 12"
+        files: [ "content/shaders/*" ]
+    }
+
+    multilanguageSupport: true
+    supportedLanguages: ["en"]
+    primaryLanguage: "en"
+
+}
diff --git a/ui/asset_imports/asset_imports.txt b/ui/asset_imports/asset_imports.txt
new file mode 100644
index 0000000000000000000000000000000000000000..84c843f100d41b805bc1dab082525ad2228526b7
--- /dev/null
+++ b/ui/asset_imports/asset_imports.txt
@@ -0,0 +1 @@
+Imported 3D assets and components imported from bundles will be created in this folder.
diff --git a/ui/content/CMakeLists.txt b/ui/content/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6811415f249fc4b4bbf3693ab27e1ec17d60f21e
--- /dev/null
+++ b/ui/content/CMakeLists.txt
@@ -0,0 +1,13 @@
+### This file is automatically generated by Qt Design Studio.
+### Do not change
+
+qt_add_library(content STATIC)
+qt6_add_qml_module(content
+    URI "content"
+    VERSION 1.0
+    QML_FILES
+        App.qml
+        Screen01.ui.qml
+    RESOURCES
+        fonts/fonts.txt
+)
diff --git a/ui/content/fonts/fonts.txt b/ui/content/fonts/fonts.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ab96122067450783de407d6200171a97ab3849be
--- /dev/null
+++ b/ui/content/fonts/fonts.txt
@@ -0,0 +1 @@
+Fonts in this folder are loaded automatically.
diff --git a/resources/dvicon.png b/ui/content/images/dvicon.png
similarity index 100%
rename from resources/dvicon.png
rename to ui/content/images/dvicon.png
diff --git a/ui/imports/CMakeLists.txt b/ui/imports/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ce806bcb08920e0b5a1e6d77b1ce1ad92086116e
--- /dev/null
+++ b/ui/imports/CMakeLists.txt
@@ -0,0 +1,4 @@
+### This file is automatically generated by Qt Design Studio.
+### Do not change
+
+add_subdirectory(DesignViewer)
diff --git a/ui/imports/DesignViewer/CMakeLists.txt b/ui/imports/DesignViewer/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..dae8551aa360dd75dfad455e3134c90593c5e228
--- /dev/null
+++ b/ui/imports/DesignViewer/CMakeLists.txt
@@ -0,0 +1,18 @@
+### This file is automatically generated by Qt Design Studio.
+### Do not change
+
+qt_add_library(DesignViewer STATIC)
+set_source_files_properties(Constants.qml
+    PROPERTIES
+        QT_QML_SINGLETON_TYPE true
+    )
+
+qt6_add_qml_module(DesignViewer
+	URI "DesignViewer"
+	VERSION 1.0
+	QML_FILES
+		Constants.qml
+		DirectoryFontLoader.qml
+		EventListModel.qml
+		EventListSimulator.qml
+)
diff --git a/ui/imports/DesignViewer/Constants.qml b/ui/imports/DesignViewer/Constants.qml
new file mode 100644
index 0000000000000000000000000000000000000000..94d3ef2710aec3f0da053a8a45794e7a73892e34
--- /dev/null
+++ b/ui/imports/DesignViewer/Constants.qml
@@ -0,0 +1,27 @@
+pragma Singleton
+import QtQuick 6.5
+import QtQuick.Studio.Application
+
+QtObject {
+    readonly property int width: 1920
+    readonly property int height: 1080
+
+    property string relativeFontDirectory: "fonts"
+
+    /* Edit this comment to add your custom font */
+    readonly property font font: Qt.font({
+                                             family: Qt.application.font.family,
+                                             pixelSize: Qt.application.font.pixelSize
+                                         })
+    readonly property font largeFont: Qt.font({
+                                                  family: Qt.application.font.family,
+                                                  pixelSize: Qt.application.font.pixelSize * 1.6
+                                              })
+
+    readonly property color backgroundColor: "#c2c2c2"
+
+
+    property StudioApplication application: StudioApplication {
+        fontPath: Qt.resolvedUrl("../../content/" + relativeFontDirectory)
+    }
+}
diff --git a/ui/imports/DesignViewer/DirectoryFontLoader.qml b/ui/imports/DesignViewer/DirectoryFontLoader.qml
new file mode 100644
index 0000000000000000000000000000000000000000..a9900795c6ddf80c9c210f44212ccfcebb8155eb
--- /dev/null
+++ b/ui/imports/DesignViewer/DirectoryFontLoader.qml
@@ -0,0 +1,34 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick 6.5
+import Qt.labs.folderlistmodel 6.5
+
+QtObject {
+    id: loader
+
+    property url fontDirectory: Qt.resolvedUrl("../../content/" + relativeFontDirectory)
+    property string relativeFontDirectory: "fonts"
+
+    function loadFont(url) {
+        var fontLoader = Qt.createQmlObject('import QtQuick 2.15; FontLoader { source: "' + url + '"; }',
+                                            loader,
+                                            "dynamicFontLoader");
+    }
+
+    property FolderListModel folderModel: FolderListModel {
+        id: folderModel
+        folder: loader.fontDirectory
+        nameFilters: [ "*.ttf", "*.otf" ]
+        showDirs: false
+
+        onStatusChanged: {
+            if (folderModel.status == FolderListModel.Ready) {
+                var i
+                for (i = 0; i < count; i++) {
+                    loadFont(folderModel.get(i, "fileURL"))
+                }
+            }
+        }
+    }
+}
diff --git a/ui/imports/DesignViewer/EventListModel.qml b/ui/imports/DesignViewer/EventListModel.qml
new file mode 100644
index 0000000000000000000000000000000000000000..630d54361fd3470ee8b4ddb32b0f74b9eec5d361
--- /dev/null
+++ b/ui/imports/DesignViewer/EventListModel.qml
@@ -0,0 +1,15 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick 6.5
+
+ListModel {
+    id: eventListModel
+
+    ListElement {
+        eventId: "enterPressed"
+        eventDescription: "Emitted when pressing the enter button"
+        shortcut: "Return"
+        parameters: "Enter"
+    }
+}
diff --git a/ui/imports/DesignViewer/EventListSimulator.qml b/ui/imports/DesignViewer/EventListSimulator.qml
new file mode 100644
index 0000000000000000000000000000000000000000..8c96292df05dfc28eeb7d281110160a2ff0ece11
--- /dev/null
+++ b/ui/imports/DesignViewer/EventListSimulator.qml
@@ -0,0 +1,25 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick 6.5
+import QtQuick.Studio.EventSimulator 1.0
+import QtQuick.Studio.EventSystem 1.0
+
+QtObject {
+    id: simulator
+    property bool active: true
+
+    property Timer __timer: Timer {
+        id: timer
+        interval: 100
+        onTriggered: {
+            EventSimulator.show()
+        }
+    }
+
+    Component.onCompleted: {
+        EventSystem.init(Qt.resolvedUrl("EventListModel.qml"))
+        if (simulator.active)
+            timer.start()
+    }
+}
diff --git a/ui/imports/DesignViewer/designer/plugin.metainfo b/ui/imports/DesignViewer/designer/plugin.metainfo
new file mode 100644
index 0000000000000000000000000000000000000000..652db90605bad009283c672062f3d54adac87150
--- /dev/null
+++ b/ui/imports/DesignViewer/designer/plugin.metainfo
@@ -0,0 +1,13 @@
+MetaInfo {
+    Type {
+        name: "DesignViewer.EventListSimulator"
+        icon: ":/qtquickplugin/images/item-icon16.png"
+
+        Hints {
+            visibleInNavigator: true
+            canBeDroppedInNavigator: true
+            canBeDroppedInFormEditor: false
+            canBeDroppedInView3D: false
+        }
+    }
+}
diff --git a/ui/imports/DesignViewer/qmldir b/ui/imports/DesignViewer/qmldir
new file mode 100644
index 0000000000000000000000000000000000000000..84d76be04ef4fee7ba9232333666a9569253ca5d
--- /dev/null
+++ b/ui/imports/DesignViewer/qmldir
@@ -0,0 +1,6 @@
+Module DesignViewer
+singleton Constants 1.0 Constants.qml
+EventListSimulator 1.0 EventListSimulator.qml
+EventListModel 1.0 EventListModel.qml
+DirectoryFontLoader 1.0 DirectoryFontLoader.qml
+
diff --git a/ui/insight b/ui/insight
new file mode 100644
index 0000000000000000000000000000000000000000..8245e31f0d95d728cdda8851023bfad8bb9267c1
--- /dev/null
+++ b/ui/insight
@@ -0,0 +1,19 @@
+### This file is automatically generated by Qt Design Studio.
+### Do not change
+
+if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/qtinsight.conf)
+    if (QT_VERSION GREATER_EQUAL 6.5.0)
+        find_package(Qt6 REQUIRED COMPONENTS InsightTracker)
+
+        qt_add_resources(${CMAKE_PROJECT_NAME} "configuration"
+            PREFIX "/"
+            FILES
+            qtinsight.conf
+        )
+        target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE
+            Qt6::InsightTracker
+        )
+    else()
+        message(WARNING "You need Qt 6.5.0 or newer to build the application.")
+    endif()
+endif()
diff --git a/resources/main.qml b/ui/main.qml
similarity index 79%
rename from resources/main.qml
rename to ui/main.qml
index 71d35137420c5f05d06772052f5031fb755a7e9f..22664621b07ab813febc98315abd42929731caac 100644
--- a/resources/main.qml
+++ b/ui/main.qml
@@ -1,151 +1,142 @@
-
-/*
-This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
-It is supposed to be strictly declarative and only uses a subset of QML. If you edit
-this file manually, you might introduce QML code that is not supported by Qt Design Studio.
-Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
-*/
-import QtQuick 6.4
-import QtQuick.Controls 6.4
-import QtQuick.Controls.Material
-import QtQuick.Layouts
-import QtQuick.Window 2.2
-
-Rectangle {
-    id: root
-    width: 400
-    height: 800
-    color: "#EAEAEA"
-
-    Material.theme: Material.Light
-    Material.accent: Material.Blue
-    Material.primary: Material.Blue
-
-    ColumnLayout {
-        id: bar
-        y: 50
-        anchors.bottom: column.top
-        anchors.bottomMargin: 24
-        anchors.horizontalCenter: parent.horizontalCenter
-        ProgressBar {
-            id: progressBar
-            Layout.minimumWidth: 380
-            to: 100
-            value: backend.downloadProgress
-        }
-    }
-
-    ColumnLayout {
-        id: column
-        height: 113
-        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
-            Layout.fillWidth: true
-            placeholderText: qsTr("Enter URL")
-        }
-
-        Button {
-            id: downloadButton
-            text: qsTr("Download and Run")
-            Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
-            onClicked: backend.downloadAndRun(urlTextField.text)
-        }
-    }
-
-    Item {
-        id: header
-        width: 351
-        height: gridLayout.height
-        anchors.top: parent.top
-        anchors.topMargin: 12
-        anchors.horizontalCenter: parent.horizontalCenter
-
-        GridLayout {
-            id: gridLayout
-            anchors.horizontalCenter: parent.horizontalCenter
-            rows: root.height > 420 ? 2 : 1
-            columns: root.height > 420 ? 1 : 2
-
-            Image {
-                id: qdsicon
-                x: 47
-                y: -23
-                width: 204
-                height: 202
-                source: "dvicon.png"
-                fillMode: Image.PreserveAspectFit
-            }
-
-            ColumnLayout {
-                Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
-
-                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"
-                }
-            }
-        }
-    }
-
-    Rectangle {
-        id: log
-        visible: root.height > 620
-        color: "#EAEAEA"
-        anchors.left: parent.left
-        anchors.right: parent.right
-        anchors.top: header.bottom
-        anchors.bottom: bar.top
-        anchors.topMargin: 15
-        anchors.bottomMargin: 24
-        anchors.leftMargin: 22
-
-        ScrollView {
-            id: scrollArea
-            anchors.left: parent.left
-            anchors.right: parent.right
-            anchors.top: parent.top
-            anchors.bottom: parent.bottom
-            topPadding: 13.1
-            clip: false
-            anchors.topMargin: 9
-            anchors.rightMargin: 2
-
-            Item {
-                width: scrollArea.width
-                height: logTextArea.height
-                TextArea {
-                    y: 20
-                    id: logTextArea
-                    text: backend.logs
-                    rightInset: 20
-                    width: scrollArea.width
-                    readOnly: true
-                    anchors.topMargin: 5
-                    placeholderText: qsTr("Application Logs")
-                }
-            }
-        }
-    }
-}
+
+/*
+This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
+It is supposed to be strictly declarative and only uses a subset of QML. If you edit
+this file manually, you might introduce QML code that is not supported by Qt Design Studio.
+Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
+*/
+import QtQuick 6.4
+import QtQuick.Controls 6.4
+import QtQuick.Controls.Material
+import QtQuick.Layouts
+import QtQuick.Window 2.2
+
+Rectangle {
+    id: root
+    width: 400
+    height: 800
+    color: "#EAEAEA"
+
+    Material.theme: Material.Light
+    Material.accent: Material.Blue
+    Material.primary: Material.Blue
+
+    ColumnLayout {
+        id: bar
+        y: 50
+        anchors.bottom: column.top
+        anchors.bottomMargin: 24
+        anchors.horizontalCenter: parent.horizontalCenter
+        ProgressBar {
+            id: progressBar
+            Layout.minimumWidth: 380
+            to: 100
+            value: backend.downloadProgress
+        }
+    }
+
+    ColumnLayout {
+        id: column
+        height: 113
+        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
+            Layout.fillWidth: true
+            placeholderText: qsTr("Enter URL")
+        }
+
+        Button {
+            id: downloadButton
+            text: qsTr("Download and Run")
+            Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
+            onClicked: backend.downloadAndRun(urlTextField.text)
+        }
+    }
+
+    Item {
+        id: header
+        width: 351
+        height: gridLayout.height
+        anchors.top: parent.top
+        anchors.topMargin: 12
+        anchors.horizontalCenter: parent.horizontalCenter
+
+        GridLayout {
+            id: gridLayout
+            anchors.horizontalCenter: parent.horizontalCenter
+            rows: root.height > 420 ? 2 : 1
+            columns: root.height > 420 ? 1 : 2
+
+            Image {
+                id: qdsicon
+                x: 47
+                y: -23
+                width: 204
+                height: 202
+                source: "content/images/dvicon.png"
+                fillMode: Image.PreserveAspectFit
+            }
+
+            ColumnLayout {
+                Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
+
+                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"
+                }
+            }
+        }
+    }
+
+    Rectangle {
+        id: log
+        visible: root.height > 620
+        color: "#EAEAEA"
+        anchors.left: parent.left
+        anchors.right: parent.right
+        anchors.top: header.bottom
+        anchors.bottom: bar.top
+        anchors.topMargin: 15
+        anchors.bottomMargin: 24
+        anchors.leftMargin: 22
+
+        ScrollView {
+            id: scrollArea
+            anchors.fill: parent
+            topPadding: 13.1
+            ScrollBar.vertical.policy: ScrollBar.AlwaysOn
+            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")
+            }
+        }
+    }
+}
diff --git a/ui/qmlcomponents b/ui/qmlcomponents
new file mode 100644
index 0000000000000000000000000000000000000000..5e2d5923b1e0c13d2caa46c3f589217692a9698c
--- /dev/null
+++ b/ui/qmlcomponents
@@ -0,0 +1,33 @@
+### This file is automatically generated by Qt Design Studio.
+### Do not change
+
+message("Building designer components.")
+
+set(QT_QML_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/qml")
+
+include(FetchContent)
+FetchContent_Declare(
+    ds
+    GIT_TAG qds-4.1
+    GIT_REPOSITORY https://code.qt.io/qt-labs/qtquickdesigner-components.git
+)
+
+FetchContent_GetProperties(ds)
+FetchContent_Populate(ds)
+
+target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE
+    QuickStudioComponentsplugin
+    QuickStudioEffectsplugin
+    QuickStudioApplicationplugin
+    FlowViewplugin
+    QuickStudioLogicHelperplugin
+    QuickStudioMultiTextplugin
+    QuickStudioEventSimulatorplugin
+    QuickStudioEventSystemplugin
+)
+
+add_subdirectory(${ds_SOURCE_DIR} ${ds_BINARY_DIR})
+
+target_compile_definitions(${CMAKE_PROJECT_NAME} PRIVATE
+  BULD_QDS_COMPONENTS=true
+)
diff --git a/ui/qmlmodules b/ui/qmlmodules
new file mode 100644
index 0000000000000000000000000000000000000000..b295765802a7472af5ff7b70795225b487fa5b6c
--- /dev/null
+++ b/ui/qmlmodules
@@ -0,0 +1,17 @@
+### This file is automatically generated by Qt Design Studio.
+### Do not change
+
+qt6_add_qml_module(${CMAKE_PROJECT_NAME}
+    URI "Main"
+    VERSION 1.0
+    NO_PLUGIN
+    QML_FILES main.qml
+)
+
+add_subdirectory(content)
+add_subdirectory(imports)
+
+target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE
+    contentplugin
+    DesignViewerplugin
+)
diff --git a/ui/qtquickcontrols2.conf b/ui/qtquickcontrols2.conf
new file mode 100644
index 0000000000000000000000000000000000000000..87a95d01144526e8cea0ad44d529c98e36deb177
--- /dev/null
+++ b/ui/qtquickcontrols2.conf
@@ -0,0 +1,6 @@
+; 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
diff --git a/resources/resources.qrc b/ui/resources.qrc
similarity index 64%
rename from resources/resources.qrc
rename to ui/resources.qrc
index 38767899f6414e4e3287fa84656d85b33df74e8e..7eb99925cbf0b2773f72b28e56222f0c54797527 100644
--- a/resources/resources.qrc
+++ b/ui/resources.qrc
@@ -1,6 +1,6 @@
 <RCC>
     <qresource prefix="/">
+        <file>content/images/dvicon.png</file>
         <file>main.qml</file>
-        <file>dvicon.png</file>
     </qresource>
 </RCC>
diff --git a/ui/src/app_environment.h b/ui/src/app_environment.h
new file mode 100644
index 0000000000000000000000000000000000000000..6b42bff0d810c5120f63b20485b7a81240d8a321
--- /dev/null
+++ b/ui/src/app_environment.h
@@ -0,0 +1,15 @@
+/*
+ * This file is automatically generated by Qt Design Studio.
+ * Do not change.
+*/
+
+#include <QGuiApplication>
+
+void set_qt_environment()
+{
+    qputenv("QT_AUTO_SCREEN_SCALE_FACTOR", "1");
+    qputenv("QT_ENABLE_HIGHDPI_SCALING", "0");
+    qputenv("QT_LOGGING_RULES", "qt.qml.connections=false");
+    qputenv("QT_QUICK_CONTROLS_CONF", ":/qtquickcontrols2.conf");
+    qputenv("QML_COMPAT_RESOLVE_URLS_ON_ASSIGNMENT", "1");
+}
diff --git a/ui/src/import_qml_components_plugins.h b/ui/src/import_qml_components_plugins.h
new file mode 100644
index 0000000000000000000000000000000000000000..25d0a98384e0cde16ca87fde027942ba2ad2ee54
--- /dev/null
+++ b/ui/src/import_qml_components_plugins.h
@@ -0,0 +1,19 @@
+/*
+ * This file is automatically generated by Qt Design Studio.
+ * Do not change.
+*/
+
+#include "qqmlextensionplugin.h"
+
+#ifdef BULD_QDS_COMPONENTS
+
+Q_IMPORT_QML_PLUGIN(QtQuick_Studio_ComponentsPlugin)
+Q_IMPORT_QML_PLUGIN(QtQuick_Studio_EffectsPlugin)
+Q_IMPORT_QML_PLUGIN(QtQuick_Studio_ApplicationPlugin)
+Q_IMPORT_QML_PLUGIN(FlowViewPlugin)
+Q_IMPORT_QML_PLUGIN(QtQuick_Studio_LogicHelperPlugin)
+Q_IMPORT_QML_PLUGIN(QtQuick_Studio_MultiTextPlugin)
+Q_IMPORT_QML_PLUGIN(QtQuick_Studio_EventSimulatorPlugin)
+Q_IMPORT_QML_PLUGIN(QtQuick_Studio_EventSystemPlugin)
+
+#endif
diff --git a/ui/src/import_qml_plugins.h b/ui/src/import_qml_plugins.h
new file mode 100644
index 0000000000000000000000000000000000000000..6f2a161bd373f354517075c46e70e7a5df5aa4c8
--- /dev/null
+++ b/ui/src/import_qml_plugins.h
@@ -0,0 +1,9 @@
+/*
+ * This file is automatically generated by Qt Design Studio.
+ * Do not change.
+*/
+
+#include <QtQml/qqmlextensionplugin.h>
+
+Q_IMPORT_QML_PLUGIN(contentPlugin)
+Q_IMPORT_QML_PLUGIN(DesignViewerPlugin)
diff --git a/ui/src/main.cpp b/ui/src/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b335b3317d0241ab3d9dd462f6f2930f22a5047e
--- /dev/null
+++ b/ui/src/main.cpp
@@ -0,0 +1,37 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QGuiApplication>
+#include <QQmlApplicationEngine>
+
+#include "app_environment.h"
+#include "import_qml_components_plugins.h"
+#include "import_qml_plugins.h"
+
+int main(int argc, char *argv[])
+{
+    set_qt_environment();
+
+    QGuiApplication app(argc, argv);
+
+    QQmlApplicationEngine engine;
+    const QUrl url(u"qrc:Main/main.qml"_qs);
+    QObject::connect(
+                &engine, &QQmlApplicationEngine::objectCreated, &app,
+                [url](QObject *obj, const QUrl &objUrl) {
+        if (!obj && url == objUrl)
+            QCoreApplication::exit(-1);
+    },
+    Qt::QueuedConnection);
+
+    engine.addImportPath(QCoreApplication::applicationDirPath() + "/qml");
+    engine.addImportPath(":/");
+
+    engine.load(url);
+
+    if (engine.rootObjects().isEmpty()) {
+        return -1;
+    }
+
+    return app.exec();
+}