diff --git a/console_backend/src/common_constants.rs b/console_backend/src/common_constants.rs index dd3c591b7..1fcfa375e 100644 --- a/console_backend/src/common_constants.rs +++ b/console_backend/src/common_constants.rs @@ -285,6 +285,8 @@ pub enum Keys { PREVIOUS_SERIAL_CONFIGS, #[strum(serialize = "RECORDING_FILENAME")] RECORDING_FILENAME, + #[strum(serialize = "CONSOLE_VERSION")] + CONSOLE_VERSION, } #[derive(Clone, Debug, Display, EnumString, EnumVariantNames, Eq, Hash, PartialEq)] diff --git a/console_backend/src/utils.rs b/console_backend/src/utils.rs index b515484ec..87fb1d85c 100644 --- a/console_backend/src/utils.rs +++ b/console_backend/src/utils.rs @@ -39,6 +39,7 @@ pub fn refresh_connection_frontend( let msg = builder.init_root::(); let mut connection_status = msg.init_connection_status(); + connection_status.set_console_version(&shared_state.console_version()); let mut ports: Vec = vec![]; if let Ok(ports_) = &mut available_ports() { // TODO(johnmichael.burke@) [CPP-114]Find solution to this hack for Linux serialport. diff --git a/resources/ConnectionScreen.qml b/resources/ConnectionScreen.qml index d52ebc645..cab1a8d7d 100644 --- a/resources/ConnectionScreen.qml +++ b/resources/ConnectionScreen.qml @@ -269,6 +269,7 @@ Item { return ; if (!available_baudrates.length || !available_flows.length) { + Globals.consoleVersion = connectionData.console_version; available_baudrates = connectionData.available_baudrates; serialDeviceBaudRate.currentIndex = 1; available_flows = connectionData.available_flows; diff --git a/resources/Constants/Constants.qml b/resources/Constants/Constants.qml index e32107438..7fa2b7297 100644 --- a/resources/Constants/Constants.qml +++ b/resources/Constants/Constants.qml @@ -16,7 +16,6 @@ QtObject { property QtObject connection property QtObject sideNavBar property QtObject loggingBar - property QtObject licensesPopup property QtObject commonChart property QtObject commonLegend property QtObject commonTable @@ -40,6 +39,7 @@ QtObject { property QtObject trackingSkyPlot property QtObject networking property QtObject fusionStatusFlags + property QtObject logoPopup readonly property int staticTimerIntervalRate: 5 // 5 Hz readonly property int staticTableTimerIntervalRate: 10 // 10 Hz readonly property int staticTimerSlowIntervalRate: 2 // 2 Hz @@ -53,6 +53,34 @@ QtObject { readonly property color materialGrey: "dimgrey" readonly property color swiftOrange: "#FF8300" + logoPopup: QtObject { + readonly property int heightPadding: 120 + readonly property int buttonWidth: 30 + readonly property int buttonRightMargin: 15 + readonly property int buttonTopMargin: 10 + property QtObject licenses + property QtObject aboutMe + + licenses: QtObject { + readonly property int dropdownHeight: 40 + readonly property string robotoFontTabLabel: "Roboto Font" + readonly property string fontAwesomeIconsTabLabel: "Font Awesome Icons" + readonly property string robotoFontLicensePath: "qrc:///fonts/Roboto-LICENSE.txt" + readonly property string fontAwesomeIconsLicensePath: "qrc:///images/fontawesome/LICENSE.txt" + } + + aboutMe: QtObject { + readonly property int logoWidth: 200 + readonly property int bottomPadding: 20 + readonly property string supportWebsite: "https://swiftnav.com/support" + readonly property string website: "https://www.swiftnav.com" + readonly property string copyrightText: "Copyright © 2011-2022 Swift Navigation Inc." + readonly property int titlePointSize: 14 + readonly property int secondaryPointSize: 10 + } + + } + sideNavBar: QtObject { readonly property int buttonSvgHeight: 15 readonly property string hamburgerPath: "images/fontawesome/bars-solid.svg" @@ -68,6 +96,9 @@ QtObject { readonly property int tabBarSpacing: 10 readonly property int buttonPadding: 0 readonly property int buttonInset: 0 + readonly property int separatorMargin: 10 + readonly property int separatorHeight: 1 + readonly property color backgroundColor: "#fafafa" } updateTab: QtObject { @@ -207,15 +238,6 @@ QtObject { property var defaultColumns: ["Item", "Value"] } - licensesPopup: QtObject { - readonly property real tabBarHeight: 40 - readonly property real dialogPopupHeightPadding: 100 - readonly property string robotoFontTabLabel: "Roboto Font" - readonly property string fontAwesomeIconsTabLabel: "Font Awesome Icons" - readonly property string robotoFontLicensePath: "../fonts/Roboto-LICENSE.txt" - readonly property string fontAwesomeIconsLicensePath: "../images/fontawesome/LICENSE.txt" - } - statusBar: QtObject { readonly property int margin: 10 readonly property int spacing: 10 @@ -552,6 +574,7 @@ QtObject { readonly property string playPath: "qrc:///images/iconic/play.svg" readonly property string solidCirclePath: "qrc:///images/fontawesome/circle-solid.svg" readonly property string squareSolidPath: "qrc:///images/fontawesome/square-solid.svg" + readonly property string swiftLogoPath: "qrc:///images/icon.png" } insSettingsPopup: QtObject { diff --git a/resources/Constants/Globals.qml b/resources/Constants/Globals.qml index a5be40c0d..b49017c42 100644 --- a/resources/Constants/Globals.qml +++ b/resources/Constants/Globals.qml @@ -2,6 +2,7 @@ import QtQuick 2.6 pragma Singleton QtObject { + property string consoleVersion: "0.0.0" property int currentRefreshRate: 5 // 5 Hz property bool useOpenGL: true property int initialMainTabIndex: 0 // Tracking diff --git a/resources/LogoPopup.qml b/resources/LogoPopup.qml new file mode 100644 index 000000000..98c592d07 --- /dev/null +++ b/resources/LogoPopup.qml @@ -0,0 +1,61 @@ +import "Constants" +import "LogoPopupComponents" as LogoPopupComponents +import QtQuick 2.5 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 + +Item { + function open() { + if (!dialog.visible) + dialog.open(); + + } + + Dialog { + id: dialog + + width: parent.width / 2 + height: parent.height - Constants.logoPopup.heightPadding + anchors.centerIn: parent + standardButtons: Dialog.Close + + ColumnLayout { + anchors.fill: parent + + TabBar { + id: logoPopupBar + + z: Constants.commonChart.zAboveCharts + Layout.fillWidth: true + Layout.preferredHeight: Constants.tabBarHeight + + Repeater { + model: ["About", "Licenses"] + + TabButton { + text: modelData + width: implicitWidth + } + + } + + } + + StackLayout { + currentIndex: logoPopupBar.currentIndex + Layout.fillWidth: true + Layout.fillHeight: true + + LogoPopupComponents.AboutMe { + } + + LogoPopupComponents.Licenses { + } + + } + + } + + } + +} diff --git a/resources/LogoPopupComponents/AboutMe.qml b/resources/LogoPopupComponents/AboutMe.qml new file mode 100644 index 000000000..45b90f77c --- /dev/null +++ b/resources/LogoPopupComponents/AboutMe.qml @@ -0,0 +1,53 @@ +import "../Constants" +import QtQuick 2.5 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 + +ColumnLayout { + Item { + Layout.fillWidth: true + Layout.fillHeight: true + + Image { + anchors.centerIn: parent + height: Constants.logoPopup.aboutMe.logoWidth + width: Constants.logoPopup.aboutMe.logoWidth + source: Constants.icons.swiftLogoPath + } + + } + + Label { + Layout.alignment: Qt.AlignHCenter + text: "Swift Navigation Console " + Globals.consoleVersion + font.pointSize: Constants.logoPopup.aboutMe.titlePointSize + font.bold: true + } + + Label { + Layout.alignment: Qt.AlignHCenter + text: Constants.logoPopup.aboutMe.copyrightText + font.pointSize: Constants.logoPopup.aboutMe.secondaryPointSize + } + + Label { + readonly property string website: Constants.logoPopup.aboutMe.supportWebsite + + Layout.alignment: Qt.AlignHCenter + text: "Find help at the Swift Navigation support portal" + font.pointSize: Constants.logoPopup.aboutMe.secondaryPointSize + onLinkActivated: { + Qt.openUrlExternally(website); + } + } + + Label { + Layout.alignment: Qt.AlignHCenter + text: "Learn more at the Swift Navigation website" + font.pointSize: Constants.logoPopup.aboutMe.secondaryPointSize + onLinkActivated: { + Qt.openUrlExternally(Constants.logoPopup.aboutMe.website); + } + } + +} diff --git a/resources/LogoPopupComponents/Licenses.qml b/resources/LogoPopupComponents/Licenses.qml new file mode 100644 index 000000000..bd326e9cc --- /dev/null +++ b/resources/LogoPopupComponents/Licenses.qml @@ -0,0 +1,64 @@ +import "../Constants" +import QtQuick 2.5 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 + +ColumnLayout { + ComboBox { + id: licenses + + Layout.preferredHeight: Constants.logoPopup.licenses.dropdownHeight + Layout.preferredWidth: parent.width / 2 + Layout.alignment: Qt.AlignHCenter + model: [Constants.logoPopup.licenses.robotoFontTabLabel, Constants.logoPopup.licenses.fontAwesomeIconsTabLabel] + } + + StackLayout { + currentIndex: licenses.currentIndex + Layout.fillWidth: true + Layout.fillHeight: true + Layout.alignment: Qt.AlignHCenter + + ScrollView { + ScrollBar.vertical.policy: ScrollBar.AlwaysOn + + TextArea { + id: robotoFontTextArea + + readOnly: true + activeFocusOnPress: false + horizontalAlignment: TextEdit.AlignJustify + selectByKeyboard: true + selectByMouse: true + } + + } + + ScrollView { + ScrollBar.vertical.policy: ScrollBar.AlwaysOn + + TextArea { + id: fontAwesomeTextArea + + readOnly: true + activeFocusOnPress: false + horizontalAlignment: TextEdit.AlignJustify + selectByKeyboard: true + selectByMouse: true + } + + } + + } + + Timer { + interval: 1 + running: true + repeat: false + onTriggered: { + Utils.readTextFile(Constants.logoPopup.licenses.robotoFontLicensePath, robotoFontTextArea); + Utils.readTextFile(Constants.logoPopup.licenses.fontAwesomeIconsLicensePath, fontAwesomeTextArea); + } + } + +} diff --git a/resources/MainDrawer.qml b/resources/MainDrawer.qml deleted file mode 100644 index 98ee1c076..000000000 --- a/resources/MainDrawer.qml +++ /dev/null @@ -1,58 +0,0 @@ -import "Constants" -import QtQuick 2.5 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import SwiftConsole 1.0 - -Item { - property alias drawer: sideDrawer - property var stackView: parent.stackView - - Drawer { - id: sideDrawer - - width: parent.width / 5 - height: parent.height - interactive: true - dim: false - dragMargin: Constants.sideNavBar.tabBarWidth / 4 - - ListView { - id: drawerItems - - anchors.fill: parent - focus: true - currentIndex: -1 - - delegate: ItemDelegate { - highlighted: ListView.isCurrentItem - width: drawerItems.width - text: model.name - onClicked: { - drawerItems.currentIndex = index; - stackView.push(model.source); - sideDrawer.close(); - } - } - - model: ListModel { - ListElement { - name: "Connection" - } - - ListElement { - name: "License" - source: "MainDrawerComponents/LicensesPopup.qml" - } - - ListElement { - name: "About" - } - - } - - } - - } - -} diff --git a/resources/MainDrawerComponents/LicensesPopup.qml b/resources/MainDrawerComponents/LicensesPopup.qml deleted file mode 100644 index fbfc6d158..000000000 --- a/resources/MainDrawerComponents/LicensesPopup.qml +++ /dev/null @@ -1,79 +0,0 @@ -import "../Constants" -import "../Constants/utils.js" as Utils -import QtQuick 2.5 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 - -Item { - Dialog { - id: dialog - - visible: true - width: Constants.width / 2 - height: parent.height - Constants.licensesPopup.dialogPopupHeightPadding - anchors.centerIn: parent - standardButtons: Dialog.Ok | Dialog.Cancel - - TabBar { - id: licenseBar - - contentHeight: Constants.licensesPopup.tabBarHeight - width: parent.width - - TabButton { - width: implicitWidth - text: Constants.licensesPopup.robotoFontTabLabel - } - - TabButton { - width: implicitWidth - text: Constants.licensesPopup.fontAwesomeIconsTabLabel - } - - } - - StackLayout { - currentIndex: licenseBar.currentIndex - width: parent.width - height: parent.height - anchors.top: licenseBar.bottom - - Flickable { - - TextArea.flickable: TextArea { - id: robotoFontTextArea - } - - ScrollBar.vertical: ScrollBar { - } - - } - - Flickable { - - TextArea.flickable: TextArea { - id: fontAwesomeTextArea - } - - ScrollBar.vertical: ScrollBar { - } - - } - - } - - Timer { - id: readStarter - - interval: 1 - running: true - repeat: false - onTriggered: { - Utils.readTextFile(Constants.licensesPopup.robotoFontLicensePath, robotoFontTextArea); - Utils.readTextFile(Constants.licensesPopup.fontAwesomeIconsLicensePath, fontAwesomeTextArea); - } - } - - } - -} diff --git a/resources/SideNavBar.qml b/resources/SideNavBar.qml index 215f3e62a..2bf34a5fb 100644 --- a/resources/SideNavBar.qml +++ b/resources/SideNavBar.qml @@ -6,7 +6,6 @@ import SwiftConsole 1.0 Rectangle { property alias curIndex: tab.currentIndex - property var drawer: parent.drawer property var tabModel: [{ "name": "Tracking", "tooltip": "Tracking", @@ -37,6 +36,8 @@ Rectangle { "source": Constants.sideNavBar.advancedPath }] + color: Constants.sideNavBar.backgroundColor + ConnectionData { id: connectionData } @@ -44,6 +45,34 @@ Rectangle { ColumnLayout { anchors.fill: parent + Button { + id: logo + + Layout.fillWidth: true + Layout.preferredHeight: Constants.sideNavBar.tabBarHeight + padding: Constants.sideNavBar.buttonPadding + icon.source: Constants.icons.swiftLogoPath + icon.color: "transparent" + ToolTip.visible: hovered + ToolTip.text: "About this application" + onClicked: { + logoPopup.open(); + } + + background: Item { + } + + } + + Rectangle { + color: Constants.materialGrey + Layout.alignment: Qt.AlignHCenter + Layout.preferredHeight: Constants.sideNavBar.separatorHeight + Layout.fillWidth: true + Layout.rightMargin: Constants.sideNavBar.separatorMargin + Layout.leftMargin: Constants.sideNavBar.separatorMargin + } + TabBar { id: tab @@ -55,22 +84,12 @@ Rectangle { contentWidth: Constants.sideNavBar.tabBarWidth currentIndex: Globals.initialMainTabIndex + 1 Component.onCompleted: { - hamburger.checkable = false; + logo.checkable = false; } TabButton { - id: hamburger - - width: Constants.sideNavBar.tabBarWidth - anchors.horizontalCenter: parent.horizontalCenter - icon.source: Constants.sideNavBar.hamburgerPath - display: AbstractButton.IconOnly - rightInset: Constants.sideNavBar.buttonInset - leftInset: Constants.sideNavBar.buttonInset - enabled: Globals.connected_at_least_once - onClicked: { - drawer.open(); - } + enabled: false + height: 0 } Repeater { diff --git a/resources/console_resources.qrc b/resources/console_resources.qrc index b8b2fc03d..6eb23fb2c 100644 --- a/resources/console_resources.qrc +++ b/resources/console_resources.qrc @@ -5,7 +5,6 @@ fonts/Roboto-Regular.ttf fonts/Roboto-Bold.ttf view.qml - MainDrawer.qml MainDialogView.qml MainTabs.qml SideNavBar.qml @@ -53,7 +52,9 @@ ObservationTab.qml ObservationTabComponents/ObservationTable.qml ObservationTabComponents/ObservationFilterColumn.qml - MainDrawerComponents/LicensesPopup.qml + LogoPopupComponents/Licenses.qml + LogoPopupComponents/AboutMe.qml + LogoPopup.qml UpdateTab.qml UpdateTabComponents/FirmwareVersionAndDownloadLabels.qml UpdateTabComponents/FirmwareRevision.qml @@ -92,6 +93,7 @@ images/fontawesome/file-export.svg images/fontawesome/file-import.svg images/fontawesome/exclamation-triangle.svg + images/icon.png TableComponents/SortableColumnHeading.qml TableComponents/TableCellDelegate.qml BaseComponents/SmallCheckBox.qml diff --git a/resources/view.qml b/resources/view.qml index b7833b1ff..a9dc1d500 100644 --- a/resources/view.qml +++ b/resources/view.qml @@ -25,16 +25,17 @@ ApplicationWindow { anchors.fill: parent } + LogoPopup { + id: logoPopup + + anchors.fill: parent + } + RowLayout { - property alias drawer: mainDrawer.drawer property alias stackView: dialogStack.dialogStack anchors.fill: parent - MainDrawer { - id: mainDrawer - } - SideNavBar { id: sideNavBar @@ -85,6 +86,7 @@ ApplicationWindow { id: mainTabs property alias curIndex: sideNavBar.curIndex + property alias logoPopup: logoPopup SplitView.fillHeight: true SplitView.fillWidth: true diff --git a/src/main/resources/base/console_backend.capnp b/src/main/resources/base/console_backend.capnp index e2010023f..3c835d543 100644 --- a/src/main/resources/base/console_backend.capnp +++ b/src/main/resources/base/console_backend.capnp @@ -159,6 +159,7 @@ struct ConnectionStatus { port @7 :Text; none @8 :Void = void; } + consoleVersion @9: Text; } struct StatusBarStatus { diff --git a/swiftnav_console/connection.py b/swiftnav_console/connection.py index dc07a3cd8..b8ec0dcbe 100644 --- a/swiftnav_console/connection.py +++ b/swiftnav_console/connection.py @@ -18,6 +18,7 @@ Keys.PREVIOUS_FILES: [], Keys.LAST_USED_SERIAL_DEVICE: None, Keys.PREVIOUS_SERIAL_CONFIGS: [], + Keys.CONSOLE_VERSION: str, } @@ -33,6 +34,7 @@ class ConnectionData(QObject): # pylint: disable=too-many-instance-attributes d _previous_files: List[str] = [] _last_used_serial_device: str _previous_serial_configs: List[List[Any]] = [] + _console_version: str = "" def get_available_ports(self) -> List[str]: return self._available_ports @@ -116,6 +118,14 @@ def set_previous_serial_configs(self, previous_serial_configs: List[List[Any]]) QTKeys.QVARIANTLIST, get_previous_serial_configs, set_previous_serial_configs # type: ignore ) + def get_console_version(self) -> str: + return self._console_version + + def set_console_version(self, console_version: str) -> None: + self._console_version = console_version + + console_version = Property(str, get_console_version, set_console_version) + class ConnectionModel(QObject): # pylint: disable=too-few-public-methods @Slot(ConnectionData) # type: ignore @@ -129,4 +139,5 @@ def fill_data(self, cp: ConnectionData) -> ConnectionData: # pylint:disable=no- cp.set_previous_files(CONNECTION[Keys.PREVIOUS_FILES]) cp.set_last_used_serial_device(CONNECTION[Keys.LAST_USED_SERIAL_DEVICE]) cp.set_previous_serial_configs(CONNECTION[Keys.PREVIOUS_SERIAL_CONFIGS]) + cp.set_console_version(CONNECTION[Keys.CONSOLE_VERSION]) return cp diff --git a/swiftnav_console/constants.py b/swiftnav_console/constants.py index 1da70b689..56128a0f8 100644 --- a/swiftnav_console/constants.py +++ b/swiftnav_console/constants.py @@ -135,6 +135,7 @@ class Keys(str, Enum): LAST_USED_SERIAL_DEVICE = "LAST_USED_SERIAL_DEVICE" PREVIOUS_SERIAL_CONFIGS = "PREVIOUS_SERIAL_CONFIGS" RECORDING_FILENAME = "RECORDING_FILENAME" + CONSOLE_VERSION = "CONSOLE_VERSION" class ConnectionState(str, Enum): diff --git a/swiftnav_console/main.py b/swiftnav_console/main.py index 0acd6f47b..19071be89 100644 --- a/swiftnav_console/main.py +++ b/swiftnav_console/main.py @@ -379,6 +379,7 @@ def receive_messages(app_, backend, messages): CONNECTION[Keys.PREVIOUS_SERIAL_CONFIGS][:] = [ [entry.device, entry.baudrate, entry.flowControl] for entry in m.connectionStatus.previousSerialConfigs ] + CONNECTION[Keys.CONSOLE_VERSION] = m.connectionStatus.consoleVersion elif m.which == Message.Union.LoggingBarStatus: LOGGING_BAR[Keys.PREVIOUS_FOLDERS][:] = m.loggingBarStatus.previousFolders LOGGING_BAR[Keys.CSV_LOGGING] = m.loggingBarStatus.csvLogging