[tvOS] Settings Cleanup (#1163)
* Settings Cleanup. Replace strings with labels. Enforce the same font. Ensure Forms don't get clipped by their boundries. Create consistent, reusable button sizing/coloring. Apply to all Settings Pages. * Remove custom Button/Form styling in exchange for just using .scrollClipDisabled() * Swap back to Jellyfin Purple from Purple. * Remove Check Button. Check all Section Inits where possible. Make Server Details Server non-focusable. Create a new menu for Server Details selection. This is a WIP awaiting feedback from https://github.com/jellyfin/Swiftfin/pull/1163#discussion_r1705957885 --------- Co-authored-by: Joseph Kribs <joseph@kribs.net>
This commit is contained in:
parent
0ae1324534
commit
e4fd98c244
|
@ -19,6 +19,7 @@ struct TextPairView: View {
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack {
|
HStack {
|
||||||
Text(leading)
|
Text(leading)
|
||||||
|
.foregroundColor(.primary)
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,8 @@ internal enum L10n {
|
||||||
internal static let accentColorDescription = L10n.tr("Localizable", "accentColorDescription", fallback: "Some views may need an app restart to update.")
|
internal static let accentColorDescription = L10n.tr("Localizable", "accentColorDescription", fallback: "Some views may need an app restart to update.")
|
||||||
/// Accessibility
|
/// Accessibility
|
||||||
internal static let accessibility = L10n.tr("Localizable", "accessibility", fallback: "Accessibility")
|
internal static let accessibility = L10n.tr("Localizable", "accessibility", fallback: "Accessibility")
|
||||||
|
/// Add Server
|
||||||
|
internal static let addServer = L10n.tr("Localizable", "addServer", fallback: "Add Server")
|
||||||
/// Add URL
|
/// Add URL
|
||||||
internal static let addURL = L10n.tr("Localizable", "addURL", fallback: "Add URL")
|
internal static let addURL = L10n.tr("Localizable", "addURL", fallback: "Add URL")
|
||||||
/// Advanced
|
/// Advanced
|
||||||
|
@ -30,6 +32,8 @@ internal enum L10n {
|
||||||
internal static let allGenres = L10n.tr("Localizable", "allGenres", fallback: "All Genres")
|
internal static let allGenres = L10n.tr("Localizable", "allGenres", fallback: "All Genres")
|
||||||
/// All Media
|
/// All Media
|
||||||
internal static let allMedia = L10n.tr("Localizable", "allMedia", fallback: "All Media")
|
internal static let allMedia = L10n.tr("Localizable", "allMedia", fallback: "All Media")
|
||||||
|
/// All Servers
|
||||||
|
internal static let allServers = L10n.tr("Localizable", "allServers", fallback: "All Servers")
|
||||||
/// Appearance
|
/// Appearance
|
||||||
internal static let appearance = L10n.tr("Localizable", "appearance", fallback: "Appearance")
|
internal static let appearance = L10n.tr("Localizable", "appearance", fallback: "Appearance")
|
||||||
/// App Icon
|
/// App Icon
|
||||||
|
@ -112,6 +116,8 @@ internal enum L10n {
|
||||||
internal static let chapterSlider = L10n.tr("Localizable", "chapterSlider", fallback: "Chapter Slider")
|
internal static let chapterSlider = L10n.tr("Localizable", "chapterSlider", fallback: "Chapter Slider")
|
||||||
/// Cinematic
|
/// Cinematic
|
||||||
internal static let cinematic = L10n.tr("Localizable", "cinematic", fallback: "Cinematic")
|
internal static let cinematic = L10n.tr("Localizable", "cinematic", fallback: "Cinematic")
|
||||||
|
/// Cinematic Background
|
||||||
|
internal static let cinematicBackground = L10n.tr("Localizable", "cinematicBackground", fallback: "Cinematic Background")
|
||||||
/// Cinematic Views
|
/// Cinematic Views
|
||||||
internal static let cinematicViews = L10n.tr("Localizable", "cinematicViews", fallback: "Cinematic Views")
|
internal static let cinematicViews = L10n.tr("Localizable", "cinematicViews", fallback: "Cinematic Views")
|
||||||
/// Close
|
/// Close
|
||||||
|
@ -160,6 +166,10 @@ internal enum L10n {
|
||||||
internal static let dark = L10n.tr("Localizable", "dark", fallback: "Dark")
|
internal static let dark = L10n.tr("Localizable", "dark", fallback: "Dark")
|
||||||
/// Default Scheme
|
/// Default Scheme
|
||||||
internal static let defaultScheme = L10n.tr("Localizable", "defaultScheme", fallback: "Default Scheme")
|
internal static let defaultScheme = L10n.tr("Localizable", "defaultScheme", fallback: "Default Scheme")
|
||||||
|
/// Delete
|
||||||
|
internal static let delete = L10n.tr("Localizable", "delete", fallback: "Delete")
|
||||||
|
/// Delete Server
|
||||||
|
internal static let deleteServer = L10n.tr("Localizable", "deleteServer", fallback: "Delete Server")
|
||||||
/// Delivery
|
/// Delivery
|
||||||
internal static let delivery = L10n.tr("Localizable", "delivery", fallback: "Delivery")
|
internal static let delivery = L10n.tr("Localizable", "delivery", fallback: "Delivery")
|
||||||
/// DIRECTOR
|
/// DIRECTOR
|
||||||
|
@ -176,6 +186,8 @@ internal enum L10n {
|
||||||
internal static let downloads = L10n.tr("Localizable", "downloads", fallback: "Downloads")
|
internal static let downloads = L10n.tr("Localizable", "downloads", fallback: "Downloads")
|
||||||
/// Edit Jump Lengths
|
/// Edit Jump Lengths
|
||||||
internal static let editJumpLengths = L10n.tr("Localizable", "editJumpLengths", fallback: "Edit Jump Lengths")
|
internal static let editJumpLengths = L10n.tr("Localizable", "editJumpLengths", fallback: "Edit Jump Lengths")
|
||||||
|
/// Edit Server
|
||||||
|
internal static let editServer = L10n.tr("Localizable", "editServer", fallback: "Edit Server")
|
||||||
/// Empty Next Up
|
/// Empty Next Up
|
||||||
internal static let emptyNextUp = L10n.tr("Localizable", "emptyNextUp", fallback: "Empty Next Up")
|
internal static let emptyNextUp = L10n.tr("Localizable", "emptyNextUp", fallback: "Empty Next Up")
|
||||||
/// Enabled
|
/// Enabled
|
||||||
|
@ -228,6 +240,8 @@ internal enum L10n {
|
||||||
internal static let invertedLight = L10n.tr("Localizable", "invertedLight", fallback: "Inverted Light")
|
internal static let invertedLight = L10n.tr("Localizable", "invertedLight", fallback: "Inverted Light")
|
||||||
/// Items
|
/// Items
|
||||||
internal static let items = L10n.tr("Localizable", "items", fallback: "Items")
|
internal static let items = L10n.tr("Localizable", "items", fallback: "Items")
|
||||||
|
/// Jellyfin
|
||||||
|
internal static let jellyfin = L10n.tr("Localizable", "jellyfin", fallback: "Jellyfin")
|
||||||
/// Jump
|
/// Jump
|
||||||
internal static let jump = L10n.tr("Localizable", "jump", fallback: "Jump")
|
internal static let jump = L10n.tr("Localizable", "jump", fallback: "Jump")
|
||||||
/// Jump Backward
|
/// Jump Backward
|
||||||
|
@ -338,6 +352,8 @@ internal enum L10n {
|
||||||
}
|
}
|
||||||
/// No title
|
/// No title
|
||||||
internal static let noTitle = L10n.tr("Localizable", "noTitle", fallback: "No title")
|
internal static let noTitle = L10n.tr("Localizable", "noTitle", fallback: "No title")
|
||||||
|
/// Offset
|
||||||
|
internal static let offset = L10n.tr("Localizable", "offset", fallback: "Offset")
|
||||||
/// Ok
|
/// Ok
|
||||||
internal static let ok = L10n.tr("Localizable", "ok", fallback: "Ok")
|
internal static let ok = L10n.tr("Localizable", "ok", fallback: "Ok")
|
||||||
/// 1 user
|
/// 1 user
|
||||||
|
@ -380,6 +396,8 @@ internal enum L10n {
|
||||||
internal static let playback = L10n.tr("Localizable", "playback", fallback: "Playback")
|
internal static let playback = L10n.tr("Localizable", "playback", fallback: "Playback")
|
||||||
/// Playback Buttons
|
/// Playback Buttons
|
||||||
internal static let playbackButtons = L10n.tr("Localizable", "playbackButtons", fallback: "Playback Buttons")
|
internal static let playbackButtons = L10n.tr("Localizable", "playbackButtons", fallback: "Playback Buttons")
|
||||||
|
/// Playback Quality
|
||||||
|
internal static let playbackQuality = L10n.tr("Localizable", "playbackQuality", fallback: "Playback Quality")
|
||||||
/// Playback settings
|
/// Playback settings
|
||||||
internal static let playbackSettings = L10n.tr("Localizable", "playbackSettings", fallback: "Playback settings")
|
internal static let playbackSettings = L10n.tr("Localizable", "playbackSettings", fallback: "Playback settings")
|
||||||
/// Playback Speed
|
/// Playback Speed
|
||||||
|
@ -474,12 +492,16 @@ internal enum L10n {
|
||||||
internal static let resetAppSettings = L10n.tr("Localizable", "resetAppSettings", fallback: "Reset App Settings")
|
internal static let resetAppSettings = L10n.tr("Localizable", "resetAppSettings", fallback: "Reset App Settings")
|
||||||
/// Reset User Settings
|
/// Reset User Settings
|
||||||
internal static let resetUserSettings = L10n.tr("Localizable", "resetUserSettings", fallback: "Reset User Settings")
|
internal static let resetUserSettings = L10n.tr("Localizable", "resetUserSettings", fallback: "Reset User Settings")
|
||||||
|
/// Resume
|
||||||
|
internal static let resume = L10n.tr("Localizable", "resume", fallback: "Resume")
|
||||||
/// Resume 5 Second Offset
|
/// Resume 5 Second Offset
|
||||||
internal static let resume5SecondOffset = L10n.tr("Localizable", "resume5SecondOffset", fallback: "Resume 5 Second Offset")
|
internal static let resume5SecondOffset = L10n.tr("Localizable", "resume5SecondOffset", fallback: "Resume 5 Second Offset")
|
||||||
/// Resume Offset
|
/// Resume Offset
|
||||||
internal static let resumeOffset = L10n.tr("Localizable", "resumeOffset", fallback: "Resume Offset")
|
internal static let resumeOffset = L10n.tr("Localizable", "resumeOffset", fallback: "Resume Offset")
|
||||||
/// Resume content seconds before the recorded resume time
|
/// Resume content seconds before the recorded resume time
|
||||||
internal static let resumeOffsetDescription = L10n.tr("Localizable", "resumeOffsetDescription", fallback: "Resume content seconds before the recorded resume time")
|
internal static let resumeOffsetDescription = L10n.tr("Localizable", "resumeOffsetDescription", fallback: "Resume content seconds before the recorded resume time")
|
||||||
|
/// Resume Offset
|
||||||
|
internal static let resumeOffsetTitle = L10n.tr("Localizable", "resumeOffsetTitle", fallback: "Resume Offset")
|
||||||
/// Retrieving media information
|
/// Retrieving media information
|
||||||
internal static let retrievingMediaInformation = L10n.tr("Localizable", "retrievingMediaInformation", fallback: "Retrieving media information")
|
internal static let retrievingMediaInformation = L10n.tr("Localizable", "retrievingMediaInformation", fallback: "Retrieving media information")
|
||||||
/// Retry
|
/// Retry
|
||||||
|
@ -540,6 +562,10 @@ internal enum L10n {
|
||||||
internal static let showCastAndCrew = L10n.tr("Localizable", "showCastAndCrew", fallback: "Show Cast & Crew")
|
internal static let showCastAndCrew = L10n.tr("Localizable", "showCastAndCrew", fallback: "Show Cast & Crew")
|
||||||
/// Show Chapters Info In Bottom Overlay
|
/// Show Chapters Info In Bottom Overlay
|
||||||
internal static let showChaptersInfoInBottomOverlay = L10n.tr("Localizable", "showChaptersInfoInBottomOverlay", fallback: "Show Chapters Info In Bottom Overlay")
|
internal static let showChaptersInfoInBottomOverlay = L10n.tr("Localizable", "showChaptersInfoInBottomOverlay", fallback: "Show Chapters Info In Bottom Overlay")
|
||||||
|
/// Show Favorited
|
||||||
|
internal static let showFavorited = L10n.tr("Localizable", "showFavorited", fallback: "Show Favorited")
|
||||||
|
/// Show Favorites
|
||||||
|
internal static let showFavorites = L10n.tr("Localizable", "showFavorites", fallback: "Show Favorites")
|
||||||
/// Flatten Library Items
|
/// Flatten Library Items
|
||||||
internal static let showFlattenView = L10n.tr("Localizable", "showFlattenView", fallback: "Flatten Library Items")
|
internal static let showFlattenView = L10n.tr("Localizable", "showFlattenView", fallback: "Flatten Library Items")
|
||||||
/// Show Missing Episodes
|
/// Show Missing Episodes
|
||||||
|
@ -548,6 +574,14 @@ internal enum L10n {
|
||||||
internal static let showMissingSeasons = L10n.tr("Localizable", "showMissingSeasons", fallback: "Show Missing Seasons")
|
internal static let showMissingSeasons = L10n.tr("Localizable", "showMissingSeasons", fallback: "Show Missing Seasons")
|
||||||
/// Show Poster Labels
|
/// Show Poster Labels
|
||||||
internal static let showPosterLabels = L10n.tr("Localizable", "showPosterLabels", fallback: "Show Poster Labels")
|
internal static let showPosterLabels = L10n.tr("Localizable", "showPosterLabels", fallback: "Show Poster Labels")
|
||||||
|
/// Show Progress
|
||||||
|
internal static let showProgress = L10n.tr("Localizable", "showProgress", fallback: "Show Progress")
|
||||||
|
/// Show Recently Added
|
||||||
|
internal static let showRecentlyAdded = L10n.tr("Localizable", "showRecentlyAdded", fallback: "Show Recently Added")
|
||||||
|
/// Show Unwatched
|
||||||
|
internal static let showUnwatched = L10n.tr("Localizable", "showUnwatched", fallback: "Show Unwatched")
|
||||||
|
/// Show Watched
|
||||||
|
internal static let showWatched = L10n.tr("Localizable", "showWatched", fallback: "Show Watched")
|
||||||
/// Signed in as %@
|
/// Signed in as %@
|
||||||
internal static func signedInAsWithString(_ p1: Any) -> String {
|
internal static func signedInAsWithString(_ p1: Any) -> String {
|
||||||
return L10n.tr("Localizable", "signedInAsWithString", String(describing: p1), fallback: "Signed in as %@")
|
return L10n.tr("Localizable", "signedInAsWithString", String(describing: p1), fallback: "Signed in as %@")
|
||||||
|
@ -594,6 +628,8 @@ internal enum L10n {
|
||||||
internal static let subtitleOffset = L10n.tr("Localizable", "subtitleOffset", fallback: "Subtitle Offset")
|
internal static let subtitleOffset = L10n.tr("Localizable", "subtitleOffset", fallback: "Subtitle Offset")
|
||||||
/// Subtitles
|
/// Subtitles
|
||||||
internal static let subtitles = L10n.tr("Localizable", "subtitles", fallback: "Subtitles")
|
internal static let subtitles = L10n.tr("Localizable", "subtitles", fallback: "Subtitles")
|
||||||
|
/// Settings only affect some subtitle types
|
||||||
|
internal static let subtitlesDisclaimer = L10n.tr("Localizable", "subtitlesDisclaimer", fallback: "Settings only affect some subtitle types")
|
||||||
/// Subtitle Size
|
/// Subtitle Size
|
||||||
internal static let subtitleSize = L10n.tr("Localizable", "subtitleSize", fallback: "Subtitle Size")
|
internal static let subtitleSize = L10n.tr("Localizable", "subtitleSize", fallback: "Subtitle Size")
|
||||||
/// Suggestions
|
/// Suggestions
|
||||||
|
|
|
@ -31,6 +31,7 @@ struct SplitFormWindowView: View {
|
||||||
.if(descriptionTopPadding) { view in
|
.if(descriptionTopPadding) { view in
|
||||||
view.padding(.top)
|
view.padding(.top)
|
||||||
}
|
}
|
||||||
|
.scrollClipDisabled()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ struct SelectServerView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
FullScreenMenu("Servers") {
|
FullScreenMenu(L10n.servers) {
|
||||||
Section {
|
Section {
|
||||||
Button {
|
Button {
|
||||||
router.popLast {
|
router.popLast {
|
||||||
|
@ -47,7 +47,7 @@ struct SelectServerView: View {
|
||||||
}
|
}
|
||||||
} label: {
|
} label: {
|
||||||
HStack {
|
HStack {
|
||||||
Text("Add Server")
|
L10n.addServer.text
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ struct SelectServerView: View {
|
||||||
}
|
}
|
||||||
} label: {
|
} label: {
|
||||||
HStack {
|
HStack {
|
||||||
Text("Edit Server")
|
L10n.editServer.text
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ struct SelectServerView: View {
|
||||||
router.popLast()
|
router.popLast()
|
||||||
} label: {
|
} label: {
|
||||||
HStack {
|
HStack {
|
||||||
Text("All Servers")
|
L10n.allServers.text
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
|
@ -116,9 +116,10 @@ struct SelectServerView: View {
|
||||||
.padding()
|
.padding()
|
||||||
}
|
}
|
||||||
.buttonStyle(.card)
|
.buttonStyle(.card)
|
||||||
|
.padding(.horizontal)
|
||||||
}
|
}
|
||||||
} header: {
|
} header: {
|
||||||
Text("Servers")
|
Text(L10n.servers)
|
||||||
}
|
}
|
||||||
.headerProminence(.increased)
|
.headerProminence(.increased)
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,36 +35,61 @@ struct EditServerView: View {
|
||||||
.frame(maxWidth: 400)
|
.frame(maxWidth: 400)
|
||||||
}
|
}
|
||||||
.contentView {
|
.contentView {
|
||||||
|
|
||||||
Section(L10n.server) {
|
Section(L10n.server) {
|
||||||
TextPairView(
|
TextPairView(
|
||||||
leading: L10n.name,
|
leading: L10n.name,
|
||||||
trailing: viewModel.server.name
|
trailing: viewModel.server.name
|
||||||
)
|
)
|
||||||
|
.focusable(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
Section("URL") {
|
Section(L10n.url) {
|
||||||
ForEach(viewModel.server.urls.sorted(using: \.absoluteString)) { url in
|
Menu {
|
||||||
if url == viewModel.server.currentURL {
|
ForEach(viewModel.server.urls.sorted(using: \.absoluteString), id: \.self) { url in
|
||||||
Button(url.absoluteString, systemImage: "checkmark") {}
|
Button(action: {
|
||||||
} else {
|
guard viewModel.server.currentURL != url else { return }
|
||||||
Button(url.absoluteString) {
|
|
||||||
viewModel.setCurrentURL(to: url)
|
viewModel.setCurrentURL(to: url)
|
||||||
|
}) {
|
||||||
|
HStack {
|
||||||
|
Text(url.absoluteString)
|
||||||
|
.foregroundColor(.primary)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
if viewModel.server.currentURL == url {
|
||||||
|
Image(systemName: "checkmark")
|
||||||
|
.font(.body.weight(.regular))
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} label: {
|
||||||
|
HStack {
|
||||||
|
Text(viewModel.server.currentURL.absoluteString)
|
||||||
|
.foregroundColor(.primary)
|
||||||
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
Spacer()
|
||||||
|
Image(systemName: "chevron.down")
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if isEditing {
|
if isEditing {
|
||||||
ListRowButton("Delete") {
|
Section {
|
||||||
isPresentingConfirmDeletion = true
|
ListRowButton(L10n.delete) {
|
||||||
|
isPresentingConfirmDeletion = true
|
||||||
|
}
|
||||||
|
.foregroundStyle(.primary, .red.opacity(0.5))
|
||||||
}
|
}
|
||||||
.foregroundStyle(.primary, .red.opacity(0.5))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.withDescriptionTopPadding()
|
.withDescriptionTopPadding()
|
||||||
.navigationTitle(L10n.server)
|
.navigationTitle(L10n.server)
|
||||||
.alert("Delete Server", isPresented: $isPresentingConfirmDeletion) {
|
.alert(L10n.deleteServer, isPresented: $isPresentingConfirmDeletion) {
|
||||||
Button("Delete", role: .destructive) {
|
Button(L10n.delete, role: .destructive) {
|
||||||
viewModel.delete()
|
viewModel.delete()
|
||||||
router.popLast()
|
router.popLast()
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,18 +53,16 @@ struct CustomizeViewsSettings: View {
|
||||||
}
|
}
|
||||||
.contentView {
|
.contentView {
|
||||||
|
|
||||||
Section {
|
Section(L10n.missingItems) {
|
||||||
|
|
||||||
Toggle(L10n.showMissingSeasons, isOn: $shouldShowMissingSeasons)
|
Toggle(L10n.showMissingSeasons, isOn: $shouldShowMissingSeasons)
|
||||||
|
|
||||||
Toggle(L10n.showMissingEpisodes, isOn: $shouldShowMissingEpisodes)
|
Toggle(L10n.showMissingEpisodes, isOn: $shouldShowMissingEpisodes)
|
||||||
} header: {
|
|
||||||
L10n.missingItems.text
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Section {
|
Section(L10n.posters) {
|
||||||
|
|
||||||
ChevronButton("Indicators")
|
ChevronButton(L10n.indicators)
|
||||||
.onSelect {
|
.onSelect {
|
||||||
router.route(to: \.indicatorSettings)
|
router.route(to: \.indicatorSettings)
|
||||||
}
|
}
|
||||||
|
@ -82,23 +80,17 @@ struct CustomizeViewsSettings: View {
|
||||||
InlineEnumToggle(title: L10n.search, selection: $searchPosterType)
|
InlineEnumToggle(title: L10n.search, selection: $searchPosterType)
|
||||||
|
|
||||||
InlineEnumToggle(title: L10n.library, selection: $libraryViewType)
|
InlineEnumToggle(title: L10n.library, selection: $libraryViewType)
|
||||||
|
|
||||||
} header: {
|
|
||||||
Text("Posters")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Section {
|
Section(L10n.library) {
|
||||||
|
|
||||||
Toggle("Cinematic Background", isOn: $cinematicBackground)
|
Toggle(L10n.cinematicBackground, isOn: $cinematicBackground)
|
||||||
|
|
||||||
Toggle("Random Image", isOn: $libraryRandomImage)
|
Toggle(L10n.randomImage, isOn: $libraryRandomImage)
|
||||||
|
|
||||||
Toggle("Show Favorites", isOn: $showFavorites)
|
Toggle(L10n.showFavorites, isOn: $showFavorites)
|
||||||
|
|
||||||
Toggle("Show Recently Added", isOn: $showRecentlyAdded)
|
Toggle(L10n.showRecentlyAdded, isOn: $showRecentlyAdded)
|
||||||
|
|
||||||
} header: {
|
|
||||||
L10n.library.text
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.withDescriptionTopPadding()
|
.withDescriptionTopPadding()
|
||||||
|
|
|
@ -25,20 +25,15 @@ struct ExperimentalSettingsView: View {
|
||||||
.frame(maxWidth: 400)
|
.frame(maxWidth: 400)
|
||||||
}
|
}
|
||||||
.contentView {
|
.contentView {
|
||||||
Section {
|
|
||||||
|
Section("Video Player") {
|
||||||
|
|
||||||
Toggle("Force Direct Play", isOn: $forceDirectPlay)
|
Toggle("Force Direct Play", isOn: $forceDirectPlay)
|
||||||
|
|
||||||
} header: {
|
|
||||||
Text("Video Player")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Section {
|
Section("Live TV") {
|
||||||
|
|
||||||
Toggle("Live TV Force Direct Play", isOn: $liveTVForceDirectPlay)
|
Toggle("Live TV Force Direct Play", isOn: $liveTVForceDirectPlay)
|
||||||
|
|
||||||
} header: {
|
|
||||||
Text("Live TV")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.navigationTitle(L10n.experimental)
|
.navigationTitle(L10n.experimental)
|
||||||
|
|
|
@ -32,18 +32,18 @@ struct IndicatorSettingsView: View {
|
||||||
}
|
}
|
||||||
.contentView {
|
.contentView {
|
||||||
|
|
||||||
Section {
|
Section(L10n.posters) {
|
||||||
|
|
||||||
Toggle("Show Favorited", isOn: $showFavorited)
|
Toggle(L10n.showFavorited, isOn: $showFavorited)
|
||||||
|
|
||||||
Toggle("Show Progress", isOn: $showProgress)
|
Toggle(L10n.showProgress, isOn: $showProgress)
|
||||||
|
|
||||||
Toggle("Show Unwatched", isOn: $showUnwatched)
|
Toggle(L10n.showUnwatched, isOn: $showUnwatched)
|
||||||
|
|
||||||
Toggle("Show Watched", isOn: $showWatched)
|
Toggle(L10n.showWatched, isOn: $showWatched)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.withDescriptionTopPadding()
|
.withDescriptionTopPadding()
|
||||||
.navigationTitle("Indicators")
|
.navigationTitle(L10n.indicators)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,21 +24,19 @@ struct MaximumBitrateSettingsView: View {
|
||||||
.frame(maxWidth: 400)
|
.frame(maxWidth: 400)
|
||||||
}
|
}
|
||||||
.contentView {
|
.contentView {
|
||||||
|
|
||||||
Section {
|
Section {
|
||||||
CaseIterablePicker(
|
|
||||||
L10n.maximumBitrate,
|
InlineEnumToggle(title: L10n.maximumBitrate, selection: $appMaximumBitrate)
|
||||||
selection: $appMaximumBitrate
|
|
||||||
)
|
|
||||||
|
|
||||||
if appMaximumBitrate == PlaybackBitrate.auto {
|
if appMaximumBitrate == PlaybackBitrate.auto {
|
||||||
CaseIterablePicker(
|
InlineEnumToggle(title: L10n.testSize, selection: $appMaximumBitrateTest)
|
||||||
L10n.testSize,
|
|
||||||
selection: $appMaximumBitrateTest
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
} header: {
|
||||||
|
L10n.playbackQuality.text
|
||||||
} footer: {
|
} footer: {
|
||||||
if appMaximumBitrate == PlaybackBitrate.auto {
|
if appMaximumBitrate == PlaybackBitrate.auto {
|
||||||
Text(L10n.bitrateTestDescription)
|
L10n.bitrateTestDescription.text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ struct SettingsView: View {
|
||||||
.frame(maxWidth: 400)
|
.frame(maxWidth: 400)
|
||||||
}
|
}
|
||||||
.contentView {
|
.contentView {
|
||||||
Section {
|
Section(L10n.jellyfin) {
|
||||||
|
|
||||||
Button {} label: {
|
Button {} label: {
|
||||||
TextPairView(
|
TextPairView(
|
||||||
|
@ -51,14 +51,23 @@ struct SettingsView: View {
|
||||||
Button {
|
Button {
|
||||||
viewModel.signOut()
|
viewModel.signOut()
|
||||||
} label: {
|
} label: {
|
||||||
L10n.switchUser.text
|
HStack {
|
||||||
.foregroundColor(.jellyfinPurple)
|
|
||||||
|
Text(L10n.switchUser)
|
||||||
|
.foregroundColor(.jellyfinPurple)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
Image(systemName: "chevron.right")
|
||||||
|
.font(.body.weight(.regular))
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Section {
|
Section(L10n.videoPlayer) {
|
||||||
|
|
||||||
InlineEnumToggle(title: "Video Player Type", selection: $videoPlayerType)
|
InlineEnumToggle(title: L10n.videoPlayerType, selection: $videoPlayerType)
|
||||||
|
|
||||||
ChevronButton(L10n.videoPlayer)
|
ChevronButton(L10n.videoPlayer)
|
||||||
.onSelect {
|
.onSelect {
|
||||||
|
@ -69,12 +78,9 @@ struct SettingsView: View {
|
||||||
.onSelect {
|
.onSelect {
|
||||||
router.route(to: \.maximumBitrateSettings)
|
router.route(to: \.maximumBitrateSettings)
|
||||||
}
|
}
|
||||||
|
|
||||||
} header: {
|
|
||||||
L10n.videoPlayer.text
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Section {
|
Section(L10n.accessibility) {
|
||||||
|
|
||||||
ChevronButton(L10n.customize)
|
ChevronButton(L10n.customize)
|
||||||
.onSelect {
|
.onSelect {
|
||||||
|
@ -85,14 +91,11 @@ struct SettingsView: View {
|
||||||
.onSelect {
|
.onSelect {
|
||||||
router.route(to: \.experimentalSettings)
|
router.route(to: \.experimentalSettings)
|
||||||
}
|
}
|
||||||
|
|
||||||
} header: {
|
|
||||||
L10n.accessibility.text
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Section {
|
Section {
|
||||||
|
|
||||||
ChevronButton("Logs")
|
ChevronButton(L10n.logs)
|
||||||
.onSelect {
|
.onSelect {
|
||||||
router.route(to: \.log)
|
router.route(to: \.log)
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,46 +43,51 @@ struct VideoPlayerSettingsView: View {
|
||||||
.contentView {
|
.contentView {
|
||||||
|
|
||||||
Section {
|
Section {
|
||||||
|
|
||||||
ChevronButton(
|
ChevronButton(
|
||||||
"Resume Offset",
|
L10n.offset,
|
||||||
subtitle: resumeOffset.secondLabel
|
subtitle: resumeOffset.secondLabel
|
||||||
)
|
)
|
||||||
.onSelect {
|
.onSelect {
|
||||||
isPresentingResumeOffsetStepper = true
|
isPresentingResumeOffsetStepper = true
|
||||||
}
|
}
|
||||||
|
} header: {
|
||||||
|
L10n.resume.text
|
||||||
} footer: {
|
} footer: {
|
||||||
Text("Resume content seconds before the recorded resume time")
|
L10n.resumeOffsetDescription.text
|
||||||
}
|
}
|
||||||
|
|
||||||
Section {
|
Section {
|
||||||
|
|
||||||
ChevronButton(L10n.subtitleFont, subtitle: subtitleFontName)
|
ChevronButton(L10n.subtitleFont, subtitle: subtitleFontName)
|
||||||
.onSelect {
|
.onSelect {
|
||||||
router.route(to: \.fontPicker, $subtitleFontName)
|
router.route(to: \.fontPicker, $subtitleFontName)
|
||||||
}
|
}
|
||||||
|
} header: {
|
||||||
|
L10n.subtitles.text
|
||||||
} footer: {
|
} footer: {
|
||||||
Text("Settings only affect some subtitle types")
|
L10n.subtitlesDisclaimer.text
|
||||||
}
|
}
|
||||||
|
|
||||||
Section {
|
Section(L10n.playback) {
|
||||||
|
Toggle(L10n.pauseOnBackground, isOn: $pauseOnBackground)
|
||||||
Toggle("Pause on background", isOn: $pauseOnBackground)
|
Toggle(L10n.playOnActive, isOn: $playOnActive)
|
||||||
Toggle("Play on active", isOn: $playOnActive)
|
|
||||||
}
|
}
|
||||||
}
|
.navigationTitle(L10n.videoPlayer.text)
|
||||||
.navigationTitle("Video Player")
|
.blurFullScreenCover(isPresented: $isPresentingResumeOffsetStepper) {
|
||||||
.blurFullScreenCover(isPresented: $isPresentingResumeOffsetStepper) {
|
StepperView(
|
||||||
StepperView(
|
title: L10n.resumeOffsetTitle,
|
||||||
title: "Resume Offset",
|
description: L10n.resumeOffsetDescription,
|
||||||
description: "Resume content seconds before the recorded resume time",
|
value: $resumeOffset,
|
||||||
value: $resumeOffset,
|
range: 0 ... 30,
|
||||||
range: 0 ... 30,
|
step: 1
|
||||||
step: 1
|
)
|
||||||
)
|
.valueFormatter {
|
||||||
.valueFormatter {
|
$0.secondLabel
|
||||||
$0.secondLabel
|
}
|
||||||
}
|
.onCloseSelected {
|
||||||
.onCloseSelected {
|
isPresentingResumeOffsetStepper = false
|
||||||
isPresentingResumeOffsetStepper = false
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
Loading…
Reference in New Issue