Add Playlists entry to sidebar main navigation

Adds a toggleable "Playlists" item that opens PlaylistsListView,
mirroring the Channels → ManageChannelsView pattern.
This commit is contained in:
Arkadiusz Fal
2026-04-17 04:12:39 +02:00
parent f8ca23308d
commit a660591e8d
4 changed files with 63 additions and 2 deletions

View File

@@ -14212,6 +14212,17 @@
}
}
},
"sidebar.mainItem.playlists" : {
"comment" : "Sidebar main navigation item for playlists",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Playlists"
}
}
}
},
"sidebar.mainItem.downloads" : {
"comment" : "Sidebar main navigation item for downloads",
"localizations" : {

View File

@@ -36,6 +36,7 @@ enum SidebarItem: Hashable, Identifiable {
case downloads
case subscriptionsFeed
case manageChannels
case playlistsList
// MARK: - Identifiable
@@ -73,6 +74,8 @@ enum SidebarItem: Hashable, Identifiable {
return "subscriptions-feed"
case .manageChannels:
return "manage-channels"
case .playlistsList:
return "playlists-list"
}
}
@@ -112,6 +115,8 @@ enum SidebarItem: Hashable, Identifiable {
return String(localized: "home.subscriptions.title")
case .manageChannels:
return String(localized: "sidebar.manageChannels")
case .playlistsList:
return String(localized: "home.playlists.title")
}
}
@@ -149,6 +154,8 @@ enum SidebarItem: Hashable, Identifiable {
return "play.square.stack.fill"
case .manageChannels:
return "person.2"
case .playlistsList:
return "list.bullet.rectangle"
}
}
@@ -180,6 +187,8 @@ enum SidebarItem: Hashable, Identifiable {
return .subscriptionsFeed
case .manageChannels:
return .manageChannels
case .playlistsList:
return .playlists
}
}

View File

@@ -16,6 +16,7 @@ enum SidebarMainItem: String, CaseIterable, Codable, Identifiable, Sendable {
case history
case downloads
case channels
case playlists
case sources
case settings
case openURL
@@ -25,7 +26,7 @@ enum SidebarMainItem: String, CaseIterable, Codable, Identifiable, Sendable {
/// Default order for sidebar main items.
static var defaultOrder: [SidebarMainItem] {
[.search, .home, .subscriptions, .bookmarks, .history, .channels, .sources, .openURL, .remoteControl, .downloads, .settings]
[.search, .home, .subscriptions, .bookmarks, .history, .channels, .playlists, .sources, .openURL, .remoteControl, .downloads, .settings]
}
/// Default visibility (all visible except subscriptions and channels).
@@ -39,6 +40,7 @@ enum SidebarMainItem: String, CaseIterable, Codable, Identifiable, Sendable {
.history: false,
.downloads: true,
.channels: false,
.playlists: false,
.sources: true,
.settings: true,
.openURL: false,
@@ -53,6 +55,7 @@ enum SidebarMainItem: String, CaseIterable, Codable, Identifiable, Sendable {
.history: false,
.downloads: true,
.channels: false,
.playlists: false,
.sources: true,
.settings: true,
.openURL: false,
@@ -71,6 +74,7 @@ enum SidebarMainItem: String, CaseIterable, Codable, Identifiable, Sendable {
case .history: "clock"
case .downloads: "arrow.down.circle"
case .channels: "person.2"
case .playlists: "list.bullet.rectangle"
case .sources: "server.rack"
case .settings: "gear"
case .openURL: "link"
@@ -88,6 +92,7 @@ enum SidebarMainItem: String, CaseIterable, Codable, Identifiable, Sendable {
case .history: String(localized: "sidebar.mainItem.history")
case .downloads: String(localized: "sidebar.mainItem.downloads")
case .channels: String(localized: "sidebar.mainItem.channels")
case .playlists: String(localized: "sidebar.mainItem.playlists")
case .sources: String(localized: "sidebar.mainItem.sources")
case .settings: String(localized: "sidebar.mainItem.settings")
case .openURL: String(localized: "sidebar.mainItem.openURL")
@@ -132,6 +137,7 @@ enum SidebarMainItem: String, CaseIterable, Codable, Identifiable, Sendable {
case .history: return TabBarItem.history.rawValue
case .downloads: return TabBarItem.downloads.rawValue
case .channels: return TabBarItem.channels.rawValue
case .playlists: return TabBarItem.playlists.rawValue
case .sources: return TabBarItem.sources.rawValue
case .settings: return TabBarItem.settings.rawValue
case .openURL: return "open-url"
@@ -149,6 +155,7 @@ enum SidebarMainItem: String, CaseIterable, Codable, Identifiable, Sendable {
case .history: return .history
case .downloads: return .downloads
case .channels: return .manageChannels
case .playlists: return .playlistsList
case .sources: return .sources
case .settings: return .settings
case .openURL: return .openURL
@@ -162,7 +169,7 @@ enum SidebarMainItem: String, CaseIterable, Codable, Identifiable, Sendable {
case .subscriptions: self = .subscriptions
case .channels: self = .channels
case .bookmarks: self = .bookmarks
case .playlists: return nil // No direct mapping - playlists isn't a SidebarMainItem
case .playlists: self = .playlists
case .history: self = .history
case .downloads: self = .downloads
case .sources: self = .sources

View File

@@ -33,6 +33,7 @@ struct UnifiedTabView: View {
@State private var downloadsPath = NavigationPath()
@State private var subscriptionsFeedPath = NavigationPath()
@State private var manageChannelsPath = NavigationPath()
@State private var playlistsListPath = NavigationPath()
@State private var sourcesPath = NavigationPath()
@State private var settingsPath = NavigationPath()
@State private var openURLPath = NavigationPath()
@@ -182,6 +183,16 @@ struct UnifiedTabView: View {
Label(SidebarItem.manageChannels.title, systemImage: SidebarItem.manageChannels.systemImage)
}
case .playlists:
Tab(value: SidebarItem.playlistsList) {
NavigationStack(path: $playlistsListPath) {
PlaylistsListView()
.withNavigationDestinations()
}
} label: {
Label(SidebarItem.playlistsList.title, systemImage: SidebarItem.playlistsList.systemImage)
}
case .sources:
Tab(value: SidebarItem.sources) {
NavigationStack(path: $sourcesPath) {
@@ -340,6 +351,7 @@ struct UnifiedTabView: View {
@State private var downloadsPath = NavigationPath()
@State private var subscriptionsFeedPath = NavigationPath()
@State private var manageChannelsPath = NavigationPath()
@State private var playlistsListPath = NavigationPath()
@State private var sourcesPath = NavigationPath()
@State private var settingsPath = NavigationPath()
@State private var openURLPath = NavigationPath()
@@ -471,6 +483,15 @@ struct UnifiedTabView: View {
Label(SidebarItem.manageChannels.title, systemImage: SidebarItem.manageChannels.systemImage)
}
case .playlists:
Tab(value: SidebarItem.playlistsList) {
NavigationStack(path: $playlistsListPath) {
PlaylistsListView().withNavigationDestinations()
}
} label: {
Label(SidebarItem.playlistsList.title, systemImage: SidebarItem.playlistsList.systemImage)
}
case .sources:
Tab(value: SidebarItem.sources) {
NavigationStack(path: $sourcesPath) {
@@ -582,6 +603,7 @@ struct UnifiedTabView: View {
@State private var historyPath = NavigationPath()
@State private var subscriptionsFeedPath = NavigationPath()
@State private var manageChannelsPath = NavigationPath()
@State private var playlistsListPath = NavigationPath()
@State private var sourcesPath = NavigationPath()
@State private var settingsPath = NavigationPath()
@State private var openURLPath = NavigationPath()
@@ -730,6 +752,16 @@ struct UnifiedTabView: View {
Label(SidebarItem.manageChannels.title, systemImage: SidebarItem.manageChannels.systemImage)
}
case .playlists:
Tab(value: SidebarItem.playlistsList) {
NavigationStack(path: $playlistsListPath) {
PlaylistsListView()
.withNavigationDestinations()
}
} label: {
Label(SidebarItem.playlistsList.title, systemImage: SidebarItem.playlistsList.systemImage)
}
case .sources:
Tab(value: SidebarItem.sources) {
NavigationStack(path: $sourcesPath) {
@@ -886,6 +918,8 @@ extension UnifiedTabView {
subscriptionsFeedPath.append(destination)
case .manageChannels:
manageChannelsPath.append(destination)
case .playlistsList:
playlistsListPath.append(destination)
case .sources:
sourcesPath.append(destination)
case .settings: