mirror of
https://github.com/jellyfin/Swiftfin.git
synced 2024-12-03 11:41:12 +00:00
localize
This commit is contained in:
parent
a02d9a225c
commit
057beca0ff
@ -32,7 +32,7 @@ final class LiveTVTabCoordinator: TabCoordinatable {
|
||||
func makeProgramsTab(isActive: Bool) -> some View {
|
||||
HStack {
|
||||
Image(systemName: "tv")
|
||||
Text("Programs")
|
||||
L10n.programs.text
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ final class LiveTVTabCoordinator: TabCoordinatable {
|
||||
func makeChannelsTab(isActive: Bool) -> some View {
|
||||
HStack {
|
||||
Image(systemName: "square.grid.3x3")
|
||||
Text("Channels")
|
||||
L10n.channels.text
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,7 +56,7 @@ final class LiveTVTabCoordinator: TabCoordinatable {
|
||||
func makeHomeTab(isActive: Bool) -> some View {
|
||||
HStack {
|
||||
Image(systemName: "house")
|
||||
Text("Home")
|
||||
L10n.home.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -43,26 +43,26 @@ final class MainTabCoordinator: TabCoordinatable {
|
||||
}
|
||||
|
||||
func makeTv() -> NavigationViewCoordinator<TVLibrariesCoordinator> {
|
||||
NavigationViewCoordinator(TVLibrariesCoordinator(viewModel: TVLibrariesViewModel(), title: "TV Shows"))
|
||||
NavigationViewCoordinator(TVLibrariesCoordinator(viewModel: TVLibrariesViewModel(), title: L10n.tvShows))
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func makeTvTab(isActive: Bool) -> some View {
|
||||
HStack {
|
||||
Image(systemName: "tv")
|
||||
Text("TV Shows")
|
||||
L10n.tvShows.text
|
||||
}
|
||||
}
|
||||
|
||||
func makeMovies() -> NavigationViewCoordinator<MovieLibrariesCoordinator> {
|
||||
NavigationViewCoordinator(MovieLibrariesCoordinator(viewModel: MovieLibrariesViewModel(), title: "Movies"))
|
||||
NavigationViewCoordinator(MovieLibrariesCoordinator(viewModel: MovieLibrariesViewModel(), title: L10n.movies))
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func makeMoviesTab(isActive: Bool) -> some View {
|
||||
HStack {
|
||||
Image(systemName: "film")
|
||||
Text("Movies")
|
||||
L10n.movies.text
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,7 +74,7 @@ final class MainTabCoordinator: TabCoordinatable {
|
||||
func makeOtherTab(isActive: Bool) -> some View {
|
||||
HStack {
|
||||
Image(systemName: "folder")
|
||||
Text("Other")
|
||||
L10n.other.text
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,7 +67,7 @@ enum NetworkError: Error {
|
||||
{
|
||||
|
||||
let errorMessage: ErrorMessage
|
||||
var logMessage = "An error has occurred."
|
||||
var logMessage = L10n.unknownError
|
||||
var logConstructor = logConstructor
|
||||
|
||||
switch response {
|
||||
@ -77,14 +77,14 @@ enum NetworkError: Error {
|
||||
// https://developer.apple.com/documentation/foundation/1508628-url_loading_system_error_codes
|
||||
switch err._code {
|
||||
case -1001:
|
||||
logMessage = "Network timed out."
|
||||
logMessage = L10n.networkTimedOut
|
||||
logConstructor.message = logMessage
|
||||
errorMessage = ErrorMessage(code: err._code,
|
||||
title: "Timed Out",
|
||||
title: L10n.error,
|
||||
displayMessage: displayMessage,
|
||||
logConstructor: logConstructor)
|
||||
case -1004:
|
||||
logMessage = "Cannot connect to host."
|
||||
logMessage = L10n.cannotConnectToHost
|
||||
logConstructor.message = logMessage
|
||||
errorMessage = ErrorMessage(code: err._code,
|
||||
title: L10n.error,
|
||||
@ -128,7 +128,7 @@ enum NetworkError: Error {
|
||||
{
|
||||
|
||||
let errorMessage: ErrorMessage
|
||||
var logMessage = "An error has occurred."
|
||||
var logMessage = L10n.unknownError
|
||||
var logConstructor = logConstructor
|
||||
|
||||
switch response {
|
||||
@ -137,10 +137,10 @@ enum NetworkError: Error {
|
||||
// Generic HTTP status codes
|
||||
switch code {
|
||||
case 401:
|
||||
logMessage = "User is unauthorized."
|
||||
logMessage = L10n.unauthorizedUser
|
||||
logConstructor.message = logMessage
|
||||
errorMessage = ErrorMessage(code: code,
|
||||
title: "Unauthorized",
|
||||
title: L10n.unauthorized,
|
||||
displayMessage: displayMessage,
|
||||
logConstructor: logConstructor)
|
||||
default:
|
||||
|
@ -248,15 +248,15 @@ public extension BaseItemDto {
|
||||
var informationItems: [ItemDetail] = []
|
||||
|
||||
if let productionYear = productionYear {
|
||||
informationItems.append(ItemDetail(title: "Released", content: "\(productionYear)"))
|
||||
informationItems.append(ItemDetail(title: L10n.released, content: "\(productionYear)"))
|
||||
}
|
||||
|
||||
if let rating = officialRating {
|
||||
informationItems.append(ItemDetail(title: "Rated", content: "\(rating)"))
|
||||
informationItems.append(ItemDetail(title: L10n.rated, content: "\(rating)"))
|
||||
}
|
||||
|
||||
if let runtime = getItemRuntime() {
|
||||
informationItems.append(ItemDetail(title: "Runtime", content: runtime))
|
||||
informationItems.append(ItemDetail(title: L10n.runtime, content: runtime))
|
||||
}
|
||||
|
||||
return informationItems
|
||||
@ -267,12 +267,7 @@ public extension BaseItemDto {
|
||||
|
||||
if let container = container {
|
||||
let containerList = container.split(separator: ",").joined(separator: ", ")
|
||||
|
||||
if containerList.count > 1 {
|
||||
mediaItems.append(ItemDetail(title: "Containers", content: containerList))
|
||||
} else {
|
||||
mediaItems.append(ItemDetail(title: "Container", content: containerList))
|
||||
}
|
||||
mediaItems.append(ItemDetail(title: L10n.containers, content: containerList))
|
||||
}
|
||||
|
||||
if let mediaStreams = mediaStreams {
|
||||
@ -280,15 +275,15 @@ public extension BaseItemDto {
|
||||
let subtitleStreams = mediaStreams.filter { $0.type == .subtitle }
|
||||
|
||||
if !audioStreams.isEmpty {
|
||||
let audioList = audioStreams.compactMap { "\($0.displayTitle ?? "No Title") (\($0.codec ?? "No Codec"))" }
|
||||
let audioList = audioStreams.compactMap { "\($0.displayTitle ?? L10n.noTitle) (\($0.codec ?? L10n.noCodec))" }
|
||||
.joined(separator: ", ")
|
||||
mediaItems.append(ItemDetail(title: "Audio", content: audioList))
|
||||
mediaItems.append(ItemDetail(title: L10n.audio, content: audioList))
|
||||
}
|
||||
|
||||
if !subtitleStreams.isEmpty {
|
||||
let subtitleList = subtitleStreams.compactMap { "\($0.displayTitle ?? "No Title") (\($0.codec ?? "No Codec"))" }
|
||||
let subtitleList = subtitleStreams.compactMap { "\($0.displayTitle ?? L10n.noTitle) (\($0.codec ?? L10n.noCodec))" }
|
||||
.joined(separator: ", ")
|
||||
mediaItems.append(ItemDetail(title: "Subtitles", content: subtitleList))
|
||||
mediaItems.append(ItemDetail(title: L10n.subtitles, content: subtitleList))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,3 @@
|
||||
//
|
||||
// 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) 2022 Jellyfin & Jellyfin Contributors
|
||||
//
|
||||
|
||||
// swiftlint:disable all
|
||||
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
|
||||
|
||||
@ -18,194 +10,385 @@ import Foundation
|
||||
// swiftlint:disable explicit_type_interface function_parameter_count identifier_name line_length
|
||||
// swiftlint:disable nesting type_body_length type_name vertical_whitespace_opening_braces
|
||||
internal enum L10n {
|
||||
/// Accessibility
|
||||
internal static let accessibility = L10n.tr("Localizable", "accessibility")
|
||||
/// Add URL
|
||||
internal static let addURL = L10n.tr("Localizable", "addURL")
|
||||
/// All Genres
|
||||
internal static let allGenres = L10n.tr("Localizable", "allGenres")
|
||||
/// All Media
|
||||
internal static let allMedia = L10n.tr("Localizable", "allMedia")
|
||||
/// Appearance
|
||||
internal static let appearance = L10n.tr("Localizable", "appearance")
|
||||
/// Apply
|
||||
internal static let apply = L10n.tr("Localizable", "apply")
|
||||
/// Audio & Captions
|
||||
internal static let audioAndCaptions = L10n.tr("Localizable", "audioAndCaptions")
|
||||
/// Audio Track
|
||||
internal static let audioTrack = L10n.tr("Localizable", "audioTrack")
|
||||
/// Back
|
||||
internal static let back = L10n.tr("Localizable", "back")
|
||||
/// CAST
|
||||
internal static let cast = L10n.tr("Localizable", "cast")
|
||||
/// Change Server
|
||||
internal static let changeServer = L10n.tr("Localizable", "changeServer")
|
||||
/// Closed Captions
|
||||
internal static let closedCaptions = L10n.tr("Localizable", "closedCaptions")
|
||||
/// Connect
|
||||
internal static let connect = L10n.tr("Localizable", "connect")
|
||||
/// Connect Manually
|
||||
internal static let connectManually = L10n.tr("Localizable", "connectManually")
|
||||
/// Connect to Jellyfin
|
||||
internal static let connectToJellyfin = L10n.tr("Localizable", "connectToJellyfin")
|
||||
/// Connect to Server
|
||||
internal static let connectToServer = L10n.tr("Localizable", "connectToServer")
|
||||
/// Continue Watching
|
||||
internal static let continueWatching = L10n.tr("Localizable", "continueWatching")
|
||||
/// Dark
|
||||
internal static let dark = L10n.tr("Localizable", "dark")
|
||||
/// DIRECTOR
|
||||
internal static let director = L10n.tr("Localizable", "director")
|
||||
/// Discovered Servers
|
||||
internal static let discoveredServers = L10n.tr("Localizable", "discoveredServers")
|
||||
/// Display order
|
||||
internal static let displayOrder = L10n.tr("Localizable", "displayOrder")
|
||||
/// Empty Next Up
|
||||
internal static let emptyNextUp = L10n.tr("Localizable", "emptyNextUp")
|
||||
/// Episodes
|
||||
internal static let episodes = L10n.tr("Localizable", "episodes")
|
||||
/// Error
|
||||
internal static let error = L10n.tr("Localizable", "error")
|
||||
/// Existing Server
|
||||
internal static let existingServer = L10n.tr("Localizable", "existingServer")
|
||||
/// Filter Results
|
||||
internal static let filterResults = L10n.tr("Localizable", "filterResults")
|
||||
/// Filters
|
||||
internal static let filters = L10n.tr("Localizable", "filters")
|
||||
/// Genres
|
||||
internal static let genres = L10n.tr("Localizable", "genres")
|
||||
/// Home
|
||||
internal static let home = L10n.tr("Localizable", "home")
|
||||
/// Latest %@
|
||||
internal static func latestWithString(_ p1: Any) -> String {
|
||||
L10n.tr("Localizable", "latestWithString", String(describing: p1))
|
||||
}
|
||||
|
||||
/// Library
|
||||
internal static let library = L10n.tr("Localizable", "library")
|
||||
/// Light
|
||||
internal static let light = L10n.tr("Localizable", "light")
|
||||
/// Loading
|
||||
internal static let loading = L10n.tr("Localizable", "loading")
|
||||
/// Local Servers
|
||||
internal static let localServers = L10n.tr("Localizable", "localServers")
|
||||
/// Login
|
||||
internal static let login = L10n.tr("Localizable", "login")
|
||||
/// Login to %@
|
||||
internal static func loginToWithString(_ p1: Any) -> String {
|
||||
L10n.tr("Localizable", "loginToWithString", String(describing: p1))
|
||||
}
|
||||
|
||||
/// More Like This
|
||||
internal static let moreLikeThis = L10n.tr("Localizable", "moreLikeThis")
|
||||
/// Next Up
|
||||
internal static let nextUp = L10n.tr("Localizable", "nextUp")
|
||||
/// No Cast devices found..
|
||||
internal static let noCastdevicesfound = L10n.tr("Localizable", "noCastdevicesfound")
|
||||
/// No results.
|
||||
internal static let noResults = L10n.tr("Localizable", "noResults")
|
||||
/// Type: %@ not implemented yet :(
|
||||
internal static func notImplementedYetWithType(_ p1: Any) -> String {
|
||||
L10n.tr("Localizable", "notImplementedYetWithType", String(describing: p1))
|
||||
}
|
||||
|
||||
/// Ok
|
||||
internal static let ok = L10n.tr("Localizable", "ok")
|
||||
/// Other User
|
||||
internal static let otherUser = L10n.tr("Localizable", "otherUser")
|
||||
/// Page %1$@ of %2$@
|
||||
internal static func pageOfWithNumbers(_ p1: Any, _ p2: Any) -> String {
|
||||
L10n.tr("Localizable", "pageOfWithNumbers", String(describing: p1), String(describing: p2))
|
||||
}
|
||||
|
||||
/// Password
|
||||
internal static let password = L10n.tr("Localizable", "password")
|
||||
/// Play
|
||||
internal static let play = L10n.tr("Localizable", "play")
|
||||
/// Playback settings
|
||||
internal static let playbackSettings = L10n.tr("Localizable", "playbackSettings")
|
||||
/// Playback Speed
|
||||
internal static let playbackSpeed = L10n.tr("Localizable", "playbackSpeed")
|
||||
/// Play Next
|
||||
internal static let playNext = L10n.tr("Localizable", "playNext")
|
||||
/// Reset
|
||||
internal static let reset = L10n.tr("Localizable", "reset")
|
||||
/// Search…
|
||||
internal static let search = L10n.tr("Localizable", "search")
|
||||
/// S%1$@:E%2$@
|
||||
internal static func seasonAndEpisode(_ p1: Any, _ p2: Any) -> String {
|
||||
L10n.tr("Localizable", "seasonAndEpisode", String(describing: p1), String(describing: p2))
|
||||
}
|
||||
|
||||
/// Seasons
|
||||
internal static let seasons = L10n.tr("Localizable", "seasons")
|
||||
/// See All
|
||||
internal static let seeAll = L10n.tr("Localizable", "seeAll")
|
||||
/// Select Cast Destination
|
||||
internal static let selectCastDestination = L10n.tr("Localizable", "selectCastDestination")
|
||||
/// Server %s already exists. Add new URL?
|
||||
internal static func serverAlreadyExistsPrompt(_ p1: UnsafePointer<CChar>) -> String {
|
||||
L10n.tr("Localizable", "serverAlreadyExistsPrompt", p1)
|
||||
}
|
||||
|
||||
/// Server Information
|
||||
internal static let serverInformation = L10n.tr("Localizable", "serverInformation")
|
||||
/// Server URL
|
||||
internal static let serverURL = L10n.tr("Localizable", "serverURL")
|
||||
/// Signed in as %@
|
||||
internal static func signedInAsWithString(_ p1: Any) -> String {
|
||||
L10n.tr("Localizable", "signedInAsWithString", String(describing: p1))
|
||||
}
|
||||
|
||||
/// Sort by
|
||||
internal static let sortBy = L10n.tr("Localizable", "sortBy")
|
||||
/// STUDIO
|
||||
internal static let studio = L10n.tr("Localizable", "studio")
|
||||
/// Studios
|
||||
internal static let studios = L10n.tr("Localizable", "studios")
|
||||
/// Suggestions
|
||||
internal static let suggestions = L10n.tr("Localizable", "suggestions")
|
||||
/// Switch user
|
||||
internal static let switchUser = L10n.tr("Localizable", "switchUser")
|
||||
/// System
|
||||
internal static let system = L10n.tr("Localizable", "system")
|
||||
/// Tags
|
||||
internal static let tags = L10n.tr("Localizable", "tags")
|
||||
/// Try again
|
||||
internal static let tryAgain = L10n.tr("Localizable", "tryAgain")
|
||||
/// Unknown Error
|
||||
internal static let unknownError = L10n.tr("Localizable", "unknownError")
|
||||
/// Username
|
||||
internal static let username = L10n.tr("Localizable", "username")
|
||||
/// Who's watching?
|
||||
internal static let whosWatching = L10n.tr("Localizable", "WhosWatching")
|
||||
/// WIP
|
||||
internal static let wip = L10n.tr("Localizable", "wip")
|
||||
/// Your Favorites
|
||||
internal static let yourFavorites = L10n.tr("Localizable", "yourFavorites")
|
||||
/// About
|
||||
internal static let about = L10n.tr("Localizable", "about")
|
||||
/// Accessibility
|
||||
internal static let accessibility = L10n.tr("Localizable", "accessibility")
|
||||
/// Add URL
|
||||
internal static let addURL = L10n.tr("Localizable", "addURL")
|
||||
/// All Genres
|
||||
internal static let allGenres = L10n.tr("Localizable", "allGenres")
|
||||
/// All Media
|
||||
internal static let allMedia = L10n.tr("Localizable", "allMedia")
|
||||
/// Appearance
|
||||
internal static let appearance = L10n.tr("Localizable", "appearance")
|
||||
/// Apply
|
||||
internal static let apply = L10n.tr("Localizable", "apply")
|
||||
/// Audio
|
||||
internal static let audio = L10n.tr("Localizable", "audio")
|
||||
/// Audio & Captions
|
||||
internal static let audioAndCaptions = L10n.tr("Localizable", "audioAndCaptions")
|
||||
/// Audio Track
|
||||
internal static let audioTrack = L10n.tr("Localizable", "audioTrack")
|
||||
/// Auto Play
|
||||
internal static let autoPlay = L10n.tr("Localizable", "autoPlay")
|
||||
/// Back
|
||||
internal static let back = L10n.tr("Localizable", "back")
|
||||
/// Cancel
|
||||
internal static let cancel = L10n.tr("Localizable", "cancel")
|
||||
/// Cannot connect to host
|
||||
internal static let cannotConnectToHost = L10n.tr("Localizable", "cannotConnectToHost")
|
||||
/// CAST
|
||||
internal static let cast = L10n.tr("Localizable", "cast")
|
||||
/// Cast & Crew
|
||||
internal static let castAndCrew = L10n.tr("Localizable", "castAndCrew")
|
||||
/// Change Server
|
||||
internal static let changeServer = L10n.tr("Localizable", "changeServer")
|
||||
/// Channels
|
||||
internal static let channels = L10n.tr("Localizable", "channels")
|
||||
/// Cinematic Views
|
||||
internal static let cinematicViews = L10n.tr("Localizable", "cinematicViews")
|
||||
/// Closed Captions
|
||||
internal static let closedCaptions = L10n.tr("Localizable", "closedCaptions")
|
||||
/// Compact
|
||||
internal static let compact = L10n.tr("Localizable", "compact")
|
||||
/// Confirm Close
|
||||
internal static let confirmClose = L10n.tr("Localizable", "confirmClose")
|
||||
/// Connect
|
||||
internal static let connect = L10n.tr("Localizable", "connect")
|
||||
/// Connect Manually
|
||||
internal static let connectManually = L10n.tr("Localizable", "connectManually")
|
||||
/// Connect to Jellyfin
|
||||
internal static let connectToJellyfin = L10n.tr("Localizable", "connectToJellyfin")
|
||||
/// Connect to a Jellyfin server
|
||||
internal static let connectToJellyfinServer = L10n.tr("Localizable", "connectToJellyfinServer")
|
||||
/// Connect to a Jellyfin server to get started
|
||||
internal static let connectToJellyfinServerStart = L10n.tr("Localizable", "connectToJellyfinServerStart")
|
||||
/// Connect to Server
|
||||
internal static let connectToServer = L10n.tr("Localizable", "connectToServer")
|
||||
/// Containers
|
||||
internal static let containers = L10n.tr("Localizable", "containers")
|
||||
/// Continue
|
||||
internal static let `continue` = L10n.tr("Localizable", "continue")
|
||||
/// Continue Watching
|
||||
internal static let continueWatching = L10n.tr("Localizable", "continueWatching")
|
||||
/// Dark
|
||||
internal static let dark = L10n.tr("Localizable", "dark")
|
||||
/// Default Scheme
|
||||
internal static let defaultScheme = L10n.tr("Localizable", "defaultScheme")
|
||||
/// DIRECTOR
|
||||
internal static let director = L10n.tr("Localizable", "director")
|
||||
/// Discovered Servers
|
||||
internal static let discoveredServers = L10n.tr("Localizable", "discoveredServers")
|
||||
/// Display order
|
||||
internal static let displayOrder = L10n.tr("Localizable", "displayOrder")
|
||||
/// Edit Jump Lengths
|
||||
internal static let editJumpLengths = L10n.tr("Localizable", "editJumpLengths")
|
||||
/// Empty Next Up
|
||||
internal static let emptyNextUp = L10n.tr("Localizable", "emptyNextUp")
|
||||
/// Episodes
|
||||
internal static let episodes = L10n.tr("Localizable", "episodes")
|
||||
/// Error
|
||||
internal static let error = L10n.tr("Localizable", "error")
|
||||
/// Existing Server
|
||||
internal static let existingServer = L10n.tr("Localizable", "existingServer")
|
||||
/// Existing User
|
||||
internal static let existingUser = L10n.tr("Localizable", "existingUser")
|
||||
/// Experimental
|
||||
internal static let experimental = L10n.tr("Localizable", "experimental")
|
||||
/// Favorites
|
||||
internal static let favorites = L10n.tr("Localizable", "favorites")
|
||||
/// Filter Results
|
||||
internal static let filterResults = L10n.tr("Localizable", "filterResults")
|
||||
/// Filters
|
||||
internal static let filters = L10n.tr("Localizable", "filters")
|
||||
/// Genres
|
||||
internal static let genres = L10n.tr("Localizable", "genres")
|
||||
/// Home
|
||||
internal static let home = L10n.tr("Localizable", "home")
|
||||
/// Information
|
||||
internal static let information = L10n.tr("Localizable", "information")
|
||||
/// Items
|
||||
internal static let items = L10n.tr("Localizable", "items")
|
||||
/// Jump Backward Length
|
||||
internal static let jumpBackwardLength = L10n.tr("Localizable", "jumpBackwardLength")
|
||||
/// Jump Forward Length
|
||||
internal static let jumpForwardLength = L10n.tr("Localizable", "jumpForwardLength")
|
||||
/// Jump Gestures Enabled
|
||||
internal static let jumpGesturesEnabled = L10n.tr("Localizable", "jumpGesturesEnabled")
|
||||
/// %s seconds
|
||||
internal static func jumpLengthSeconds(_ p1: UnsafePointer<CChar>) -> String {
|
||||
return L10n.tr("Localizable", "jumpLengthSeconds", p1)
|
||||
}
|
||||
/// Larger
|
||||
internal static let larger = L10n.tr("Localizable", "larger")
|
||||
/// Largest
|
||||
internal static let largest = L10n.tr("Localizable", "largest")
|
||||
/// Latest %@
|
||||
internal static func latestWithString(_ p1: Any) -> String {
|
||||
return L10n.tr("Localizable", "latestWithString", String(describing: p1))
|
||||
}
|
||||
/// Library
|
||||
internal static let library = L10n.tr("Localizable", "library")
|
||||
/// Light
|
||||
internal static let light = L10n.tr("Localizable", "light")
|
||||
/// Loading
|
||||
internal static let loading = L10n.tr("Localizable", "loading")
|
||||
/// Local Servers
|
||||
internal static let localServers = L10n.tr("Localizable", "localServers")
|
||||
/// Login
|
||||
internal static let login = L10n.tr("Localizable", "login")
|
||||
/// Login to %@
|
||||
internal static func loginToWithString(_ p1: Any) -> String {
|
||||
return L10n.tr("Localizable", "loginToWithString", String(describing: p1))
|
||||
}
|
||||
/// Media
|
||||
internal static let media = L10n.tr("Localizable", "media")
|
||||
/// More Like This
|
||||
internal static let moreLikeThis = L10n.tr("Localizable", "moreLikeThis")
|
||||
/// Movies
|
||||
internal static let movies = L10n.tr("Localizable", "movies")
|
||||
/// %d users
|
||||
internal static func multipleUsers(_ p1: Int) -> String {
|
||||
return L10n.tr("Localizable", "multipleUsers", p1)
|
||||
}
|
||||
/// Name
|
||||
internal static let name = L10n.tr("Localizable", "name")
|
||||
/// Networking
|
||||
internal static let networking = L10n.tr("Localizable", "networking")
|
||||
/// Network timed out
|
||||
internal static let networkTimedOut = L10n.tr("Localizable", "networkTimedOut")
|
||||
/// Next
|
||||
internal static let next = L10n.tr("Localizable", "next")
|
||||
/// Next Up
|
||||
internal static let nextUp = L10n.tr("Localizable", "nextUp")
|
||||
/// No Cast devices found..
|
||||
internal static let noCastdevicesfound = L10n.tr("Localizable", "noCastdevicesfound")
|
||||
/// No Codec
|
||||
internal static let noCodec = L10n.tr("Localizable", "noCodec")
|
||||
/// No episodes available
|
||||
internal static let noEpisodesAvailable = L10n.tr("Localizable", "noEpisodesAvailable")
|
||||
/// No local servers found
|
||||
internal static let noLocalServersFound = L10n.tr("Localizable", "noLocalServersFound")
|
||||
/// None
|
||||
internal static let `none` = L10n.tr("Localizable", "none")
|
||||
/// No overview available
|
||||
internal static let noOverviewAvailable = L10n.tr("Localizable", "noOverviewAvailable")
|
||||
/// No results.
|
||||
internal static let noResults = L10n.tr("Localizable", "noResults")
|
||||
/// Normal
|
||||
internal static let normal = L10n.tr("Localizable", "normal")
|
||||
/// N/A
|
||||
internal static let notAvailableSlash = L10n.tr("Localizable", "notAvailableSlash")
|
||||
/// Type: %@ not implemented yet :(
|
||||
internal static func notImplementedYetWithType(_ p1: Any) -> String {
|
||||
return L10n.tr("Localizable", "notImplementedYetWithType", String(describing: p1))
|
||||
}
|
||||
/// No title
|
||||
internal static let noTitle = L10n.tr("Localizable", "noTitle")
|
||||
/// Ok
|
||||
internal static let ok = L10n.tr("Localizable", "ok")
|
||||
/// 1 user
|
||||
internal static let oneUser = L10n.tr("Localizable", "oneUser")
|
||||
/// Operating System
|
||||
internal static let operatingSystem = L10n.tr("Localizable", "operatingSystem")
|
||||
/// Other
|
||||
internal static let other = L10n.tr("Localizable", "other")
|
||||
/// Other User
|
||||
internal static let otherUser = L10n.tr("Localizable", "otherUser")
|
||||
/// Overlay
|
||||
internal static let overlay = L10n.tr("Localizable", "overlay")
|
||||
/// Overlay Type
|
||||
internal static let overlayType = L10n.tr("Localizable", "overlayType")
|
||||
/// Overview
|
||||
internal static let overview = L10n.tr("Localizable", "overview")
|
||||
/// Page %1$@ of %2$@
|
||||
internal static func pageOfWithNumbers(_ p1: Any, _ p2: Any) -> String {
|
||||
return L10n.tr("Localizable", "pageOfWithNumbers", String(describing: p1), String(describing: p2))
|
||||
}
|
||||
/// Password
|
||||
internal static let password = L10n.tr("Localizable", "password")
|
||||
/// Play
|
||||
internal static let play = L10n.tr("Localizable", "play")
|
||||
/// Playback settings
|
||||
internal static let playbackSettings = L10n.tr("Localizable", "playbackSettings")
|
||||
/// Playback Speed
|
||||
internal static let playbackSpeed = L10n.tr("Localizable", "playbackSpeed")
|
||||
/// Play Next
|
||||
internal static let playNext = L10n.tr("Localizable", "playNext")
|
||||
/// Play Next Item
|
||||
internal static let playNextItem = L10n.tr("Localizable", "playNextItem")
|
||||
/// Play Previous Item
|
||||
internal static let playPreviousItem = L10n.tr("Localizable", "playPreviousItem")
|
||||
/// Present
|
||||
internal static let present = L10n.tr("Localizable", "present")
|
||||
/// Press Down for Menu
|
||||
internal static let pressDownForMenu = L10n.tr("Localizable", "pressDownForMenu")
|
||||
/// Programs
|
||||
internal static let programs = L10n.tr("Localizable", "programs")
|
||||
/// Rated
|
||||
internal static let rated = L10n.tr("Localizable", "rated")
|
||||
/// Recently Added
|
||||
internal static let recentlyAdded = L10n.tr("Localizable", "recentlyAdded")
|
||||
/// Recommended
|
||||
internal static let recommended = L10n.tr("Localizable", "recommended")
|
||||
/// Refresh
|
||||
internal static let refresh = L10n.tr("Localizable", "refresh")
|
||||
/// Regular
|
||||
internal static let regular = L10n.tr("Localizable", "regular")
|
||||
/// Released
|
||||
internal static let released = L10n.tr("Localizable", "released")
|
||||
/// Remove
|
||||
internal static let remove = L10n.tr("Localizable", "remove")
|
||||
/// Remove All Users
|
||||
internal static let removeAllUsers = L10n.tr("Localizable", "removeAllUsers")
|
||||
/// Reset
|
||||
internal static let reset = L10n.tr("Localizable", "reset")
|
||||
/// Reset App Settings
|
||||
internal static let resetAppSettings = L10n.tr("Localizable", "resetAppSettings")
|
||||
/// Reset User Settings
|
||||
internal static let resetUserSettings = L10n.tr("Localizable", "resetUserSettings")
|
||||
/// Resume 5 Second Offset
|
||||
internal static let resume5SecondOffset = L10n.tr("Localizable", "resume5SecondOffset")
|
||||
/// Retry
|
||||
internal static let retry = L10n.tr("Localizable", "retry")
|
||||
/// Runtime
|
||||
internal static let runtime = L10n.tr("Localizable", "runtime")
|
||||
/// Search
|
||||
internal static let search = L10n.tr("Localizable", "search")
|
||||
/// Search…
|
||||
internal static let searchDots = L10n.tr("Localizable", "searchDots")
|
||||
/// Searching…
|
||||
internal static let searchingDots = L10n.tr("Localizable", "searchingDots")
|
||||
/// Season
|
||||
internal static let season = L10n.tr("Localizable", "season")
|
||||
/// S%1$@:E%2$@
|
||||
internal static func seasonAndEpisode(_ p1: Any, _ p2: Any) -> String {
|
||||
return L10n.tr("Localizable", "seasonAndEpisode", String(describing: p1), String(describing: p2))
|
||||
}
|
||||
/// Seasons
|
||||
internal static let seasons = L10n.tr("Localizable", "seasons")
|
||||
/// See All
|
||||
internal static let seeAll = L10n.tr("Localizable", "seeAll")
|
||||
/// See More
|
||||
internal static let seeMore = L10n.tr("Localizable", "seeMore")
|
||||
/// Select Cast Destination
|
||||
internal static let selectCastDestination = L10n.tr("Localizable", "selectCastDestination")
|
||||
/// Series
|
||||
internal static let series = L10n.tr("Localizable", "series")
|
||||
/// Server
|
||||
internal static let server = L10n.tr("Localizable", "server")
|
||||
/// Server %s is already connected
|
||||
internal static func serverAlreadyConnected(_ p1: UnsafePointer<CChar>) -> String {
|
||||
return L10n.tr("Localizable", "serverAlreadyConnected", p1)
|
||||
}
|
||||
/// Server %s already exists. Add new URL?
|
||||
internal static func serverAlreadyExistsPrompt(_ p1: UnsafePointer<CChar>) -> String {
|
||||
return L10n.tr("Localizable", "serverAlreadyExistsPrompt", p1)
|
||||
}
|
||||
/// Server Details
|
||||
internal static let serverDetails = L10n.tr("Localizable", "serverDetails")
|
||||
/// Server Information
|
||||
internal static let serverInformation = L10n.tr("Localizable", "serverInformation")
|
||||
/// Servers
|
||||
internal static let servers = L10n.tr("Localizable", "servers")
|
||||
/// Server URL
|
||||
internal static let serverURL = L10n.tr("Localizable", "serverURL")
|
||||
/// Settings
|
||||
internal static let settings = L10n.tr("Localizable", "settings")
|
||||
/// Show Cast & Crew
|
||||
internal static let showCastAndCrew = L10n.tr("Localizable", "showCastAndCrew")
|
||||
/// Show Poster Labels
|
||||
internal static let showPosterLabels = L10n.tr("Localizable", "showPosterLabels")
|
||||
/// Signed in as %@
|
||||
internal static func signedInAsWithString(_ p1: Any) -> String {
|
||||
return L10n.tr("Localizable", "signedInAsWithString", String(describing: p1))
|
||||
}
|
||||
/// Sign In
|
||||
internal static let signIn = L10n.tr("Localizable", "signIn")
|
||||
/// Sign in to get started
|
||||
internal static let signInGetStarted = L10n.tr("Localizable", "signInGetStarted")
|
||||
/// Sign In to %s
|
||||
internal static func signInToServer(_ p1: UnsafePointer<CChar>) -> String {
|
||||
return L10n.tr("Localizable", "signInToServer", p1)
|
||||
}
|
||||
/// Smaller
|
||||
internal static let smaller = L10n.tr("Localizable", "smaller")
|
||||
/// Smallest
|
||||
internal static let smallest = L10n.tr("Localizable", "smallest")
|
||||
/// Sort by
|
||||
internal static let sortBy = L10n.tr("Localizable", "sortBy")
|
||||
/// STUDIO
|
||||
internal static let studio = L10n.tr("Localizable", "studio")
|
||||
/// Studios
|
||||
internal static let studios = L10n.tr("Localizable", "studios")
|
||||
/// Subtitles
|
||||
internal static let subtitles = L10n.tr("Localizable", "subtitles")
|
||||
/// Subtitle Size
|
||||
internal static let subtitleSize = L10n.tr("Localizable", "subtitleSize")
|
||||
/// Suggestions
|
||||
internal static let suggestions = L10n.tr("Localizable", "suggestions")
|
||||
/// Switch User
|
||||
internal static let switchUser = L10n.tr("Localizable", "switchUser")
|
||||
/// System
|
||||
internal static let system = L10n.tr("Localizable", "system")
|
||||
/// Tags
|
||||
internal static let tags = L10n.tr("Localizable", "tags")
|
||||
/// Try again
|
||||
internal static let tryAgain = L10n.tr("Localizable", "tryAgain")
|
||||
/// TV Shows
|
||||
internal static let tvShows = L10n.tr("Localizable", "tvShows")
|
||||
/// Unable to connect to server
|
||||
internal static let unableToConnectServer = L10n.tr("Localizable", "unableToConnectServer")
|
||||
/// Unauthorized
|
||||
internal static let unauthorized = L10n.tr("Localizable", "unauthorized")
|
||||
/// Unauthorized user
|
||||
internal static let unauthorizedUser = L10n.tr("Localizable", "unauthorizedUser")
|
||||
/// Unknown
|
||||
internal static let unknown = L10n.tr("Localizable", "unknown")
|
||||
/// Unknown Error
|
||||
internal static let unknownError = L10n.tr("Localizable", "unknownError")
|
||||
/// URL
|
||||
internal static let url = L10n.tr("Localizable", "url")
|
||||
/// User
|
||||
internal static let user = L10n.tr("Localizable", "user")
|
||||
/// User %s is already signed in
|
||||
internal static func userAlreadySignedIn(_ p1: UnsafePointer<CChar>) -> String {
|
||||
return L10n.tr("Localizable", "userAlreadySignedIn", p1)
|
||||
}
|
||||
/// Username
|
||||
internal static let username = L10n.tr("Localizable", "username")
|
||||
/// Version
|
||||
internal static let version = L10n.tr("Localizable", "version")
|
||||
/// Video Player
|
||||
internal static let videoPlayer = L10n.tr("Localizable", "videoPlayer")
|
||||
/// Who's watching?
|
||||
internal static let whosWatching = L10n.tr("Localizable", "WhosWatching")
|
||||
/// WIP
|
||||
internal static let wip = L10n.tr("Localizable", "wip")
|
||||
/// Your Favorites
|
||||
internal static let yourFavorites = L10n.tr("Localizable", "yourFavorites")
|
||||
}
|
||||
|
||||
// swiftlint:enable explicit_type_interface function_parameter_count identifier_name line_length
|
||||
// swiftlint:enable nesting type_body_length type_name vertical_whitespace_opening_braces
|
||||
|
||||
// MARK: - Implementation Details
|
||||
|
||||
extension L10n {
|
||||
private static func tr(_ table: String, _ key: String, _ args: CVarArg...) -> String {
|
||||
let format = BundleToken.bundle.localizedString(forKey: key, value: nil, table: table)
|
||||
return String(format: format, locale: Locale.current, arguments: args)
|
||||
}
|
||||
private static func tr(_ table: String, _ key: String, _ args: CVarArg...) -> String {
|
||||
let format = BundleToken.bundle.localizedString(forKey: key, value: nil, table: table)
|
||||
return String(format: format, locale: Locale.current, arguments: args)
|
||||
}
|
||||
}
|
||||
|
||||
// swiftlint:disable convenience_type
|
||||
private final class BundleToken {
|
||||
static let bundle: Bundle = {
|
||||
#if SWIFT_PACKAGE
|
||||
return Bundle.module
|
||||
#else
|
||||
return Bundle(for: BundleToken.self)
|
||||
#endif
|
||||
}()
|
||||
static let bundle: Bundle = {
|
||||
#if SWIFT_PACKAGE
|
||||
return Bundle.module
|
||||
#else
|
||||
return Bundle(for: BundleToken.self)
|
||||
#endif
|
||||
}()
|
||||
}
|
||||
|
||||
// swiftlint:enable convenience_type
|
||||
|
@ -1,23 +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) 2022 Jellyfin & Jellyfin Contributors
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import JellyfinAPI
|
||||
|
||||
enum DetailItemType: String {
|
||||
case movie = "Movie"
|
||||
case season = "Season"
|
||||
case series = "Series"
|
||||
case episode = "Episode"
|
||||
}
|
||||
|
||||
struct DetailItem {
|
||||
|
||||
let baseItem: BaseItemDto
|
||||
let type: DetailItemType
|
||||
}
|
@ -16,9 +16,9 @@ enum OverlayType: String, CaseIterable, Defaults.Serializable {
|
||||
var label: String {
|
||||
switch self {
|
||||
case .normal:
|
||||
return "Normal"
|
||||
return L10n.normal
|
||||
case .compact:
|
||||
return "Compact"
|
||||
return L10n.compact
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,15 +22,15 @@ extension SubtitleSize {
|
||||
var label: String {
|
||||
switch self {
|
||||
case .smallest:
|
||||
return "Smallest"
|
||||
return L10n.smallest
|
||||
case .smaller:
|
||||
return "Smaller"
|
||||
return L10n.smaller
|
||||
case .regular:
|
||||
return "Regular"
|
||||
return L10n.regular
|
||||
case .larger:
|
||||
return "Larger"
|
||||
return L10n.larger
|
||||
case .largest:
|
||||
return "Largest"
|
||||
return L10n.largest
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ enum VideoPlayerJumpLength: Int32, CaseIterable, Defaults.Serializable {
|
||||
case five = 5
|
||||
|
||||
var label: String {
|
||||
"\(self.rawValue) seconds"
|
||||
L10n.jumpLengthSeconds("\(self.rawValue)")
|
||||
}
|
||||
|
||||
var shortLabel: String {
|
||||
|
@ -198,18 +198,18 @@ extension SwiftfinStore.Errors: LocalizedError {
|
||||
var title: String {
|
||||
switch self {
|
||||
case .existingServer:
|
||||
return "Existing Server"
|
||||
return L10n.existingServer
|
||||
case .existingUser:
|
||||
return "Existing User"
|
||||
return L10n.existingUser
|
||||
}
|
||||
}
|
||||
|
||||
var errorDescription: String? {
|
||||
switch self {
|
||||
case let .existingServer(server):
|
||||
return "Server \(server.name) already exists with same server ID"
|
||||
return L10n.serverAlreadyConnected(server.name)
|
||||
case let .existingUser(user):
|
||||
return "User \(user.username) already exists with same user ID"
|
||||
return L10n.userAlreadySignedIn(user.username)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ final class ConnectToServerViewModel: ViewModel {
|
||||
if errorMessage?.code != ErrorMessage.noShowErrorCode {
|
||||
message.append(contentsOf: "\(errorMessage?.code ?? ErrorMessage.noShowErrorCode)\n")
|
||||
}
|
||||
message.append(contentsOf: "\(errorMessage?.title ?? "Unkown Error")")
|
||||
message.append(contentsOf: "\(errorMessage?.title ?? L10n.unknownError)")
|
||||
return message
|
||||
}
|
||||
|
||||
@ -70,12 +70,12 @@ final class ConnectToServerViewModel: ViewModel {
|
||||
self.addServerURIPayload = AddServerURIPayload(server: server, uri: uri)
|
||||
self.backAddServerURIPayload = AddServerURIPayload(server: server, uri: uri)
|
||||
default:
|
||||
self.handleAPIRequestError(displayMessage: "Unable to connect to server.", logLevel: .critical,
|
||||
self.handleAPIRequestError(displayMessage: L10n.unableToConnectServer, logLevel: .critical,
|
||||
tag: "connectToServer",
|
||||
completion: completion)
|
||||
}
|
||||
default:
|
||||
self.handleAPIRequestError(displayMessage: "Unable to connect to server.", logLevel: .critical,
|
||||
self.handleAPIRequestError(displayMessage: L10n.unableToConnectServer, logLevel: .critical,
|
||||
tag: "connectToServer",
|
||||
completion: completion)
|
||||
}
|
||||
@ -106,12 +106,12 @@ final class ConnectToServerViewModel: ViewModel {
|
||||
func addURIToServer(addServerURIPayload: AddServerURIPayload) {
|
||||
SessionManager.main.addURIToServer(server: addServerURIPayload.server, uri: addServerURIPayload.uri)
|
||||
.sink { completion in
|
||||
self.handleAPIRequestError(displayMessage: "Unable to connect to server.", logLevel: .critical, tag: "connectToServer",
|
||||
self.handleAPIRequestError(displayMessage: L10n.unableToConnectServer, logLevel: .critical, tag: "connectToServer",
|
||||
completion: completion)
|
||||
} receiveValue: { server in
|
||||
SessionManager.main.setServerCurrentURI(server: server, uri: addServerURIPayload.uri)
|
||||
.sink { completion in
|
||||
self.handleAPIRequestError(displayMessage: "Unable to connect to server.", logLevel: .critical,
|
||||
self.handleAPIRequestError(displayMessage: L10n.unableToConnectServer, logLevel: .critical,
|
||||
tag: "connectToServer",
|
||||
completion: completion)
|
||||
} receiveValue: { _ in
|
||||
|
@ -64,7 +64,7 @@ final class SeriesItemViewModel: ItemViewModel {
|
||||
endYear = dateFormatter.string(from: item.endDate!)
|
||||
}
|
||||
|
||||
return "\(startYear ?? "Unknown") - \(endYear ?? "Present")"
|
||||
return "\(startYear ?? L10n.unknown) - \(endYear ?? L10n.present)"
|
||||
}
|
||||
|
||||
private func requestSeasons() {
|
||||
|
@ -30,9 +30,9 @@ class ServerListViewModel: ObservableObject {
|
||||
|
||||
func userTextFor(server: SwiftfinStore.State.Server) -> String {
|
||||
if server.userIDs.count == 1 {
|
||||
return "1 user"
|
||||
return L10n.oneUser
|
||||
} else {
|
||||
return "\(server.userIDs.count) users"
|
||||
return L10n.multipleUsers(server.userIDs.count)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ final class UserSignInViewModel: ViewModel {
|
||||
SessionManager.main.loginUser(server: server, username: username, password: password)
|
||||
.trackActivity(loading)
|
||||
.sink { completion in
|
||||
self.handleAPIRequestError(displayMessage: "Unable to connect to server.", logLevel: .critical, tag: "login",
|
||||
self.handleAPIRequestError(displayMessage: L10n.unableToConnectServer, logLevel: .critical, tag: "login",
|
||||
completion: completion)
|
||||
} receiveValue: { _ in
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ struct LiveTVChannelItemElement: View {
|
||||
.font(.footnote)
|
||||
.lineLimit(1)
|
||||
.frame(alignment: .center)
|
||||
Text(program?.name ?? "N/A")
|
||||
Text(program?.name ?? L10n.notAvailableSlash)
|
||||
.font(.body)
|
||||
.lineLimit(1)
|
||||
.foregroundColor(.green)
|
||||
|
@ -17,7 +17,7 @@ struct SearchBar: View {
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: 8) {
|
||||
TextField(L10n.search, text: $text)
|
||||
TextField(L10n.searchDots, text: $text)
|
||||
.padding(8)
|
||||
.padding(.horizontal, 16)
|
||||
#if os(iOS)
|
||||
|
@ -19,7 +19,7 @@ struct EpisodesRowView: View {
|
||||
var body: some View {
|
||||
VStack(alignment: .leading) {
|
||||
|
||||
Text(viewModel.selectedSeason?.name ?? "Episodes")
|
||||
Text(viewModel.selectedSeason?.name ?? L10n.episodes)
|
||||
.font(.title3)
|
||||
.padding(.horizontal, 50)
|
||||
|
||||
@ -67,7 +67,7 @@ struct EpisodesRowView: View {
|
||||
Text("--")
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
Text("No episodes available")
|
||||
L10n.noEpisodesAvailable.text
|
||||
.font(.footnote)
|
||||
.padding(.bottom, 1)
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ struct CinematicNextUpCardView: View {
|
||||
|
||||
if showOverlay {
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
Text("Next")
|
||||
L10n.next.text
|
||||
.font(.subheadline)
|
||||
.padding(.vertical, 5)
|
||||
.padding(.leading, 10)
|
||||
|
@ -24,7 +24,7 @@ struct ItemDetailsView: View {
|
||||
|
||||
HStack(alignment: .top) {
|
||||
VStack(alignment: .leading, spacing: 20) {
|
||||
Text("Information")
|
||||
L10n.information.text
|
||||
.font(.title3)
|
||||
.padding(.bottom, 5)
|
||||
|
||||
@ -36,7 +36,7 @@ struct ItemDetailsView: View {
|
||||
Spacer()
|
||||
|
||||
VStack(alignment: .leading, spacing: 20) {
|
||||
Text("Media")
|
||||
L10n.media.text
|
||||
.font(.title3)
|
||||
.padding(.bottom, 5)
|
||||
|
||||
|
@ -19,7 +19,7 @@ struct SingleSeasonEpisodesRowView: View {
|
||||
var body: some View {
|
||||
VStack(alignment: .leading) {
|
||||
|
||||
Text("Episodes")
|
||||
L10n.episodes.text
|
||||
.font(.title3)
|
||||
.padding(.horizontal, 50)
|
||||
|
||||
@ -66,7 +66,7 @@ struct SingleSeasonEpisodesRowView: View {
|
||||
Text("--")
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
Text("No episodes available")
|
||||
L10n.noEpisodesAvailable.text
|
||||
.font(.footnote)
|
||||
.padding(.bottom, 1)
|
||||
}
|
||||
|
@ -48,6 +48,6 @@ struct BasicAppSettingsView: View {
|
||||
L10n.reset.text
|
||||
}
|
||||
})
|
||||
.navigationTitle("Settings")
|
||||
.navigationTitle(L10n.settings)
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ struct ConnectToServerView: View {
|
||||
}
|
||||
.disabled(viewModel.isLoading || uri.isEmpty)
|
||||
} header: {
|
||||
Text("Connect to a Jellyfin server")
|
||||
L10n.connectToJellyfinServer.text
|
||||
}
|
||||
|
||||
Section(header: L10n.localServers.text) {
|
||||
@ -77,7 +77,7 @@ struct ConnectToServerView: View {
|
||||
}
|
||||
.alert(item: $viewModel.errorMessage) { _ in
|
||||
Alert(title: Text(viewModel.alertTitle),
|
||||
message: Text(viewModel.errorMessage?.displayMessage ?? "Unknown Error"),
|
||||
message: Text(viewModel.errorMessage?.displayMessage ?? L10n.unknownError),
|
||||
dismissButton: .cancel())
|
||||
}
|
||||
.navigationTitle(L10n.connect)
|
||||
|
@ -33,7 +33,7 @@ struct HomeView: View {
|
||||
|
||||
if viewModel.resumeItems.isEmpty {
|
||||
HomeCinematicView(items: viewModel.latestAddedItems.map { .init(item: $0, type: .plain) },
|
||||
forcedItemSubtitle: "Recently Added")
|
||||
forcedItemSubtitle: L10n.recentlyAdded)
|
||||
|
||||
if !viewModel.nextUpItems.isEmpty {
|
||||
NextUpView(items: viewModel.nextUpItems)
|
||||
@ -47,7 +47,7 @@ struct HomeView: View {
|
||||
.focusSection()
|
||||
}
|
||||
|
||||
PortraitItemsRowView(rowTitle: "Recently Added",
|
||||
PortraitItemsRowView(rowTitle: L10n.recentlyAdded,
|
||||
items: viewModel.latestAddedItems,
|
||||
showItemTitles: showPosterLabels) { item in
|
||||
homeRouter.route(to: \.modalItem, item)
|
||||
@ -67,7 +67,7 @@ struct HomeView: View {
|
||||
Button {
|
||||
viewModel.refresh()
|
||||
} label: {
|
||||
Text("Refresh")
|
||||
L10n.refresh.text
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
@ -46,13 +46,13 @@ struct CinematicCollectionItemView: View {
|
||||
|
||||
CinematicItemAboutView(viewModel: viewModel)
|
||||
|
||||
PortraitItemsRowView(rowTitle: "Items",
|
||||
PortraitItemsRowView(rowTitle: L10n.items,
|
||||
items: viewModel.collectionItems) { item in
|
||||
itemRouter.route(to: \.item, item)
|
||||
}
|
||||
|
||||
if !viewModel.similarItems.isEmpty {
|
||||
PortraitItemsRowView(rowTitle: "Recommended",
|
||||
PortraitItemsRowView(rowTitle: L10n.recommended,
|
||||
items: viewModel.similarItems,
|
||||
showItemTitles: showPosterLabels) { item in
|
||||
itemRouter.route(to: \.item, item)
|
||||
|
@ -60,14 +60,14 @@ struct CinematicEpisodeItemView: View {
|
||||
.focusSection()
|
||||
|
||||
if let seriesItem = viewModel.series {
|
||||
PortraitItemsRowView(rowTitle: "Series",
|
||||
PortraitItemsRowView(rowTitle: L10n.series,
|
||||
items: [seriesItem]) { seriesItem in
|
||||
itemRouter.route(to: \.item, seriesItem)
|
||||
}
|
||||
}
|
||||
|
||||
if !viewModel.similarItems.isEmpty {
|
||||
PortraitItemsRowView(rowTitle: "Recommended",
|
||||
PortraitItemsRowView(rowTitle: L10n.recommended,
|
||||
items: viewModel.similarItems,
|
||||
showItemTitles: showPosterLabels) { item in
|
||||
itemRouter.route(to: \.item, item)
|
||||
|
@ -26,10 +26,10 @@ struct CinematicItemAboutView: View {
|
||||
.frame(height: 385.5)
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
Text("About")
|
||||
L10n.about.text
|
||||
.font(.title3)
|
||||
|
||||
Text(viewModel.item.overview ?? "No details available")
|
||||
Text(viewModel.item.overview ?? L10n.noOverviewAvailable)
|
||||
.padding(.top, 2)
|
||||
.lineLimit(7)
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ struct CinematicMovieItemView: View {
|
||||
CinematicItemAboutView(viewModel: viewModel)
|
||||
|
||||
if !viewModel.similarItems.isEmpty {
|
||||
PortraitItemsRowView(rowTitle: "Recommended",
|
||||
PortraitItemsRowView(rowTitle: L10n.recommended,
|
||||
items: viewModel.similarItems,
|
||||
showItemTitles: showPosterLabels) { item in
|
||||
itemRouter.route(to: \.item, item)
|
||||
|
@ -56,14 +56,14 @@ struct CinematicSeasonItemView: View {
|
||||
SingleSeasonEpisodesRowView(viewModel: SingleSeasonEpisodesRowViewModel(seasonItemViewModel: viewModel))
|
||||
|
||||
if let seriesItem = viewModel.seriesItem {
|
||||
PortraitItemsRowView(rowTitle: "Series",
|
||||
PortraitItemsRowView(rowTitle: L10n.series,
|
||||
items: [seriesItem]) { seriesItem in
|
||||
itemRouter.route(to: \.item, seriesItem)
|
||||
}
|
||||
}
|
||||
|
||||
if !viewModel.similarItems.isEmpty {
|
||||
PortraitItemsRowView(rowTitle: "Recommended",
|
||||
PortraitItemsRowView(rowTitle: L10n.recommended,
|
||||
items: viewModel.similarItems,
|
||||
showItemTitles: showPosterLabels) { item in
|
||||
itemRouter.route(to: \.item, item)
|
||||
|
@ -45,14 +45,14 @@ struct CinematicSeriesItemView: View {
|
||||
|
||||
CinematicItemAboutView(viewModel: viewModel)
|
||||
|
||||
PortraitItemsRowView(rowTitle: "Seasons",
|
||||
PortraitItemsRowView(rowTitle: L10n.seasons,
|
||||
items: viewModel.seasons,
|
||||
showItemTitles: showPosterLabels) { season in
|
||||
itemRouter.route(to: \.item, season)
|
||||
}
|
||||
|
||||
if !viewModel.similarItems.isEmpty {
|
||||
PortraitItemsRowView(rowTitle: "Recommended",
|
||||
PortraitItemsRowView(rowTitle: L10n.recommended,
|
||||
items: viewModel.similarItems,
|
||||
showItemTitles: showPosterLabels) { item in
|
||||
itemRouter.route(to: \.item, item)
|
||||
|
@ -42,7 +42,7 @@ struct LibrarySearchView: View {
|
||||
.onChange(of: searchQuery) { query in
|
||||
viewModel.searchQuerySubject.send(query)
|
||||
}
|
||||
.navigationBarTitle("Search")
|
||||
.navigationBarTitle(L10n.search)
|
||||
}
|
||||
|
||||
var suggestionsListView: some View {
|
||||
|
@ -85,7 +85,7 @@ struct LibraryView: View {
|
||||
VStack {
|
||||
L10n.noResults.text
|
||||
Button {} label: {
|
||||
Text("Reload")
|
||||
L10n.refresh.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ struct MovieLibrariesView: View {
|
||||
Button {
|
||||
print("movieLibraries reload")
|
||||
} label: {
|
||||
Text("Reload")
|
||||
L10n.refresh.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,9 +15,9 @@ struct ServerDetailView: View {
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
Section(header: Text("Server Details")) {
|
||||
Section(header: L10n.serverDetails.text) {
|
||||
HStack {
|
||||
Text("Name")
|
||||
L10n.name.text
|
||||
Spacer()
|
||||
Text(SessionManager.main.currentLogin.server.name)
|
||||
.foregroundColor(.secondary)
|
||||
@ -25,21 +25,21 @@ struct ServerDetailView: View {
|
||||
.focusable()
|
||||
|
||||
HStack {
|
||||
Text("URI")
|
||||
L10n.url.text
|
||||
Spacer()
|
||||
Text(SessionManager.main.currentLogin.server.currentURI)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
|
||||
HStack {
|
||||
Text("Version")
|
||||
L10n.version.text
|
||||
Spacer()
|
||||
Text(SessionManager.main.currentLogin.server.version)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
|
||||
HStack {
|
||||
Text("Operating System")
|
||||
L10n.operatingSystem.text
|
||||
Spacer()
|
||||
Text(SessionManager.main.currentLogin.server.os)
|
||||
.foregroundColor(.secondary)
|
||||
|
@ -52,7 +52,7 @@ struct ServerListView: View {
|
||||
Button(role: .destructive) {
|
||||
viewModel.remove(server: server)
|
||||
} label: {
|
||||
Label("Remove", systemImage: "trash")
|
||||
Label(L10n.remove, systemImage: "trash")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -65,7 +65,7 @@ struct ServerListView: View {
|
||||
@ViewBuilder
|
||||
private var noServerView: some View {
|
||||
VStack {
|
||||
Text("Connect to a Jellyfin server to get started")
|
||||
L10n.connectToJellyfinServerStart.text
|
||||
.frame(minWidth: 50, maxWidth: 500)
|
||||
.multilineTextAlignment(.center)
|
||||
.font(.body)
|
||||
@ -109,7 +109,7 @@ struct ServerListView: View {
|
||||
Button {
|
||||
serverListRouter.route(to: \.basicAppSettings)
|
||||
} label: {
|
||||
Text("Settings")
|
||||
L10n.settings.text
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -117,7 +117,7 @@ struct ServerListView: View {
|
||||
|
||||
var body: some View {
|
||||
innerBody
|
||||
.navigationTitle("Servers")
|
||||
.navigationTitle(L10n.servers)
|
||||
.toolbar {
|
||||
ToolbarItemGroup(placement: .navigationBarTrailing) {
|
||||
trailingToolbarContent
|
||||
|
@ -25,7 +25,7 @@ struct ExperimentalSettingsView: View {
|
||||
Toggle("Live TV (Alpha)", isOn: $liveTVAlphaEnabled)
|
||||
|
||||
} header: {
|
||||
Text("Experimental")
|
||||
L10n.experimental.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,11 +20,28 @@ struct OverlaySettingsView: View {
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
Section(header: Text("Overlay")) {
|
||||
Section(header: L10n.overlay.text) {
|
||||
|
||||
Toggle("\(Image(systemName: "chevron.left.circle")) Play Previous Item", isOn: $shouldShowPlayPreviousItem)
|
||||
Toggle("\(Image(systemName: "chevron.right.circle")) Play Next Item", isOn: $shouldShowPlayNextItem)
|
||||
Toggle("\(Image(systemName: "play.circle.fill")) Auto Play", isOn: $shouldShowAutoPlay)
|
||||
Toggle(isOn: $shouldShowPlayPreviousItem) {
|
||||
HStack {
|
||||
Image(systemName: "chevron.left.circle")
|
||||
L10n.playPreviousItem.text
|
||||
}
|
||||
}
|
||||
|
||||
Toggle(isOn: $shouldShowPlayNextItem) {
|
||||
HStack {
|
||||
Image(systemName: "chevron.right.circle")
|
||||
L10n.playNextItem.text
|
||||
}
|
||||
}
|
||||
|
||||
Toggle(isOn: $shouldShowAutoPlay) {
|
||||
HStack {
|
||||
Image(systemName: "play.circle.fill")
|
||||
L10n.autoPlay.text
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ struct SettingsView: View {
|
||||
|
||||
Button {} label: {
|
||||
HStack {
|
||||
Text("User")
|
||||
L10n.user.text
|
||||
Spacer()
|
||||
Text(viewModel.user.username)
|
||||
.foregroundColor(.jellyfinPurple)
|
||||
@ -62,7 +62,7 @@ struct SettingsView: View {
|
||||
settingsRouter.route(to: \.serverDetail)
|
||||
} label: {
|
||||
HStack {
|
||||
Text("Server")
|
||||
L10n.server.text
|
||||
.foregroundColor(.primary)
|
||||
Spacer()
|
||||
Text(viewModel.server.name)
|
||||
@ -76,36 +76,36 @@ struct SettingsView: View {
|
||||
Button {
|
||||
SessionManager.main.logout()
|
||||
} label: {
|
||||
Text("Switch User")
|
||||
L10n.switchUser.text
|
||||
.foregroundColor(Color.jellyfinPurple)
|
||||
.font(.callout)
|
||||
}
|
||||
}
|
||||
|
||||
Section(header: Text("Video Player")) {
|
||||
Picker("Jump Forward Length", selection: $jumpForwardLength) {
|
||||
Section(header: L10n.videoPlayer.text) {
|
||||
Picker(L10n.jumpForwardLength, selection: $jumpForwardLength) {
|
||||
ForEach(VideoPlayerJumpLength.allCases, id: \.self) { length in
|
||||
Text(length.label).tag(length.rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
Picker("Jump Backward Length", selection: $jumpBackwardLength) {
|
||||
Picker(L10n.jumpBackwardLength, selection: $jumpBackwardLength) {
|
||||
ForEach(VideoPlayerJumpLength.allCases, id: \.self) { length in
|
||||
Text(length.label).tag(length.rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
Toggle("Resume 5 Second Offset", isOn: $resumeOffset)
|
||||
Toggle(L10n.resume5SecondOffset, isOn: $resumeOffset)
|
||||
|
||||
Toggle("Press Down for Menu", isOn: $downActionShowsMenu)
|
||||
Toggle(L10n.pressDownForMenu, isOn: $downActionShowsMenu)
|
||||
|
||||
Toggle("Confirm Close", isOn: $confirmClose)
|
||||
Toggle(L10n.confirmClose, isOn: $confirmClose)
|
||||
|
||||
Button {
|
||||
settingsRouter.route(to: \.overlaySettings)
|
||||
} label: {
|
||||
HStack {
|
||||
Text("Overlay")
|
||||
L10n.overlay.text
|
||||
.foregroundColor(.primary)
|
||||
Spacer()
|
||||
Image(systemName: "chevron.right")
|
||||
@ -116,7 +116,7 @@ struct SettingsView: View {
|
||||
settingsRouter.route(to: \.experimentalSettings)
|
||||
} label: {
|
||||
HStack {
|
||||
Text("Experimental")
|
||||
L10n.experimental.text
|
||||
.foregroundColor(.primary)
|
||||
Spacer()
|
||||
Image(systemName: "chevron.right")
|
||||
@ -125,15 +125,15 @@ struct SettingsView: View {
|
||||
}
|
||||
|
||||
Section {
|
||||
Toggle("Cinematic Views", isOn: $tvOSCinematicViews)
|
||||
Toggle(L10n.cinematicViews, isOn: $tvOSCinematicViews)
|
||||
} header: {
|
||||
Text("Appearance")
|
||||
L10n.appearance.text
|
||||
}
|
||||
|
||||
Section(header: L10n.accessibility.text) {
|
||||
Toggle("Show Poster Labels", isOn: $showPosterLabels)
|
||||
Toggle(L10n.showPosterLabels, isOn: $showPosterLabels)
|
||||
|
||||
Picker("Subtitle size", selection: $subtitleSize) {
|
||||
Picker(L10n.subtitleSize, selection: $subtitleSize) {
|
||||
ForEach(SubtitleSize.allCases, id: \.self) { size in
|
||||
Text(size.label).tag(size.rawValue)
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ struct TVLibrariesView: View {
|
||||
Button {
|
||||
print("tvLibraries reload")
|
||||
} label: {
|
||||
Text("Reload")
|
||||
L10n.refresh.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ struct UserListView: View {
|
||||
Button(role: .destructive) {
|
||||
viewModel.remove(user: user)
|
||||
} label: {
|
||||
Label("Remove", systemImage: "trash")
|
||||
Label(L10n.remove, systemImage: "trash")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -52,7 +52,7 @@ struct UserListView: View {
|
||||
@ViewBuilder
|
||||
private var noUserView: some View {
|
||||
VStack {
|
||||
Text("Sign in to get started")
|
||||
L10n.signInGetStarted.text
|
||||
.frame(minWidth: 50, maxWidth: 500)
|
||||
.multilineTextAlignment(.center)
|
||||
.font(.callout)
|
||||
@ -60,7 +60,7 @@ struct UserListView: View {
|
||||
Button {
|
||||
userListRouter.route(to: \.userSignIn, viewModel.server)
|
||||
} label: {
|
||||
Text("Sign in")
|
||||
L10n.signIn.text
|
||||
.bold()
|
||||
.font(.callout)
|
||||
}
|
||||
|
@ -44,14 +44,14 @@ struct UserSignInView: View {
|
||||
.disabled(viewModel.isLoading || username.isEmpty)
|
||||
|
||||
} header: {
|
||||
Text("Sign In to \(viewModel.server.name)")
|
||||
L10n.signInToServer(viewModel.server.name).text
|
||||
}
|
||||
}
|
||||
.alert(item: $viewModel.errorMessage) { _ in
|
||||
Alert(title: Text(viewModel.alertTitle),
|
||||
message: Text(viewModel.errorMessage?.displayMessage ?? "Unknown Error"),
|
||||
message: Text(viewModel.errorMessage?.displayMessage ?? L10n.unknownError),
|
||||
dismissButton: .cancel())
|
||||
}
|
||||
.navigationTitle("Sign In")
|
||||
.navigationTitle(L10n.signIn)
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ struct SmallMediaStreamSelectionView: View {
|
||||
if updateFocusedLayer == .subtitles {
|
||||
HStack(spacing: 15) {
|
||||
Image(systemName: "captions.bubble")
|
||||
Text("Subtitles")
|
||||
L10n.subtitles.text
|
||||
}
|
||||
.padding()
|
||||
.background(Color.white)
|
||||
@ -82,7 +82,7 @@ struct SmallMediaStreamSelectionView: View {
|
||||
} else {
|
||||
HStack(spacing: 15) {
|
||||
Image(systemName: "captions.bubble")
|
||||
Text("Subtitles")
|
||||
L10n.subtitles.text
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
@ -106,7 +106,7 @@ struct SmallMediaStreamSelectionView: View {
|
||||
if updateFocusedLayer == .audio {
|
||||
HStack(spacing: 15) {
|
||||
Image(systemName: "speaker.wave.3")
|
||||
Text("Audio")
|
||||
L10n.audio.text
|
||||
}
|
||||
.padding()
|
||||
.background(Color.white)
|
||||
@ -114,7 +114,7 @@ struct SmallMediaStreamSelectionView: View {
|
||||
} else {
|
||||
HStack(spacing: 15) {
|
||||
Image(systemName: "speaker.wave.3")
|
||||
Text("Audio")
|
||||
L10n.audio.text
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
@ -138,7 +138,7 @@ struct SmallMediaStreamSelectionView: View {
|
||||
if updateFocusedLayer == .playbackSpeed {
|
||||
HStack(spacing: 15) {
|
||||
Image(systemName: "speedometer")
|
||||
Text("Playback Speed")
|
||||
L10n.playbackSpeed.text
|
||||
}
|
||||
.padding()
|
||||
.background(Color.white)
|
||||
@ -146,7 +146,7 @@ struct SmallMediaStreamSelectionView: View {
|
||||
} else {
|
||||
HStack(spacing: 15) {
|
||||
Image(systemName: "speedometer")
|
||||
Text("Playback Speed")
|
||||
L10n.playbackSpeed.text
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
@ -185,7 +185,7 @@ struct SmallMediaStreamSelectionView: View {
|
||||
HStack {
|
||||
if viewModel.subtitleStreams.isEmpty {
|
||||
Button {} label: {
|
||||
Text("None")
|
||||
L10n.none.text
|
||||
}
|
||||
} else {
|
||||
ForEach(viewModel.subtitleStreams, id: \.self) { subtitleStream in
|
||||
@ -193,9 +193,9 @@ struct SmallMediaStreamSelectionView: View {
|
||||
viewModel.selectedSubtitleStreamIndex = subtitleStream.index ?? -1
|
||||
} label: {
|
||||
if subtitleStream.index == viewModel.selectedSubtitleStreamIndex {
|
||||
Label(subtitleStream.displayTitle ?? "No Title", systemImage: "checkmark")
|
||||
Label(subtitleStream.displayTitle ?? L10n.noTitle, systemImage: "checkmark")
|
||||
} else {
|
||||
Text(subtitleStream.displayTitle ?? "No Title")
|
||||
Text(subtitleStream.displayTitle ?? L10n.noTitle)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -220,9 +220,9 @@ struct SmallMediaStreamSelectionView: View {
|
||||
viewModel.selectedAudioStreamIndex = audioStream.index ?? -1
|
||||
} label: {
|
||||
if audioStream.index == viewModel.selectedAudioStreamIndex {
|
||||
Label(audioStream.displayTitle ?? "No Title", systemImage: "checkmark")
|
||||
Label(audioStream.displayTitle ?? L10n.noTitle, systemImage: "checkmark")
|
||||
} else {
|
||||
Text(audioStream.displayTitle ?? "No Title")
|
||||
Text(audioStream.displayTitle ?? L10n.noTitle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -375,8 +375,6 @@
|
||||
E1AA33222782648000F6439C /* OverlaySliderColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AA33212782648000F6439C /* OverlaySliderColor.swift */; };
|
||||
E1AA33232782648000F6439C /* OverlaySliderColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AA33212782648000F6439C /* OverlaySliderColor.swift */; };
|
||||
E1AA332427829B5200F6439C /* OverlayType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AA331E2782639D00F6439C /* OverlayType.swift */; };
|
||||
E1AD104A26D94822003E4A08 /* DetailItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AD104926D94822003E4A08 /* DetailItem.swift */; };
|
||||
E1AD104B26D94822003E4A08 /* DetailItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AD104926D94822003E4A08 /* DetailItem.swift */; };
|
||||
E1AD104D26D96CE3003E4A08 /* BaseItemDtoExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AD104C26D96CE3003E4A08 /* BaseItemDtoExtensions.swift */; };
|
||||
E1AD104E26D96CE3003E4A08 /* BaseItemDtoExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AD104C26D96CE3003E4A08 /* BaseItemDtoExtensions.swift */; };
|
||||
E1AD105426D97161003E4A08 /* BaseItemDtoExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AD104C26D96CE3003E4A08 /* BaseItemDtoExtensions.swift */; };
|
||||
@ -721,7 +719,6 @@
|
||||
E1AA331C2782541500F6439C /* PrimaryButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrimaryButtonView.swift; sourceTree = "<group>"; };
|
||||
E1AA331E2782639D00F6439C /* OverlayType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverlayType.swift; sourceTree = "<group>"; };
|
||||
E1AA33212782648000F6439C /* OverlaySliderColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverlaySliderColor.swift; sourceTree = "<group>"; };
|
||||
E1AD104926D94822003E4A08 /* DetailItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailItem.swift; sourceTree = "<group>"; };
|
||||
E1AD104C26D96CE3003E4A08 /* BaseItemDtoExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseItemDtoExtensions.swift; sourceTree = "<group>"; };
|
||||
E1AD105526D981CE003E4A08 /* PortraitHStackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PortraitHStackView.swift; sourceTree = "<group>"; };
|
||||
E1AD105B26D9ABDD003E4A08 /* PillHStackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillHStackView.swift; sourceTree = "<group>"; };
|
||||
@ -974,7 +971,6 @@
|
||||
children = (
|
||||
E1D4BF802719D22800A11E64 /* AppAppearance.swift */,
|
||||
E1D4BF862719D27100A11E64 /* Bitrates.swift */,
|
||||
E1AD104926D94822003E4A08 /* DetailItem.swift */,
|
||||
53192D5C265AA78A008A4215 /* DeviceProfileBuilder.swift */,
|
||||
62EC353326766B03000E9F2D /* DeviceRotationViewModifier.swift */,
|
||||
E19169CD272514760085832A /* HTTPScheme.swift */,
|
||||
@ -1674,7 +1670,6 @@
|
||||
buildPhases = (
|
||||
3D0F2756C71CDF6B9EEBD4E0 /* [CP] Check Pods Manifest.lock */,
|
||||
6286F0A3271C0ABA00C40ED5 /* R.swift */,
|
||||
C6EE6AB295A273FF14E6EF56 /* [CP] Prepare Artifacts */,
|
||||
5358705C2669D21600D05A09 /* Sources */,
|
||||
5358705D2669D21600D05A09 /* Frameworks */,
|
||||
5358705E2669D21600D05A09 /* Resources */,
|
||||
@ -1819,7 +1814,7 @@
|
||||
536D3D82267BEA550004248C /* XCRemoteSwiftPackageReference "ParallaxView" */,
|
||||
53649AAB269CFAEA00A2D8B7 /* XCRemoteSwiftPackageReference "Puppy" */,
|
||||
62C29E9A26D0FE4100C1D2E7 /* XCRemoteSwiftPackageReference "stinsen" */,
|
||||
E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore" */,
|
||||
E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore.git" */,
|
||||
E13DD3D127168E65009D4DAF /* XCRemoteSwiftPackageReference "Defaults" */,
|
||||
E1267D42271A212C003C492E /* XCRemoteSwiftPackageReference "CombineExt" */,
|
||||
E1C16B89271A2180009A5D25 /* XCRemoteSwiftPackageReference "SwiftyJSON" */,
|
||||
@ -2033,23 +2028,6 @@
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Swiftfin iOS/Pods-Swiftfin iOS-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
C6EE6AB295A273FF14E6EF56 /* [CP] Prepare Artifacts */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Swiftfin tvOS/Pods-Swiftfin tvOS-artifacts-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Prepare Artifacts";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Swiftfin tvOS/Pods-Swiftfin tvOS-artifacts-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Swiftfin tvOS/Pods-Swiftfin tvOS-artifacts.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
D4D3981ADF75BCD341D590C0 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@ -2148,7 +2126,6 @@
|
||||
62EC3530267666A5000E9F2D /* SessionManager.swift in Sources */,
|
||||
E1E5D5372783A52C00692DFE /* CinematicEpisodeItemView.swift in Sources */,
|
||||
C4BE078E27298818003F4AD1 /* LiveTVHomeView.swift in Sources */,
|
||||
E1AD104B26D94822003E4A08 /* DetailItem.swift in Sources */,
|
||||
E13DD3E227176BD3009D4DAF /* ServerListViewModel.swift in Sources */,
|
||||
53272539268C20100035FBF1 /* EpisodeItemView.swift in Sources */,
|
||||
E178859B2780F1F40094FBCF /* tvOSSlider.swift in Sources */,
|
||||
@ -2375,7 +2352,6 @@
|
||||
E13DD3E927177ED6009D4DAF /* ServerListCoordinator.swift in Sources */,
|
||||
E1C812BD277A8E5D00918266 /* PlayerOverlayDelegate.swift in Sources */,
|
||||
E13DD3C227164941009D4DAF /* SwiftfinStore.swift in Sources */,
|
||||
E1AD104A26D94822003E4A08 /* DetailItem.swift in Sources */,
|
||||
62E632E0267D30CA0063E547 /* LibraryViewModel.swift in Sources */,
|
||||
E193D4DB27193CCA00900D82 /* PillStackable.swift in Sources */,
|
||||
E1AA331F2782639D00F6439C /* OverlayType.swift in Sources */,
|
||||
@ -2797,7 +2773,7 @@
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 66;
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DEVELOPMENT_TEAM = TY84JMYEFE;
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
EXCLUDED_ARCHS = "";
|
||||
@ -2834,7 +2810,7 @@
|
||||
CURRENT_PROJECT_VERSION = 66;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DEVELOPMENT_TEAM = TY84JMYEFE;
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
EXCLUDED_ARCHS = "";
|
||||
@ -2865,7 +2841,7 @@
|
||||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 66;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DEVELOPMENT_TEAM = TY84JMYEFE;
|
||||
INFOPLIST_FILE = WidgetExtension/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
@ -2892,7 +2868,7 @@
|
||||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 66;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DEVELOPMENT_TEAM = TY84JMYEFE;
|
||||
INFOPLIST_FILE = WidgetExtension/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
@ -3024,7 +3000,7 @@
|
||||
minimumVersion = 1.0.0;
|
||||
};
|
||||
};
|
||||
E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore" */ = {
|
||||
E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore.git" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/JohnEstropia/CoreStore.git";
|
||||
requirement = {
|
||||
@ -3141,17 +3117,17 @@
|
||||
};
|
||||
E13DD3C52716499E009D4DAF /* CoreStore */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore" */;
|
||||
package = E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore.git" */;
|
||||
productName = CoreStore;
|
||||
};
|
||||
E13DD3CC27164CA7009D4DAF /* CoreStore */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore" */;
|
||||
package = E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore.git" */;
|
||||
productName = CoreStore;
|
||||
};
|
||||
E13DD3CE27164E1F009D4DAF /* CoreStore */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore" */;
|
||||
package = E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore.git" */;
|
||||
productName = CoreStore;
|
||||
};
|
||||
E13DD3D227168E65009D4DAF /* Defaults */ = {
|
||||
|
@ -26,15 +26,15 @@ struct EpisodesRowView: View {
|
||||
viewModel.selectedSeason = season
|
||||
} label: {
|
||||
if season.id == viewModel.selectedSeason?.id {
|
||||
Label(season.name ?? "Season", systemImage: "checkmark")
|
||||
Label(season.name ?? L10n.season, systemImage: "checkmark")
|
||||
} else {
|
||||
Text(season.name ?? "Season")
|
||||
Text(season.name ?? L10n.season)
|
||||
}
|
||||
}
|
||||
}
|
||||
} label: {
|
||||
HStack(spacing: 5) {
|
||||
Text(viewModel.selectedSeason?.name ?? "Unknown")
|
||||
Text(viewModel.selectedSeason?.name ?? L10n.unknown)
|
||||
.fontWeight(.semibold)
|
||||
.fixedSize()
|
||||
Image(systemName: "chevron.down")
|
||||
@ -85,7 +85,8 @@ struct EpisodesRowView: View {
|
||||
Text("--")
|
||||
.font(.footnote)
|
||||
.foregroundColor(.secondary)
|
||||
Text("No episodes available")
|
||||
|
||||
L10n.noEpisodesAvailable.text
|
||||
.font(.body)
|
||||
.padding(.bottom, 1)
|
||||
.lineLimit(2)
|
||||
|
@ -23,7 +23,7 @@ struct TruncatedTextView: View {
|
||||
if !truncated {
|
||||
return ""
|
||||
} else {
|
||||
return "See More"
|
||||
return L10n.seeMore
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,55 +41,55 @@ struct BasicAppSettingsView: View {
|
||||
}
|
||||
|
||||
Section {
|
||||
Picker("Default Scheme", selection: $defaultHTTPScheme) {
|
||||
Picker(L10n.defaultScheme, selection: $defaultHTTPScheme) {
|
||||
ForEach(HTTPScheme.allCases, id: \.self) { scheme in
|
||||
Text("\(scheme.rawValue)")
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
Text("Networking")
|
||||
L10n.networking.text
|
||||
}
|
||||
|
||||
Button {
|
||||
resetUserSettingsTapped = true
|
||||
} label: {
|
||||
Text("Reset User Settings")
|
||||
L10n.resetUserSettings.text
|
||||
}
|
||||
|
||||
Button {
|
||||
resetAppSettingsTapped = true
|
||||
} label: {
|
||||
Text("Reset App Settings")
|
||||
L10n.resetAppSettings.text
|
||||
}
|
||||
|
||||
Button {
|
||||
removeAllUsersTapped = true
|
||||
} label: {
|
||||
Text("Remove All Users")
|
||||
L10n.removeAllUsers.text
|
||||
}
|
||||
}
|
||||
.alert("Reset User Settings", isPresented: $resetUserSettingsTapped, actions: {
|
||||
.alert(L10n.resetUserSettings, isPresented: $resetUserSettingsTapped, actions: {
|
||||
Button(role: .destructive) {
|
||||
viewModel.resetUserSettings()
|
||||
} label: {
|
||||
L10n.reset.text
|
||||
}
|
||||
})
|
||||
.alert("Reset App Settings", isPresented: $resetAppSettingsTapped, actions: {
|
||||
.alert(L10n.resetAppSettings, isPresented: $resetAppSettingsTapped, actions: {
|
||||
Button(role: .destructive) {
|
||||
viewModel.resetAppSettings()
|
||||
} label: {
|
||||
L10n.reset.text
|
||||
}
|
||||
})
|
||||
.alert("Remove All Users", isPresented: $removeAllUsersTapped, actions: {
|
||||
.alert(L10n.removeAllUsers, isPresented: $removeAllUsersTapped, actions: {
|
||||
Button(role: .destructive) {
|
||||
viewModel.removeAllUsers()
|
||||
} label: {
|
||||
L10n.reset.text
|
||||
}
|
||||
})
|
||||
.navigationBarTitle("Settings", displayMode: .inline)
|
||||
.navigationBarTitle(L10n.settings, displayMode: .inline)
|
||||
.toolbar {
|
||||
ToolbarItemGroup(placement: .navigationBarLeading) {
|
||||
Button {
|
||||
|
@ -37,7 +37,7 @@ struct ConnectToServerView: View {
|
||||
Button(role: .destructive) {
|
||||
viewModel.cancelConnection()
|
||||
} label: {
|
||||
Text("Cancel")
|
||||
L10n.cancel.text
|
||||
}
|
||||
} else {
|
||||
Button {
|
||||
@ -48,17 +48,14 @@ struct ConnectToServerView: View {
|
||||
.disabled(uri.isEmpty)
|
||||
}
|
||||
} header: {
|
||||
Text("Connect to a Jellyfin server")
|
||||
L10n.connectToJellyfinServer.text
|
||||
}
|
||||
|
||||
Section {
|
||||
if viewModel.searching {
|
||||
HStack(alignment: .center, spacing: 5) {
|
||||
Spacer()
|
||||
// Oct. 15, 2021
|
||||
// There is a bug where ProgressView() won't appear sometimes when searching,
|
||||
// dots were used instead but ProgressView() is preferred
|
||||
Text("Searching...")
|
||||
L10n.searchingDots.text
|
||||
.foregroundColor(.secondary)
|
||||
Spacer()
|
||||
}
|
||||
@ -66,7 +63,7 @@ struct ConnectToServerView: View {
|
||||
if viewModel.discoveredServers.isEmpty {
|
||||
HStack(alignment: .center) {
|
||||
Spacer()
|
||||
Text("No local servers found")
|
||||
L10n.noLocalServersFound.text
|
||||
.font(.callout)
|
||||
.foregroundColor(.secondary)
|
||||
Spacer()
|
||||
@ -106,7 +103,7 @@ struct ConnectToServerView: View {
|
||||
}
|
||||
.alert(item: $viewModel.errorMessage) { _ in
|
||||
Alert(title: Text(viewModel.alertTitle),
|
||||
message: Text(viewModel.errorMessage?.displayMessage ?? "Unknown Error"),
|
||||
message: Text(viewModel.errorMessage?.displayMessage ?? L10n.unknownError),
|
||||
dismissButton: .cancel())
|
||||
}
|
||||
.alert(item: $viewModel.addServerURIPayload) { _ in
|
||||
|
@ -43,7 +43,7 @@ struct ContinueWatchingView: View {
|
||||
.frame(height: 35)
|
||||
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
Text(item.getItemProgressString() ?? "Continue")
|
||||
Text(item.getItemProgressString() ?? L10n.continue)
|
||||
.font(.subheadline)
|
||||
.padding(.bottom, 5)
|
||||
.padding(.leading, 10)
|
||||
|
@ -39,7 +39,7 @@ struct HomeView: View {
|
||||
.frame(minWidth: 50, maxWidth: 240)
|
||||
.multilineTextAlignment(.center)
|
||||
|
||||
PrimaryButtonView(title: "Retry") {
|
||||
PrimaryButtonView(title: L10n.retry) {
|
||||
viewModel.refresh()
|
||||
}
|
||||
}
|
||||
@ -69,7 +69,7 @@ struct HomeView: View {
|
||||
|
||||
if !viewModel.latestAddedItems.isEmpty {
|
||||
PortraitImageHStackView(items: viewModel.latestAddedItems) {
|
||||
Text("Recently Added")
|
||||
L10n.recentlyAdded.text
|
||||
.font(.title2)
|
||||
.fontWeight(.bold)
|
||||
.padding()
|
||||
|
@ -21,7 +21,7 @@ struct ItemOverviewView: View {
|
||||
.font(.footnote)
|
||||
.padding()
|
||||
}
|
||||
.navigationBarTitle("Overview", displayMode: .inline)
|
||||
.navigationBarTitle(L10n.overview, displayMode: .inline)
|
||||
.toolbar {
|
||||
ToolbarItemGroup(placement: .navigationBarLeading) {
|
||||
Button {
|
||||
|
@ -42,7 +42,7 @@ struct ItemViewBody: View {
|
||||
.padding()
|
||||
}
|
||||
} else {
|
||||
Text("No overview available")
|
||||
L10n.noOverviewAvailable.text
|
||||
.font(.footnote)
|
||||
.padding()
|
||||
}
|
||||
@ -92,7 +92,7 @@ struct ItemViewBody: View {
|
||||
if let seriesItem = episodeViewModel.series {
|
||||
let a = [seriesItem]
|
||||
PortraitImageHStackView(items: a) {
|
||||
Text("Series")
|
||||
L10n.series.text
|
||||
.fontWeight(.semibold)
|
||||
.padding(.bottom)
|
||||
.padding(.horizontal)
|
||||
@ -106,7 +106,7 @@ struct ItemViewBody: View {
|
||||
|
||||
if let collectionViewModel = viewModel as? CollectionItemViewModel {
|
||||
PortraitImageHStackView(items: collectionViewModel.collectionItems) {
|
||||
Text("Items")
|
||||
L10n.items.text
|
||||
.fontWeight(.semibold)
|
||||
.padding(.bottom)
|
||||
.padding(.horizontal)
|
||||
@ -121,7 +121,7 @@ struct ItemViewBody: View {
|
||||
if let castAndCrew = viewModel.item.people {
|
||||
PortraitImageHStackView(items: castAndCrew.filter { BaseItemPerson.DisplayedType.allCasesRaw.contains($0.type ?? "") },
|
||||
topBarView: {
|
||||
Text("Cast & Crew")
|
||||
L10n.castAndCrew.text
|
||||
.fontWeight(.semibold)
|
||||
.padding(.bottom)
|
||||
.padding(.horizontal)
|
||||
|
@ -19,7 +19,7 @@ struct ItemViewDetailsView: View {
|
||||
|
||||
if !viewModel.informationItems.isEmpty {
|
||||
VStack(alignment: .leading, spacing: 20) {
|
||||
Text("Information")
|
||||
L10n.information.text
|
||||
.font(.title3)
|
||||
.fontWeight(.bold)
|
||||
|
||||
@ -38,7 +38,7 @@ struct ItemViewDetailsView: View {
|
||||
|
||||
if !viewModel.mediaItems.isEmpty {
|
||||
VStack(alignment: .leading, spacing: 20) {
|
||||
Text("Media")
|
||||
L10n.media.text
|
||||
.font(.title3)
|
||||
.fontWeight(.bold)
|
||||
|
||||
|
@ -21,7 +21,7 @@ struct LibraryListView: View {
|
||||
LazyVStack {
|
||||
Button {
|
||||
libraryListRouter.route(to: \.library,
|
||||
(viewModel: LibraryViewModel(filters: viewModel.withFavorites), title: "Favorites"))
|
||||
(viewModel: LibraryViewModel(filters: viewModel.withFavorites), title: L10n.favorites))
|
||||
} label: {
|
||||
ZStack {
|
||||
HStack {
|
||||
|
@ -45,7 +45,7 @@ struct LibrarySearchView: View {
|
||||
.onChange(of: searchQuery) { query in
|
||||
viewModel.searchQuerySubject.send(query)
|
||||
}
|
||||
.navigationBarTitle("Search", displayMode: .inline)
|
||||
.navigationBarTitle(L10n.search, displayMode: .inline)
|
||||
}
|
||||
|
||||
var suggestionsListView: some View {
|
||||
|
@ -22,15 +22,15 @@ struct ServerDetailView: View {
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
Section(header: Text("Server Details")) {
|
||||
Section(header: L10n.serverDetails.text) {
|
||||
HStack {
|
||||
Text("Name")
|
||||
L10n.name.text
|
||||
Spacer()
|
||||
Text(viewModel.server.name)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
|
||||
Picker("URI", selection: $currentServerURI) {
|
||||
Picker(L10n.url, selection: $currentServerURI) {
|
||||
ForEach(viewModel.server.uris.sorted(), id: \.self) { uri in
|
||||
Text(uri).tag(uri)
|
||||
.foregroundColor(.secondary)
|
||||
@ -40,14 +40,14 @@ struct ServerDetailView: View {
|
||||
}
|
||||
|
||||
HStack {
|
||||
Text("Version")
|
||||
L10n.version.text
|
||||
Spacer()
|
||||
Text(viewModel.server.version)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
|
||||
HStack {
|
||||
Text("Operating System")
|
||||
L10n.operatingSystem.text
|
||||
Spacer()
|
||||
Text(viewModel.server.os)
|
||||
.foregroundColor(.secondary)
|
||||
|
@ -56,7 +56,7 @@ struct ServerListView: View {
|
||||
Button(role: .destructive) {
|
||||
viewModel.remove(server: server)
|
||||
} label: {
|
||||
Label("Remove", systemImage: "trash")
|
||||
Label(L10n.remove, systemImage: "trash")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -66,7 +66,7 @@ struct ServerListView: View {
|
||||
|
||||
private var noServerView: some View {
|
||||
VStack {
|
||||
Text("Connect to a Jellyfin server to get started")
|
||||
L10n.connectToJellyfinServerStart.text
|
||||
.frame(minWidth: 50, maxWidth: 240)
|
||||
.multilineTextAlignment(.center)
|
||||
|
||||
@ -109,7 +109,7 @@ struct ServerListView: View {
|
||||
|
||||
var body: some View {
|
||||
innerBody
|
||||
.navigationTitle("Servers")
|
||||
.navigationTitle(L10n.servers)
|
||||
.toolbar {
|
||||
ToolbarItemGroup(placement: .navigationBarTrailing) {
|
||||
trailingToolbarContent
|
||||
|
@ -21,7 +21,7 @@ struct ExperimentalSettingsView: View {
|
||||
Toggle("Sync Subtitles with Adjacent Episodes", isOn: $syncSubtitleStateWithAdjacent)
|
||||
|
||||
} header: {
|
||||
Text("Experimental")
|
||||
L10n.experimental.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,17 +24,35 @@ struct OverlaySettingsView: View {
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
Section(header: Text("Overlay")) {
|
||||
Picker("Overlay Type", selection: $overlayType) {
|
||||
Section(header: L10n.overlay.text) {
|
||||
Picker(L10n.overlayType, selection: $overlayType) {
|
||||
ForEach(OverlayType.allCases, id: \.self) { overlay in
|
||||
Text(overlay.label).tag(overlay)
|
||||
}
|
||||
}
|
||||
|
||||
Toggle("\(Image(systemName: "chevron.left.circle")) Play Previous Item", isOn: $shouldShowPlayPreviousItem)
|
||||
Toggle("\(Image(systemName: "chevron.right.circle")) Play Next Item", isOn: $shouldShowPlayNextItem)
|
||||
Toggle("\(Image(systemName: "play.circle.fill")) Auto Play", isOn: $shouldShowAutoPlay)
|
||||
Toggle("Edit Jump Lengths", isOn: $shouldShowJumpButtonsInOverlayMenu)
|
||||
Toggle(isOn: $shouldShowPlayPreviousItem) {
|
||||
HStack {
|
||||
Image(systemName: "chevron.left.circle")
|
||||
L10n.playPreviousItem.text
|
||||
}
|
||||
}
|
||||
|
||||
Toggle(isOn: $shouldShowPlayNextItem) {
|
||||
HStack {
|
||||
Image(systemName: "chevron.right.circle")
|
||||
L10n.playNextItem.text
|
||||
}
|
||||
}
|
||||
|
||||
Toggle(isOn: $shouldShowAutoPlay) {
|
||||
HStack {
|
||||
Image(systemName: "play.circle.fill")
|
||||
L10n.autoPlay.text
|
||||
}
|
||||
}
|
||||
|
||||
Toggle(L10n.editJumpLengths, isOn: $shouldShowJumpButtonsInOverlayMenu)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ struct SettingsView: View {
|
||||
Form {
|
||||
Section(header: EmptyView()) {
|
||||
HStack {
|
||||
Text("User")
|
||||
L10n.user.text
|
||||
Spacer()
|
||||
Text(viewModel.user.username)
|
||||
.foregroundColor(.jellyfinPurple)
|
||||
@ -61,7 +61,7 @@ struct SettingsView: View {
|
||||
settingsRouter.route(to: \.serverDetail)
|
||||
} label: {
|
||||
HStack {
|
||||
Text("Server")
|
||||
L10n.server.text
|
||||
.foregroundColor(.primary)
|
||||
Spacer()
|
||||
Text(viewModel.server.name)
|
||||
@ -76,7 +76,7 @@ struct SettingsView: View {
|
||||
SessionManager.main.logout()
|
||||
}
|
||||
} label: {
|
||||
Text("Switch User")
|
||||
L10n.switchUser.text
|
||||
.font(.callout)
|
||||
}
|
||||
}
|
||||
@ -96,28 +96,28 @@ struct SettingsView: View {
|
||||
// }
|
||||
// }
|
||||
|
||||
Section(header: Text("Video Player")) {
|
||||
Picker("Jump Forward Length", selection: $jumpForwardLength) {
|
||||
Section(header: L10n.videoPlayer.text) {
|
||||
Picker(L10n.jumpForwardLength, selection: $jumpForwardLength) {
|
||||
ForEach(VideoPlayerJumpLength.allCases, id: \.self) { length in
|
||||
Text(length.label).tag(length.rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
Picker("Jump Backward Length", selection: $jumpBackwardLength) {
|
||||
Picker(L10n.jumpBackwardLength, selection: $jumpBackwardLength) {
|
||||
ForEach(VideoPlayerJumpLength.allCases, id: \.self) { length in
|
||||
Text(length.label).tag(length.rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
Toggle("Jump Gestures Enabled", isOn: $jumpGesturesEnabled)
|
||||
Toggle(L10n.jumpGesturesEnabled, isOn: $jumpGesturesEnabled)
|
||||
|
||||
Toggle("Resume 5 Second Offset", isOn: $resumeOffset)
|
||||
Toggle(L10n.resume5SecondOffset, isOn: $resumeOffset)
|
||||
|
||||
Button {
|
||||
settingsRouter.route(to: \.overlaySettings)
|
||||
} label: {
|
||||
HStack {
|
||||
Text("Overlay")
|
||||
L10n.overlay.text
|
||||
.foregroundColor(.primary)
|
||||
Spacer()
|
||||
Text(overlayType.label)
|
||||
@ -129,7 +129,7 @@ struct SettingsView: View {
|
||||
settingsRouter.route(to: \.experimentalSettings)
|
||||
} label: {
|
||||
HStack {
|
||||
Text("Experimental")
|
||||
L10n.experimental.text
|
||||
.foregroundColor(.primary)
|
||||
Spacer()
|
||||
Image(systemName: "chevron.right")
|
||||
@ -138,22 +138,22 @@ struct SettingsView: View {
|
||||
}
|
||||
|
||||
Section(header: L10n.accessibility.text) {
|
||||
Toggle("Show Poster Labels", isOn: $showPosterLabels)
|
||||
Toggle("Show Cast and Crew", isOn: $showCastAndCrew)
|
||||
Toggle(L10n.showPosterLabels, isOn: $showPosterLabels)
|
||||
Toggle(L10n.showCastAndCrew, isOn: $showCastAndCrew)
|
||||
|
||||
Picker(L10n.appearance, selection: $appAppearance) {
|
||||
ForEach(AppAppearance.allCases, id: \.self) { appearance in
|
||||
Text(appearance.localizedName).tag(appearance.rawValue)
|
||||
}
|
||||
}
|
||||
Picker("Subtitle size", selection: $subtitleSize) {
|
||||
Picker(L10n.subtitleSize, selection: $subtitleSize) {
|
||||
ForEach(SubtitleSize.allCases, id: \.self) { size in
|
||||
Text(size.label).tag(size.rawValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationBarTitle("Settings", displayMode: .inline)
|
||||
.navigationBarTitle(L10n.settings, displayMode: .inline)
|
||||
.toolbar {
|
||||
ToolbarItemGroup(placement: .navigationBarLeading) {
|
||||
Button {
|
||||
|
@ -45,7 +45,7 @@ struct UserListView: View {
|
||||
Button(role: .destructive) {
|
||||
viewModel.remove(user: user)
|
||||
} label: {
|
||||
Label("Remove", systemImage: "trash")
|
||||
Label(L10n.remove, systemImage: "trash")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -55,7 +55,7 @@ struct UserListView: View {
|
||||
|
||||
private var noUserView: some View {
|
||||
VStack {
|
||||
Text("Sign in to get started")
|
||||
L10n.signInGetStarted.text
|
||||
.frame(minWidth: 50, maxWidth: 240)
|
||||
.multilineTextAlignment(.center)
|
||||
|
||||
@ -71,7 +71,7 @@ struct UserListView: View {
|
||||
.padding(.horizontal, 30)
|
||||
.padding([.top, .bottom], 20)
|
||||
|
||||
Text("Sign in")
|
||||
L10n.signIn.text
|
||||
.foregroundColor(Color.white)
|
||||
.bold()
|
||||
}
|
||||
|
@ -34,26 +34,26 @@ struct UserSignInView: View {
|
||||
Button(role: .destructive) {
|
||||
viewModel.cancelSignIn()
|
||||
} label: {
|
||||
Text("Cancel")
|
||||
L10n.cancel.text
|
||||
}
|
||||
} else {
|
||||
Button {
|
||||
viewModel.login(username: username, password: password)
|
||||
} label: {
|
||||
Text("Sign In")
|
||||
L10n.signIn.text
|
||||
}
|
||||
.disabled(username.isEmpty)
|
||||
}
|
||||
} header: {
|
||||
Text("Sign In to \(viewModel.server.name)")
|
||||
L10n.signInToServer(viewModel.server.name).text
|
||||
}
|
||||
}
|
||||
.alert(item: $viewModel.errorMessage) { _ in
|
||||
Alert(title: Text(viewModel.alertTitle),
|
||||
message: Text(viewModel.errorMessage?.displayMessage ?? "Unknown Error"),
|
||||
message: Text(viewModel.errorMessage?.displayMessage ?? L10n.unknownError),
|
||||
dismissButton: .cancel())
|
||||
}
|
||||
.navigationTitle("Sign In")
|
||||
.navigationTitle(L10n.signIn)
|
||||
.navigationBarBackButtonHidden(viewModel.isLoading)
|
||||
}
|
||||
}
|
||||
|
@ -142,16 +142,16 @@ struct VLCPlayerOverlayView: View {
|
||||
viewModel.selectedAudioStreamIndex = audioStream.index ?? -1
|
||||
} label: {
|
||||
if audioStream.index == viewModel.selectedAudioStreamIndex {
|
||||
Label(audioStream.displayTitle ?? "No Title", systemImage: "checkmark")
|
||||
Label(audioStream.displayTitle ?? L10n.noTitle, systemImage: "checkmark")
|
||||
} else {
|
||||
Text(audioStream.displayTitle ?? "No Title")
|
||||
Text(audioStream.displayTitle ?? L10n.noTitle)
|
||||
}
|
||||
}
|
||||
}
|
||||
} label: {
|
||||
HStack {
|
||||
Image(systemName: "speaker.wave.3")
|
||||
Text("Audio")
|
||||
L10n.audio.text
|
||||
}
|
||||
}
|
||||
|
||||
@ -161,16 +161,16 @@ struct VLCPlayerOverlayView: View {
|
||||
viewModel.selectedSubtitleStreamIndex = subtitleStream.index ?? -1
|
||||
} label: {
|
||||
if subtitleStream.index == viewModel.selectedSubtitleStreamIndex {
|
||||
Label(subtitleStream.displayTitle ?? "No Title", systemImage: "checkmark")
|
||||
Label(subtitleStream.displayTitle ?? L10n.noTitle, systemImage: "checkmark")
|
||||
} else {
|
||||
Text(subtitleStream.displayTitle ?? "No Title")
|
||||
Text(subtitleStream.displayTitle ?? L10n.noTitle)
|
||||
}
|
||||
}
|
||||
}
|
||||
} label: {
|
||||
HStack {
|
||||
Image(systemName: "captions.bubble")
|
||||
Text("Subtitles")
|
||||
L10n.subtitles.text
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,7 +189,7 @@ struct VLCPlayerOverlayView: View {
|
||||
} label: {
|
||||
HStack {
|
||||
Image(systemName: "speedometer")
|
||||
Text("Playback Speed")
|
||||
L10n.playbackSpeed.text
|
||||
}
|
||||
}
|
||||
|
||||
@ -209,7 +209,7 @@ struct VLCPlayerOverlayView: View {
|
||||
} label: {
|
||||
HStack {
|
||||
Image(systemName: "goforward")
|
||||
Text("Jump Forward Length")
|
||||
L10n.jumpForwardLength.text
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,7 +228,7 @@ struct VLCPlayerOverlayView: View {
|
||||
} label: {
|
||||
HStack {
|
||||
Image(systemName: "gobackward")
|
||||
Text("Jump Backward Length")
|
||||
L10n.jumpBackwardLength.text
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -337,10 +337,7 @@ struct VLCPlayerOverlayView: View {
|
||||
Capsule().foregroundColor(.purple))
|
||||
.background(Capsule().foregroundColor(Color.gray.opacity(0.25)))
|
||||
.frame(height: 4),
|
||||
thumb: Circle().foregroundColor(.purple)
|
||||
.onLongPressGesture(perform: {
|
||||
print("got it here")
|
||||
}),
|
||||
thumb: Circle().foregroundColor(.purple),
|
||||
thumbSize: CGSize.Circle(radius: viewModel.sliderIsScrubbing ? 20 : 15),
|
||||
thumbInteractiveSize: CGSize.Circle(radius: 40),
|
||||
options: .defaultOptions))
|
||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user