diff --git a/mobile/main.qml b/mobile/main.qml index 512d0bfec..1f15543d7 100644 --- a/mobile/main.qml +++ b/mobile/main.qml @@ -16,12 +16,13 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ - + import QtQuick 2.10 import QtQuick.Controls 2.10 import QtQuick.Controls.Material 2.2 import QtQuick.Layouts 1.3 import QtQuick.Window 2.10 +import QtGraphicalEffects 1.0 import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.commands 1.0 @@ -48,7 +49,6 @@ ApplicationWindow { property int notchRight: 0 property int notchBot: 0 property int notchTop: 0 - property bool mainIsHorizontal: appWindow.width > appWindow.height // https://github.com/ekke/c2gQtWS_x/blob/master/qml/main.qml flags: Qt.platform.os === "ios" ? (Qt.Window | Qt.MaximizeUsingFullscreenGeometryHint) : Qt.Window @@ -67,22 +67,28 @@ ApplicationWindow { Timer { id: oriTimer - interval: 100 - running: true - repeat: true - + interval: 100; running: true; repeat: false onTriggered: { updateNotch() } } Screen.orientationUpdateMask: Qt.LandscapeOrientation | Qt.PortraitOrientation + Screen.onPrimaryOrientationChanged: { + oriTimer.start() + } Component.onCompleted: { if (!VescIf.isIntroDone()) { introWizard.openDialog() } updateNotch() + mainSwipeView.insertItem(4, confPageApp) + tabBar.insertItem(4, confAppButton) + mainSwipeView.insertItem(4, confPageMotor) + tabBar.insertItem(4, confMotorButton) + confPageMotor.visible = true + confPageApp.visible = true Utility.keepScreenOn(VescIf.keepScreenOn()) Utility.allowScreenRotation(VescIf.getAllowScreenRotation()) Utility.stopGnssForegroundService() @@ -302,7 +308,6 @@ ApplicationWindow { anchors.fill: parent anchors.leftMargin: 10 anchors.rightMargin: 10 - isHorizontal: mainIsHorizontal onRequestOpenControls: { controls.openDialog() @@ -368,7 +373,6 @@ ApplicationWindow { sourceComponent: RtData { anchors.fill: parent updateData: tabBar.currentIndex == (1 + indexOffset()) && rtSwipeView.currentIndex == 0 - isHorizontal: mainIsHorizontal } } } @@ -382,7 +386,6 @@ ApplicationWindow { anchors.fill: parent dialogParent: mainSwipeView updateData: tabBar.currentIndex == (1 + indexOffset()) && rtSwipeView.currentIndex == 1 - isHorizontal: mainIsHorizontal } } } @@ -435,7 +438,6 @@ ApplicationWindow { sourceComponent: StatPage { anchors.fill: parent - isHorizontal: mainIsHorizontal } } } @@ -450,7 +452,6 @@ ApplicationWindow { visible: status == Loader.Ready sourceComponent: BMS { anchors.fill: parent - isHorizontal: mainIsHorizontal } } } @@ -496,15 +497,128 @@ ApplicationWindow { } } + // --- HEADER: Connection status bar (moved from footer) --- header: Rectangle { id: headerBar + clip: true + color: Utility.getAppHexColor("lightBackground") + width: parent.width + height: 35 + notchTop + Rectangle { + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + height: parent.height/2.0 + gradient: Gradient { + GradientStop { position: 0.0; color: "#15ffffff"} + GradientStop { position: 0.3; color: "#04ffffff"} + GradientStop { position: 1.0; color: "transparent" } + } + } + Behavior on color { + ColorAnimation { + duration: 200; + easing.type: Easing.OutBounce + easing.overshoot: 3 + } + } + + RowLayout { + enabled: true + anchors.fill: parent + spacing: 0 + ToolButton { + id: settingsButton + Layout.fillHeight: true + Layout.preferredWidth: 70 + Image { + anchors.centerIn: parent + anchors.verticalCenterOffset: notchTop/2 + antialiasing: true + height: parent.width*0.35 + width: height + source: "qrc" + Utility.getThemePath() + "icons/Settings-96.png" + } + onClicked: { + if (drawer.visible) { + drawer.close() + } else { + drawer.open() + } + } + } + Rectangle{ + Layout.fillHeight: true + Layout.preferredWidth: 1 + color: "#33000000" + } + Rectangle{ + Layout.fillHeight: true + Layout.preferredWidth: 1 + color: "#33ffffff" + } + ColumnLayout{ + spacing: 0 + Layout.fillWidth: true + Layout.fillHeight: true + Rectangle{ + Layout.fillWidth: true + Layout.preferredHeight: notchTop + opacity: 0 + } + Text { + id: connectedText + Layout.fillWidth: true + Layout.fillHeight: true + color: Utility.getAppHexColor("lightText") + text: VescIf.getConnectedPortName() + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.Wrap + } + } + Rectangle{ + Layout.fillHeight: true + Layout.preferredWidth: 1 + color: "#33000000" + } + Rectangle{ + Layout.fillHeight: true + Layout.preferredWidth: 1 + color: "#33ffffff" + } + ToolButton { + Layout.fillHeight: true + Layout.preferredWidth: 70 + Image { + anchors.centerIn: parent + anchors.verticalCenterOffset: notchTop/2 + antialiasing: true + height: parent.width*0.35 + width: height + source: "qrc" + Utility.getThemePath() + "icons/can_off.png" + } + onClicked: { + if (canDrawerLoader.item.visible) { + canDrawerLoader.item.close() + } else { + canDrawerLoader.item.open() + } + } + } + } + } + + // --- FOOTER: Tab navigation bar (moved from header) --- + footer: Rectangle { + id: connectedRect color: Utility.getAppHexColor("lightestBackground") - height: tabBar.implicitHeight + notchTop // iPhone X Workaround + height: tabBar.implicitHeight + notchBot RowLayout { anchors.left: parent.left anchors.right: parent.right - anchors.bottom: parent.bottom + anchors.top: parent.top spacing: 0 TabBar { @@ -512,6 +626,7 @@ ApplicationWindow { currentIndex: mainSwipeView.currentIndex Layout.fillWidth: true implicitWidth: 0 + implicitHeight: 48 clip: true background: Rectangle { @@ -519,7 +634,19 @@ ApplicationWindow { color: Utility.getAppHexColor("lightBackground") } - property int buttonWidth: Math.max(120, + // Disable touch-scrolling and all programmatic scrolling + contentItem: ListView { + model: tabBar.contentModel + interactive: false + spacing: tabBar.spacing + orientation: ListView.Horizontal + boundsBehavior: Flickable.StopAtBounds + highlightRangeMode: ListView.NoHighlightRange + highlightMoveDuration: 0 + clip: true + } + + property int buttonWidth: Math.max(50, tabBar.width / (rep.model.length + (uiHwPage.visible ? 1 : 0) + @@ -530,11 +657,38 @@ ApplicationWindow { Repeater { id: rep - model: ["Start", "RT Data", "BMS", "Profiles", "Terminal", "LispBM"] + model: [ + "icons/navbar_start.png", + "icons/navbar_rtdata.png", + "icons/navbar_bms.png", + "icons/navbar_profiles.png", + "icons/navbar_terminal.png", + "icons/navbar_lispbm.png" + ] TabButton { - text: modelData width: tabBar.buttonWidth + implicitHeight: 48 + background: Rectangle { color: "transparent" } + contentItem: Item { + anchors.fill: parent + Image { + id: repImg + anchors.centerIn: parent + source: "qrc:/res/" + modelData + sourceSize.width: 96 + sourceSize.height: 96 + width: 28 + height: 28 + fillMode: Image.PreserveAspectFit + visible: false + } + ColorOverlay { + anchors.fill: repImg + source: repImg + color: parent.parent.checked ? Material.accent : Utility.getAppHexColor("lightText") + } + } } } } @@ -544,8 +698,28 @@ ApplicationWindow { TabButton { id: uiHwButton visible: uiHwPage.visible - text: "HwUi" width: tabBar.buttonWidth + implicitHeight: 48 + background: Rectangle { color: "transparent" } + contentItem: Item { + anchors.fill: parent + Image { + id: imgHw + anchors.centerIn: parent + source: "qrc:/res/icons/navbar_hwui.png" + sourceSize.width: 96 + sourceSize.height: 96 + width: 28 + height: 28 + fillMode: Image.PreserveAspectFit + visible: false + } + ColorOverlay { + anchors.fill: imgHw + source: imgHw + color: parent.parent.checked ? Material.accent : Utility.getAppHexColor("lightText") + } + } } Page { @@ -563,8 +737,28 @@ ApplicationWindow { TabButton { id: uiAppButton visible: uiAppPage.visible - text: "AppUi" width: tabBar.buttonWidth + implicitHeight: 48 + background: Rectangle { color: "transparent" } + contentItem: Item { + anchors.fill: parent + Image { + id: imgApp + anchors.centerIn: parent + source: "qrc:/res/icons/navbar_appui.png" + sourceSize.width: 96 + sourceSize.height: 96 + width: 28 + height: 28 + fillMode: Image.PreserveAspectFit + visible: false + } + ColorOverlay { + anchors.fill: imgApp + source: imgApp + color: parent.parent.checked ? Material.accent : Utility.getAppHexColor("lightText") + } + } } Page { @@ -582,22 +776,82 @@ ApplicationWindow { TabButton { id: confMotorButton visible: confPageMotor.visible - text: "Motor Cfg" width: tabBar.buttonWidth + implicitHeight: 48 + background: Rectangle { color: "transparent" } + contentItem: Item { + anchors.fill: parent + Image { + id: imgMotor + anchors.centerIn: parent + source: "qrc:/res/icons/navbar_mcconf.png" + sourceSize.width: 96 + sourceSize.height: 96 + width: 28 + height: 28 + fillMode: Image.PreserveAspectFit + visible: false + } + ColorOverlay { + anchors.fill: imgMotor + source: imgMotor + color: parent.parent.checked ? Material.accent : Utility.getAppHexColor("lightText") + } + } } TabButton { id: confAppButton visible: confPageApp.visible - text: "App Cfg" width: tabBar.buttonWidth + implicitHeight: 48 + background: Rectangle { color: "transparent" } + contentItem: Item { + anchors.fill: parent + Image { + id: imgAppConf + anchors.centerIn: parent + source: "qrc:/res/icons/navbar_appconf.png" + sourceSize.width: 96 + sourceSize.height: 96 + width: 28 + height: 28 + fillMode: Image.PreserveAspectFit + visible: false + } + ColorOverlay { + anchors.fill: imgAppConf + source: imgAppConf + color: parent.parent.checked ? Material.accent : Utility.getAppHexColor("lightText") + } + } } TabButton { id: confCustomButton visible: confCustomPage.visible - text: "Custom Cfg" width: tabBar.buttonWidth + implicitHeight: 48 + background: Rectangle { color: "transparent" } + contentItem: Item { + anchors.fill: parent + Image { + id: imgCustom + anchors.centerIn: parent + source: "qrc:/res/icons/navbar_customconf.png" + sourceSize.width: 96 + sourceSize.height: 96 + width: 28 + height: 28 + fillMode: Image.PreserveAspectFit + visible: false + } + ColorOverlay { + anchors.fill: imgCustom + source: imgCustom + color: parent.parent.checked ? Material.accent : Utility.getAppHexColor("lightText") + } + } } Page { @@ -613,7 +867,6 @@ ApplicationWindow { dialogParent: mainSwipeView anchors.leftMargin: 10 anchors.rightMargin: 10 - isHorizontal: mainIsHorizontal } } } @@ -631,7 +884,6 @@ ApplicationWindow { anchors.fill: parent anchors.leftMargin: 10 anchors.rightMargin: 10 - isHorizontal: mainIsHorizontal } } } @@ -648,119 +900,6 @@ ApplicationWindow { anchors.fill: parent anchors.leftMargin: 10 anchors.rightMargin: 10 - isHorizontal: mainIsHorizontal - } - } - } - - footer: Rectangle { - id: connectedRect - clip: true - color: Utility.getAppHexColor("lightBackground") - width: parent.width - height: 35 + notchBot - Rectangle { - anchors.left: parent.left - anchors.right: parent.right - anchors.top:parent.top - height: parent.height/2.0 - gradient: Gradient { - GradientStop { position: 0.0; color: "#15ffffff"} - GradientStop { position: 0.3; color: "#04ffffff"} - GradientStop { position: 1.0; color: "transparent" } - } - } - Behavior on color { - ColorAnimation { - duration: 200; - easing.type: Easing.OutBounce - easing.overshoot: 3 - } - } - - RowLayout{ - enabled:true - anchors.fill: parent - spacing: 0 - ToolButton { - id:settingsButton - Layout.fillHeight: true - Layout.preferredWidth: 70 - Image { - anchors.centerIn: parent - anchors.verticalCenterOffset: -notchBot/2 - antialiasing: true - height: parent.width*0.35 - width: height - source: "qrc" + Utility.getThemePath() + "icons/Settings-96.png" - } - onClicked: { - if (drawer.visible) { - drawer.close() - } else { - drawer.open() - } - } - - } - Rectangle{ - Layout.fillHeight: true - Layout.preferredWidth: 1 - color: "#33000000" - } - Rectangle{ - Layout.fillHeight: true - Layout.preferredWidth: 1 - color: "#33ffffff" - } - ColumnLayout{ - spacing: 0 - Layout.fillWidth: true - Layout.fillHeight: true - Text { - id: connectedText - Layout.fillWidth: true - Layout.fillHeight: true - color: Utility.getAppHexColor("lightText") - text: VescIf.getConnectedPortName() - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - wrapMode: Text.Wrap - } - Rectangle{ - Layout.fillWidth: true - Layout.preferredHeight: notchBot - opacity: 0 - } - } - Rectangle{ - Layout.fillHeight: true - Layout.preferredWidth: 1 - color: "#33000000" - } - Rectangle{ - Layout.fillHeight: true - Layout.preferredWidth: 1 - color: "#33ffffff" - } - ToolButton { - Layout.fillHeight: true - Layout.preferredWidth: 70 - Image { - anchors.centerIn: parent - anchors.verticalCenterOffset: -notchBot/2 - antialiasing: true - height: parent.width*0.35 - width: height - source: "qrc" + Utility.getThemePath() + "icons/can_off.png" - } - onClicked: { - if (canDrawerLoader.item.visible) { - canDrawerLoader.item.close() - } else { - canDrawerLoader.item.open() - } - } } } } @@ -806,7 +945,7 @@ ApplicationWindow { repeat: false onTriggered: { connectedText.text = VescIf.getConnectedPortName() - connectedRect.color = Utility.getAppHexColor("lightBackground") + headerBar.color = Utility.getAppHexColor("lightBackground") } } @@ -983,7 +1122,7 @@ ApplicationWindow { tabBar.insertItem(1, uiHwButton) uiHwPage.visible = true - uiHwButton.text = "HwUi" + uiHwButton.text = "" if (hwUiObj.tabTitle) { uiHwButton.text = hwUiObj.tabTitle } @@ -1010,7 +1149,7 @@ ApplicationWindow { tabBar.insertItem(1, uiAppButton) uiAppPage.visible = true - uiAppButton.text = "AppUi" + uiAppButton.text = "" if (appUiObj.tabTitle) { uiAppButton.text = appUiObj.tabTitle } @@ -1094,7 +1233,7 @@ ApplicationWindow { function onStatusMessage(msg, isGood) { connectedText.text = msg - connectedRect.color = isGood ? Utility.getAppHexColor("lightAccent") : Utility.getAppHexColor("red") + headerBar.color = isGood ? Utility.getAppHexColor("lightAccent") : Utility.getAppHexColor("red") statusTimer.restart() } @@ -1113,23 +1252,6 @@ ApplicationWindow { function onFwRxChanged(rx, limited) { if (rx) { - if (VescIf.getFwSupportsConfiguration()) { - confPageMotor.visible = true - confPageApp.visible = true - - mainSwipeView.insertItem(4, confPageApp) - tabBar.insertItem(4, confAppButton) - mainSwipeView.insertItem(4, confPageMotor) - tabBar.insertItem(4, confMotorButton) - } else { - confPageMotor.visible = false - confPageApp.visible = false - confPageMotor.parent = null - confPageApp.parent = null - confMotorButton.parent = null - confAppButton.parent = null - } - if (VescIf.getFwSupportsConfiguration()) { confTimer.restart() confTimer.mcConfRx = false diff --git a/res.qrc b/res.qrc index c59721028..330700b36 100644 --- a/res.qrc +++ b/res.qrc @@ -187,6 +187,28 @@ res/icons_textedit/Align Center-96.png res/icons_textedit/Add Image-96.png res/logo_vertical.png + res/icons/navbar_start.png + res/icons/navbar_rtdata.png + res/icons/navbar_bms.png + res/icons/navbar_profiles.png + res/icons/navbar_terminal.png + res/icons/navbar_lispbm.png + res/icons/navbar_mcconf.png + res/icons/navbar_appconf.png + res/icons/navbar_customconf.png + res/icons/navbar_hwui.png + res/icons/navbar_appui.png + res/+theme_light/icons/navbar_start.png + res/+theme_light/icons/navbar_rtdata.png + res/+theme_light/icons/navbar_bms.png + res/+theme_light/icons/navbar_profiles.png + res/+theme_light/icons/navbar_terminal.png + res/+theme_light/icons/navbar_lispbm.png + res/+theme_light/icons/navbar_mcconf.png + res/+theme_light/icons/navbar_appconf.png + res/+theme_light/icons/navbar_customconf.png + res/+theme_light/icons/navbar_hwui.png + res/+theme_light/icons/navbar_appui.png res/+theme_light/icons/Wizard-96.png res/+theme_light/icons/Wii-96.png res/+theme_light/icons/Waypoint Map-96.png diff --git a/res/+theme_light/icons/navbar_appconf.png b/res/+theme_light/icons/navbar_appconf.png new file mode 100644 index 000000000..1e87cf6fe Binary files /dev/null and b/res/+theme_light/icons/navbar_appconf.png differ diff --git a/res/+theme_light/icons/navbar_appui.png b/res/+theme_light/icons/navbar_appui.png new file mode 100644 index 000000000..c9260728c Binary files /dev/null and b/res/+theme_light/icons/navbar_appui.png differ diff --git a/res/+theme_light/icons/navbar_bms.png b/res/+theme_light/icons/navbar_bms.png new file mode 100644 index 000000000..1b38fc6fa Binary files /dev/null and b/res/+theme_light/icons/navbar_bms.png differ diff --git a/res/+theme_light/icons/navbar_customconf.png b/res/+theme_light/icons/navbar_customconf.png new file mode 100644 index 000000000..92a5d79fc Binary files /dev/null and b/res/+theme_light/icons/navbar_customconf.png differ diff --git a/res/+theme_light/icons/navbar_hwui.png b/res/+theme_light/icons/navbar_hwui.png new file mode 100644 index 000000000..677d16bbb Binary files /dev/null and b/res/+theme_light/icons/navbar_hwui.png differ diff --git a/res/+theme_light/icons/navbar_lispbm.png b/res/+theme_light/icons/navbar_lispbm.png new file mode 100644 index 000000000..ae67780da Binary files /dev/null and b/res/+theme_light/icons/navbar_lispbm.png differ diff --git a/res/+theme_light/icons/navbar_mcconf.png b/res/+theme_light/icons/navbar_mcconf.png new file mode 100644 index 000000000..8a4d4db7c Binary files /dev/null and b/res/+theme_light/icons/navbar_mcconf.png differ diff --git a/res/+theme_light/icons/navbar_profiles.png b/res/+theme_light/icons/navbar_profiles.png new file mode 100644 index 000000000..c15cfaf9f Binary files /dev/null and b/res/+theme_light/icons/navbar_profiles.png differ diff --git a/res/+theme_light/icons/navbar_rtdata.png b/res/+theme_light/icons/navbar_rtdata.png new file mode 100644 index 000000000..28ae7d754 Binary files /dev/null and b/res/+theme_light/icons/navbar_rtdata.png differ diff --git a/res/+theme_light/icons/navbar_start.png b/res/+theme_light/icons/navbar_start.png new file mode 100644 index 000000000..5329d5858 Binary files /dev/null and b/res/+theme_light/icons/navbar_start.png differ diff --git a/res/+theme_light/icons/navbar_terminal.png b/res/+theme_light/icons/navbar_terminal.png new file mode 100644 index 000000000..a106027bd Binary files /dev/null and b/res/+theme_light/icons/navbar_terminal.png differ diff --git a/res/icons/navbar_appconf.png b/res/icons/navbar_appconf.png new file mode 100644 index 000000000..33263f8a5 Binary files /dev/null and b/res/icons/navbar_appconf.png differ diff --git a/res/icons/navbar_appui.png b/res/icons/navbar_appui.png new file mode 100644 index 000000000..f10a86acf Binary files /dev/null and b/res/icons/navbar_appui.png differ diff --git a/res/icons/navbar_bms.png b/res/icons/navbar_bms.png new file mode 100644 index 000000000..a5f597213 Binary files /dev/null and b/res/icons/navbar_bms.png differ diff --git a/res/icons/navbar_customconf.png b/res/icons/navbar_customconf.png new file mode 100644 index 000000000..7ccc2bdfa Binary files /dev/null and b/res/icons/navbar_customconf.png differ diff --git a/res/icons/navbar_hwui.png b/res/icons/navbar_hwui.png new file mode 100644 index 000000000..e422d89ba Binary files /dev/null and b/res/icons/navbar_hwui.png differ diff --git a/res/icons/navbar_lispbm.png b/res/icons/navbar_lispbm.png new file mode 100644 index 000000000..4673a3ff7 Binary files /dev/null and b/res/icons/navbar_lispbm.png differ diff --git a/res/icons/navbar_mcconf.png b/res/icons/navbar_mcconf.png new file mode 100644 index 000000000..cc3149d9c Binary files /dev/null and b/res/icons/navbar_mcconf.png differ diff --git a/res/icons/navbar_profiles.png b/res/icons/navbar_profiles.png new file mode 100644 index 000000000..cacc764ba Binary files /dev/null and b/res/icons/navbar_profiles.png differ diff --git a/res/icons/navbar_rtdata.png b/res/icons/navbar_rtdata.png new file mode 100644 index 000000000..1e256ecb3 Binary files /dev/null and b/res/icons/navbar_rtdata.png differ diff --git a/res/icons/navbar_start.png b/res/icons/navbar_start.png new file mode 100644 index 000000000..a2a9c5f54 Binary files /dev/null and b/res/icons/navbar_start.png differ diff --git a/res/icons/navbar_terminal.png b/res/icons/navbar_terminal.png new file mode 100644 index 000000000..cd73abb1c Binary files /dev/null and b/res/icons/navbar_terminal.png differ