diff --git a/Shared/Strings/Strings.swift b/Shared/Strings/Strings.swift index e6db15e74..2239cd641 100644 --- a/Shared/Strings/Strings.swift +++ b/Shared/Strings/Strings.swift @@ -516,6 +516,8 @@ internal enum L10n { internal static func duplicateUserSaved(_ p1: Any) -> String { return L10n.tr("Localizable", "duplicateUserSaved", String(describing: p1), fallback: "%@ is already saved") } + /// Duration + internal static let duration = L10n.tr("Localizable", "duration", fallback: "Duration") /// DVD internal static let dvd = L10n.tr("Localizable", "dvd", fallback: "DVD") /// Edit @@ -1202,6 +1204,14 @@ internal enum L10n { internal static func signInToServer(_ p1: UnsafePointer) -> String { return L10n.tr("Localizable", "signInToServer", p1, fallback: "Sign In to %s") } + /// Sign out on background + internal static let signoutBackground = L10n.tr("Localizable", "signoutBackground", fallback: "Sign out on background") + /// Signs out the last user when Swiftfin has been in the background without media playback after some time + internal static let signoutBackgroundFooter = L10n.tr("Localizable", "signoutBackgroundFooter", fallback: "Signs out the last user when Swiftfin has been in the background without media playback after some time") + /// Sign out on close + internal static let signoutClose = L10n.tr("Localizable", "signoutClose", fallback: "Sign out on close") + /// Signs out the last user when Swiftfin has been force closed + internal static let signoutCloseFooter = L10n.tr("Localizable", "signoutCloseFooter", fallback: "Signs out the last user when Swiftfin has been force closed") /// Slider internal static let slider = L10n.tr("Localizable", "slider", fallback: "Slider") /// Slider Color @@ -1222,6 +1232,10 @@ internal enum L10n { internal static let sourceCode = L10n.tr("Localizable", "sourceCode", fallback: "Source Code") /// Special Features internal static let specialFeatures = L10n.tr("Localizable", "specialFeatures", fallback: "Special Features") + /// Splashscreen + internal static let splashscreen = L10n.tr("Localizable", "splashscreen", fallback: "Splashscreen") + /// When All Servers is selected, use the splashscreen from a single server or a random server + internal static let splashscreenFooter = L10n.tr("Localizable", "splashscreenFooter", fallback: "When All Servers is selected, use the splashscreen from a single server or a random server") /// Sports internal static let sports = L10n.tr("Localizable", "sports", fallback: "Sports") /// Start Time @@ -1402,6 +1416,8 @@ internal enum L10n { } /// Users internal static let users = L10n.tr("Localizable", "users", fallback: "Users") + /// Use splashscreen + internal static let useSplashscreen = L10n.tr("Localizable", "useSplashscreen", fallback: "Use splashscreen") /// Version internal static let version = L10n.tr("Localizable", "version", fallback: "Version") /// Video diff --git a/Shared/ViewModels/SettingsViewModel.swift b/Shared/ViewModels/SettingsViewModel.swift index 820f07516..109267f4f 100644 --- a/Shared/ViewModels/SettingsViewModel.swift +++ b/Shared/ViewModels/SettingsViewModel.swift @@ -26,30 +26,28 @@ final class SettingsViewModel: ViewModel { override init() { - guard let iconName = UIApplication.shared.alternateIconName else { - currentAppIcon = PrimaryAppIcon.primary - super.init() - return - } - - if let appicon = PrimaryAppIcon.createCase(iconName: iconName) { - currentAppIcon = appicon - } + if let iconName = UIApplication.shared.alternateIconName { + if let appicon = PrimaryAppIcon.createCase(iconName: iconName) { + currentAppIcon = appicon + } - if let appicon = DarkAppIcon.createCase(iconName: iconName) { - currentAppIcon = appicon - } + if let appicon = DarkAppIcon.createCase(iconName: iconName) { + currentAppIcon = appicon + } - if let appicon = InvertedDarkAppIcon.createCase(iconName: iconName) { - currentAppIcon = appicon - } + if let appicon = InvertedDarkAppIcon.createCase(iconName: iconName) { + currentAppIcon = appicon + } - if let appicon = InvertedLightAppIcon.createCase(iconName: iconName) { - currentAppIcon = appicon - } + if let appicon = InvertedLightAppIcon.createCase(iconName: iconName) { + currentAppIcon = appicon + } - if let appicon = LightAppIcon.createCase(iconName: iconName) { - currentAppIcon = appicon + if let appicon = LightAppIcon.createCase(iconName: iconName) { + currentAppIcon = appicon + } + } else { + currentAppIcon = PrimaryAppIcon.primary } super.init() diff --git a/Swiftfin tvOS/App/SwiftfinApp.swift b/Swiftfin tvOS/App/SwiftfinApp.swift index 361cd2f07..b55f27d7d 100644 --- a/Swiftfin tvOS/App/SwiftfinApp.swift +++ b/Swiftfin tvOS/App/SwiftfinApp.swift @@ -52,6 +52,11 @@ struct SwiftfinApp: App { // UIKit UINavigationBar.appearance().titleTextAttributes = [.foregroundColor: UIColor.label] + + // don't keep last user id + if Defaults[.signOutOnClose] { + Defaults[.lastSignedInUserID] = .signedOut + } } var body: some Scene { diff --git a/Swiftfin tvOS/Views/AppSettingsView/AppSettingsView.swift b/Swiftfin tvOS/Views/AppSettingsView/AppSettingsView.swift new file mode 100644 index 000000000..582442adf --- /dev/null +++ b/Swiftfin tvOS/Views/AppSettingsView/AppSettingsView.swift @@ -0,0 +1,100 @@ +// +// 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) 2025 Jellyfin & Jellyfin Contributors +// + +import Defaults +import Stinsen +import SwiftUI + +struct AppSettingsView: View { + + @Default(.selectUserUseSplashscreen) + private var selectUserUseSplashscreen + @Default(.selectUserAllServersSplashscreen) + private var selectUserAllServersSplashscreen + + @Default(.appAppearance) + private var appearance + + @EnvironmentObject + private var router: AppSettingsCoordinator.Router + + @StateObject + private var viewModel = SettingsViewModel() + + @State + private var resetUserSettingsSelected: Bool = false + @State + private var removeAllServersSelected: Bool = false + + var body: some View { + SplitFormWindowView() + .descriptionView { + Image(.jellyfinBlobBlue) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(maxWidth: 400) + } + .contentView { + + TextPairView( + leading: L10n.version, + trailing: "\(UIApplication.appVersion ?? .emptyDash) (\(UIApplication.bundleVersion ?? .emptyDash))" + ) + + Section { + + Toggle(L10n.useSplashscreen, isOn: $selectUserUseSplashscreen) + + if selectUserUseSplashscreen { + Menu { + Picker(L10n.servers, selection: $selectUserAllServersSplashscreen) { + + Label(L10n.random, systemImage: "dice.fill") + .tag(SelectUserServerSelection.all) + + ForEach(viewModel.servers) { server in + Text(server.name) + .tag(SelectUserServerSelection.server(id: server.id)) + } + } + } label: { + HStack { + Text(L10n.servers) + .frame(maxWidth: .infinity, alignment: .leading) + + if selectUserAllServersSplashscreen == .all { + Label(L10n.random, systemImage: "dice.fill") + } else if let server = viewModel.servers.first( + where: { server in + selectUserAllServersSplashscreen == .server(id: server.id) + } + ) { + Text(server.name) + } + } + } + .listRowBackground(Color.clear) + .listRowInsets(.zero) + } + } header: { + Text(L10n.splashscreen) + } footer: { + if selectUserUseSplashscreen { + Text(L10n.splashscreenFooter) + } + } + + SignOutIntervalSection() + + ChevronButton(L10n.logs) + .onSelect { + router.route(to: \.log) + } + } + } +} diff --git a/Swiftfin tvOS/Views/AppSettingsView/Components/SignOutIntervalSection.swift b/Swiftfin tvOS/Views/AppSettingsView/Components/SignOutIntervalSection.swift new file mode 100644 index 000000000..be5be8818 --- /dev/null +++ b/Swiftfin tvOS/Views/AppSettingsView/Components/SignOutIntervalSection.swift @@ -0,0 +1,72 @@ +// +// 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) 2025 Jellyfin & Jellyfin Contributors +// + +import Defaults +import SwiftUI + +extension AppSettingsView { + + struct SignOutIntervalSection: View { + + @Default(.backgroundSignOutInterval) + private var backgroundSignOutInterval + @Default(.signOutOnBackground) + private var signOutOnBackground + @Default(.signOutOnClose) + private var signOutOnClose + + @State + private var isEditingBackgroundSignOutInterval: Bool = false + + var body: some View { + Section { + Toggle(L10n.signoutClose, isOn: $signOutOnClose) + } footer: { + Text(L10n.signoutCloseFooter) + } + + // TODO: need to consider date picker options to re-enable +// Section { +// Toggle(L10n.signoutBackground, isOn: $signOutOnBackground) +// +// if signOutOnBackground { +// HStack { +// Text(L10n.duration) +// +// Spacer() +// +// Button { +// isEditingBackgroundSignOutInterval.toggle() +// } label: { +// HStack { +// Text(backgroundSignOutInterval, format: .hourMinute) +// .foregroundStyle(.secondary) +// +// Image(systemName: "chevron.right") +// .font(.body.weight(.semibold)) +// .foregroundStyle(.secondary) +// .rotationEffect(isEditingBackgroundSignOutInterval ? .degrees(90) : .zero) +// .animation(.linear(duration: 0.075), value: isEditingBackgroundSignOutInterval) +// } +// } +// .foregroundStyle(.primary, .secondary) +// } +// +// if isEditingBackgroundSignOutInterval { +// HourMinutePicker(interval: $backgroundSignOutInterval) +// } +// } +// } footer: { +// Text( +// L10n.signoutBackgroundFooter +// ) +// } +// .animation(.linear(duration: 0.15), value: isEditingBackgroundSignOutInterval) + } + } +} diff --git a/Swiftfin tvOS/Views/BasicAppSettingsView.swift b/Swiftfin tvOS/Views/BasicAppSettingsView.swift deleted file mode 100644 index 3cd265ab5..000000000 --- a/Swiftfin tvOS/Views/BasicAppSettingsView.swift +++ /dev/null @@ -1,90 +0,0 @@ -// -// 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) 2025 Jellyfin & Jellyfin Contributors -// - -import Defaults -import Stinsen -import SwiftUI - -#warning("TODO: implement") - -struct AppSettingsView: View { - - var body: some View { - Text("TODO") - } -} - -// struct BasicAppSettingsView: View { -// -// @EnvironmentObject -// private var router: BasicAppSettingsCoordinator.Router -// -// @ObservedObject -// var viewModel: SettingsViewModel -// -// @State -// private var resetUserSettingsSelected: Bool = false -// @State -// private var removeAllServersSelected: Bool = false -// -// var body: some View { -// SplitFormWindowView() -// .descriptionView { -// Image(.jellyfinBlobBlue) -// .resizable() -// .aspectRatio(contentMode: .fit) -// .frame(maxWidth: 400) -// } -// .contentView { -// -// Section { -// -// Button { -// TextPairView( -// leading: L10n.version, -// trailing: "\(UIApplication.appVersion ?? .emptyDash) (\(UIApplication.bundleVersion ?? .emptyDash))" -// ) -// } -// -// ChevronButton(L10n.logs) -// .onSelect { -// router.route(to: \.log) -// } -// } -// -// Section { -// -// Button { -// resetUserSettingsSelected = true -// } label: { -// L10n.resetUserSettings.text -// } -// -// Button { -// removeAllServersSelected = true -// } label: { -// Text(L10n.removeAllServers) -// } -// } -// } -// .withDescriptionTopPadding() -// .navigationTitle(L10n.settings) -// .alert(L10n.resetUserSettings, isPresented: $resetUserSettingsSelected) { -// Button(L10n.reset, role: .destructive) { -//// viewModel.resetUserSettings() -// } -// } message: { -// Text(L10n.resetAllSettings) -// } -// .alert(L10n.removeAllServers, isPresented: $removeAllServersSelected) { -// Button(L10n.reset, role: .destructive) { -//// viewModel.removeAllServers() -// } -// } -// } -// } diff --git a/Swiftfin tvOS/Views/SelectUserView/Components/SelectUserBottomBar.swift b/Swiftfin tvOS/Views/SelectUserView/Components/SelectUserBottomBar.swift index ece7b9b16..2f61a93da 100644 --- a/Swiftfin tvOS/Views/SelectUserView/Components/SelectUserBottomBar.swift +++ b/Swiftfin tvOS/Views/SelectUserView/Components/SelectUserBottomBar.swift @@ -12,6 +12,11 @@ extension SelectUserView { struct SelectUserBottomBar: View { + // MARK: - State & Environment Objects + + @EnvironmentObject + private var router: SelectUserCoordinator.Router + @Binding private var isEditing: Bool @@ -21,6 +26,8 @@ extension SelectUserView { @ObservedObject private var viewModel: SelectUserViewModel + // MARK: - Variables + private let areUsersSelected: Bool private let userCount: Int @@ -35,13 +42,12 @@ extension SelectUserView { Button(L10n.editUsers, systemImage: "person.crop.circle") { isEditing.toggle() } - // TODO: Advanced settings on tvOS? - // - // Divider() - // - // Button(L10n.advanced, systemImage: "gearshape.fill") { - // router.route(to: \.advancedSettings) - // } + + Divider() + + Button(L10n.advanced, systemImage: "gearshape.fill") { + router.route(to: \.advancedSettings) + } } label: { Label(L10n.advanced, systemImage: "gearshape.fill") .font(.body.weight(.semibold)) diff --git a/Swiftfin tvOS/Views/SelectUserView/SelectUserView.swift b/Swiftfin tvOS/Views/SelectUserView/SelectUserView.swift index c96a54a74..2ed0dc831 100644 --- a/Swiftfin tvOS/Views/SelectUserView/SelectUserView.swift +++ b/Swiftfin tvOS/Views/SelectUserView/SelectUserView.swift @@ -28,6 +28,8 @@ struct SelectUserView: View { @Default(.selectUserServerSelection) private var serverSelection + @Default(.selectUserUseSplashscreen) + private var selectUserUseSplashscreen // MARK: - Environment Variable @@ -286,7 +288,7 @@ struct SelectUserView: View { } .animation(.linear(duration: 0.1), value: scrollViewOffset) .background { - if let splashScreenImageSource { + if let splashScreenImageSource, selectUserUseSplashscreen { ZStack { ImageView(splashScreenImageSource) .aspectRatio(contentMode: .fill) diff --git a/Swiftfin.xcodeproj/project.pbxproj b/Swiftfin.xcodeproj/project.pbxproj index fd6addffa..5bbabb062 100644 --- a/Swiftfin.xcodeproj/project.pbxproj +++ b/Swiftfin.xcodeproj/project.pbxproj @@ -396,6 +396,7 @@ BD39577C2C113FAA0078CEF8 /* TimestampSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD39577B2C113FAA0078CEF8 /* TimestampSection.swift */; }; BD39577E2C1140810078CEF8 /* TransitionSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD39577D2C1140810078CEF8 /* TransitionSection.swift */; }; BDA623532D0D0854009A157F /* SelectUserBottomBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDA623522D0D0854009A157F /* SelectUserBottomBar.swift */; }; + BDF8BB6C2D5456B400628ADB /* SignOutIntervalSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDF8BB6B2D5456B400628ADB /* SignOutIntervalSection.swift */; }; BDFF67B02D2CA59A009A9A3A /* UserLocalSecurityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDFF67AD2D2CA59A009A9A3A /* UserLocalSecurityView.swift */; }; BDFF67B22D2CA59A009A9A3A /* UserProfileSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDFF67AE2D2CA59A009A9A3A /* UserProfileSettingsView.swift */; }; BDFF67B32D2CA99D009A9A3A /* UserProfileRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1BE1CED2BDB68CD008176A9 /* UserProfileRow.swift */; }; @@ -1067,7 +1068,7 @@ E1D4BF812719D22800A11E64 /* AppAppearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D4BF802719D22800A11E64 /* AppAppearance.swift */; }; E1D4BF8A2719D3D000A11E64 /* AppSettingsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D4BF892719D3D000A11E64 /* AppSettingsCoordinator.swift */; }; E1D4BF8B2719D3D000A11E64 /* AppSettingsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D4BF892719D3D000A11E64 /* AppSettingsCoordinator.swift */; }; - E1D4BF8F271A079A00A11E64 /* BasicAppSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D4BF8E271A079A00A11E64 /* BasicAppSettingsView.swift */; }; + E1D4BF8F271A079A00A11E64 /* AppSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D4BF8E271A079A00A11E64 /* AppSettingsView.swift */; }; E1D5C39628DF90C100CDBEFB /* Slider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D5C39528DF90C100CDBEFB /* Slider.swift */; }; E1D5C39928DF914700CDBEFB /* CapsuleSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D5C39828DF914700CDBEFB /* CapsuleSlider.swift */; }; E1D5C39B28DF993400CDBEFB /* ThumbSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D5C39A28DF993400CDBEFB /* ThumbSlider.swift */; }; @@ -1533,6 +1534,7 @@ BD39577B2C113FAA0078CEF8 /* TimestampSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimestampSection.swift; sourceTree = ""; }; BD39577D2C1140810078CEF8 /* TransitionSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransitionSection.swift; sourceTree = ""; }; BDA623522D0D0854009A157F /* SelectUserBottomBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectUserBottomBar.swift; sourceTree = ""; }; + BDF8BB6B2D5456B400628ADB /* SignOutIntervalSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignOutIntervalSection.swift; sourceTree = ""; }; BDFF67AD2D2CA59A009A9A3A /* UserLocalSecurityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserLocalSecurityView.swift; sourceTree = ""; }; BDFF67AE2D2CA59A009A9A3A /* UserProfileSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserProfileSettingsView.swift; sourceTree = ""; }; C44FA6DE2AACD19C00EDEB56 /* LiveSmallPlaybackButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LiveSmallPlaybackButton.swift; sourceTree = ""; }; @@ -1944,7 +1946,7 @@ E1D4BF7B2719D05000A11E64 /* AppSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSettingsView.swift; sourceTree = ""; }; E1D4BF802719D22800A11E64 /* AppAppearance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppAppearance.swift; sourceTree = ""; }; E1D4BF892719D3D000A11E64 /* AppSettingsCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSettingsCoordinator.swift; sourceTree = ""; }; - E1D4BF8E271A079A00A11E64 /* BasicAppSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BasicAppSettingsView.swift; sourceTree = ""; }; + E1D4BF8E271A079A00A11E64 /* AppSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSettingsView.swift; sourceTree = ""; }; E1D5C39528DF90C100CDBEFB /* Slider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Slider.swift; sourceTree = ""; }; E1D5C39828DF914700CDBEFB /* CapsuleSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CapsuleSlider.swift; sourceTree = ""; }; E1D5C39A28DF993400CDBEFB /* ThumbSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThumbSlider.swift; sourceTree = ""; }; @@ -3624,6 +3626,23 @@ path = Sections; sourceTree = ""; }; + BDF8BB692D54566400628ADB /* AppSettingsView */ = { + isa = PBXGroup; + children = ( + BDF8BB6A2D5456AA00628ADB /* Components */, + E1D4BF8E271A079A00A11E64 /* AppSettingsView.swift */, + ); + path = AppSettingsView; + sourceTree = ""; + }; + BDF8BB6A2D5456AA00628ADB /* Components */ = { + isa = PBXGroup; + children = ( + BDF8BB6B2D5456B400628ADB /* SignOutIntervalSection.swift */, + ); + path = Components; + sourceTree = ""; + }; BDFF67AF2D2CA59A009A9A3A /* UserProfileSettingsView */ = { isa = PBXGroup; children = ( @@ -3997,8 +4016,8 @@ E12186E02718F23B0010884C /* Views */ = { isa = PBXGroup; children = ( + BDF8BB692D54566400628ADB /* AppSettingsView */, E1763A752BF3FF01004DF6AB /* AppLoadingView.swift */, - E1D4BF8E271A079A00A11E64 /* BasicAppSettingsView.swift */, E10231522BCF8AF8009D71FC /* ChannelLibraryView */, 4E4DAC3A2D11F54300E13FF9 /* ConnectToServerView */, E154967B296CBB1A00C4EF88 /* FontPickerView.swift */, @@ -5668,6 +5687,7 @@ 4EF18B282CB9936D00343666 /* ListColumnsPickerView.swift in Sources */, E11BDF7B2B85529D0045C54A /* SupportedCaseIterable.swift in Sources */, BDFF67B02D2CA59A009A9A3A /* UserLocalSecurityView.swift in Sources */, + BDF8BB6C2D5456B400628ADB /* SignOutIntervalSection.swift in Sources */, BDFF67B22D2CA59A009A9A3A /* UserProfileSettingsView.swift in Sources */, 4E204E592C574FD9004D22A2 /* CustomizeSettingsCoordinator.swift in Sources */, E1575E8C293E7B1E001665B1 /* UIScreen.swift in Sources */, @@ -5784,7 +5804,7 @@ E10231582BCF8AF8009D71FC /* WideChannelGridItem.swift in Sources */, E15D4F082B1B12C300442DB8 /* Backport.swift in Sources */, BDA623532D0D0854009A157F /* SelectUserBottomBar.swift in Sources */, - E1D4BF8F271A079A00A11E64 /* BasicAppSettingsView.swift in Sources */, + E1D4BF8F271A079A00A11E64 /* AppSettingsView.swift in Sources */, E1575E9A293E7B1E001665B1 /* Array.swift in Sources */, E1575E8D293E7B1E001665B1 /* URLComponents.swift in Sources */, E187A60329AB28F0008387E6 /* RotateContentView.swift in Sources */, diff --git a/Swiftfin/Views/AppSettingsView/AppSettingsView.swift b/Swiftfin/Views/AppSettingsView/AppSettingsView.swift index f6d3988d0..a23656b42 100644 --- a/Swiftfin/Views/AppSettingsView/AppSettingsView.swift +++ b/Swiftfin/Views/AppSettingsView/AppSettingsView.swift @@ -59,7 +59,7 @@ struct AppSettingsView: View { Section { - Toggle("Use splashscreen", isOn: $selectUserUseSplashscreen) + Toggle(L10n.useSplashscreen, isOn: $selectUserUseSplashscreen) if selectUserUseSplashscreen { Picker(L10n.servers, selection: $selectUserAllServersSplashscreen) { @@ -76,10 +76,10 @@ struct AppSettingsView: View { } } } header: { - Text("Splashscreen") + Text(L10n.splashscreen) } footer: { if selectUserUseSplashscreen { - Text("When All Servers is selected, use the splashscreen from a single server or a random server") + Text(L10n.splashscreenFooter) } } diff --git a/Swiftfin/Views/AppSettingsView/Components/SignOutIntervalSection.swift b/Swiftfin/Views/AppSettingsView/Components/SignOutIntervalSection.swift index 4e94f2c3a..cdc1542f6 100644 --- a/Swiftfin/Views/AppSettingsView/Components/SignOutIntervalSection.swift +++ b/Swiftfin/Views/AppSettingsView/Components/SignOutIntervalSection.swift @@ -25,17 +25,17 @@ extension AppSettingsView { var body: some View { Section { - Toggle("Sign out on close", isOn: $signOutOnClose) + Toggle(L10n.signoutClose, isOn: $signOutOnClose) } footer: { - Text("Signs out the last user when Swiftfin has been force closed") + Text(L10n.signoutCloseFooter) } Section { - Toggle("Sign out on background", isOn: $signOutOnBackground) + Toggle(L10n.signoutBackground, isOn: $signOutOnBackground) if signOutOnBackground { HStack { - Text("Duration") + Text(L10n.duration) Spacer() @@ -62,7 +62,7 @@ extension AppSettingsView { } } footer: { Text( - "Signs out the last user when Swiftfin has been in the background without media playback after some time" + L10n.signoutBackgroundFooter ) } .animation(.linear(duration: 0.15), value: isEditingBackgroundSignOutInterval) diff --git a/Translations/en.lproj/Localizable.strings b/Translations/en.lproj/Localizable.strings index a14893e87..2bea7ad19 100644 --- a/Translations/en.lproj/Localizable.strings +++ b/Translations/en.lproj/Localizable.strings @@ -727,6 +727,9 @@ /// %@ is already saved "duplicateUserSaved" = "%@ is already saved"; +/// Duration +"duration" = "Duration"; + /// DVD "dvd" = "DVD"; @@ -1717,6 +1720,18 @@ /// Sign In to %s "signInToServer" = "Sign In to %s"; +/// Sign out on background +"signoutBackground" = "Sign out on background"; + +/// Signs out the last user when Swiftfin has been in the background without media playback after some time +"signoutBackgroundFooter" = "Signs out the last user when Swiftfin has been in the background without media playback after some time"; + +/// Sign out on close +"signoutClose" = "Sign out on close"; + +/// Signs out the last user when Swiftfin has been force closed +"signoutCloseFooter" = "Signs out the last user when Swiftfin has been force closed"; + /// Slider "slider" = "Slider"; @@ -1747,6 +1762,12 @@ /// Special Features "specialFeatures" = "Special Features"; +/// Splashscreen +"splashscreen" = "Splashscreen"; + +/// When All Servers is selected, use the splashscreen from a single server or a random server +"splashscreenFooter" = "When All Servers is selected, use the splashscreen from a single server or a random server"; + /// Sports "sports" = "Sports"; @@ -2011,6 +2032,9 @@ /// Users "users" = "Users"; +/// Use splashscreen +"useSplashscreen" = "Use splashscreen"; + /// Version "version" = "Version";