From 8172e3ff429503fc9d5e4755e9bcd2e501eff99a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Till=20Kru=CC=88ss?= Date: Sun, 8 Nov 2026 14:12:47 -0700 Subject: [PATCH] Keep library toolbar buttons together on folded iPhone Duo On the folded Duo, iOS moves plain toolbar items into the side rail but keeps items that host their own view in a bar at the top. Since #831 the filter hosts its own icon to keep the theme-colored badge, while sort was still a Label from #819, so the group split: filter on top, sort in the rail. The instance switcher was hidden when folded because the rail had no room for it. Sort and the iPhone instance switcher now use ToolbarIconLabel, the same hosted image with an invisible title as the filter, so all three sit together on top and only + stays in the rail. The switcher shows on the folded Duo again and always uses the navigation placement, so isFolded and hasVerticalToolbar are no longer needed there. The hosted sort image honors .imageScale(.medium), which the native item ignored, so the modifier is dropped to keep the glyph size unchanged. --- CHANGELOG.md | 3 +++ Ruddarr/Utilities/Environment.swift | 10 ---------- Ruddarr/Views/Movies/MoviesView+Toolbar.swift | 17 +++++------------ Ruddarr/Views/MoviesView.swift | 4 +--- Ruddarr/Views/Series/SeriesView+Toolbar.swift | 17 +++++------------ Ruddarr/Views/SeriesView.swift | 4 +--- Ruddarr/Views/Shared/Toolbar.swift | 13 +++++++++++++ TestFlight/WhatToTest.en-US.txt | 3 +++ 8 files changed, 31 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53c12747..e6053db9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Improved x265, H.266, VC1 and VVC codec replacements - Open the exact movie on Letterboxd instead of a search +### Changed +- Show filter, sort and instance buttons together on folded iPhone Duo + ### Fixed - Fixed a freeze when opening some movies and series on iPhone diff --git a/Ruddarr/Utilities/Environment.swift b/Ruddarr/Utilities/Environment.swift index 72bf7a33..e08c5b75 100644 --- a/Ruddarr/Utilities/Environment.swift +++ b/Ruddarr/Utilities/Environment.swift @@ -14,16 +14,6 @@ extension EnvironmentValues { // swiftlint:disable:next implicit_optional_initialization @Entry var deleteSeries: Binding? = nil - var hasVerticalToolbar: Bool { - #if os(iOS) - if #available(iOS 27.1, *) { - return toolbarVerticalEdge != nil - } - #endif - - return false - } - var isCompactPhone: Bool { deviceType == .phone && horizontalSizeClass != .regular } diff --git a/Ruddarr/Views/Movies/MoviesView+Toolbar.swift b/Ruddarr/Views/Movies/MoviesView+Toolbar.swift index 0beeeb1f..db22fa4b 100644 --- a/Ruddarr/Views/Movies/MoviesView+Toolbar.swift +++ b/Ruddarr/Views/Movies/MoviesView+Toolbar.swift @@ -83,8 +83,7 @@ extension MoviesView { }.pickerStyle(.inline) } } label: { - Label("Sort By", systemImage: "arrow.up.arrow.down") - .imageScale(.medium) + ToolbarIconLabel(title: Text("Sort By"), systemImage: "arrow.up.arrow.down") } } @@ -121,15 +120,9 @@ extension MoviesView { var toolbarInstancePicker: some ToolbarContent { @Bindable var settings = settings - #if os(iOS) - let placement: ToolbarItemPlacement = hasVerticalToolbar ? .bottomBar : .navigation - #else - let placement: ToolbarItemPlacement = .navigation - #endif + ToolbarSpacer(.fixed, placement: .navigation) - ToolbarSpacer(.fixed, placement: placement) - - ToolbarItem(placement: placement) { + ToolbarItem(placement: .navigation) { Menu { Picker(selection: $settings.radarrInstanceId, label: Text("Instances")) { ForEach(settings.radarrInstances) { instance in @@ -138,8 +131,8 @@ extension MoviesView { } .pickerStyle(.inline) } label: { - Label( - settings.radarrInstance?.label ?? String(localized: "Instance"), + ToolbarIconLabel( + title: Text(settings.radarrInstance?.label ?? String(localized: "Instance")), systemImage: "internaldrive" ) } diff --git a/Ruddarr/Views/MoviesView.swift b/Ruddarr/Views/MoviesView.swift index c3208885..7ddbeeab 100644 --- a/Ruddarr/Views/MoviesView.swift +++ b/Ruddarr/Views/MoviesView.swift @@ -16,8 +16,6 @@ struct MoviesView: View { @Environment(RadarrInstance.self) var instance @Environment(\.deviceType) var deviceType - @Environment(\.hasVerticalToolbar) var hasVerticalToolbar - @Environment(\.isFolded) private var isFolded @State private var scrollView: ScrollViewProxy? @@ -88,7 +86,7 @@ struct MoviesView: View { toolbarSearchButton if settings.radarrInstances.count > 1 { - if deviceType == .phone && !isFolded { toolbarInstancePicker } + if deviceType == .phone { toolbarInstancePicker } if deviceType == .pad { bottomBarInstancePicker } } } diff --git a/Ruddarr/Views/Series/SeriesView+Toolbar.swift b/Ruddarr/Views/Series/SeriesView+Toolbar.swift index 83e0a0d9..77cee50d 100644 --- a/Ruddarr/Views/Series/SeriesView+Toolbar.swift +++ b/Ruddarr/Views/Series/SeriesView+Toolbar.swift @@ -83,8 +83,7 @@ extension SeriesView { }.pickerStyle(.inline) } } label: { - Label("Sort By", systemImage: "arrow.up.arrow.down") - .imageScale(.medium) + ToolbarIconLabel(title: Text("Sort By"), systemImage: "arrow.up.arrow.down") } } @@ -121,15 +120,9 @@ extension SeriesView { var toolbarInstancePicker: some ToolbarContent { @Bindable var settings = settings - #if os(iOS) - let placement: ToolbarItemPlacement = hasVerticalToolbar ? .bottomBar : .navigation - #else - let placement: ToolbarItemPlacement = .navigation - #endif + ToolbarSpacer(.fixed, placement: .navigation) - ToolbarSpacer(.fixed, placement: placement) - - ToolbarItem(placement: placement) { + ToolbarItem(placement: .navigation) { Menu { Picker(selection: $settings.sonarrInstanceId, label: Text("Instances")) { ForEach(settings.sonarrInstances) { instance in @@ -138,8 +131,8 @@ extension SeriesView { } .pickerStyle(.inline) } label: { - Label( - settings.sonarrInstance?.label ?? String(localized: "Instance"), + ToolbarIconLabel( + title: Text(settings.sonarrInstance?.label ?? String(localized: "Instance")), systemImage: "internaldrive" ) } diff --git a/Ruddarr/Views/SeriesView.swift b/Ruddarr/Views/SeriesView.swift index 537c0e1e..05c0525e 100644 --- a/Ruddarr/Views/SeriesView.swift +++ b/Ruddarr/Views/SeriesView.swift @@ -17,8 +17,6 @@ struct SeriesView: View { @Environment(SonarrInstance.self) var instance @Environment(\.deviceType) var deviceType - @Environment(\.hasVerticalToolbar) var hasVerticalToolbar - @Environment(\.isFolded) private var isFolded @State private var scrollView: ScrollViewProxy? @@ -91,7 +89,7 @@ struct SeriesView: View { toolbarSearchButton if settings.sonarrInstances.count > 1 { - if deviceType == .phone && !isFolded { toolbarInstancePicker } + if deviceType == .phone { toolbarInstancePicker } if deviceType == .pad { bottomBarInstancePicker } } } diff --git a/Ruddarr/Views/Shared/Toolbar.swift b/Ruddarr/Views/Shared/Toolbar.swift index dd3c85d8..d17495ee 100644 --- a/Ruddarr/Views/Shared/Toolbar.swift +++ b/Ruddarr/Views/Shared/Toolbar.swift @@ -79,6 +79,19 @@ struct ToolbarFilterLabel: View { } } +struct ToolbarIconLabel: View { + var title: Text + var systemImage: String + + var body: some View { + Image(systemName: systemImage) + .background { + title.opacity(0) + } + .accessibilityLabel(title) + } +} + struct MonitorBookmark: View { var monitored: Bool var loading: Bool = false diff --git a/TestFlight/WhatToTest.en-US.txt b/TestFlight/WhatToTest.en-US.txt index 662c96af..c4c39606 100644 --- a/TestFlight/WhatToTest.en-US.txt +++ b/TestFlight/WhatToTest.en-US.txt @@ -6,5 +6,8 @@ Added - Improved x265, H.266, VC1 and VVC codec replacements - Open the exact movie on Letterboxd instead of a search +Changed +- Show filter, sort and instance buttons together on folded iPhone Duo + Fixed - Fixed a freeze when opening some movies and series on iPhone