Repository navigation
v3.8.47: qui proxy fix, plugin-link add fix, recent searches, plugin pinning, theme presets - #288
Merged
Merged
Conversation
- A qui proxy URL pasted into the plain Host field could never connect: the Port was appended after the key (/proxy/<key>:<port>/...), so qui logged "Invalid client API key". The add/edit forms now detect a qui URL in Host and switch to qui Proxy mode with the URL moved over. - The Full Diagnostic refused to run in qui Proxy mode, demanding the hidden username/password. It now skips that check, and explains a 403 in qui mode as qBittorrent rejecting qui's own session. - Add a real-HTTP regression suite (real axios against a qui-shaped server); the existing qui tests mock axios and never saw the request URL. - Changelog: v3.8.47.
Closes #283
Some search plugins (e.g. LimeTorrents) return an HTML description page as a result's link and can only turn it into a torrent through their own download_torrent(). The Search + button opens the add dialog with that URL pre-filled, and both dialogs (and cart checkout) only ever called torrents/add with it, so qBittorrent downloaded the page, failed to parse it, and still answered 200: the app said "added" and nothing appeared. Hand such URLs to their plugin: - torrents/add gains a `downloader` option (WebAPI >= 2.13.1), which routes the URL through the plugin while keeping every other add option. - On 5.0-5.1 fall back to search/downloadTorrent (default options only, with an info toast saying so); qBittorrent 4.x has no equivalent and is unchanged. - Search passes the plugin to both dialogs as a `sourcePlugin` route param, applied only while the submitted URL is still exactly the pre-filled one. - Cart items carry their `downloader`, checkout splits batches by it. - Instant add prefers torrents/add + downloader (tags applied by the add). - getResultDownloader() is the single rule for "does this result need its plugin", shared with the duplicate-grouping hash resolver. Closes #284
Closes #286
Replace the star button and picker with a tap on each plugin chip's own icon: tapping it pins (star) or unpins the plugin, and pinned plugins sort to the front. The rest of the chip still selects the plugin. After pinning, the row scrolls back to the start so the chip is visible where it landed. FilterChip gains an optional onIconPress (a separate tap target for the icon, plus a VoiceOver custom action since the chip is one element). Refs #283
Unpinned plugin chips now show an outline star (tap to pin) and pinned ones a filled star (tap to unpin), instead of the puzzle icon. Refs #283
The "Search torrent indexers…" placeholder ran past the right edge of the search field (iOS clips a placeholder without an ellipsis), and the Russian and Polish versions were longer still. Use a shorter string in every locale; es/zh/fr/de were still English and are translated now.
The clock button only appeared after a search had been saved, so on a fresh install the feature was invisible. Show it whenever history is on (and the field is empty); with nothing saved yet, the dropdown explains how searches get saved. Refs #282
Ionicons' pin is a map-style needle that didn't read as "pin this". Use MaterialCommunityIcons' thumbtack (outline to pin, filled when pinned) for the row toggle and the pinned row's leading icon. Refs #282
- Preferences: add storageService.updatePreferences, which queues writes
and re-reads inside the queue. Recent searches and plugin pins use it,
so overlapping saves no longer drop each other's keys.
- Recent searches: record only on submit and when picking an entry. The
filter is live, so recording on blur saved half-typed fragments.
- Plugin pins: toggle from a ref so quick back-to-back taps don't lose a pin.
- 5.0-5.1 cart checkout: plugin-resolved items now get their indexer tag
via the same best-effort poll instant add uses (moved to
services/search-tracker-topup.ts as tagNewlyDownloadedTorrent).
- A path typed into the Host field now goes after the port in the API
client and the debug panel ("host/qbit" + 8443 -> host:8443/qbit), and
Origin no longer includes that path.
- Recent-search pin icon: back to Ionicons (tilted pin) instead of pulling
in the MaterialCommunityIcons font for two glyphs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Everything in the v3.8.47 milestone: two bug fixes, three features, and one more bug fix, in 10 commits (one per issue, plus follow-ups). 49 files, +4683 / −417. Every new preference is additive and optional, no stored key is renamed, and every new string is translated in all 7 locales.
c908dfea688c77ffd57313692d73c67505e5964622b484ecaab375eecccd8b3fe21065package-lock.jsontransitive refresh, kept in its own commitWhat changed, per issue
#278 qui Proxy
The qui Proxy mode itself worked (verified over real HTTP against a server that routes and checks keys the way qui does). The reports came from two other problems:
/proxy/<key>:<port>/api/v2/…. qui logs "Invalid client API key" and the app shows an auth failure. The add/edit forms now detect a qui URL in Host (detectQuiProxyUrlInHost, only when the key is 32+ hex characters, so a real qBittorrent at/proxy/<name>is untouched), switch to qui Proxy mode and move the URL over, with a toast.tests/services/qui-proxy-e2e.test.tsuses real axios against a local qui-shaped server (the existing qui tests mock axios and never saw the request URL).#275 Spinner overlapping the search box
RefreshControlwas bound toisLoading, so iOS showed its spinner on every background load, drawn under the absolute-overlay header. It now follows a localisPullRefreshingand usesprogressViewOffset={selectMode ? 0 : headerHeight}. The small spinner inside the search field stays as the background-load indicator.#282 Recent searches
SearchHistoryDropdown) of recent and pinned searches: tap to reuse, pin, remove, or "Clear recent" (keeps pinned). It is mutually exclusive with the sort menu.utils/search-history.ts(31 tests) plus a component test.#283 Plugin pinning
searchPinnedPluginspref (plugin ids); pins for uninstalled plugins are ignored and pruned.FilterChipgained an optionalonIconPress(separate tap target plus a VoiceOver custom action, since the chip is a single accessibility element). Nothing else uses it yet.#284 Search results that "add" but never appear
Plugins like LimeTorrents return an
.htmldescription page as the result link and can only turn it into a torrent in their owndownload_torrent(). Since #217 the+opens the add dialog, which sent that page URL to a plaintorrents/add. qBittorrent downloads the HTML, fails to parse it and still returns 200, so the app said "added" and nothing showed up.torrents/addwithdownloader=<plugin>(all dialog options still apply).search/downloadTorrent(default add options only; an info toast says dialog options don't apply).apikey=link). The old whole-screen "all results share one site" heuristic misfires for a single-plugin search, so it is no longer used for this decision.utils/search-download.ts, withdownloadersupport intorrentsApi.addTorrent.engineNameis the plugin id (searchResult.engineName = plugin->namein qBittorrent's source).#286 Theme presets: existing users are not affected
Default, OLED, Nord, Dracula, Solarized, High Contrast, qBittorrent Classic, each with light and dark variants, in a horizontally scrolling Presets row at the top of Settings → Theme.
ThemeContext.tsxhas no diff, so the default palettes and merge logic are untouched. Nothing runs at launch, and there is no migration or auto-apply. Existing custom colors are classifiedcustomand are only replaced after a confirm dialog. Selection is derived by comparing stored colors with the preset, never from the saved id alone. Applying a preset is one read-modify-write of both modes. "Default" clears both modes and the preset id.ColorThemegained optional preset-onlyprimaryOpacandonAccentso a preset's accent doesn't leave default-blue highlights behind (not editable rows).themePresetId; never rename one.Search tab placeholder
"Search torrent indexers…" ran off the field and iOS clips a placeholder with no ellipsis; Russian and Polish were longer still. Shortened in every locale (e.g. "Search indexers…"). Spanish, Chinese, French and German had been left in English and are now translated.
Compatibility and risk
searchPinnedPlugins,torrentSearchHistory,torrentSearchPinned,torrentSearchHistoryLimit,themePresetId.package.jsonis bumped to 3.8.47 with"easBuild": true, so merging this tomainbuilds and submits to the App Store (see docs/RELEASING.md).Test plan
Automated (all passing locally and in CI, 4/4 checks):
npx tsc --noEmit: exit 0npm test: 100 suites, 1856 tests (new: qui real-HTTP suite, search-history, search-plugins, search-download, search-cart, theme presets and safety/contrast, FilterChip icon button, ThemeContext/theme screen, SearchHistoryDropdown)npm run lint: 0 errors (38 warnings, the existing baseline) ·npm run format: no changesOn a device (not yet done):
+→ Add; the torrent appears in the list. Cart checkout and a magnet result also still work.Five fake search plugins (Alpha/Bravo/Charlie/Zulu/HTML Dummy) were used to test pinning and #284. They are not part of this PR.
Not included
expo-updatesand the Jest tooling and aren't imported by or shipped in the app. Left open; Dependabot will open PRs when fixes ship.Closes #275
Closes #278
Closes #282
Closes #283
Closes #284
Closes #286
🤖 Generated with Claude Code