diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3039166..e4cfe63 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -24,20 +24,22 @@ jobs: - os: ubuntu-20.04 qt_host: linux + qt_target: desktop qt_version: '6.8.1' qt_arch: gcc_64 - os: ubuntu-20.04 qt_host: linux qt_target: android - qt_arch: android_arm64_v8a qt_version: '6.8.1' + qt_arch: android_arm64_v8a - os: ubuntu-20.04 - qt_host: linux - qt_version: '6.6.0' + qt_host: all_os + qt_target: wasm + qt_version: '6.8.1' qt_arch: wasm_singlethread - emsdk_version: 3.1.37 + emsdk_version: 3.1.56 - os: windows-2022 qt_host: windows @@ -82,29 +84,24 @@ jobs: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' - - name: Install Qt ${{ matrix.qt_version }} - uses: jurplel/install-qt-action@v4 + - name: Install Qt ${{ matrix.qt_version }} (Host) + uses: Kidev/install-qt-action@v4.2.0 with: cache: on version: ${{ matrix.qt_version }} - - name: Install Qt ${{ matrix.qt_version }} (WASM) - if: matrix.qt_arch == 'wasm_singlethread' - uses: jurplel/install-qt-action@v4 + - name: Install Qt ${{ matrix.qt_version }} (WASM/Android) + if: runner.os == 'Linux' && matrix.qt_arch != 'gcc_64' + uses: Kidev/install-qt-action@v4.2.0 with: cache: on host: ${{ matrix.qt_host }} - version: ${{ matrix.qt_version }} - arch: ${{ matrix.qt_arch }} - - - name: Install Qt ${{ matrix.qt_version }} (Android) - if: matrix.qt_target == 'android' - uses: jurplel/install-qt-action@v4 - with: - cache: on - version: ${{ matrix.qt_version }} target: ${{ matrix.qt_target }} + version: ${{ matrix.qt_version }} arch: ${{ matrix.qt_arch }} + set-env: true + modules: 'qtquick3d' + aqtsource: 'git+https://github.com/Kidev/aqtinstall.git@wasm' - name: Install Build Dependencies (macOS) if: runner.os == 'macOS' @@ -131,9 +128,9 @@ jobs: if: runner.os == 'Linux' run: | git submodule update --init - declare QTPATH="${{ github.workspace }}/../Qt/${{ matrix.qt_version }}" + declare QTPATH="${{ runner.workspace }}/Qt/${{ matrix.qt_version }}" - cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DCMAKE_TOOLCHAIN_FILE=$QTPATH/${{ matrix.qt_arch }}/lib/cmake/Qt6/qt.toolchain.cmake -DQT_HOST_PATH=$QTPATH/gcc_64 -DQT_HOST_PATH_CMAKE_DIR=$QTPATH/${{ matrix.qt_arch }}/lib/cmake -DCMAKE_PREFIX_PATH=$QTPATH/${{ matrix.qt_arch }}/lib/cmake -DTBA_AUTH_KEY=${{ secrets.TBA_AUTH_KEY }} + cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DCMAKE_TOOLCHAIN_FILE=$QTPATH/${{ matrix.qt_arch }}/lib/cmake/Qt6/qt.toolchain.cmake -DQT_HOST_PATH=$QTPATH/gcc_64 -DQT_HOST_PATH_CMAKE_DIR=$QTPATH/gcc_64/lib/cmake -DCMAKE_PREFIX_PATH=$QTPATH/${{ matrix.qt_arch }} -DTBA_AUTH_KEY=${{ secrets.TBA_AUTH_KEY }} - name: Configure (Windows, macOS) if: runner.os != 'Linux' @@ -181,13 +178,13 @@ jobs: cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_APPIMAGE_DIR }}/usr export OUTPUT="QFRCScouter-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage" - export QML_SOURCES_PATHS="${{ runner.workspace }}/Qt/${{ matrix.qt_version }}/gcc_64/qml:${{ github.workspace }}" + export QML_SOURCES_PATHS="${{ runner.workspace }}/Qt/${{ matrix.qt_version }}/${{ matrix.qt_arch }}/qml:${{ github.workspace }}" chmod +x linuxdeploy-*.AppImage mkdir -p ${{ env.INSTALL_APPIMAGE_DIR }}/usr/plugins/iconengines - cp -r ${{ runner.workspace }}/Qt/${{ matrix.qt_version }}/gcc_64/plugins/ ${{ env.INSTALL_APPIMAGE_DIR }}/usr/ + cp -r ${{ runner.workspace }}/Qt/${{ matrix.qt_version }}/${{ matrix.qt_arch }}/plugins/ ${{ env.INSTALL_APPIMAGE_DIR }}/usr/ cp /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/ cp /usr/lib/x86_64-linux-gnu/libssl.so.1.1 ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/ diff --git a/include/Config.h b/include/Config.h index 5f04eb1..d9d9fba 100644 --- a/include/Config.h +++ b/include/Config.h @@ -18,6 +18,10 @@ class ScouterConfig : public QObject QJsonObject object() const; void setObject(const QJsonObject &newObject); +#if !defined(Q_OS_WASM) && !defined(Q_OS_ANDROID) + void saveCsv() const; +#endif + PhaseDataModel *autoModel() const; PhaseDataModel *teleModel() const; diff --git a/items/LabeledSpinBox.qml b/items/LabeledSpinBox.qml index 5a1ceda..32a825d 100644 --- a/items/LabeledSpinBox.qml +++ b/items/LabeledSpinBox.qml @@ -33,6 +33,8 @@ SpinBox { horizontalAlignment: Qt.AlignHCenter verticalAlignment: Qt.AlignVCenter + readOnly: !spin.editable + width: parent.width / 3 inputMethodHints: Qt.ImhFormattedNumbersOnly diff --git a/items/MatchSpinBox.qml b/items/MatchSpinBox.qml index 051756f..422e403 100644 --- a/items/MatchSpinBox.qml +++ b/items/MatchSpinBox.qml @@ -28,7 +28,7 @@ SpinBox { from: min to: max - editable: true + editable: false value: 0 onValueModified: { @@ -44,6 +44,7 @@ SpinBox { verticalAlignment: Qt.AlignVCenter width: parent.width / 3 + readOnly: !spin.editable inputMethodHints: Qt.ImhFormattedNumbersOnly diff --git a/items/ScaleItem.qml b/items/ScaleItem.qml index 4ddd5ee..a785152 100644 --- a/items/ScaleItem.qml +++ b/items/ScaleItem.qml @@ -38,6 +38,7 @@ ColumnLayout { RowLayout { Layout.fillWidth: true + uniformCellSizes: true spacing: 2 Repeater { diff --git a/pages/ScalesPage.qml b/pages/ScalesPage.qml index d16b2b5..e5c739b 100644 --- a/pages/ScalesPage.qml +++ b/pages/ScalesPage.qml @@ -21,6 +21,8 @@ Rectangle { property list values ColumnLayout { + uniformCellSizes: true + anchors { top: banner.bottom bottom: parent.bottom diff --git a/screen/MainScreen.qml b/screen/MainScreen.qml index 8cba2aa..39dfe62 100644 --- a/screen/MainScreen.qml +++ b/screen/MainScreen.qml @@ -26,6 +26,7 @@ Rectangle { onHeightChanged: resetScalar() SwipeView { + onCurrentIndexChanged: forceActiveFocus() id: swipe currentIndex: 0 diff --git a/src/Config.cpp b/src/Config.cpp index f7b9d85..8d1d76b 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -1,5 +1,6 @@ #include "Config.h" +#include #include #include @@ -25,6 +26,10 @@ ScouterConfig::ScouterConfig(QObject *parent) m_teleModel = new PhaseDataModel(pages.value("tele").toObject(), this); m_endModel = new PhaseDataModel(pages.value("end").toObject(), this); m_scalesModel = new ScalesModel(pages.value("scales").toArray(), this); + +#if !defined(Q_OS_WASM) && !defined(Q_OS_ANDROID) + saveCsv(); +#endif } QJsonObject ScouterConfig::object() const @@ -40,6 +45,44 @@ void ScouterConfig::setObject(const QJsonObject &newObject) emit objectChanged(); } +#if !defined(Q_OS_WASM) && !defined(Q_OS_ANDROID) +void ScouterConfig::saveCsv() const +{ + QStringList csv; + csv << "Scouter Initials" + << "Match Number" + << "Team Number"; + + QJsonObject pages = m_object.value("pages").toObject(); + QJsonArray autoPage = pages.value("auto").toArray(); + QJsonArray telePage = pages.value("tele").toArray(); + QJsonArray scalesPage = pages.value("scales").toArray(); + + for (QJsonValueConstRef ref : autoPage) { + csv << ("Auto " + ref.toObject().value("text").toString()); + } + + for (QJsonValueConstRef ref : telePage) { + csv << ("Teleop " + ref.toObject().value("text").toString()); + } + + for (QJsonValueConstRef ref : scalesPage) { + csv << ref.toObject().value("title").toString(); + } + + // save to home directory for easy access + QDir home = QDir::home(); + QFile file(home.absoluteFilePath("data.csv")); + + if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + qCritical() << "Failed to write CSV."; + } else { + file.write(csv.join(",").toUtf8()); + file.close(); + } +} +#endif + PhaseDataModel *ScouterConfig::autoModel() const { return m_autoModel;