[tvOS] Various Setting Cleanup (#1473)

* Various setting cleanup

* Remove Double headers

* My gradient did nothing... So resetting back to less.

* Reduce unnecessary formatting changes.

* Revisions https://github.com/jellyfin/Swiftfin/pull/1473#pullrequestreview-2745279339

* Subtitles was missing brightness. Subtitle shouldn't mirror title but image.

* Remove TODO.
This commit is contained in:
Joe Kribs 2025-04-06 16:05:33 -06:00 committed by GitHub
parent df89832647
commit c0b875ed2a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 102 additions and 57 deletions

View File

@ -512,6 +512,8 @@ internal enum L10n {
internal static let displayOrder = L10n.tr("Localizable", "displayOrder", fallback: "Display Order")
/// Done
internal static let done = L10n.tr("Localizable", "done", fallback: "Done")
/// Double touch
internal static let doubleTouch = L10n.tr("Localizable", "doubleTouch", fallback: "Double touch")
/// Downloads
internal static let downloads = L10n.tr("Localizable", "downloads", fallback: "Downloads")
/// Duplicate User
@ -646,6 +648,10 @@ internal enum L10n {
internal static let hint = L10n.tr("Localizable", "hint", fallback: "Hint")
/// Home
internal static let home = L10n.tr("Localizable", "home", fallback: "Home")
/// Horizontal pan
internal static let horizontalPan = L10n.tr("Localizable", "horizontalPan", fallback: "Horizontal pan")
/// Horizontal swipe
internal static let horizontalSwipe = L10n.tr("Localizable", "horizontalSwipe", fallback: "Horizontal swipe")
/// Hours
internal static let hours = L10n.tr("Localizable", "hours", fallback: "Hours")
/// ID
@ -724,6 +730,8 @@ internal enum L10n {
internal static let learnMoreEllipsis = L10n.tr("Localizable", "learnMoreEllipsis", fallback: "Learn more...")
/// Left
internal static let `left` = L10n.tr("Localizable", "left", fallback: "Left")
/// Left vertical pan
internal static let leftVerticalPan = L10n.tr("Localizable", "leftVerticalPan", fallback: "Left vertical pan")
/// Letter
internal static let letter = L10n.tr("Localizable", "letter", fallback: "Letter")
/// Letterer
@ -768,6 +776,8 @@ internal enum L10n {
internal static let logs = L10n.tr("Localizable", "logs", fallback: "Logs")
/// Access the Jellyfin server logs for troubleshooting and monitoring purposes.
internal static let logsDescription = L10n.tr("Localizable", "logsDescription", fallback: "Access the Jellyfin server logs for troubleshooting and monitoring purposes.")
/// Long press
internal static let longPress = L10n.tr("Localizable", "longPress", fallback: "Long press")
/// Lyricist
internal static let lyricist = L10n.tr("Localizable", "lyricist", fallback: "Lyricist")
/// Lyrics
@ -820,12 +830,16 @@ internal enum L10n {
internal static let minutes = L10n.tr("Localizable", "minutes", fallback: "Minutes")
/// Missing
internal static let missing = L10n.tr("Localizable", "missing", fallback: "Missing")
/// Missing codec values
internal static let missingCodecValues = L10n.tr("Localizable", "missingCodecValues", fallback: "Missing codec values")
/// Missing Items
internal static let missingItems = L10n.tr("Localizable", "missingItems", fallback: "Missing Items")
/// Mixer
internal static let mixer = L10n.tr("Localizable", "mixer", fallback: "Mixer")
/// Movies
internal static let movies = L10n.tr("Localizable", "movies", fallback: "Movies")
/// Multi tap
internal static let multiTap = L10n.tr("Localizable", "multiTap", fallback: "Multi tap")
/// Music
internal static let music = L10n.tr("Localizable", "music", fallback: "Music")
/// MVC
@ -860,6 +874,8 @@ internal enum L10n {
internal static let nextUpRewatch = L10n.tr("Localizable", "nextUpRewatch", fallback: "Rewatching in Next Up")
/// No
internal static let no = L10n.tr("Localizable", "no", fallback: "No")
/// No profiles defined. Playback issues may occur.
internal static let noDeviceProfileWarning = L10n.tr("Localizable", "noDeviceProfileWarning", fallback: "No profiles defined. Playback issues may occur.")
/// No episodes available
internal static let noEpisodesAvailable = L10n.tr("Localizable", "noEpisodesAvailable", fallback: "No episodes available")
/// No local servers found
@ -936,6 +952,8 @@ internal enum L10n {
internal static let permissions = L10n.tr("Localizable", "permissions", fallback: "Permissions")
/// Pin
internal static let pin = L10n.tr("Localizable", "pin", fallback: "Pin")
/// Pinch
internal static let pinch = L10n.tr("Localizable", "pinch", fallback: "Pinch")
/// Play
internal static let play = L10n.tr("Localizable", "play", fallback: "Play")
/// Play / Pause
@ -980,6 +998,8 @@ internal enum L10n {
internal static let profile = L10n.tr("Localizable", "profile", fallback: "Profile")
/// Profile Image
internal static let profileImage = L10n.tr("Localizable", "profileImage", fallback: "Profile Image")
/// Profile not saved
internal static let profileNotSaved = L10n.tr("Localizable", "profileNotSaved", fallback: "Profile not saved")
/// Profiles
internal static let profiles = L10n.tr("Localizable", "profiles", fallback: "Profiles")
/// Programs
@ -1058,6 +1078,8 @@ internal enum L10n {
internal static let replaceAll = L10n.tr("Localizable", "replaceAll", fallback: "Replace All")
/// Replace all unlocked metadata and images with new information.
internal static let replaceAllDescription = L10n.tr("Localizable", "replaceAllDescription", fallback: "Replace all unlocked metadata and images with new information.")
/// Current profile values may cause playback issues
internal static let replaceDeviceProfileWarning = L10n.tr("Localizable", "replaceDeviceProfileWarning", fallback: "Current profile values may cause playback issues")
/// Replace Images
internal static let replaceImages = L10n.tr("Localizable", "replaceImages", fallback: "Replace Images")
/// Replace all images with new images.
@ -1110,6 +1132,8 @@ internal enum L10n {
internal static let reviews = L10n.tr("Localizable", "reviews", fallback: "Reviews")
/// Right
internal static let `right` = L10n.tr("Localizable", "right", fallback: "Right")
/// Right vertical pan
internal static let rightVerticalPan = L10n.tr("Localizable", "rightVerticalPan", fallback: "Right vertical pan")
/// Role
internal static let role = L10n.tr("Localizable", "role", fallback: "Role")
/// Rotate

View File

@ -25,32 +25,32 @@ struct ListRowMenu<Content: View, Subtitle: View>: View {
var body: some View {
Menu(content: content) {
ZStack {
RoundedRectangle(cornerRadius: 10)
.fill(isFocused ? Color.white : Color.clear)
HStack {
title
.foregroundStyle(isFocused ? .black : .white)
.padding(.leading, 4)
HStack {
title
.foregroundStyle(isFocused ? Color.black : Color.white)
.padding(.leading, 4)
Spacer()
Spacer()
if let subtitle {
subtitle
.foregroundStyle(isFocused ? Color.black : Color.secondary)
.brightness(isFocused ? 0.4 : 0)
}
Image(systemName: "chevron.up.chevron.down")
.font(.body.weight(.regular))
.foregroundStyle(isFocused ? Color.black : Color.secondary)
if let subtitle {
subtitle
.foregroundStyle(isFocused ? .black : .secondary)
.brightness(isFocused ? 0.4 : 0)
}
.padding(.horizontal)
Image(systemName: "chevron.up.chevron.down")
.font(.body.weight(.regular))
.foregroundStyle(isFocused ? .black : .secondary)
.brightness(isFocused ? 0.4 : 0)
}
.scaleEffect(isFocused ? 1.05 : 1.0)
.animation(.spring(response: 0.15, dampingFraction: 0.75), value: isFocused)
.padding(.horizontal)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
.background(
RoundedRectangle(cornerRadius: 10)
.fill(isFocused ? Color.white : Color.clear)
)
.scaleEffect(isFocused ? 1.04 : 1.0)
.animation(.easeInOut(duration: 0.125), value: isFocused)
}
.menuStyle(.borderlessButton)
.listRowInsets(.zero)

View File

@ -90,7 +90,6 @@ struct OrderedSectionSelectorView<Element: Displayable & Hashable>: View {
}
.environment(\.editMode, editMode)
}
.withDescriptionTopPadding()
.animation(.linear(duration: 0.2), value: selection.value)
}
}

View File

@ -8,12 +8,8 @@
import SwiftUI
// TODO: See if `descriptionTopPadding` is really necessary to fix the navigation bar padding, or just add all the time
struct SplitFormWindowView: View {
private var descriptionTopPadding: Bool = false
private var contentView: () -> any View
private var descriptionView: () -> any View
@ -28,9 +24,7 @@ struct SplitFormWindowView: View {
contentView()
.eraseToAnyView()
}
.if(descriptionTopPadding) { view in
view.padding(.top)
}
.padding(.top)
.scrollClipDisabled()
}
}
@ -52,8 +46,4 @@ extension SplitFormWindowView {
func descriptionView(@ViewBuilder _ content: @escaping () -> any View) -> Self {
copy(modifying: \.descriptionView, with: content)
}
func withDescriptionTopPadding() -> Self {
copy(modifying: \.descriptionTopPadding, with: true)
}
}

View File

@ -49,6 +49,5 @@ struct FontPickerView: View {
}
}
}
.withDescriptionTopPadding()
}
}

View File

@ -78,7 +78,6 @@ struct EditServerView: View {
}
}
}
.withDescriptionTopPadding()
.navigationTitle(L10n.server)
.alert(L10n.deleteServer, isPresented: $isPresentingConfirmDeletion) {
Button(L10n.delete, role: .destructive) {

View File

@ -130,11 +130,11 @@ extension CustomDeviceProfileSettingsView {
.padding(.vertical)
if !isValid {
Label("Current profile values may cause playback issues", systemImage: "exclamationmark.circle.fill")
Label(L10n.replaceDeviceProfileWarning, systemImage: "exclamationmark.circle.fill")
}
}
.navigationTitle(L10n.customProfile)
.alert("Profile not saved", isPresented: $isPresentingNotSaved) {
.alert(L10n.profileNotSaved, isPresented: $isPresentingNotSaved) {
Button(L10n.close, role: .destructive) {
router.dismissCoordinator()
}

View File

@ -58,14 +58,14 @@ struct CustomDeviceProfileSettingsView: View {
}
if !isValid {
Label("No profiles defined. Playback issues may occur.", systemImage: "exclamationmark.circle.fill")
Label(L10n.noDeviceProfileWarning, systemImage: "exclamationmark.circle.fill")
}
}
}
Section {
if customProfiles.isEmpty {
Button("Add profile") {
Button(L10n.add) {
router.route(to: \.createCustomDeviceProfile)
}
}

View File

@ -77,7 +77,6 @@ struct CustomizeViewsSettings: View {
HomeSection()
}
.withDescriptionTopPadding()
.navigationTitle(L10n.customize)
}
}

View File

@ -43,7 +43,6 @@ struct IndicatorSettingsView: View {
Toggle(L10n.showWatched, isOn: $showWatched)
}
}
.withDescriptionTopPadding()
.navigationTitle(L10n.indicators)
}
}

View File

@ -71,7 +71,6 @@ struct UserProfileSettingsView: View {
// Text(L10n.resetSettingsDescription)
// }
}
.withDescriptionTopPadding()
.navigationTitle(L10n.user)
.confirmationDialog(
L10n.resetSettings,

View File

@ -73,7 +73,6 @@ struct VideoPlayerSettingsView: View {
Toggle(L10n.pauseOnBackground, isOn: $pauseOnBackground)
Toggle(L10n.playOnActive, isOn: $playOnActive)
}
.navigationTitle(L10n.videoPlayer.text)
.blurredFullScreenCover(isPresented: $isPresentingResumeOffsetStepper) {
StepperView(
title: L10n.resumeOffsetTitle,
@ -90,5 +89,6 @@ struct VideoPlayerSettingsView: View {
}
}
}
.navigationTitle(L10n.videoPlayer)
}
}

View File

@ -102,12 +102,13 @@ struct UserSignInView: View {
}
viewModel.send(.signIn(username: username, password: password, policy: .none))
}
.padding(.bottom)
if case .signingIn = viewModel.state {
ListRowButton(L10n.cancel, role: .cancel) {
viewModel.send(.cancel)
}
.padding(.vertical)
.padding(.bottom)
} else {
ListRowButton(L10n.signIn) {
viewModel.send(.signIn(username: username, password: password, policy: .none))
@ -118,7 +119,7 @@ struct UserSignInView: View {
username.isEmpty ? Color.white.opacity(0.5) : accentColor
)
.opacity(username.isEmpty ? 0.5 : 1)
.padding(.vertical)
.padding(.bottom)
}
if viewModel.isQuickConnectEnabled {

View File

@ -110,7 +110,7 @@ extension CustomDeviceProfileSettingsView {
}
} footer: {
if !isValid {
Label("Missing codec values", systemImage: "exclamationmark.circle.fill")
Label(L10n.missingCodecValues, systemImage: "exclamationmark.circle.fill")
.labelStyle(.sectionFooterWithImage(imageStyle: .orange))
}
}
@ -136,7 +136,7 @@ extension CustomDeviceProfileSettingsView {
.buttonStyle(.toolbarPill)
.disabled(!isValid)
}
.alert("Profile not saved", isPresented: $isPresentingNotSaved) {
.alert(L10n.profileNotSaved, isPresented: $isPresentingNotSaved) {
Button(L10n.close, role: .destructive) {
router.dismissCoordinator()
}

View File

@ -47,7 +47,7 @@ struct CustomDeviceProfileSettingsView: View {
}
if !isValid {
Label("No profiles defined. Playback issues may occur.", systemImage: "exclamationmark.circle.fill")
Label(L10n.noDeviceProfileWarning, systemImage: "exclamationmark.circle.fill")
.labelStyle(.sectionFooterWithImage(imageStyle: .orange))
}
}
@ -56,7 +56,7 @@ struct CustomDeviceProfileSettingsView: View {
Section(L10n.profiles) {
if customProfiles.isEmpty {
Button("Add profile") {
Button(L10n.add) {
router.route(to: \.createCustomDeviceProfile)
}
}

View File

@ -38,23 +38,23 @@ struct GestureSettingsView: View {
Section {
CaseIterablePicker("Horizontal Pan", selection: $horizontalPanGesture)
CaseIterablePicker(L10n.horizontalPan, selection: $horizontalPanGesture)
.disabled(horizontalSwipeGesture != .none && horizontalPanGesture == .none)
CaseIterablePicker("Horizontal Swipe", selection: $horizontalSwipeGesture)
CaseIterablePicker(L10n.horizontalSwipe, selection: $horizontalSwipeGesture)
.disabled(horizontalPanGesture != .none && horizontalSwipeGesture == .none)
CaseIterablePicker("Long Press", selection: $longPressGesture)
CaseIterablePicker(L10n.longPress, selection: $longPressGesture)
CaseIterablePicker("Multi Tap", selection: $multiTapGesture)
CaseIterablePicker(L10n.multiTap, selection: $multiTapGesture)
CaseIterablePicker("Double Touch", selection: $doubleTouchGesture)
CaseIterablePicker(L10n.doubleTouch, selection: $doubleTouchGesture)
CaseIterablePicker("Pinch", selection: $pinchGesture)
CaseIterablePicker(L10n.pinch, selection: $pinchGesture)
CaseIterablePicker("Left Vertical Pan", selection: $verticalPanGestureLeft)
CaseIterablePicker(L10n.leftVerticalPan, selection: $verticalPanGestureLeft)
CaseIterablePicker("Right Vertical Pan", selection: $verticalPanGestureRight)
CaseIterablePicker(L10n.rightVerticalPan, selection: $verticalPanGestureRight)
}
}
.navigationTitle(L10n.gestures)

View File

@ -724,6 +724,9 @@
/// Done
"done" = "Done";
/// Double touch
"doubleTouch" = "Double touch";
/// Downloads
"downloads" = "Downloads";
@ -913,6 +916,12 @@
/// Home
"home" = "Home";
/// Horizontal pan
"horizontalPan" = "Horizontal pan";
/// Horizontal swipe
"horizontalSwipe" = "Horizontal swipe";
/// Hours
"hours" = "Hours";
@ -1021,6 +1030,9 @@
/// Left
"left" = "Left";
/// Left vertical pan
"leftVerticalPan" = "Left vertical pan";
/// Letter
"letter" = "Letter";
@ -1087,6 +1099,9 @@
/// Access the Jellyfin server logs for troubleshooting and monitoring purposes.
"logsDescription" = "Access the Jellyfin server logs for troubleshooting and monitoring purposes.";
/// Long press
"longPress" = "Long press";
/// Lyricist
"lyricist" = "Lyricist";
@ -1165,6 +1180,9 @@
/// Missing
"missing" = "Missing";
/// Missing codec values
"missingCodecValues" = "Missing codec values";
/// Missing Items
"missingItems" = "Missing Items";
@ -1174,6 +1192,9 @@
/// Movies
"movies" = "Movies";
/// Multi tap
"multiTap" = "Multi tap";
/// Music
"music" = "Music";
@ -1225,6 +1246,9 @@
/// No
"no" = "No";
/// No profiles defined. Playback issues may occur.
"noDeviceProfileWarning" = "No profiles defined. Playback issues may occur.";
/// No episodes available
"noEpisodesAvailable" = "No episodes available";
@ -1336,6 +1360,9 @@
/// Pin
"pin" = "Pin";
/// Pinch
"pinch" = "Pinch";
/// Play
"play" = "Play";
@ -1402,6 +1429,9 @@
/// Profile Image
"profileImage" = "Profile Image";
/// Profile not saved
"profileNotSaved" = "Profile not saved";
/// Profiles
"profiles" = "Profiles";
@ -1516,6 +1546,9 @@
/// Replace all unlocked metadata and images with new information.
"replaceAllDescription" = "Replace all unlocked metadata and images with new information.";
/// Current profile values may cause playback issues
"replaceDeviceProfileWarning" = "Current profile values may cause playback issues";
/// Replace Images
"replaceImages" = "Replace Images";
@ -1591,6 +1624,9 @@
/// Right
"right" = "Right";
/// Right vertical pan
"rightVerticalPan" = "Right vertical pan";
/// Role
"role" = "Role";