diff --git a/Shared/Extensions/FormatStyle.swift b/Shared/Extensions/FormatStyle.swift index e251934a..b0bbabb6 100644 --- a/Shared/Extensions/FormatStyle.swift +++ b/Shared/Extensions/FormatStyle.swift @@ -52,3 +52,28 @@ extension FormatStyle where Self == RunTimeFormatStyle { static var runtime: RunTimeFormatStyle { RunTimeFormatStyle() } } + +/// Represent intervals as 24 hour, 60 minute, 60 second days +struct DayIntervalParseableFormatStyle: ParseableFormatStyle { + + let range: ClosedRange + var parseStrategy: DayIntervalParseStrategy = .init() + + func format(_ value: TimeInterval) -> String { + "\(clamp(Int(value / 86400), min: range.lowerBound, max: range.upperBound))" + } +} + +struct DayIntervalParseStrategy: ParseStrategy { + + func parse(_ value: String) throws -> TimeInterval { + (TimeInterval(value) ?? 0) * 86400 + } +} + +extension ParseableFormatStyle where Self == DayIntervalParseableFormatStyle { + + static func dayInterval(range: ClosedRange) -> DayIntervalParseableFormatStyle { + .init(range: range) + } +} diff --git a/Shared/Services/SwiftfinDefaults.swift b/Shared/Services/SwiftfinDefaults.swift index 155b3cb7..7c072123 100644 --- a/Shared/Services/SwiftfinDefaults.swift +++ b/Shared/Services/SwiftfinDefaults.swift @@ -117,7 +117,6 @@ extension Defaults.Keys { static let showPosterLabels: Key = UserKey("showPosterLabels", default: true) static let nextUpPosterType: Key = UserKey("nextUpPosterType", default: .portrait) static let recentlyAddedPosterType: Key = UserKey("recentlyAddedPosterType", default: .portrait) - static let showRecentlyAdded: Key = UserKey("showRecentlyAdded", default: true) static let latestInLibraryPosterType: Key = UserKey("latestInLibraryPosterType", default: .portrait) static let shouldShowMissingSeasons: Key = UserKey("shouldShowMissingSeasons", default: true) static let shouldShowMissingEpisodes: Key = UserKey("shouldShowMissingEpisodes", default: true) @@ -165,6 +164,15 @@ extension Defaults.Keys { static let rememberSort: Key = UserKey("libraryRememberSort", default: false) } + enum Home { + static let showRecentlyAdded: Key = UserKey("showRecentlyAdded", default: true) + static let resumeNextUp: Key = UserKey("homeResumeNextUp", default: true) + static let maxNextUp: Key = UserKey( + "homeMaxNextUp", + default: 366 * 86400 + ) + } + enum Search { static let enabledDrawerFilters: Key<[ItemFilterType]> = UserKey( diff --git a/Shared/Strings/Strings.swift b/Shared/Strings/Strings.swift index 36978a8a..4433c2d7 100644 --- a/Shared/Strings/Strings.swift +++ b/Shared/Strings/Strings.swift @@ -258,6 +258,8 @@ internal enum L10n { internal static let dismiss = L10n.tr("Localizable", "dismiss", fallback: "Dismiss") /// Display order internal static let displayOrder = L10n.tr("Localizable", "displayOrder", fallback: "Display order") + /// Done + internal static let done = L10n.tr("Localizable", "done", fallback: "Done") /// Downloads internal static let downloads = L10n.tr("Localizable", "downloads", fallback: "Downloads") /// Edit @@ -428,6 +430,12 @@ internal enum L10n { internal static let nextItem = L10n.tr("Localizable", "nextItem", fallback: "Next Item") /// Next Up internal static let nextUp = L10n.tr("Localizable", "nextUp", fallback: "Next Up") + /// Days in Next Up + internal static let nextUpDays = L10n.tr("Localizable", "nextUpDays", fallback: "Days in Next Up") + /// Set the maximum amount of days a show should stay in the 'Next Up' list without watching it. + internal static let nextUpDaysDescription = L10n.tr("Localizable", "nextUpDaysDescription", fallback: "Set the maximum amount of days a show should stay in the 'Next Up' list without watching it.") + /// Rewatching in Next Up + internal static let nextUpRewatch = L10n.tr("Localizable", "nextUpRewatch", fallback: "Rewatching in Next Up") /// No Cast devices found.. internal static let noCastdevicesfound = L10n.tr("Localizable", "noCastdevicesfound", fallback: "No Cast devices found..") /// No Codec diff --git a/Shared/ViewModels/LibraryViewModel/NextUpLibraryViewModel.swift b/Shared/ViewModels/LibraryViewModel/NextUpLibraryViewModel.swift index ef733ff3..e80e28e7 100644 --- a/Shared/ViewModels/LibraryViewModel/NextUpLibraryViewModel.swift +++ b/Shared/ViewModels/LibraryViewModel/NextUpLibraryViewModel.swift @@ -7,11 +7,15 @@ // import Combine +import Defaults import Foundation import JellyfinAPI final class NextUpLibraryViewModel: PagingLibraryViewModel { + let maxNextUp = Defaults[.Customization.Home.maxNextUp] + let resumeNextUp = Defaults[.Customization.Home.resumeNextUp] + init() { super.init(parent: TitledLibraryParent(displayTitle: L10n.nextUp, id: "nextUp")) } @@ -31,6 +35,10 @@ final class NextUpLibraryViewModel: PagingLibraryViewModel { parameters.enableUserData = true parameters.fields = .MinimumFields parameters.limit = pageSize + if maxNextUp > 0 { + parameters.nextUpDateCutoff = Date.now.addingTimeInterval(-maxNextUp) + } + parameters.enableRewatching = resumeNextUp parameters.startIndex = page parameters.userID = userSession.user.id diff --git a/Swiftfin tvOS/Components/ChevronButton.swift b/Swiftfin tvOS/Components/ChevronButton.swift index 88d1c33e..ce2d19d5 100644 --- a/Swiftfin tvOS/Components/ChevronButton.swift +++ b/Swiftfin tvOS/Components/ChevronButton.swift @@ -10,8 +10,9 @@ import SwiftUI struct ChevronButton: View { - private let title: String - private let subtitle: String? + private let isExternal: Bool + private let title: Text + private let subtitle: Text? private var leadingView: () -> any View private var onSelect: () -> Void @@ -24,17 +25,17 @@ struct ChevronButton: View { leadingView() .eraseToAnyView() - Text(title) + title .foregroundColor(.primary) Spacer() if let subtitle { - Text(subtitle) + subtitle .foregroundColor(.secondary) } - Image(systemName: "chevron.right") + Image(systemName: isExternal ? "arrow.up.forward" : "chevron.right") .font(.body.weight(.regular)) .foregroundColor(.secondary) } @@ -44,10 +45,31 @@ struct ChevronButton: View { extension ChevronButton { - init(_ title: String, subtitle: String? = nil) { + init( + _ title: String, + subtitle: String? = nil, + external: Bool = false + ) { self.init( - title: title, - subtitle: subtitle, + isExternal: external, + title: Text(title), + subtitle: { + if let subtitle { + Text(subtitle) + } else { + nil + } + }(), + leadingView: { EmptyView() }, + onSelect: {} + ) + } + + init(_ title: String, external: Bool = false, subtitle: @autoclosure () -> Text) { + self.init( + isExternal: external, + title: Text(title), + subtitle: subtitle(), leadingView: { EmptyView() }, onSelect: {} ) diff --git a/Swiftfin tvOS/Views/HomeView/HomeView.swift b/Swiftfin tvOS/Views/HomeView/HomeView.swift index daa04589..16e4919c 100644 --- a/Swiftfin tvOS/Views/HomeView/HomeView.swift +++ b/Swiftfin tvOS/Views/HomeView/HomeView.swift @@ -19,7 +19,7 @@ struct HomeView: View { @StateObject private var viewModel = HomeViewModel() - @Default(.Customization.showRecentlyAdded) + @Default(.Customization.Home.showRecentlyAdded) private var showRecentlyAdded @ViewBuilder diff --git a/Swiftfin tvOS/Views/SettingsView/CustomizeViewsSettings/Components/Sections/HomeSection.swift b/Swiftfin tvOS/Views/SettingsView/CustomizeViewsSettings/Components/Sections/HomeSection.swift new file mode 100644 index 00000000..e7d76ee7 --- /dev/null +++ b/Swiftfin tvOS/Views/SettingsView/CustomizeViewsSettings/Components/Sections/HomeSection.swift @@ -0,0 +1,64 @@ +// +// Swiftfin is subject to the terms of the Mozilla Public +// License, v2.0. If a copy of the MPL was not distributed with this +// file, you can obtain one at https://mozilla.org/MPL/2.0/. +// +// Copyright (c) 2024 Jellyfin & Jellyfin Contributors +// + +import Defaults +import SwiftUI + +extension CustomizeViewsSettings { + struct HomeSection: View { + + @Default(.Customization.Home.showRecentlyAdded) + private var showRecentlyAdded + @Default(.Customization.Home.maxNextUp) + private var maxNextUp + @Default(.Customization.Home.resumeNextUp) + private var resumeNextUp + + @State + private var isPresentingNextUpDays = false + + var body: some View { + Section(L10n.home) { + + Toggle(L10n.showRecentlyAdded, isOn: $showRecentlyAdded) + + Toggle(L10n.nextUpRewatch, isOn: $resumeNextUp) + + ChevronButton( + L10n.nextUpDays, + subtitle: { + if maxNextUp > 0 { + return Text( + Date.now.addingTimeInterval(-maxNextUp) ..< Date.now, + format: .components(style: .narrow, fields: [.year, .month, .week, .day]) + ) + } else { + return Text(L10n.disabled) + } + }() + ) + .onSelect { + isPresentingNextUpDays = true + } + .alert(L10n.nextUpDays, isPresented: $isPresentingNextUpDays) { + + // TODO: Validate whether this says Done or a Number + TextField( + L10n.nextUpDays, + value: $maxNextUp, + format: .dayInterval(range: 0 ... 1000) + ) + .keyboardType(.numberPad) + + } message: { + L10n.nextUpDaysDescription.text + } + } + } + } +} diff --git a/Swiftfin tvOS/Views/SettingsView/CustomizeViewsSettings.swift b/Swiftfin tvOS/Views/SettingsView/CustomizeViewsSettings/CustomizeViewsSettings.swift similarity index 95% rename from Swiftfin tvOS/Views/SettingsView/CustomizeViewsSettings.swift rename to Swiftfin tvOS/Views/SettingsView/CustomizeViewsSettings/CustomizeViewsSettings.swift index ed54c55b..17d22628 100644 --- a/Swiftfin tvOS/Views/SettingsView/CustomizeViewsSettings.swift +++ b/Swiftfin tvOS/Views/SettingsView/CustomizeViewsSettings/CustomizeViewsSettings.swift @@ -37,8 +37,6 @@ struct CustomizeViewsSettings: View { private var libraryRandomImage @Default(.Customization.Library.showFavorites) private var showFavorites - @Default(.Customization.showRecentlyAdded) - private var showRecentlyAdded @EnvironmentObject private var router: CustomizeSettingsCoordinator.Router @@ -89,9 +87,9 @@ struct CustomizeViewsSettings: View { Toggle(L10n.randomImage, isOn: $libraryRandomImage) Toggle(L10n.showFavorites, isOn: $showFavorites) - - Toggle(L10n.showRecentlyAdded, isOn: $showRecentlyAdded) } + + HomeSection() } .withDescriptionTopPadding() .navigationTitle(L10n.customize) diff --git a/Swiftfin.xcodeproj/project.pbxproj b/Swiftfin.xcodeproj/project.pbxproj index 65356413..12401b08 100644 --- a/Swiftfin.xcodeproj/project.pbxproj +++ b/Swiftfin.xcodeproj/project.pbxproj @@ -37,6 +37,8 @@ 4E5E48E52AB59806003F1B48 /* CustomizeViewsSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E5E48E42AB59806003F1B48 /* CustomizeViewsSettings.swift */; }; 4E63B9FA2C8A5BEF00C25378 /* UserDashboardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E63B9F42C8A5BEF00C25378 /* UserDashboardView.swift */; }; 4E63B9FC2C8A5C3E00C25378 /* ActiveSessionsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E63B9FB2C8A5C3E00C25378 /* ActiveSessionsViewModel.swift */; }; + 4E699BB92CB33FC2007CBD5D /* HomeSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E699BB82CB33FB5007CBD5D /* HomeSection.swift */; }; + 4E699BC02CB3477D007CBD5D /* HomeSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E699BBF2CB34775007CBD5D /* HomeSection.swift */; }; 4E6C27082C8BD0AD00FD2185 /* ActiveSessionDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E6C27072C8BD0AD00FD2185 /* ActiveSessionDetailView.swift */; }; 4E71D6892C80910900A0174D /* EditCustomDeviceProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E71D6882C80910900A0174D /* EditCustomDeviceProfileView.swift */; }; 4E73E2A62C41CFD3002D2A78 /* PlaybackBitrateTestSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E73E2A52C41CFD3002D2A78 /* PlaybackBitrateTestSize.swift */; }; @@ -1033,6 +1035,8 @@ 4E5E48E42AB59806003F1B48 /* CustomizeViewsSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomizeViewsSettings.swift; sourceTree = ""; }; 4E63B9F42C8A5BEF00C25378 /* UserDashboardView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDashboardView.swift; sourceTree = ""; }; 4E63B9FB2C8A5C3E00C25378 /* ActiveSessionsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActiveSessionsViewModel.swift; sourceTree = ""; }; + 4E699BB82CB33FB5007CBD5D /* HomeSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeSection.swift; sourceTree = ""; }; + 4E699BBF2CB34775007CBD5D /* HomeSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeSection.swift; sourceTree = ""; }; 4E6C27072C8BD0AD00FD2185 /* ActiveSessionDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActiveSessionDetailView.swift; sourceTree = ""; }; 4E71D6882C80910900A0174D /* EditCustomDeviceProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditCustomDeviceProfileView.swift; sourceTree = ""; }; 4E73E2A52C41CFD3002D2A78 /* PlaybackBitrateTestSize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaybackBitrateTestSize.swift; sourceTree = ""; }; @@ -1864,6 +1868,56 @@ path = UserDashboardView; sourceTree = ""; }; + 4E699BB52CB33F4B007CBD5D /* CustomizeViewsSettings */ = { + isa = PBXGroup; + children = ( + 4E699BB62CB33FA8007CBD5D /* Components */, + 4E5E48E42AB59806003F1B48 /* CustomizeViewsSettings.swift */, + ); + path = CustomizeViewsSettings; + sourceTree = ""; + }; + 4E699BB62CB33FA8007CBD5D /* Components */ = { + isa = PBXGroup; + children = ( + 4E699BB72CB33FB0007CBD5D /* Sections */, + ); + path = Components; + sourceTree = ""; + }; + 4E699BB72CB33FB0007CBD5D /* Sections */ = { + isa = PBXGroup; + children = ( + 4E699BB82CB33FB5007CBD5D /* HomeSection.swift */, + ); + path = Sections; + sourceTree = ""; + }; + 4E699BBC2CB34740007CBD5D /* CustomizeViewsSettings */ = { + isa = PBXGroup; + children = ( + 4E699BBD2CB34746007CBD5D /* Components */, + E1CEFBF627914E6400F60429 /* CustomizeViewsSettings.swift */, + ); + path = CustomizeViewsSettings; + sourceTree = ""; + }; + 4E699BBD2CB34746007CBD5D /* Components */ = { + isa = PBXGroup; + children = ( + 4E699BBE2CB3474C007CBD5D /* Sections */, + ); + path = Components; + sourceTree = ""; + }; + 4E699BBE2CB3474C007CBD5D /* Sections */ = { + isa = PBXGroup; + children = ( + 4E699BBF2CB34775007CBD5D /* HomeSection.swift */, + ); + path = Sections; + sourceTree = ""; + }; 4E6C27062C8BD09200FD2185 /* ActiveSessionDetailView */ = { isa = PBXGroup; children = ( @@ -3760,7 +3814,7 @@ isa = PBXGroup; children = ( 4EC1C86A2C80900B00E2879E /* CustomDeviceProfileSettingsView */, - 4E5E48E42AB59806003F1B48 /* CustomizeViewsSettings.swift */, + 4E699BB52CB33F4B007CBD5D /* CustomizeViewsSettings */, E175AFF2299AC117004DCF52 /* DebugSettingsView.swift */, E1E5D54B2783E27200692DFE /* ExperimentalSettingsView.swift */, E16AF11B292C98A7001422A8 /* GestureSettingsView.swift */, @@ -3779,7 +3833,7 @@ isa = PBXGroup; children = ( 4E9A24E32C82B4700023DA83 /* CustomDeviceProfileSettingsView */, - E1CEFBF627914E6400F60429 /* CustomizeViewsSettings.swift */, + 4E699BBC2CB34740007CBD5D /* CustomizeViewsSettings */, E1E5D5502783E67700692DFE /* ExperimentalSettingsView.swift */, E104C872296E0D0A00C1C3F9 /* IndicatorSettingsView.swift */, 4E2AC4D52C6C4CDC00DD600D /* PlaybackQualitySettingsView.swift */, @@ -4233,6 +4287,7 @@ E102314B2BCF8A6D009D71FC /* ProgramsViewModel.swift in Sources */, E1DD55382B6EE533007501C0 /* Task.swift in Sources */, E1575EA1293E7B1E001665B1 /* String.swift in Sources */, + 4E699BC02CB3477D007CBD5D /* HomeSection.swift in Sources */, E1E6C45429B1304E0064123F /* ChaptersActionButton.swift in Sources */, E1763A292BF3046A004DF6AB /* AddUserButton.swift in Sources */, E1E6C44229AECCD50064123F /* ActionButtons.swift in Sources */, @@ -4611,6 +4666,7 @@ E102314A2BCF8A6D009D71FC /* ProgramsViewModel.swift in Sources */, E1721FAA28FB7CAC00762992 /* CompactTimeStamp.swift in Sources */, E1803EA12BFBD6CF0039F90E /* Hashable.swift in Sources */, + 4E699BB92CB33FC2007CBD5D /* HomeSection.swift in Sources */, 62C29E9F26D1016600C1D2E7 /* iOSMainCoordinator.swift in Sources */, E12CC1B128D1008F00678D5D /* NextUpView.swift in Sources */, E11895AF2893840F0042947B /* NavigationBarOffsetView.swift in Sources */, diff --git a/Swiftfin/Components/ChevronButton.swift b/Swiftfin/Components/ChevronButton.swift index 6cc1dba8..ce2d19d5 100644 --- a/Swiftfin/Components/ChevronButton.swift +++ b/Swiftfin/Components/ChevronButton.swift @@ -11,8 +11,8 @@ import SwiftUI struct ChevronButton: View { private let isExternal: Bool - private let title: String - private let subtitle: String? + private let title: Text + private let subtitle: Text? private var leadingView: () -> any View private var onSelect: () -> Void @@ -25,13 +25,13 @@ struct ChevronButton: View { leadingView() .eraseToAnyView() - Text(title) + title .foregroundColor(.primary) Spacer() if let subtitle { - Text(subtitle) + subtitle .foregroundColor(.secondary) } @@ -45,11 +45,31 @@ struct ChevronButton: View { extension ChevronButton { - init(_ title: String, subtitle: String? = nil, external: Bool = false) { + init( + _ title: String, + subtitle: String? = nil, + external: Bool = false + ) { self.init( isExternal: external, - title: title, - subtitle: subtitle, + title: Text(title), + subtitle: { + if let subtitle { + Text(subtitle) + } else { + nil + } + }(), + leadingView: { EmptyView() }, + onSelect: {} + ) + } + + init(_ title: String, external: Bool = false, subtitle: @autoclosure () -> Text) { + self.init( + isExternal: external, + title: Text(title), + subtitle: subtitle(), leadingView: { EmptyView() }, onSelect: {} ) diff --git a/Swiftfin/Views/HomeView/HomeView.swift b/Swiftfin/Views/HomeView/HomeView.swift index 94a674a1..64da0366 100644 --- a/Swiftfin/Views/HomeView/HomeView.swift +++ b/Swiftfin/Views/HomeView/HomeView.swift @@ -18,7 +18,7 @@ struct HomeView: View { @Default(.Customization.nextUpPosterType) private var nextUpPosterType - @Default(.Customization.showRecentlyAdded) + @Default(.Customization.Home.showRecentlyAdded) private var showRecentlyAdded @Default(.Customization.recentlyAddedPosterType) private var recentlyAddedPosterType diff --git a/Swiftfin/Views/SettingsView/CustomizeViewsSettings/Components/Sections/HomeSection.swift b/Swiftfin/Views/SettingsView/CustomizeViewsSettings/Components/Sections/HomeSection.swift new file mode 100644 index 00000000..bb7da2d0 --- /dev/null +++ b/Swiftfin/Views/SettingsView/CustomizeViewsSettings/Components/Sections/HomeSection.swift @@ -0,0 +1,63 @@ +// +// Swiftfin is subject to the terms of the Mozilla Public +// License, v2.0. If a copy of the MPL was not distributed with this +// file, you can obtain one at https://mozilla.org/MPL/2.0/. +// +// Copyright (c) 2024 Jellyfin & Jellyfin Contributors +// + +import Defaults +import SwiftUI + +extension CustomizeViewsSettings { + struct HomeSection: View { + + @Default(.Customization.Home.showRecentlyAdded) + private var showRecentlyAdded + @Default(.Customization.Home.maxNextUp) + private var maxNextUp + @Default(.Customization.Home.resumeNextUp) + private var resumeNextUp + + @State + private var isPresentingNextUpDays = false + + var body: some View { + Section(L10n.home) { + + Toggle(L10n.showRecentlyAdded, isOn: $showRecentlyAdded) + + Toggle(L10n.nextUpRewatch, isOn: $resumeNextUp) + + ChevronButton( + L10n.nextUpDays, + subtitle: { + if maxNextUp > 0 { + return Text( + Date.now.addingTimeInterval(-maxNextUp) ..< Date.now, + format: .components(style: .narrow, fields: [.year, .month, .week, .day]) + ) + } else { + return Text(L10n.disabled) + } + }() + ) + .onSelect { + isPresentingNextUpDays = true + } + .alert(L10n.nextUpDays, isPresented: $isPresentingNextUpDays) { + + TextField( + L10n.nextUpDays, + value: $maxNextUp, + format: .dayInterval(range: 0 ... 1000) + ) + .keyboardType(.numberPad) + + } message: { + L10n.nextUpDaysDescription.text + } + } + } + } +} diff --git a/Swiftfin/Views/SettingsView/CustomizeViewsSettings.swift b/Swiftfin/Views/SettingsView/CustomizeViewsSettings/CustomizeViewsSettings.swift similarity index 95% rename from Swiftfin/Views/SettingsView/CustomizeViewsSettings.swift rename to Swiftfin/Views/SettingsView/CustomizeViewsSettings/CustomizeViewsSettings.swift index 885e9836..b4ae734b 100644 --- a/Swiftfin/Views/SettingsView/CustomizeViewsSettings.swift +++ b/Swiftfin/Views/SettingsView/CustomizeViewsSettings/CustomizeViewsSettings.swift @@ -37,8 +37,6 @@ struct CustomizeViewsSettings: View { @Default(.Customization.nextUpPosterType) private var nextUpPosterType @Default(.Customization.recentlyAddedPosterType) - private var recentlyAddedPosterType - @Default(.Customization.showRecentlyAdded) private var showRecentlyAdded @Default(.Customization.latestInLibraryPosterType) private var latestInLibraryPosterType @@ -138,8 +136,6 @@ struct CustomizeViewsSettings: View { CaseIterablePicker(L10n.next, selection: $nextUpPosterType) - CaseIterablePicker(L10n.recentlyAdded, selection: $recentlyAddedPosterType) - CaseIterablePicker(L10n.latestWithString(L10n.library), selection: $latestInLibraryPosterType) CaseIterablePicker(L10n.recommended, selection: $similarPosterType) @@ -162,9 +158,7 @@ struct CustomizeViewsSettings: View { } } - Section("Home") { - Toggle("Show recently added", isOn: $showRecentlyAdded) - } + HomeSection() Section { Toggle("Remember layout", isOn: $rememberLibraryLayout) diff --git a/Translations/en.lproj/Localizable.strings b/Translations/en.lproj/Localizable.strings index c941137e..4d5157e5 100644 Binary files a/Translations/en.lproj/Localizable.strings and b/Translations/en.lproj/Localizable.strings differ