From 1d1dac877eab67e8ebb579925fa5880d8ce4b109 Mon Sep 17 00:00:00 2001 From: austin-smith Date: Sun, 8 Mar 2026 18:49:37 -0700 Subject: [PATCH] align menu bar ratio behavior and layout --- AGENTS.md | 6 ++ BitDream/Views/Shared/ContentView.swift | 58 +++++++++++++------ .../MenuBar/MenuBarTorrentSelectors.swift | 15 ++--- .../MenuBar/macOSMenuBarTorrentWidget.swift | 13 ++++- 4 files changed, 63 insertions(+), 29 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 56b054e..54731a9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -82,6 +82,12 @@ From repo root (`/Users/austinsmith/Developer/Repos/BitDream`), run macOS tests test ``` +Testing guidance: + +- Add tests when they protect meaningful user-visible behavior, cross-file integration, bug regressions, or non-trivial logic that is easy to break. +- Do not add dedicated tests for every small helper extraction, straightforward computed property, or internal refactor unless the change introduces real behavioral risk. +- Prefer a small number of high-signal tests over many narrow tests that only restate the implementation. + ## Linting From repo root (`/Users/austinsmith/Developer/Repos/BitDream`), run: diff --git a/BitDream/Views/Shared/ContentView.swift b/BitDream/Views/Shared/ContentView.swift index f02f2d9..6d40ecb 100644 --- a/BitDream/Views/Shared/ContentView.swift +++ b/BitDream/Views/Shared/ContentView.swift @@ -143,6 +143,40 @@ func ensureStartupConnectionBehaviorApplied(store: TransmissionStore, modelConte // MARK: - Shared Views +struct RatioSummarySnapshot: Equatable { + let uploaded: Int64 + let downloaded: Int64 + + var ratio: Double { + downloaded > 0 ? Double(uploaded) / Double(downloaded) : 0 + } +} + +@MainActor +func makeRatioSummarySnapshot(store: TransmissionStore, displayMode: RatioDisplayMode) -> RatioSummarySnapshot { + switch displayMode { + case .cumulative: + if let stats = store.sessionStats?.cumulativeStats { + return RatioSummarySnapshot( + uploaded: stats.uploadedBytes, + downloaded: stats.downloadedBytes + ) + } + case .current: + if let stats = store.sessionStats?.currentStats { + return RatioSummarySnapshot( + uploaded: stats.uploadedBytes, + downloaded: stats.downloadedBytes + ) + } + } + + return RatioSummarySnapshot( + uploaded: store.torrents.reduce(0) { $0 + $1.uploadedEver }, + downloaded: store.torrents.reduce(0) { $0 + $1.downloadedEver } + ) +} + // Stats header view used on both platforms struct StatsHeaderView: View { @ObservedObject var store: TransmissionStore @@ -154,32 +188,18 @@ struct StatsHeaderView: View { RatioDisplayMode(rawValue: ratioDisplayModeRaw) ?? AppDefaults.ratioDisplayMode } - private var overallTotals: (uploaded: Int64, downloaded: Int64) { - switch ratioDisplayMode { - case .cumulative: - if let stats = store.sessionStats?.cumulativeStats { - return (uploaded: stats.uploadedBytes, downloaded: stats.downloadedBytes) - } - case .current: - if let stats = store.sessionStats?.currentStats { - return (uploaded: stats.uploadedBytes, downloaded: stats.downloadedBytes) - } - } - let fallbackDownloaded = store.torrents.reduce(0) { $0 + $1.downloadedEver } - let fallbackUploaded = store.torrents.reduce(0) { $0 + $1.uploadedEver } - return (uploaded: fallbackUploaded, downloaded: fallbackDownloaded) + private var ratioSummary: RatioSummarySnapshot { + makeRatioSummarySnapshot(store: store, displayMode: ratioDisplayMode) } private var overallRatio: Double { - let totals = overallTotals - return totals.downloaded > 0 ? Double(totals.uploaded) / Double(totals.downloaded) : 0.0 + ratioSummary.ratio } private var ratioTooltip: String { - let totals = overallTotals let mode = ratioDisplayMode == .cumulative ? "Total Ratio" : "Session Ratio" - let uploaded = formatByteCount(totals.uploaded) - let downloaded = formatByteCount(totals.downloaded) + let uploaded = formatByteCount(ratioSummary.uploaded) + let downloaded = formatByteCount(ratioSummary.downloaded) return "\(mode)\n----------\nUploaded: \(uploaded)\nDownloaded: \(downloaded)" } diff --git a/BitDream/Views/macOS/MenuBar/MenuBarTorrentSelectors.swift b/BitDream/Views/macOS/MenuBar/MenuBarTorrentSelectors.swift index ec509a4..f5a8992 100644 --- a/BitDream/Views/macOS/MenuBar/MenuBarTorrentSelectors.swift +++ b/BitDream/Views/macOS/MenuBar/MenuBarTorrentSelectors.swift @@ -26,23 +26,24 @@ func menuBarActiveTorrents(from store: TransmissionStore, sortMode: MenuBarSortM @MainActor func menuBarSummary(from store: TransmissionStore) -> MenuBarTorrentSummary { - menuBarSummary(from: store, activeTorrents: menuBarActiveTorrents(from: store, sortMode: .activity)) + menuBarSummary( + from: store, + activeTorrents: menuBarActiveTorrents(from: store, sortMode: .activity), + ratioDisplayMode: AppDefaults.ratioDisplayMode + ) } @MainActor -func menuBarSummary(from store: TransmissionStore, activeTorrents: [Torrent]) -> MenuBarTorrentSummary { +func menuBarSummary(from store: TransmissionStore, activeTorrents: [Torrent], ratioDisplayMode: RatioDisplayMode) -> MenuBarTorrentSummary { let stats = store.sessionStats - - let uploaded = stats?.currentStats?.uploadedBytes ?? 0 - let downloaded = stats?.currentStats?.downloadedBytes ?? 0 - let ratio = downloaded > 0 ? Double(uploaded) / Double(downloaded) : 0 + let ratioSummary = makeRatioSummarySnapshot(store: store, displayMode: ratioDisplayMode) return MenuBarTorrentSummary( serverName: store.host?.name ?? "No Server", activeCount: activeTorrents.count, downloadSpeed: stats?.downloadSpeed ?? 0, uploadSpeed: stats?.uploadSpeed ?? 0, - ratio: ratio + ratio: ratioSummary.ratio ) } diff --git a/BitDream/Views/macOS/MenuBar/macOSMenuBarTorrentWidget.swift b/BitDream/Views/macOS/MenuBar/macOSMenuBarTorrentWidget.swift index 6108947..5be592c 100644 --- a/BitDream/Views/macOS/MenuBar/macOSMenuBarTorrentWidget.swift +++ b/BitDream/Views/macOS/MenuBar/macOSMenuBarTorrentWidget.swift @@ -5,6 +5,7 @@ struct macOSMenuBarTorrentWidget: View { @EnvironmentObject private var store: TransmissionStore @State private var torrentRowsHeight: CGFloat = 0 @AppStorage(UserDefaultsKeys.menuBarSortMode) private var menuBarSortModeRaw: String = AppDefaults.menuBarSortMode.rawValue + @AppStorage(UserDefaultsKeys.ratioDisplayMode) private var ratioDisplayModeRaw: String = AppDefaults.ratioDisplayMode.rawValue let onOpenMainWindow: () -> Void private let panelWidth: CGFloat = 380 @@ -21,12 +22,16 @@ struct macOSMenuBarTorrentWidget: View { MenuBarSortMode(rawValue: menuBarSortModeRaw) ?? AppDefaults.menuBarSortMode } + private var ratioDisplayMode: RatioDisplayMode { + RatioDisplayMode(rawValue: ratioDisplayModeRaw) ?? AppDefaults.ratioDisplayMode + } + private var activeTorrents: [Torrent] { menuBarActiveTorrents(from: store, sortMode: menuBarSortMode) } private var summary: MenuBarTorrentSummary { - menuBarSummary(from: store, activeTorrents: activeTorrents) + menuBarSummary(from: store, activeTorrents: activeTorrents, ratioDisplayMode: ratioDisplayMode) } private var isConnected: Bool { @@ -96,10 +101,12 @@ struct macOSMenuBarTorrentWidget: View { } HStack(spacing: 8) { - SpeedChip(speed: summary.downloadSpeed, direction: .download, style: .chip, size: .compact) - SpeedChip(speed: summary.uploadSpeed, direction: .upload, style: .chip, size: .compact) RatioChip(ratio: summary.ratio, size: .compact) Spacer(minLength: 0) + HStack(spacing: 8) { + SpeedChip(speed: summary.downloadSpeed, direction: .download, style: .chip, size: .compact) + SpeedChip(speed: summary.uploadSpeed, direction: .upload, style: .chip, size: .compact) + } } } }