diff --git a/.github/workflows/ci_macos.yaml b/.github/workflows/ci_macos.yaml index 4b2709516..0b60cf989 100644 --- a/.github/workflows/ci_macos.yaml +++ b/.github/workflows/ci_macos.yaml @@ -49,8 +49,10 @@ jobs: - name: Setup ccache uses: Chocobo1/setup-ccache-action@v1 with: - store_cache: ${{ startsWith(github.ref, 'refs/heads/') }} + store_cache: ${{ github.ref == 'refs/heads/master' }} update_packager_index: false + ccache_options: | + max_size=2G - name: Install boost run: | @@ -136,8 +138,18 @@ jobs: if [ "${{ matrix.qbt_gui }}" = "GUI=OFF" ]; then appName="qbittorrent-nox" fi + # package pushd build - macdeployqt "$appName.app" -dmg -no-strip + PACKAGE_RETRY=0 + while [ "$PACKAGE_RETRY" -lt "3" ]; do + macdeployqt "$appName.app" -dmg -no-strip + if [ -f "$appName.dmg" ]; then + break + fi + sleep 5 + PACKAGE_RETRY=$((PACKAGE_RETRY + 1)) + echo "Retry $PACKAGE_RETRY..." + done popd # prepare upload folder mkdir upload diff --git a/.github/workflows/ci_ubuntu.yaml b/.github/workflows/ci_ubuntu.yaml index 313275b07..406b3917a 100644 --- a/.github/workflows/ci_ubuntu.yaml +++ b/.github/workflows/ci_ubuntu.yaml @@ -39,7 +39,7 @@ jobs: - name: Setup ccache uses: Chocobo1/setup-ccache-action@v1 with: - store_cache: ${{ startsWith(github.ref, 'refs/heads/') }} + store_cache: ${{ github.ref == 'refs/heads/master' }} update_packager_index: false ccache_options: | max_size=2G diff --git a/dist/unix/org.qbittorrent.qBittorrent.metainfo.xml b/dist/unix/org.qbittorrent.qBittorrent.metainfo.xml index c6cfa3ba8..370ddabc0 100644 --- a/dist/unix/org.qbittorrent.qBittorrent.metainfo.xml +++ b/dist/unix/org.qbittorrent.qBittorrent.metainfo.xml @@ -33,19 +33,19 @@ Main window (General tab collapsed) - https://alexpl.fedorapeople.org/AppData/qbittorrent/screens/qbittorrent_01.png + https://raw.githubusercontent.com/qbittorrent/qBittorrent-website/2741f2a90854604e268c6bba9e6859aad0103583/src/img/screenshots/linux/1.webp Main window (General tab expanded) - https://alexpl.fedorapeople.org/AppData/qbittorrent/screens/qbittorrent_03.png + https://raw.githubusercontent.com/qbittorrent/qBittorrent-website/2741f2a90854604e268c6bba9e6859aad0103583/src/img/screenshots/linux/2.webp Options dialog - https://alexpl.fedorapeople.org/AppData/qbittorrent/screens/qbittorrent_04.png + https://raw.githubusercontent.com/qbittorrent/qBittorrent-website/2741f2a90854604e268c6bba9e6859aad0103583/src/img/screenshots/linux/3.webp Search engine - https://alexpl.fedorapeople.org/AppData/qbittorrent/screens/qbittorrent_02.png + https://raw.githubusercontent.com/qbittorrent/qBittorrent-website/2741f2a90854604e268c6bba9e6859aad0103583/src/img/screenshots/linux/4.webp sledgehammer999@qbittorrent.org diff --git a/src/app/application.cpp b/src/app/application.cpp index 0244e40f1..3026b69b1 100644 --- a/src/app/application.cpp +++ b/src/app/application.cpp @@ -258,6 +258,7 @@ Application::Application(int &argc, char **argv) setAttribute(Qt::AA_UseHighDpiPixmaps, true); // opt-in to the high DPI pixmap support #endif setQuitOnLastWindowClosed(false); + setQuitLockEnabled(false); QPixmapCache::setCacheLimit(PIXMAP_CACHE_SIZE); #endif diff --git a/src/base/bittorrent/torrentimpl.cpp b/src/base/bittorrent/torrentimpl.cpp index 7cab602d7..fea7c3858 100644 --- a/src/base/bittorrent/torrentimpl.cpp +++ b/src/base/bittorrent/torrentimpl.cpp @@ -1519,7 +1519,17 @@ void TorrentImpl::forceRecheck() // an incorrect one during the interval until the cached state is updated in a regular way. m_nativeStatus.state = lt::torrent_status::checking_resume_data; - m_hasMissingFiles = false; + if (m_hasMissingFiles) + { + m_hasMissingFiles = false; + if (!isPaused()) + { + setAutoManaged(m_operatingMode == TorrentOperatingMode::AutoManaged); + if (m_operatingMode == TorrentOperatingMode::Forced) + m_nativeHandle.resume(); + } + } + m_unchecked = false; m_completedFiles.fill(false); diff --git a/src/base/torrentfilter.h b/src/base/torrentfilter.h index 3358ef380..4c49d904b 100644 --- a/src/base/torrentfilter.h +++ b/src/base/torrentfilter.h @@ -60,7 +60,9 @@ public: StalledDownloading, Checking, Moving, - Errored + Errored, + + _Count }; // These mean any permutation, including no category / tag. diff --git a/src/gui/addnewtorrentdialog.cpp b/src/gui/addnewtorrentdialog.cpp index 89133e084..a2d9d49db 100644 --- a/src/gui/addnewtorrentdialog.cpp +++ b/src/gui/addnewtorrentdialog.cpp @@ -159,7 +159,8 @@ namespace delta.setY(0); dialogGeometry.translate(delta); - delta = screenGeometry.topLeft() - dialogGeometry.topLeft(); + const QPoint frameOffset {10, 40}; + delta = screenGeometry.topLeft() - dialogGeometry.topLeft() + frameOffset; if (delta.x() < 0) delta.setX(0); if (delta.y() < 0) diff --git a/src/gui/fspathedit_p.cpp b/src/gui/fspathedit_p.cpp index 1e58002e3..ba6efec12 100644 --- a/src/gui/fspathedit_p.cpp +++ b/src/gui/fspathedit_p.cpp @@ -164,6 +164,7 @@ QValidator::State Private::FileSystemPathValidator::validate(QString &input, int Private::FileLineEdit::FileLineEdit(QWidget *parent) : QLineEdit(parent) { + setCompleter(new QCompleter(this)); connect(this, &QLineEdit::textChanged, this, &FileLineEdit::validateText); } @@ -222,7 +223,7 @@ void Private::FileLineEdit::keyPressEvent(QKeyEvent *e) if ((e->key() == Qt::Key_Space) && (e->modifiers() == Qt::CTRL)) { - if (!m_completer) + if (!m_completerModel) { m_iconProvider = new QFileIconProvider; m_iconProvider->setOptions(QFileIconProvider::DontUseCustomDirectoryIcons); @@ -235,9 +236,7 @@ void Private::FileLineEdit::keyPressEvent(QKeyEvent *e) | (m_completeDirectoriesOnly ? QDir::Dirs : QDir::AllEntries); m_completerModel->setFilter(filters); - m_completer = new QCompleter(this); - m_completer->setModel(m_completerModel); - setCompleter(m_completer); + completer()->setModel(m_completerModel); } m_completerModel->setRootPath(Path(text()).data()); @@ -261,8 +260,8 @@ void Private::FileLineEdit::contextMenuEvent(QContextMenuEvent *event) void Private::FileLineEdit::showCompletionPopup() { - m_completer->setCompletionPrefix(text()); - m_completer->complete(); + completer()->setCompletionPrefix(text()); + completer()->complete(); } void Private::FileLineEdit::validateText() diff --git a/src/gui/fspathedit_p.h b/src/gui/fspathedit_p.h index 153cf4b08..e52face0f 100644 --- a/src/gui/fspathedit_p.h +++ b/src/gui/fspathedit_p.h @@ -37,7 +37,6 @@ #include "base/pathfwd.h" class QAction; -class QCompleter; class QContextMenuEvent; class QFileIconProvider; class QFileSystemModel; @@ -141,7 +140,6 @@ namespace Private static QString warningText(FileSystemPathValidator::TestResult result); QFileSystemModel *m_completerModel = nullptr; - QCompleter *m_completer = nullptr; QAction *m_browseAction = nullptr; QAction *m_warningAction = nullptr; QFileIconProvider *m_iconProvider = nullptr; diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp index c7e15e40c..fb01833f1 100644 --- a/src/gui/mainwindow.cpp +++ b/src/gui/mainwindow.cpp @@ -781,8 +781,11 @@ void MainWindow::saveSplitterSettings() const void MainWindow::cleanup() { - saveSettings(); - saveSplitterSettings(); + if (!m_neverShown) + { + saveSettings(); + saveSplitterSettings(); + } // delete RSSWidget explicitly to avoid crash in // handleRSSUnreadCountUpdated() at application shutdown diff --git a/src/gui/transferlistfilters/statusfilterwidget.cpp b/src/gui/transferlistfilters/statusfilterwidget.cpp index 99b00af76..731b4fe52 100644 --- a/src/gui/transferlistfilters/statusfilterwidget.cpp +++ b/src/gui/transferlistfilters/statusfilterwidget.cpp @@ -95,7 +95,7 @@ StatusFilterWidget::StatusFilterWidget(QWidget *parent, TransferListWidget *tran connect(pref, &Preferences::changed, this, &StatusFilterWidget::configure); const int storedRow = pref->getTransSelFilter(); - if (item((storedRow < count()) ? storedRow : 0)->isHidden()) + if (item(((storedRow >= 0) && (storedRow < count())) ? storedRow : 0)->isHidden()) setCurrentRow(TorrentFilter::All, QItemSelectionModel::SelectCurrent); else setCurrentRow(storedRow, QItemSelectionModel::SelectCurrent); diff --git a/src/gui/transferlistwidget.cpp b/src/gui/transferlistwidget.cpp index 38300d05c..ff76167f8 100644 --- a/src/gui/transferlistwidget.cpp +++ b/src/gui/transferlistwidget.cpp @@ -1330,9 +1330,10 @@ void TransferListWidget::applyFilter(const QString &name, const TransferListMode m_sortFilterModel->setFilterRegularExpression(QRegularExpression(pattern, QRegularExpression::CaseInsensitiveOption)); } -void TransferListWidget::applyStatusFilter(int f) +void TransferListWidget::applyStatusFilter(const int filterIndex) { - m_sortFilterModel->setStatusFilter(static_cast(f)); + const auto filterType = static_cast(filterIndex); + m_sortFilterModel->setStatusFilter(((filterType >= TorrentFilter::All) && (filterType < TorrentFilter::_Count)) ? filterType : TorrentFilter::All); // Select first item if nothing is selected if (selectionModel()->selectedRows(0).empty() && (m_sortFilterModel->rowCount() > 0)) { diff --git a/src/gui/transferlistwidget.h b/src/gui/transferlistwidget.h index ad9b0f37b..84a965d4e 100644 --- a/src/gui/transferlistwidget.h +++ b/src/gui/transferlistwidget.h @@ -93,7 +93,7 @@ public slots: void previewSelectedTorrents(); void hideQueuePosColumn(bool hide); void applyFilter(const QString &name, const TransferListModel::Column &type); - void applyStatusFilter(int f); + void applyStatusFilter(int filterIndex); void applyCategoryFilter(const QString &category); void applyTagFilter(const QString &tag); void applyTrackerFilterAll(); diff --git a/src/webui/www/package.json b/src/webui/www/package.json index 6be44e273..e527fed26 100644 --- a/src/webui/www/package.json +++ b/src/webui/www/package.json @@ -10,8 +10,8 @@ "lint": "eslint private/*.html private/scripts/*.js private/views/*.html public/*.html public/scripts/*.js && stylelint **/*.css && html-validate private public" }, "devDependencies": { - "eslint": "*", - "eslint-plugin-html": "*", + "eslint": "^8", + "eslint-plugin-html": "^8", "html-validate": "*", "js-beautify": "*", "prettier": "*", diff --git a/src/webui/www/private/scripts/prop-trackers.js b/src/webui/www/private/scripts/prop-trackers.js index e1c4ddaa0..d808c5de9 100644 --- a/src/webui/www/private/scripts/prop-trackers.js +++ b/src/webui/www/private/scripts/prop-trackers.js @@ -100,7 +100,7 @@ window.qBittorrent.PropTrackers = (function() { tier: (tracker.tier >= 0) ? tracker.tier : "", url: tracker.url, status: status, - peers: tracker.num_peers, + peers: (tracker.num_peers >= 0) ? tracker.num_peers : "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]", seeds: (tracker.num_seeds >= 0) ? tracker.num_seeds : "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]", leeches: (tracker.num_leeches >= 0) ? tracker.num_leeches : "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]", downloaded: (tracker.num_downloaded >= 0) ? tracker.num_downloaded : "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]",