From c0184712a923cc6b8fe3c090e42a9e713aad4867 Mon Sep 17 00:00:00 2001 From: Arkadiusz Fal Date: Fri, 17 Apr 2026 21:22:25 +0200 Subject: [PATCH] Add Continue Watching toggle to sidebar settings Exposes ContinueWatchingView as an opt-in main sidebar item, hidden by default. --- Yattee/Localizable.xcstrings | 11 ++++++ Yattee/Models/Navigation/SidebarItem.swift | 9 +++++ .../Models/Navigation/SidebarMainItem.swift | 13 +++++-- Yattee/Views/Navigation/UnifiedTabView.swift | 35 +++++++++++++++++++ 4 files changed, 65 insertions(+), 3 deletions(-) diff --git a/Yattee/Localizable.xcstrings b/Yattee/Localizable.xcstrings index abe111a9..9f095671 100644 --- a/Yattee/Localizable.xcstrings +++ b/Yattee/Localizable.xcstrings @@ -14311,6 +14311,17 @@ } } }, + "sidebar.mainItem.continueWatching" : { + "comment" : "Sidebar main navigation item for continue watching", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Continue Watching" + } + } + } + }, "sidebar.mainItem.channels" : { "comment" : "Sidebar main navigation item for channels", "localizations" : { diff --git a/Yattee/Models/Navigation/SidebarItem.swift b/Yattee/Models/Navigation/SidebarItem.swift index 3ebd9764..fe155a6f 100644 --- a/Yattee/Models/Navigation/SidebarItem.swift +++ b/Yattee/Models/Navigation/SidebarItem.swift @@ -37,6 +37,7 @@ enum SidebarItem: Hashable, Identifiable { case subscriptionsFeed case manageChannels case playlistsList + case continueWatching // MARK: - Identifiable @@ -76,6 +77,8 @@ enum SidebarItem: Hashable, Identifiable { return "manage-channels" case .playlistsList: return "playlists-list" + case .continueWatching: + return "continue-watching" } } @@ -117,6 +120,8 @@ enum SidebarItem: Hashable, Identifiable { return String(localized: "sidebar.manageChannels") case .playlistsList: return String(localized: "home.playlists.title") + case .continueWatching: + return String(localized: "home.continueWatching.title") } } @@ -156,6 +161,8 @@ enum SidebarItem: Hashable, Identifiable { return "person.2" case .playlistsList: return "list.bullet.rectangle" + case .continueWatching: + return "play.circle" } } @@ -189,6 +196,8 @@ enum SidebarItem: Hashable, Identifiable { return .manageChannels case .playlistsList: return .playlists + case .continueWatching: + return .continueWatching } } diff --git a/Yattee/Models/Navigation/SidebarMainItem.swift b/Yattee/Models/Navigation/SidebarMainItem.swift index 5784d329..ee6d60a9 100644 --- a/Yattee/Models/Navigation/SidebarMainItem.swift +++ b/Yattee/Models/Navigation/SidebarMainItem.swift @@ -21,12 +21,13 @@ enum SidebarMainItem: String, CaseIterable, Codable, Identifiable, Sendable { case settings case openURL case remoteControl + case continueWatching var id: String { rawValue } /// Default order for sidebar main items. static var defaultOrder: [SidebarMainItem] { - [.search, .home, .subscriptions, .bookmarks, .history, .channels, .playlists, .sources, .openURL, .remoteControl, .downloads, .settings] + [.search, .home, .subscriptions, .bookmarks, .history, .channels, .playlists, .sources, .openURL, .remoteControl, .downloads, .continueWatching, .settings] } /// Default visibility (all visible except subscriptions and channels). @@ -44,7 +45,8 @@ enum SidebarMainItem: String, CaseIterable, Codable, Identifiable, Sendable { .sources: true, .settings: true, .openURL: false, - .remoteControl: true + .remoteControl: true, + .continueWatching: false ] #else [ @@ -59,7 +61,8 @@ enum SidebarMainItem: String, CaseIterable, Codable, Identifiable, Sendable { .sources: true, .settings: true, .openURL: false, - .remoteControl: false + .remoteControl: false, + .continueWatching: false ] #endif } @@ -79,6 +82,7 @@ enum SidebarMainItem: String, CaseIterable, Codable, Identifiable, Sendable { case .settings: "gear" case .openURL: "link" case .remoteControl: "antenna.radiowaves.left.and.right" + case .continueWatching: "play.circle" } } @@ -97,6 +101,7 @@ enum SidebarMainItem: String, CaseIterable, Codable, Identifiable, Sendable { case .settings: String(localized: "sidebar.mainItem.settings") case .openURL: String(localized: "sidebar.mainItem.openURL") case .remoteControl: String(localized: "sidebar.mainItem.remoteControl") + case .continueWatching: String(localized: "sidebar.mainItem.continueWatching") } } @@ -142,6 +147,7 @@ enum SidebarMainItem: String, CaseIterable, Codable, Identifiable, Sendable { case .settings: return TabBarItem.settings.rawValue case .openURL: return "open-url" case .remoteControl: return "remote-control" + case .continueWatching: return "continue-watching" } } @@ -160,6 +166,7 @@ enum SidebarMainItem: String, CaseIterable, Codable, Identifiable, Sendable { case .settings: return .settings case .openURL: return .openURL case .remoteControl: return .remoteControl + case .continueWatching: return .continueWatching } } diff --git a/Yattee/Views/Navigation/UnifiedTabView.swift b/Yattee/Views/Navigation/UnifiedTabView.swift index f4017089..ac0543be 100644 --- a/Yattee/Views/Navigation/UnifiedTabView.swift +++ b/Yattee/Views/Navigation/UnifiedTabView.swift @@ -38,6 +38,7 @@ struct UnifiedTabView: View { @State private var settingsPath = NavigationPath() @State private var openURLPath = NavigationPath() @State private var remoteControlPath = NavigationPath() + @State private var continueWatchingPath = NavigationPath() // Current selection - initial value is a placeholder; actual startup tab is applied in onAppear @State private var selection: SidebarItem = .home @@ -233,6 +234,16 @@ struct UnifiedTabView: View { } label: { Label(SidebarItem.remoteControl.title, systemImage: SidebarItem.remoteControl.systemImage) } + + case .continueWatching: + Tab(value: SidebarItem.continueWatching) { + NavigationStack(path: $continueWatchingPath) { + ContinueWatchingView() + .withNavigationDestinations() + } + } label: { + Label(SidebarItem.continueWatching.title, systemImage: SidebarItem.continueWatching.systemImage) + } } } @@ -356,6 +367,7 @@ struct UnifiedTabView: View { @State private var settingsPath = NavigationPath() @State private var openURLPath = NavigationPath() @State private var remoteControlPath = NavigationPath() + @State private var continueWatchingPath = NavigationPath() // Current selection - initial value is a placeholder; actual startup tab is applied in onAppear @State private var selection: SidebarItem = .home @@ -529,6 +541,16 @@ struct UnifiedTabView: View { } label: { Label(SidebarItem.remoteControl.title, systemImage: SidebarItem.remoteControl.systemImage) } + + case .continueWatching: + Tab(value: SidebarItem.continueWatching) { + NavigationStack(path: $continueWatchingPath) { + ContinueWatchingView() + .withNavigationDestinations() + } + } label: { + Label(SidebarItem.continueWatching.title, systemImage: SidebarItem.continueWatching.systemImage) + } } } @@ -608,6 +630,7 @@ struct UnifiedTabView: View { @State private var settingsPath = NavigationPath() @State private var openURLPath = NavigationPath() @State private var remoteControlPath = NavigationPath() + @State private var continueWatchingPath = NavigationPath() // Current selection - initial value is a placeholder; actual startup tab is applied in onAppear @State private var selection: SidebarItem = .home @@ -811,6 +834,16 @@ struct UnifiedTabView: View { } label: { Label(SidebarItem.remoteControl.title, systemImage: SidebarItem.remoteControl.systemImage) } + + case .continueWatching: + Tab(value: SidebarItem.continueWatching) { + NavigationStack(path: $continueWatchingPath) { + ContinueWatchingView() + .withNavigationDestinations() + } + } label: { + Label(SidebarItem.continueWatching.title, systemImage: SidebarItem.continueWatching.systemImage) + } } } @@ -928,6 +961,8 @@ extension UnifiedTabView { openURLPath.append(destination) case .remoteControl: remoteControlPath.append(destination) + case .continueWatching: + continueWatchingPath.append(destination) } navigationCoordinator?.clearPendingNavigation() }