diff --git a/client/amnezia_application.cpp b/client/amnezia_application.cpp
index 588854d3..3fb76be2 100644
--- a/client/amnezia_application.cpp
+++ b/client/amnezia_application.cpp
@@ -92,7 +92,7 @@ void AmneziaApplication::init()
m_engine = new QQmlApplicationEngine;
m_uiLogic = new UiLogic(m_settings, m_configurator, m_serverController);
- const QUrl url(QStringLiteral("qrc:/ui/qml/main.qml"));
+ const QUrl url(QStringLiteral("qrc:/ui/qml/main2.qml"));
QObject::connect(m_engine, &QQmlApplicationEngine::objectCreated,
this, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
diff --git a/client/images/amneziaBigLogo.png b/client/images/amneziaBigLogo.png
new file mode 100644
index 00000000..35a45f3b
Binary files /dev/null and b/client/images/amneziaBigLogo.png differ
diff --git a/client/images/amneziaBigLogo.svg b/client/images/amneziaBigLogo.svg
new file mode 100644
index 00000000..c50c7743
--- /dev/null
+++ b/client/images/amneziaBigLogo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/client/images/controls/arrow-left.svg b/client/images/controls/arrow-left.svg
new file mode 100644
index 00000000..98c9950b
--- /dev/null
+++ b/client/images/controls/arrow-left.svg
@@ -0,0 +1,4 @@
+
diff --git a/client/resources.qrc b/client/resources.qrc
index bda89bf2..f95ef585 100644
--- a/client/resources.qrc
+++ b/client/resources.qrc
@@ -176,5 +176,17 @@
ui/qml/Controls2/CardType.qml
ui/qml/Controls2/CheckBoxType.qml
images/controls/check.svg
+ ui/qml/Controls2/DropDownType.qml
+ ui/qml/Pages2/PageStart.qml
+ ui/qml/main2.qml
+ ui/qml/PageLoader.qml
+ images/amneziaBigLogo.png
+ images/amneziaBigLogo.svg
+ ui/qml/Controls2/BodyTextType.qml
+ ui/qml/Controls2/FlickableType.qml
+ ui/qml/Controls2/Header2TextType.qml
+ ui/qml/Pages2/PageCredentials.qml
+ ui/qml/Controls2/HeaderTextType.qml
+ images/controls/arrow-left.svg
diff --git a/client/ui/pages.h b/client/ui/pages.h
index a639d63b..c33289bb 100644
--- a/client/ui/pages.h
+++ b/client/ui/pages.h
@@ -24,7 +24,7 @@ enum class Page {Start = 0, NewServer, NewServerProtocols, Vpn,
Wizard, WizardLow, WizardMedium, WizardHigh, WizardVpnMode, ServerConfiguringProgress,
GeneralSettings, AppSettings, NetworkSettings, ServerSettings,
ServerContainers, ServersList, ShareConnection, Sites,
- ProtocolSettings, ProtocolShare, QrDecoder, QrDecoderIos, About, ViewConfig, AdvancedServerSettings, Test};
+ ProtocolSettings, ProtocolShare, QrDecoder, QrDecoderIos, About, ViewConfig, AdvancedServerSettings, Test, Credentials};
Q_ENUM_NS(Page)
static void declareQmlPageEnum() {
diff --git a/client/ui/qml/Controls2/BodyTextType.qml b/client/ui/qml/Controls2/BodyTextType.qml
new file mode 100644
index 00000000..9d789385
--- /dev/null
+++ b/client/ui/qml/Controls2/BodyTextType.qml
@@ -0,0 +1,12 @@
+import QtQuick
+
+Text {
+ text: root.bodyText
+ wrapMode: Text.WordWrap
+ color: "#D7D8DB"
+ font.pixelSize: 16
+ font.weight: 400
+ font.family: "PT Root UI VF"
+
+ height: 24
+}
diff --git a/client/ui/qml/Controls2/DropDownType.qml b/client/ui/qml/Controls2/DropDownType.qml
new file mode 100644
index 00000000..5560aee7
--- /dev/null
+++ b/client/ui/qml/Controls2/DropDownType.qml
@@ -0,0 +1,5 @@
+import QtQuick
+
+Item {
+
+}
diff --git a/client/ui/qml/Controls2/FlickableType.qml b/client/ui/qml/Controls2/FlickableType.qml
new file mode 100644
index 00000000..b7c1203f
--- /dev/null
+++ b/client/ui/qml/Controls2/FlickableType.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+import "../Config"
+
+Flickable {
+ id: fl
+
+ clip: true
+ width: parent.width
+
+ anchors.bottom: parent.bottom
+ anchors.left: root.left
+ anchors.right: root.right
+ anchors.rightMargin: 1
+
+ Keys.onUpPressed: scrollBar.decrease()
+ Keys.onDownPressed: scrollBar.increase()
+
+ ScrollBar.vertical: ScrollBar {
+ id: scrollBar
+ policy: fl.height >= fl.contentHeight ? ScrollBar.AlwaysOff : ScrollBar.AlwaysOn
+ }
+}
diff --git a/client/ui/qml/Controls2/Header2TextType.qml b/client/ui/qml/Controls2/Header2TextType.qml
new file mode 100644
index 00000000..4bbbc0d6
--- /dev/null
+++ b/client/ui/qml/Controls2/Header2TextType.qml
@@ -0,0 +1,10 @@
+import QtQuick
+
+Text {
+ color: "#D7D8DB"
+ font.pixelSize: 25
+ font.weight: 700
+ font.family: "PT Root UI VF"
+
+ height: 30
+}
diff --git a/client/ui/qml/Controls2/HeaderTextType.qml b/client/ui/qml/Controls2/HeaderTextType.qml
new file mode 100644
index 00000000..60fa4e95
--- /dev/null
+++ b/client/ui/qml/Controls2/HeaderTextType.qml
@@ -0,0 +1,40 @@
+import QtQuick
+import QtQuick.Layouts
+
+ColumnLayout {
+ id: root
+
+ property string buttonImage
+ property string headerText
+ property var wrapMode
+
+ ImageButtonType {
+ id: button
+
+ Layout.leftMargin: -6
+
+ hoverEnabled: false
+ image: root.buttonImage
+ onClicked: {
+ if (onClickedFunc && typeof onClickedFunc === "function") {
+ onClickedFunc()
+ }
+ }
+ }
+
+ Text {
+ id: header
+
+ text: root.headerText
+
+ color: "#D7D8DB"
+ font.pixelSize: 36
+ font.weight: 700
+ font.family: "PT Root UI VF"
+ font.letterSpacing: -0.03
+
+ wrapMode: Text.WordWrap
+
+ height: 38
+ }
+}
diff --git a/client/ui/qml/Controls2/TextFieldWithHeaderType.qml b/client/ui/qml/Controls2/TextFieldWithHeaderType.qml
index 18f62344..dd0d2907 100644
--- a/client/ui/qml/Controls2/TextFieldWithHeaderType.qml
+++ b/client/ui/qml/Controls2/TextFieldWithHeaderType.qml
@@ -7,6 +7,7 @@ Item {
property string headerText
property string textFieldText
+ property string textFieldPlaceholderText
property bool textFieldEditable: true
implicitWidth: 328
@@ -45,6 +46,9 @@ Item {
enabled: root.textFieldEditable
text: root.textFieldText
color: "#d7d8db"
+
+ placeholderText: textFieldPlaceholderText
+
font.pixelSize: 16
font.weight: 400
font.family: "PT Root UI VF"
diff --git a/client/ui/qml/PageLoader.qml b/client/ui/qml/PageLoader.qml
new file mode 100644
index 00000000..5f2fc3c2
--- /dev/null
+++ b/client/ui/qml/PageLoader.qml
@@ -0,0 +1,57 @@
+import QtQuick
+
+import Qt.labs.folderlistmodel
+
+import PageType 1.0
+
+Item {
+ property var pages: ({})
+
+ signal finished()
+
+ FolderListModel {
+ id: folderModelPages
+ folder: "qrc:/ui/qml/Pages2/"
+ nameFilters: ["*.qml"]
+ showDirs: false
+
+ onStatusChanged: {
+ if (status == FolderListModel.Ready) {
+ for (var i = 0; i < folderModelPages.count; i++) {
+ createPagesObjects(folderModelPages.get(i, "filePath"), PageType.Basic);
+ }
+ finished()
+ }
+ }
+
+ function createPagesObjects(file, type) {
+ if (file.indexOf("Base") !== -1) {
+ return; // skip Base Pages
+ }
+
+ var c = Qt.createComponent("qrc" + file);
+
+ var finishCreation = function(component) {
+ if (component.status === Component.Ready) {
+ var obj = component.createObject(root);
+ if (obj === null) {
+ console.debug("Error creating object " + component.url);
+ } else {
+ obj.visible = false
+ if (type === PageType.Basic) {
+ pages[obj.page] = obj
+ }
+ }
+ } else if (component.status === Component.Error) {
+ console.debug("Error loading component:", component.errorString());
+ }
+ }
+
+ if (c.status === Component.Ready) {
+ finishCreation(c);
+ } else {
+ console.debug("Warning: " + file + " page components are not ready " + c.errorString());
+ }
+ }
+ }
+}
diff --git a/client/ui/qml/Pages/PageTest.qml b/client/ui/qml/Pages/PageTest.qml
index 9f820389..4c571ae0 100644
--- a/client/ui/qml/Pages/PageTest.qml
+++ b/client/ui/qml/Pages/PageTest.qml
@@ -13,7 +13,6 @@ PageBase {
logic: ViewConfigLogic
Rectangle {
- y: 0
anchors.fill: parent
color: "#0E0E11"
}
diff --git a/client/ui/qml/Pages2/PageCredentials.qml b/client/ui/qml/Pages2/PageCredentials.qml
new file mode 100644
index 00000000..509ee6a6
--- /dev/null
+++ b/client/ui/qml/Pages2/PageCredentials.qml
@@ -0,0 +1,83 @@
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+import PageEnum 1.0
+
+import "./"
+import "../Pages"
+import "../Controls2"
+import "../Config"
+
+PageBase {
+ id: root
+ page: PageEnum.Credentials
+
+ FlickableType {
+ id: fl
+ anchors.top: root.top
+ anchors.bottom: root.bottom
+ contentHeight: content.height
+
+ ColumnLayout {
+ id: content
+
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.rightMargin: 16
+ anchors.leftMargin: 16
+
+ spacing: 16
+
+ HeaderTextType {
+ Layout.fillWidth: true
+ Layout.bottomMargin: 16
+ Layout.topMargin: 66
+
+ Layout.preferredWidth: 328
+
+ buttonImage: "qrc:/images/controls/arrow-left.svg"
+
+ headerText: "Подключение к серверу"
+ wrapMode: Text.WordWrap
+ }
+
+ TextFieldWithHeaderType {
+ Layout.fillWidth: true
+ headerText: "Server IP adress [:port]"
+ }
+
+ TextFieldWithHeaderType {
+ Layout.fillWidth: true
+ headerText: "Login to connect via SSH"
+ }
+
+ TextFieldWithHeaderType {
+ Layout.fillWidth: true
+ headerText: "Password / Private key"
+ }
+
+ BasicButtonType {
+ Layout.fillWidth: true
+ Layout.topMargin: 40
+
+ text: qsTr("Настроить сервер простым образом")
+ }
+
+ BasicButtonType {
+ Layout.fillWidth: true
+ Layout.topMargin: 8
+
+ defaultColor: "transparent"
+ hoveredColor: Qt.rgba(255, 255, 255, 0.08)
+ pressedColor: Qt.rgba(255, 255, 255, 0.12)
+ disabledColor: "#878B91"
+ textColor: "#D7D8DB"
+ borderWidth: 1
+
+ text: qsTr("Выбрать протокол для установки")
+ }
+ }
+ }
+}
diff --git a/client/ui/qml/Pages2/PageStart.qml b/client/ui/qml/Pages2/PageStart.qml
new file mode 100644
index 00000000..6f8f0356
--- /dev/null
+++ b/client/ui/qml/Pages2/PageStart.qml
@@ -0,0 +1,163 @@
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+import PageEnum 1.0
+
+import "./"
+import "../Pages"
+import "../Controls2"
+import "../Config"
+
+PageBase {
+ id: root
+ page: PageEnum.Start
+
+ FlickableType {
+ id: fl
+ anchors.top: root.top
+ anchors.bottom: root.bottom
+ contentHeight: content.height
+
+ ColumnLayout {
+ id: content
+
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+
+ Image {
+ id: image
+ source: "qrc:/images/amneziaBigLogo.png"
+
+ Layout.alignment: Qt.AlignCenter
+ Layout.topMargin: 80
+ Layout.leftMargin: 8
+ Layout.rightMargin: 8
+ Layout.preferredWidth: 344
+ Layout.preferredHeight: 279
+ }
+
+ BodyTextType {
+ Layout.fillWidth: true
+ Layout.topMargin: 50
+ Layout.leftMargin: 16
+ Layout.rightMargin: 16
+
+ text: "Бесплатный сервис для создания личного VPN на вашем сервере. Помогаем получать доступ к заблокированному контенту, не раскрывая конфиденциальность даже провайдерам VPN."
+ }
+
+ BasicButtonType {
+ Layout.fillWidth: true
+ Layout.topMargin: 32
+ Layout.leftMargin: 16
+ Layout.rightMargin: 16
+
+ text: qsTr("У меня есть данные для подключения")
+
+ onClicked: {
+ drawer.visible = true
+ }
+ }
+
+ BasicButtonType {
+ Layout.fillWidth: true
+ Layout.topMargin: 8
+ Layout.leftMargin: 16
+ Layout.rightMargin: 16
+
+ defaultColor: "transparent"
+ hoveredColor: Qt.rgba(255, 255, 255, 0.08)
+ pressedColor: Qt.rgba(255, 255, 255, 0.12)
+ disabledColor: "#878B91"
+ textColor: "#D7D8DB"
+ borderWidth: 1
+
+ text: qsTr("У меня ничего нет")
+
+// onClicked: {
+// UiLogic.goToPage(PageEnum.Start)
+// }
+ }
+ }
+
+ Drawer {
+ id: drawer
+
+ y: 0
+ x: 0
+ edge: Qt.BottomEdge
+ width: parent.width
+ height: parent.height * 0.4375
+
+ clip: true
+
+ background: Rectangle {
+ anchors.fill: parent
+ anchors.bottomMargin: -radius
+ radius: 16
+ color: "#1C1D21"
+ }
+
+ modal: true
+ //interactive: activeFocus
+
+// onAboutToHide: {
+// pageLoader.focus = true
+// }
+// onAboutToShow: {
+// tfSshLog.focus = true
+// }
+
+ ColumnLayout {
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+
+ anchors.rightMargin: 16
+ anchors.leftMargin: 16
+
+ Header2TextType {
+ Layout.fillWidth: true
+ Layout.topMargin: 24
+ Layout.alignment: Qt.AlignHCenter
+
+ text: "Данные для подключения"
+ }
+
+ LabelWithButtonType {
+ id: ip
+ Layout.fillWidth: true
+ Layout.topMargin: 32
+
+ text: "IP, логин и пароль от сервера"
+ buttonImage: "qrc:/images/controls/chevron-right.svg"
+
+ onClickedFunc: function() {
+ UiLogic.goToPage(PageEnum.Credentials)
+ }
+ }
+ Rectangle {
+ Layout.fillWidth: true
+ height: 1
+ color: "#2C2D30"
+ }
+ LabelWithButtonType {
+ Layout.fillWidth: true
+
+ text: "QR-код, ключ или файл настроек"
+ buttonImage: "qrc:/images/controls/chevron-right.svg"
+
+ // onClickedFunc: function() {
+ // UiLogic.goToPage(PageEnum.Start)
+ // }
+ }
+ Rectangle {
+ Layout.fillWidth: true
+ height: 1
+ color: "#2C2D30"
+ }
+ }
+ }
+ }
+}
diff --git a/client/ui/qml/main.qml b/client/ui/qml/main.qml
index b8758384..5194073e 100644
--- a/client/ui/qml/main.qml
+++ b/client/ui/qml/main.qml
@@ -85,7 +85,6 @@ Window {
}
Rectangle {
- y: 0
anchors.fill: parent
color: "white"
}
diff --git a/client/ui/qml/main2.qml b/client/ui/qml/main2.qml
new file mode 100644
index 00000000..deb64e89
--- /dev/null
+++ b/client/ui/qml/main2.qml
@@ -0,0 +1,142 @@
+import QtQuick
+import QtQuick.Window
+import QtQuick.Controls
+import QtQuick.Layouts
+
+import PageType 1.0
+
+import "Config"
+
+Window {
+ id: root
+ visible: true
+ width: GC.screenWidth
+ height: GC.screenHeight
+ minimumWidth: GC.isDesktop() ? 360 : 0
+ minimumHeight: GC.isDesktop() ? 640 : 0
+ onClosing: function() {
+ console.debug("QML onClosing signal")
+ UiLogic.onCloseWindow()
+ }
+
+ title: "AmneziaVPN"
+
+ function gotoPage(type, page, reset, slide) {
+ let p_obj;
+ if (type === PageType.Basic) p_obj = pageLoader.pages[page]
+ else if (type === PageType.Proto) p_obj = protocolPages[page]
+ else if (type === PageType.ShareProto) p_obj = sharePages[page]
+ else return
+
+ if (pageStackView.depth > 0) {
+ pageStackView.currentItem.deactivated()
+ }
+
+ if (slide) {
+ pageStackView.push(p_obj, {}, StackView.PushTransition)
+ } else {
+ pageStackView.push(p_obj, {}, StackView.Immediate)
+ }
+
+// if (reset) {
+// p_obj.logic.onUpdatePage();
+// }
+
+ p_obj.activated(reset)
+ }
+
+ function closePage() {
+ if (pageStackView.depth <= 1) {
+ return
+ }
+ pageStackView.currentItem.deactivated()
+ pageStackView.pop()
+ }
+
+ function setStartPage(page, slide) {
+ if (pageStackView.depth > 0) {
+ pageStackView.currentItem.deactivated()
+ }
+
+ pageStackView.clear()
+ if (slide) {
+ pageStackView.push(pages[page], {}, StackView.PushTransition)
+ } else {
+ pageStackView.push(pages[page], {}, StackView.Immediate)
+ }
+ if (page === PageEnum.Start) {
+ UiLogic.pushButtonBackFromStartVisible = !pageStackView.empty
+ UiLogic.onUpdatePage();
+ }
+ }
+
+ Rectangle {
+ anchors.fill: parent
+ color: "#0E0E11"
+ }
+
+ StackView {
+ id: pageStackView
+ anchors.fill: parent
+ focus: true
+
+ onCurrentItemChanged: function() {
+ UiLogic.currentPageValue = currentItem.page
+ }
+
+ onDepthChanged: function() {
+ UiLogic.pagesStackDepth = depth
+ }
+
+ Keys.onPressed: function(event) {
+ UiLogic.keyPressEvent(event.key)
+ event.accepted = true
+ }
+ }
+
+ Connections {
+ target: UiLogic
+ function onGoToPage(page, reset, slide) {
+ root.gotoPage(PageType.Basic, page, reset, slide)
+ }
+
+ function onGoToProtocolPage(protocol, reset, slide) {
+ root.gotoPage(PageType.Proto, protocol, reset, slide)
+ }
+
+ function onGoToShareProtocolPage(protocol, reset, slide) {
+ root.gotoPage(PageType.ShareProto, protocol, reset, slide)
+ }
+
+ function onClosePage() {
+ root.closePage()
+ }
+
+ function onSetStartPage(page, slide) {
+ root.setStartPage(page, slide)
+ }
+
+ function onShow() {
+ root.show()
+ }
+
+ function onHide() {
+ root.hide()
+ }
+
+ function onRaise() {
+ root.show()
+ root.raise()
+ root.requestActivate()
+ }
+ }
+
+ PageLoader {
+ id: pageLoader
+
+ onFinished: {
+ UiLogic.initalizeUiLogic()
+ }
+ }
+
+}