Skip to content

Please add dark mode - #10

Open
LiranYzhak wants to merge 187 commits into
zebraxxl:masterfrom
xombiemp:master
Open

LiranYzhak wants to merge 187 commits into
zebraxxl:masterfrom
xombiemp:master

Conversation

@LiranYzhak

Copy link
Copy Markdown

please add option to change white background to black background and white fonts

The word-break directive makes a long string break to wrap even in a
non-breakable place in order to stay with in the width of it's parent
element.  This makes it so that there is never any horizontal scrolling
required because the torrent names etc. just wrap to the next line.
Adds the required elements to make a web app on iOS devices.
This makes the navigation tabs stationary like the other nav bar. This
way you don't have to scroll all the way to the top or bottom to change
tabs, they are in a fixed position.
Added Global speed indicators.
Added speed indicators on the torrent list.
Added torrent size on the torrent list progress bar.
Added Size property on the torrent details.
Update Boostrap to v2.3.2
If there is a long label name that goes off the screen, it will be
truncated with ellipsis added.
Remove unneeded css.
Turns out these were needed.
Displays the torrent size on the progress bar even when the parent div
is too small (low progress percentage).  It use to only show up when
the percentage got high enough.
This adds all the filter options that the desktop interface has,
including Active, Inactive and Error.  All the statuses have been
combined into a dropdown.

This also adds trackers filter.  It will produce the same list in a
dropdown that the trackerslabel plugin makes, but that plugin is not
required for this to work.
Account for multiple trackers per torrent and add all of them as filter
classes.
Delete some unneeded  code.
…thDataDefault set to true in init.js and webui.confirm_when_deleting set to false in the gui settings.
Fixed various bugs.
xombiemp and others added 30 commits July 13, 2026 19:46
The label was rendered inside the bar element, so on a partially
complete torrent it spilled onto the light track (white on light,
unreadable) and clipped at the container edge. It is now its own layer
sized to the bar: centered in the filled part, clamped so it never
clips when the bar is narrower than the text, with a stronger dark halo
and medium font weight.
Buttons, progress bars, links, tab highlights, toolbar icons,
selections and the expanded accordion tint follow a --mobile-accent CSS
variable, which init.js points at the configured Bootstrap color
('primary' by default). Also completes the plugin.sort value list in
the options comment.
Uses the same green-to-red RGBackground gradient as the desktop status
bar meter, and raises the desktop's disk-full alert (free space below
the plugin's configured notifySpaceLimit) when the settings page is
opened.
Filter rows get icons: the status options mirror the desktop state
panel's iconography, and custom labels and trackers load the same
images the desktop panels show from the tracklabels plugin.

Selections are now multi-select like the desktop panels: tapping
options toggles them, choices within a category are ORed and categories
ANDed, and the All rows clear their category. The toolbar filter text
truncates with an ellipsis so the icons stay on one line and the
count/size stays visible.
The geoip plugin is no longer disabled on mobile; its getpeers hook
annotates peers with a country code (cached lookups via its own
endpoint), and the peers table gets a first column with the same flag
images and translated country name plus city as the desktop column.
The column hides itself when geoip is unavailable.
Drops the desktop's 1 KiB/s threshold for the Active/Inactive state:
a started torrent with any upload or download rate is active. Slow
seeds no longer disappear from the Active filter.
README documents the ruTorrent 4.3+ requirement, the five newer plugin
integrations (datadir, diskspace, check_port, geoip, tracklabels) and
the corrected option count; the repo sort default matches the
documented 'name'.

The settings page gets an accent color dropdown that restyles the UI
on the fly, with color swatches in the option list and the select text
tinted to the active accent. It isn't persisted, so a reload reverts
to the configured plugin.accentColor.
While visible, the files tab refreshes each file's done size and
percentage when the torrent's downloaded counter changes, and the
trackers tab refreshes seeds, peers, scrape counts and announce times
every cycle. Both update values in place, so expanded rows, open
priority selects and the open accordion panel are not disturbed.
Drop the standalone repo's install instructions, empty .gitignore and
GPL-3 LICENSE copy (the core's LICENSE.md covers bundled plugins); keep
fonts/bootstrap-icons-LICENSE, since the MIT notice must travel with the
font files. Point the issue link at the upstream tracker.
The plugin talks to rTorrent only through the core's request layer
(theWebUI.request*), which works over httprpc or a direct XML-RPC
mount; since v4.0 the core normalizes responses identically for both
(js/rtorrent.js *ParseXML/*Response). Only httprpc is regularly
tested, so keep it as the recommendation.
The ratio and throttle plugins stay enabled on mobile and install
their own rTorrentStub methods, so the copied stubs only overrode
them: setratio with a byte-identical duplicate, setthrottle with the
old client-side d.stop/d.set_throttle_name/d.start implementation the
throttle plugin has since replaced with a server-side one. Removing
them (and the now-unused plugin.getRatioData) lets mobile track the
host plugins' behavior automatically.
Rename pt to pt-br and add pt-pt, bn, ko and no (English strings for
now, like most of the other files) so plugin.loadLang() finds a file
for every language the core offers instead of falling back through a
404. Strip the trailing whitespace from the lang file headers, make
the mobile global alias explicit (window.mobile) and bump plugin.info
for the Bootstrap 5 rework.
…ic hooks

- Keep any plugin the server marks un-shutdownable enabled instead of
  hardcoding backend names, so pluggable RPC backends survive takeover
- Stub theWebUI.loadRSS/addRSSItems so the rss plugin's polling loop
  stops refreshing the discarded desktop category panel
- Shut down the trafic plugin's Flot plot to unbind its window-resize
  handler, which throws once the desktop layout is gone
An audit of all bundled plugins for the same failure class found more
leftovers that disable() doesn't undo:

- cpuload creates its Flot plot and window-resize handler from an
  unguarded retry loop, throwing "Invalid dimensions for plot" after
  the desktop layout is gone (the likely source of the reported error;
  the trafic graph can't exist while disabled since onLangLoaded is
  skipped), and re-fetches the CPU load on every list poll
- diskspace keeps its self-rescheduling free-space poll running,
  duplicating the mobile UI's own diskspace request
- rss's config wrap starts getrsssettings plus two perpetual timers
- history's config wrap spins a 1s wait loop that never terminates
  while disabled; _task's fires a pointless tasklist request
- trafic keeps polling getratios every updateInterval minutes

Entry points reachable via theWebUI.config wraps are stubbed in
disableOthers (before config runs); the cpuload/diskspace status-bar
widgets are dismantled after the takeover, once the removed desktop
stylesheets keep their retry loops from re-creating anything.
… testing-round fixes

Navigation (per review): every back/cancel/OK control used
history.go(-1), which walks the browser's global history and can land
outside the app or full-page-reload a stale URL. Controls now call the
app's own navigation: a goBack() that knows each page's parent, and a
navbar home button (house icon, replacing the back arrow) that always
returns to the torrent list. Hardware/browser back still works through
the existing hashchange listener. All bare buttons got type="button".

Behavior fixes found while testing the round:
- Restore the list scroll position after the hash update (assigning an
  empty fragment scrolls to top), and reset it when the sort or filter
  actually changes, since the old position is meaningless then
- Make the filter page transactional: taps still apply live, OK commits,
  and leaving any other way rolls the changes back; show the matched
  count / total size on the filter page itself
- Neutralize sticky :hover on touch devices, which left tapped buttons
  looking permanently pressed (Bootstrap's outline-button hover is a
  filled state)
- Return to the list after a successful torrent add (errors keep the
  form for correction)
- Scope toast dismiss timers to their own element - a previous toast's
  timers could hide the current one early - and position toasts below
  the top edge so iOS doesn't extend their color into the status bar
- Route noty() notifications into mobile toasts, and toast deleted
  torrents (detected from the list diff; the desktop gets this from the
  history plugin, which is disabled on mobile)
- Truncate file percentages like the desktop does (theConverter.round
  floors) instead of rounding
- Shrink the filter tab's tap target to its content, so taps on the
  empty tab-bar space no longer open the filter page
- Show the full content path (base_path) as Save As on the General tab,
  like the desktop details; the move form still prefills the directory
- Live-refresh the settings page speed-limit selects when the limits
  change elsewhere (e.g. from the desktop UI)
- Treat OK without changes on the save-path page as cancel; the datadir
  worker stops and closes the torrent even when there is nothing to move
After a successful add, the list scrolls to the new torrent's row once
it appears (magnet and URL adds can take a few polls to materialize;
the intent expires after 30s) and fades an accent-colored highlight on
it. Detection rides the existing per-cycle row diff, picking the
topmost added row in display order when several arrive at once, and is
skipped when the user has navigated away or the active filter hides
the row. The highlight is an inset box-shadow on the cell: it renders
above the table striping, and row-level classes are reset by every
row update.
A search icon right of the sort icon toggles a search bar fixed below
the tab bar; typing filters the list live with the same semantics as
the desktop quick search (case-insensitive substring on the name, * as
a wildcard, 220ms debounce; see TextSearch in js/panel.js). The search
narrows whatever the status/label/tracker filters matched, so the
filter chip and the filter page totals reflect it, and the chip shows
the active term in quotes. Closing the bar (its X button or the search
icon) clears the search so the list can't stay invisibly narrowed.

iOS details: the bar is tucked 1px under the measured tab-bar height
so fractional heights can't leave a see-through gap, and the keyboard
is dismissed when a scroll gesture starts, since position:fixed
elements drift off-screen while it's open (touchmove, not scroll:
Safari's scroll-into-view on focus would close it as it opens).
The markup was fetched without a cache-buster, so after an update the
browser could keep serving a stale cached mobile.html while the new
init.js loads through the plugin loader's ?v= token - new code running
against old markup with missing element ids. Use the core's
cacheBust() for the fetch, so the markup stays cached between releases
and refreshes together with the code on a version bump.
- Fix the empty torrent list on the direct XML-RPC mount (reported on
  the bundling PR): the tracker fetch sent ?action=getalltrackers with
  no hashes. httprpc treats that as "all torrents", but the direct
  mount's stub builds one t.multicall per given hash and silently
  sends nothing for an empty list - its callback never fires, and the
  list render lives in that callback. Name every hash explicitly, like
  the desktop's getAllTrackers, and short-circuit the zero-torrent
  case (the render also removes deleted torrents' rows, so it must
  still run)
- Insert torrents that appear between full renders (e.g. added from
  another session) at their sorted position instead of appending them
  to the end of the list
- Toast torrents added from elsewhere (another session, rss,
  automation), like the deletion toasts; a local add keeps its upload
  receipt and scroll-to-torrent instead. Skip the first render cycle,
  when every torrent counts as new
- Dismiss the on-screen keyboard on scroll for all text fields, not
  just the quick search
- Commit a new-label edit only via its check button or the return key;
  tapping or scrolling away now cancels instead of saving
plugin.request drops timeouts and errors by design (the next poll
retries), and an exception thrown in a response handler died invisibly
inside the ajax machinery. Each of the recent blank-torrent-list bugs
was hidden by exactly this silence. Log all three cases to the console
with the request that owned them - diagnostic breadcrumbs only, no
user-facing noise.
Per review: the list fetch bypassed plugin.request (so a throwing
processTorrents stayed invisible there), and the addTorrents hook
isn't a request at all. Route the fetch through plugin.request and
give the hook its own try/catch, so every path into processTorrents
leaves a named console breadcrumb instead of a silent blank list.
plugin.theme picks the color scheme, with a live try-before-you-buy
selector on the settings page like the accent one; 'system' tracks the
device's preference live. Everything themes off Bootstrap's
data-bs-theme, with the hardcoded light colors in mobile.css moved to
the corresponding CSS variables.

The near-black accent would vanish on the dark theme's near-black
background, so there it resolves to its counterpart, near-white
(it's relabeled "Contrast" to match), with the progress-bar stripes,
progress labels and selected-filter text flipping dark to stay
legible on the near-white fills. Progress labels also gain a bolder
weight across all themes.
Naming every hash regressed large lists on transports that carry the
query string in the request line: at ~950 torrents the URL outgrows
nginx's default buffers and is 414-rejected before PHP could collapse
it (stock httprpc was unaffected — its stub override collapses >50
hashes to the hashless form and POSTs a body either way).

The PHP transports all treat a hashless getalltrackers as "all
torrents", which is exactly what this fetch wants, so send that form.
Enumerate the hashes only when a probe shows the active transport is
the base XML-RPC stub — the one case that silently drops the hashless
form, and the bug the enumeration was added for. There the hashes
travel as POSTed XML with the stub's existing fragmentation, so no
list size can overflow anything.
processTorrents() read the desktop categoryList "plabel" panel
unconditionally to build the label filter list. That access threw a
TypeError in two real situations, aborting the function before any row
was rendered and leaving the torrent list blank (the error was swallowed
by the update request's empty error handler):

  - the panel is not always populated when the mobile view first paints;
  - the "no label" bucket ("-_-_-nlb-_-_-") only exists when at least one
    torrent is unlabelled, so it is missing when every torrent has a
    label -- a common configuration.

Guard both reads: fall back to a zero "no label" count and skip the
label loop when the panel is absent. When the panel is present the
behaviour is unchanged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants