mirror of
https://github.com/jellyfin/Swiftfin.git
synced 2024-11-27 00:00:37 +00:00
Add 'Enable Rewatching' and ' Max days' to Next Up (#1258)
* Rebasing https://github.com/jellyfin/Swiftfin/pull/1212 on Main. Also, less baggage and random crap. * Change 0 to Disabled. Better mirror iOS and tvOS Alerts for MaxNextUpDays. * Review Changes: Don't use the property wrappers in non-view contexts. While they technically can still work, use the subscript instead at the usage sites. Use the dayInterval(0 ... 1000) format instead, then we don't need maxNextUpDays. * Remove unused strings, and unused variables * Add a tvOS TODO to double check the Done/Number button on the alert.
This commit is contained in:
parent
973a9ea3a4
commit
1405d2695c
@ -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<Int>
|
||||
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<Int>) -> DayIntervalParseableFormatStyle {
|
||||
.init(range: range)
|
||||
}
|
||||
}
|
||||
|
@ -117,7 +117,6 @@ extension Defaults.Keys {
|
||||
static let showPosterLabels: Key<Bool> = UserKey("showPosterLabels", default: true)
|
||||
static let nextUpPosterType: Key<PosterDisplayType> = UserKey("nextUpPosterType", default: .portrait)
|
||||
static let recentlyAddedPosterType: Key<PosterDisplayType> = UserKey("recentlyAddedPosterType", default: .portrait)
|
||||
static let showRecentlyAdded: Key<Bool> = UserKey("showRecentlyAdded", default: true)
|
||||
static let latestInLibraryPosterType: Key<PosterDisplayType> = UserKey("latestInLibraryPosterType", default: .portrait)
|
||||
static let shouldShowMissingSeasons: Key<Bool> = UserKey("shouldShowMissingSeasons", default: true)
|
||||
static let shouldShowMissingEpisodes: Key<Bool> = UserKey("shouldShowMissingEpisodes", default: true)
|
||||
@ -165,6 +164,15 @@ extension Defaults.Keys {
|
||||
static let rememberSort: Key<Bool> = UserKey("libraryRememberSort", default: false)
|
||||
}
|
||||
|
||||
enum Home {
|
||||
static let showRecentlyAdded: Key<Bool> = UserKey("showRecentlyAdded", default: true)
|
||||
static let resumeNextUp: Key<Bool> = UserKey("homeResumeNextUp", default: true)
|
||||
static let maxNextUp: Key<TimeInterval> = UserKey(
|
||||
"homeMaxNextUp",
|
||||
default: 366 * 86400
|
||||
)
|
||||
}
|
||||
|
||||
enum Search {
|
||||
|
||||
static let enabledDrawerFilters: Key<[ItemFilterType]> = UserKey(
|
||||
|
@ -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
|
||||
|
@ -7,11 +7,15 @@
|
||||
//
|
||||
|
||||
import Combine
|
||||
import Defaults
|
||||
import Foundation
|
||||
import JellyfinAPI
|
||||
|
||||
final class NextUpLibraryViewModel: PagingLibraryViewModel<BaseItemDto> {
|
||||
|
||||
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<BaseItemDto> {
|
||||
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
|
||||
|
||||
|
@ -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: {}
|
||||
)
|
||||
|
@ -19,7 +19,7 @@ struct HomeView: View {
|
||||
@StateObject
|
||||
private var viewModel = HomeViewModel()
|
||||
|
||||
@Default(.Customization.showRecentlyAdded)
|
||||
@Default(.Customization.Home.showRecentlyAdded)
|
||||
private var showRecentlyAdded
|
||||
|
||||
@ViewBuilder
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
@ -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 = "<group>"; };
|
||||
4E63B9F42C8A5BEF00C25378 /* UserDashboardView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDashboardView.swift; sourceTree = "<group>"; };
|
||||
4E63B9FB2C8A5C3E00C25378 /* ActiveSessionsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActiveSessionsViewModel.swift; sourceTree = "<group>"; };
|
||||
4E699BB82CB33FB5007CBD5D /* HomeSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeSection.swift; sourceTree = "<group>"; };
|
||||
4E699BBF2CB34775007CBD5D /* HomeSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeSection.swift; sourceTree = "<group>"; };
|
||||
4E6C27072C8BD0AD00FD2185 /* ActiveSessionDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActiveSessionDetailView.swift; sourceTree = "<group>"; };
|
||||
4E71D6882C80910900A0174D /* EditCustomDeviceProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditCustomDeviceProfileView.swift; sourceTree = "<group>"; };
|
||||
4E73E2A52C41CFD3002D2A78 /* PlaybackBitrateTestSize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaybackBitrateTestSize.swift; sourceTree = "<group>"; };
|
||||
@ -1864,6 +1868,56 @@
|
||||
path = UserDashboardView;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4E699BB52CB33F4B007CBD5D /* CustomizeViewsSettings */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4E699BB62CB33FA8007CBD5D /* Components */,
|
||||
4E5E48E42AB59806003F1B48 /* CustomizeViewsSettings.swift */,
|
||||
);
|
||||
path = CustomizeViewsSettings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4E699BB62CB33FA8007CBD5D /* Components */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4E699BB72CB33FB0007CBD5D /* Sections */,
|
||||
);
|
||||
path = Components;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4E699BB72CB33FB0007CBD5D /* Sections */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4E699BB82CB33FB5007CBD5D /* HomeSection.swift */,
|
||||
);
|
||||
path = Sections;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4E699BBC2CB34740007CBD5D /* CustomizeViewsSettings */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4E699BBD2CB34746007CBD5D /* Components */,
|
||||
E1CEFBF627914E6400F60429 /* CustomizeViewsSettings.swift */,
|
||||
);
|
||||
path = CustomizeViewsSettings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4E699BBD2CB34746007CBD5D /* Components */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4E699BBE2CB3474C007CBD5D /* Sections */,
|
||||
);
|
||||
path = Components;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4E699BBE2CB3474C007CBD5D /* Sections */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4E699BBF2CB34775007CBD5D /* HomeSection.swift */,
|
||||
);
|
||||
path = Sections;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
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 */,
|
||||
|
@ -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: {}
|
||||
)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user