diff --git a/Shared/Extensions/JellyfinAPI/DeviceType.swift b/Shared/Extensions/JellyfinAPI/DeviceType.swift new file mode 100644 index 000000000..0c102c82b --- /dev/null +++ b/Shared/Extensions/JellyfinAPI/DeviceType.swift @@ -0,0 +1,276 @@ +// +// Swiftfin is subject to the terms of the Mozilla Public +// License, v2.0. If a copy of the MPL was not distributed with this +// file, you can obtain one at https://mozilla.org/MPL/2.0/. +// +// Copyright (c) 2024 Jellyfin & Jellyfin Contributors +// + +import SwiftUI + +enum DeviceType: String, Displayable, Codable, CaseIterable { + case android + case apple + case chrome + case edge + case edgechromium + case finamp + case firefox + case homeAssistant + case html5 + case kodi + case msie + case opera + case playstation + case roku + case safari + case samsungtv + case webos + case windows + case xbox + case other + + // MARK: - Display Title + + var displayTitle: String { + switch self { + case .android: + return "Android" + case .apple: + return "Apple" + case .chrome: + return "Chrome" + case .edge: + return "Edge" + case .edgechromium: + return "Edge Chromium" + case .finamp: + return "Finamp" + case .firefox: + return "Firefox" + case .homeAssistant: + return "Home Assistant" + case .html5: + return "HTML5" + case .kodi: + return "Kodi" + case .msie: + return "Internet Explorer" + case .opera: + return "Opera" + case .playstation: + return "PlayStation" + case .roku: + return "Roku" + case .safari: + return "Safari" + case .samsungtv: + return "Samsung TV" + case .webos: + return "WebOS" + case .windows: + return "Windows" + case .xbox: + return "Xbox" + case .other: + return "Other" + } + } + + // MARK: - Initialize the Client + + init(client: String?, deviceName: String?) { + guard let client = client?.lowercased() else { + self = .other + return + } + + switch client { + + /* Android or Findroid */ + case let str where str.range(of: #"android|findroid"#, options: .regularExpression) != nil: + self = .android + + /* Apple devices: iOS, tvOS, iPadOS, Swiftfin, or Infuse */ + case let str where str.range(of: #"ios|tvos|ipados|swiftfin|infuse"#, options: .regularExpression) != nil: + self = .apple + + /* Finamp */ + case let str where str.range(of: #"finamp"#, options: .regularExpression) != nil: + self = .finamp + + /* Home Assistant or HomeAssistant */ + case let str where str.range(of: #"home.assistant|homeassistant"#, options: .regularExpression) != nil: + self = .homeAssistant + + /* Jellyfin Web or JellyfinWeb (Vue versions included) */ + case let str where str.range(of: #"jellyfin.web|jellyfinweb"#, options: .regularExpression) != nil: + self = DeviceType(webBrowser: deviceName) + + /* Kodi or JellyCon */ + case let str where str.range(of: #"kodi|jellycon"#, options: .regularExpression) != nil: + self = .kodi + + /* LG TV, LG Smart TV, or WebOS devices */ + case let str where str.range(of: #"lg.+tv|webos"#, options: .regularExpression) != nil: + self = .webos + + /* PlayStation: Sony PS3, PS4, or any PlayStation */ + case let str where str.range(of: #"sony\sps[3-4]|playstation"#, options: .regularExpression) != nil: + self = .playstation + + /* Roku devices */ + case let str where str.range(of: #"roku"#, options: .regularExpression) != nil: + self = .roku + + /* Samsung TV, Samsung Smart TV, or devices running Tizen */ + case let str where str.range(of: #"samsung.+tv|tizen"#, options: .regularExpression) != nil: + self = .samsungtv + + /* Xbox One or any Xbox device */ + case let str where str.range(of: #"xbox"#, options: .regularExpression) != nil: + self = .xbox + + /* Default case for anything else */ + default: + self = .other + } + } + + // MARK: - Initialize the Browser if Jellyfin-Web + + private init(webBrowser: String?) { + guard let webBrowser = webBrowser?.lowercased() else { + self = .html5 + return + } + + switch webBrowser { + + /* Matches any string containing 'chrome' */ + case let str where str.range(of: #"chrome"#, options: .regularExpression) != nil: + self = .chrome + + /* Matches any string containing 'edge chromium' or 'edgechromium' */ + case let str where str.range(of: #"edge.chromium|edgechromium"#, options: .regularExpression) != nil: + self = .edgechromium + + /* Matches any string containing 'edge' but not 'chromium' */ + case let str + where str.range(of: #"edge"#, options: .regularExpression) != nil && str + .range(of: #"chromium"#, options: .regularExpression) == nil: + self = .edge + + /* Matches any string containing 'firefox' */ + case let str where str.range(of: #"firefox"#, options: .regularExpression) != nil: + self = .firefox + + /* Matches any string containing 'internet explorer', 'IE', 'MSIE', or 'MSFT IE' */ + case let str + where str.range(of: #"internet.explorer|internetexplorer|ie\d|ie.\d|msie|msft.ie"#, options: .regularExpression) != nil: + self = .msie + + /* Matches any string containing 'opera' */ + case let str where str.range(of: #"opera"#, options: .regularExpression) != nil: + self = .opera + + /* Matches any string containing 'safari' */ + case let str where str.range(of: #"safari"#, options: .regularExpression) != nil: + self = .safari + + /* Default case for anything else */ + default: + self = .html5 + } + } + + // MARK: - Client Image + + var image: ImageResource { + switch self { + case .android: + return .deviceClientAndroid + case .apple: + return .deviceClientApple + case .chrome: + return .deviceBrowserChrome + case .edge: + return .deviceBrowserEdge + case .edgechromium: + return .deviceBrowserEdgechromium + case .finamp: + return .deviceClientFinamp + case .firefox: + return .deviceBrowserFirefox + case .homeAssistant: + return .deviceOtherHomeassistant + case .html5: + return .deviceBrowserHtml5 + case .kodi: + return .deviceClientKodi + case .msie: + return .deviceBrowserMsie + case .opera: + return .deviceBrowserOpera + case .playstation: + return .deviceClientPlaystation + case .roku: + return .deviceClientRoku + case .safari: + return .deviceBrowserSafari + case .samsungtv: + return .deviceClientSamsungtv + case .webos: + return .deviceClientWebos + case .windows: + return .deviceClientWindows + case .xbox: + return .deviceClientXbox + case .other: + return .deviceOtherOther + } + } + + // MARK: - Client Color + + var clientColor: Color { + switch self { + case .android: + return Color(red: 0.18, green: 0.8, blue: 0.44) // Android Green + case .apple: + return Color(red: 0.35, green: 0.35, blue: 0.35) // Apple Gray + case .chrome: + return Color(red: 0.98, green: 0.75, blue: 0.18) // Chrome Yellow + case .edge: + return Color(red: 0.19, green: 0.31, blue: 0.51) // Edge Gray + case .edgechromium: + return Color(red: 0.0, green: 0.45, blue: 0.75) // Edge Chromium Blue + case .firefox: + return Color(red: 1.0, green: 0.33, blue: 0.0) // Firefox Orange + case .finamp: + return Color(red: 0.61, green: 0.32, blue: 0.88) // Finamp Purple + case .homeAssistant: + return Color(red: 0.0, green: 0.55, blue: 0.87) // Home Assistant Blue + case .kodi: + return Color(red: 0.0, green: 0.58, blue: 0.83) // Kodi Blue + case .msie: + return Color(red: 0.0, green: 0.53, blue: 1.0) // Internet Explorer Blue + case .opera: + return Color(red: 1.0, green: 0.0, blue: 0.0) // Opera Red + case .playstation: + return Color(red: 0.0, green: 0.32, blue: 0.65) // PlayStation Blue + case .roku: + return Color(red: 0.31, green: 0.09, blue: 0.55) // Roku Purple + case .safari: + return Color(red: 0.0, green: 0.48, blue: 1.0) // Safari Blue + case .samsungtv: + return Color(red: 0.0, green: 0.44, blue: 0.74) // Samsung Blue + case .webos: + return Color(red: 0.6667, green: 0.1569, blue: 0.2745) // WebOS Pink + case .xbox: + return Color(red: 0.0, green: 0.5, blue: 0.0) // Xbox Green + default: + return Color.secondarySystemFill + } + } +} diff --git a/Shared/Extensions/JellyfinAPI/SessionInfo.swift b/Shared/Extensions/JellyfinAPI/SessionInfo.swift index 26e9092ea..6c50f6afb 100644 --- a/Shared/Extensions/JellyfinAPI/SessionInfo.swift +++ b/Shared/Extensions/JellyfinAPI/SessionInfo.swift @@ -11,6 +11,13 @@ import JellyfinAPI extension SessionInfo { + var device: DeviceType { + DeviceType( + client: client, + deviceName: deviceName + ) + } + var playMethodDisplayTitle: String? { guard nowPlayingItem != nil, let playState, let playMethod = playState.playMethod else { return nil } diff --git a/Swiftfin.xcodeproj/project.pbxproj b/Swiftfin.xcodeproj/project.pbxproj index 9a5039737..8c9c9bcef 100644 --- a/Swiftfin.xcodeproj/project.pbxproj +++ b/Swiftfin.xcodeproj/project.pbxproj @@ -9,8 +9,11 @@ /* Begin PBXBuildFile section */ 091B5A8A2683142E00D78B61 /* ServerDiscovery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 091B5A872683142E00D78B61 /* ServerDiscovery.swift */; }; 091B5A8D268315D400D78B61 /* ServerDiscovery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 091B5A872683142E00D78B61 /* ServerDiscovery.swift */; }; + 4E0253BD2CBF0C06007EB9CD /* DeviceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E12F9152CBE9615006C217E /* DeviceType.swift */; }; 4E0A8FFB2CAF74D20014B047 /* TaskCompletionStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E0A8FFA2CAF74CD0014B047 /* TaskCompletionStatus.swift */; }; 4E0A8FFC2CAF74D20014B047 /* TaskCompletionStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E0A8FFA2CAF74CD0014B047 /* TaskCompletionStatus.swift */; }; + 4E11805F2CBF52380077A588 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5377CBF8263B596B003A4E83 /* Assets.xcassets */; }; + 4E12F9172CBE9619006C217E /* DeviceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E12F9152CBE9615006C217E /* DeviceType.swift */; }; 4E16FD512C0183DB00110147 /* LetterPickerButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E16FD502C0183DB00110147 /* LetterPickerButton.swift */; }; 4E16FD532C01840C00110147 /* LetterPickerBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E16FD522C01840C00110147 /* LetterPickerBar.swift */; }; 4E16FD572C01A32700110147 /* LetterPickerOrientation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E16FD562C01A32700110147 /* LetterPickerOrientation.swift */; }; @@ -57,6 +60,8 @@ 4EB1A8CA2C9A766200F43898 /* ActiveSessionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB1A8C92C9A765800F43898 /* ActiveSessionsView.swift */; }; 4EB1A8CC2C9B1BA200F43898 /* ServerTaskButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB1A8CB2C9B1B9700F43898 /* ServerTaskButton.swift */; }; 4EB1A8CE2C9B2D0800F43898 /* ActiveSessionRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB1A8CD2C9B2D0100F43898 /* ActiveSessionRow.swift */; }; + 4EB4ECE32CBEFC4D002FF2FC /* SessionInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB4ECE22CBEFC49002FF2FC /* SessionInfo.swift */; }; + 4EB4ECE42CBEFC4D002FF2FC /* SessionInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB4ECE22CBEFC49002FF2FC /* SessionInfo.swift */; }; 4EB7B33B2CBDE645004A342E /* ChevronAlertButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB7B33A2CBDE63F004A342E /* ChevronAlertButton.swift */; }; 4EBE06462C7E9509004A6C03 /* PlaybackCompatibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EBE06452C7E9509004A6C03 /* PlaybackCompatibility.swift */; }; 4EBE06472C7E9509004A6C03 /* PlaybackCompatibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EBE06452C7E9509004A6C03 /* PlaybackCompatibility.swift */; }; @@ -1023,6 +1028,7 @@ /* Begin PBXFileReference section */ 091B5A872683142E00D78B61 /* ServerDiscovery.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServerDiscovery.swift; sourceTree = ""; }; 4E0A8FFA2CAF74CD0014B047 /* TaskCompletionStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskCompletionStatus.swift; sourceTree = ""; }; + 4E12F9152CBE9615006C217E /* DeviceType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceType.swift; sourceTree = ""; }; 4E16FD502C0183DB00110147 /* LetterPickerButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LetterPickerButton.swift; sourceTree = ""; }; 4E16FD522C01840C00110147 /* LetterPickerBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LetterPickerBar.swift; sourceTree = ""; }; 4E16FD562C01A32700110147 /* LetterPickerOrientation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LetterPickerOrientation.swift; sourceTree = ""; }; @@ -1057,6 +1063,7 @@ 4EB1A8C92C9A765800F43898 /* ActiveSessionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActiveSessionsView.swift; sourceTree = ""; }; 4EB1A8CB2C9B1B9700F43898 /* ServerTaskButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerTaskButton.swift; sourceTree = ""; }; 4EB1A8CD2C9B2D0100F43898 /* ActiveSessionRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActiveSessionRow.swift; sourceTree = ""; }; + 4EB4ECE22CBEFC49002FF2FC /* SessionInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionInfo.swift; sourceTree = ""; }; 4EB7B33A2CBDE63F004A342E /* ChevronAlertButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChevronAlertButton.swift; sourceTree = ""; }; 4EBE06452C7E9509004A6C03 /* PlaybackCompatibility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaybackCompatibility.swift; sourceTree = ""; }; 4EBE064C2C7EB6D3004A6C03 /* VideoPlayerType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoPlayerType.swift; sourceTree = ""; }; @@ -3569,6 +3576,8 @@ E1ED7FDA2CAA4B6D00ACB6E3 /* PlayerStateInfo.swift */, E1CB758A2C80F9EC00217C76 /* CodecProfile.swift */, 4EBE06502C7ED0E1004A6C03 /* DeviceProfile.swift */, + 4E12F9152CBE9615006C217E /* DeviceType.swift */, + 4EB4ECE22CBEFC49002FF2FC /* SessionInfo.swift */, 4E0A8FFA2CAF74CD0014B047 /* TaskCompletionStatus.swift */, E1CB75712C80E71800217C76 /* DirectPlayProfile.swift */, E1722DB029491C3900CC0239 /* ImageBlurHashes.swift */, @@ -4157,6 +4166,7 @@ 53913BF026D323FE00EB3286 /* Localizable.strings in Resources */, 53913C0826D323FE00EB3286 /* Localizable.strings in Resources */, 53913C1126D323FE00EB3286 /* Localizable.strings in Resources */, + 4E11805F2CBF52380077A588 /* Assets.xcassets in Resources */, 535870672669D21700D05A09 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -4279,6 +4289,7 @@ E1B490452967E26300D3EDCE /* PersistentLogHandler.swift in Sources */, E193D53327193F7D00900D82 /* FilterCoordinator.swift in Sources */, E18E021E2887492B0022598C /* RowDivider.swift in Sources */, + 4EB4ECE42CBEFC4D002FF2FC /* SessionInfo.swift in Sources */, E1DC983E296DEB9B00982F06 /* UnwatchedIndicator.swift in Sources */, 4E2AC4BF2C6C48D200DD600D /* CustomDeviceProfileAction.swift in Sources */, 4EBE06472C7E9509004A6C03 /* PlaybackCompatibility.swift in Sources */, @@ -4450,6 +4461,7 @@ E1575E6C293E77B5001665B1 /* SliderType.swift in Sources */, E1E2F8402B757DFA00B75998 /* OnFinalDisappearModifier.swift in Sources */, E17DC74B2BE740D900B42379 /* StoredValues+Server.swift in Sources */, + 4E0253BD2CBF0C06007EB9CD /* DeviceType.swift in Sources */, E10E842A29A587110064EA49 /* LoadingView.swift in Sources */, E193D53927193F8E00900D82 /* SearchCoordinator.swift in Sources */, E13316FF2ADE42B6009BF865 /* OnSizeChangedModifier.swift in Sources */, @@ -4678,6 +4690,7 @@ 621338932660107500A81A2A /* String.swift in Sources */, E17AC96F2954EE4B003D2BC2 /* DownloadListViewModel.swift in Sources */, BD39577C2C113FAA0078CEF8 /* TimestampSection.swift in Sources */, + 4EB4ECE32CBEFC4D002FF2FC /* SessionInfo.swift in Sources */, 4EC6C16B2C92999800FC904B /* TranscodeSection.swift in Sources */, 62C83B08288C6A630004ED0C /* FontPickerView.swift in Sources */, E122A9132788EAAD0060FA63 /* MediaStream.swift in Sources */, @@ -5040,6 +5053,7 @@ E10B1EB62BD98C6600A92EAF /* AddUserRow.swift in Sources */, E1CB75802C80F28F00217C76 /* SubtitleProfile.swift in Sources */, E1DD20412BE1EB8C00C0DE51 /* AddUserButton.swift in Sources */, + 4E12F9172CBE9619006C217E /* DeviceType.swift in Sources */, E145EB422BE0A6EE003BF6F3 /* ServerSelectionMenu.swift in Sources */, 4E5E48E52AB59806003F1B48 /* CustomizeViewsSettings.swift in Sources */, E14EA15E2BF6F72900DE757A /* PhotoPicker.swift in Sources */, diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Contents.json b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-chrome.imageset/Contents.json b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-chrome.imageset/Contents.json new file mode 100644 index 000000000..9d8a820ae --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-chrome.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "chrome.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-chrome.imageset/chrome.svg b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-chrome.imageset/chrome.svg new file mode 100644 index 000000000..fab308dc2 --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-chrome.imageset/chrome.svg @@ -0,0 +1 @@ +Google Chrome icon diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-edge.imageset/Contents.json b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-edge.imageset/Contents.json new file mode 100644 index 000000000..5029adefd --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-edge.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "edge.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-edge.imageset/edge.svg b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-edge.imageset/edge.svg new file mode 100644 index 000000000..8a552924d --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-edge.imageset/edge.svg @@ -0,0 +1 @@ +Microsoft Edge icon diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-edgechromium.imageset/Contents.json b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-edgechromium.imageset/Contents.json new file mode 100644 index 000000000..1913d0ce8 --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-edgechromium.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "edgechromium.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-edgechromium.imageset/edgechromium.svg b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-edgechromium.imageset/edgechromium.svg new file mode 100644 index 000000000..14d68a5d4 --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-edgechromium.imageset/edgechromium.svg @@ -0,0 +1 @@ +Microsoft Edge icon diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-firefox.imageset/Contents.json b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-firefox.imageset/Contents.json new file mode 100644 index 000000000..59e17e676 --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-firefox.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "firefox.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-firefox.imageset/firefox.svg b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-firefox.imageset/firefox.svg new file mode 100644 index 000000000..7f468b3f0 --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-firefox.imageset/firefox.svg @@ -0,0 +1 @@ +Mozilla Firefox icon diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-html5.imageset/Contents.json b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-html5.imageset/Contents.json new file mode 100644 index 000000000..83f2b872f --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-html5.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "html5.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-html5.imageset/html5.svg b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-html5.imageset/html5.svg new file mode 100644 index 000000000..63704799c --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-html5.imageset/html5.svg @@ -0,0 +1 @@ +HTML5 icon diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-msie.imageset/Contents.json b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-msie.imageset/Contents.json new file mode 100644 index 000000000..2b8e8f694 --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-msie.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "msie.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-msie.imageset/msie.svg b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-msie.imageset/msie.svg new file mode 100644 index 000000000..f5b362d7c --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-msie.imageset/msie.svg @@ -0,0 +1 @@ +Internet Explorer icon diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-opera.imageset/Contents.json b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-opera.imageset/Contents.json new file mode 100644 index 000000000..e73067c2a --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-opera.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "opera.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-opera.imageset/opera.svg b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-opera.imageset/opera.svg new file mode 100644 index 000000000..dd57f924a --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-opera.imageset/opera.svg @@ -0,0 +1 @@ +Opera icon diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-safari.imageset/Contents.json b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-safari.imageset/Contents.json new file mode 100644 index 000000000..feaf24957 --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-safari.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "safari.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-safari.imageset/safari.svg b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-safari.imageset/safari.svg new file mode 100644 index 000000000..12abbb95f --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Browsers/Device-browser-safari.imageset/safari.svg @@ -0,0 +1 @@ +safari icon diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Contents.json b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-android.imageset/Contents.json b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-android.imageset/Contents.json new file mode 100644 index 000000000..26c167e3f --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-android.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "android.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-android.imageset/android.svg b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-android.imageset/android.svg new file mode 100644 index 000000000..24edc8bbf --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-android.imageset/android.svg @@ -0,0 +1,4 @@ + + + + diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-apple.imageset/Contents.json b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-apple.imageset/Contents.json new file mode 100644 index 000000000..a011cbd83 --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-apple.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "apple.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-apple.imageset/apple.svg b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-apple.imageset/apple.svg new file mode 100644 index 000000000..4477a4525 --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-apple.imageset/apple.svg @@ -0,0 +1 @@ +Apple diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-finamp.imageset/Contents.json b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-finamp.imageset/Contents.json new file mode 100644 index 000000000..35feb3d58 --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-finamp.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "finamp.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-finamp.imageset/finamp.svg b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-finamp.imageset/finamp.svg new file mode 100644 index 000000000..8bd3a90ca --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-finamp.imageset/finamp.svg @@ -0,0 +1,7 @@ + + Finamp icon + diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-kodi.imageset/Contents.json b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-kodi.imageset/Contents.json new file mode 100644 index 000000000..99d22c490 --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-kodi.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "kodi.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-kodi.imageset/kodi.svg b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-kodi.imageset/kodi.svg new file mode 100644 index 000000000..3618149b1 --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-kodi.imageset/kodi.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-playstation.imageset/Contents.json b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-playstation.imageset/Contents.json new file mode 100644 index 000000000..31c0ff530 --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-playstation.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "playstation.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-playstation.imageset/playstation.svg b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-playstation.imageset/playstation.svg new file mode 100644 index 000000000..c6595340e --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-playstation.imageset/playstation.svg @@ -0,0 +1 @@ +PlayStation icon diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-roku.imageset/Contents.json b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-roku.imageset/Contents.json new file mode 100644 index 000000000..8ea8fc438 --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-roku.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "roku.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-roku.imageset/roku.svg b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-roku.imageset/roku.svg new file mode 100644 index 000000000..eb1e621b5 --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-roku.imageset/roku.svg @@ -0,0 +1,7 @@ + + Roku icon + diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-samsungtv.imageset/Contents.json b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-samsungtv.imageset/Contents.json new file mode 100644 index 000000000..cf998a9c9 --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-samsungtv.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "samsungtv.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-samsungtv.imageset/samsungtv.svg b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-samsungtv.imageset/samsungtv.svg new file mode 100644 index 000000000..afdd19e24 --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-samsungtv.imageset/samsungtv.svg @@ -0,0 +1 @@ +Samsung icon diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-webos.imageset/Contents.json b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-webos.imageset/Contents.json new file mode 100644 index 000000000..63b3674da --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-webos.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "webOS.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-webos.imageset/webOS.svg b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-webos.imageset/webOS.svg new file mode 100644 index 000000000..611ba9630 --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-webos.imageset/webOS.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-windows.imageset/Contents.json b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-windows.imageset/Contents.json new file mode 100644 index 000000000..e6f157d1c --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-windows.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "windows.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-windows.imageset/windows.svg b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-windows.imageset/windows.svg new file mode 100644 index 000000000..531e72e1d --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-windows.imageset/windows.svg @@ -0,0 +1 @@ +Windows icon diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-xbox.imageset/Contents.json b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-xbox.imageset/Contents.json new file mode 100644 index 000000000..847c1b551 --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-xbox.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "xbox.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-xbox.imageset/xbox.svg b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-xbox.imageset/xbox.svg new file mode 100644 index 000000000..640dd34a5 --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Clients/Device-client-xbox.imageset/xbox.svg @@ -0,0 +1 @@ +Xbox icon diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Contents.json b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Other/Contents.json b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Other/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Other/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Other/Device-other-homeassistant.imageset/Contents.json b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Other/Device-other-homeassistant.imageset/Contents.json new file mode 100644 index 000000000..41d3d101c --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Other/Device-other-homeassistant.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "home-assistant.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Other/Device-other-homeassistant.imageset/home-assistant.svg b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Other/Device-other-homeassistant.imageset/home-assistant.svg new file mode 100644 index 000000000..a34be98de --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Other/Device-other-homeassistant.imageset/home-assistant.svg @@ -0,0 +1 @@ + diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Other/Device-other-other.imageset/Contents.json b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Other/Device-other-other.imageset/Contents.json new file mode 100644 index 000000000..44a542466 --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Other/Device-other-other.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "other.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Other/Device-other-other.imageset/other.svg b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Other/Device-other-other.imageset/other.svg new file mode 100644 index 000000000..91e1d9e25 --- /dev/null +++ b/Swiftfin/Resources/Assets.xcassets/DeviceIcons/Other/Device-other-other.imageset/other.svg @@ -0,0 +1 @@ + diff --git a/Swiftfin/Views/SettingsView/UserDashboardView/ActiveSessionsView/Components/ActiveSessionRow.swift b/Swiftfin/Views/SettingsView/UserDashboardView/ActiveSessionsView/Components/ActiveSessionRow.swift index 52bb1ca40..11dbb978f 100644 --- a/Swiftfin/Views/SettingsView/UserDashboardView/ActiveSessionsView/Components/ActiveSessionRow.swift +++ b/Swiftfin/Views/SettingsView/UserDashboardView/ActiveSessionsView/Components/ActiveSessionRow.swift @@ -10,8 +10,6 @@ import Defaults import JellyfinAPI import SwiftUI -// TODO: inactive session device image - extension ActiveSessionsView { struct ActiveSessionRow: View { @@ -24,7 +22,6 @@ extension ActiveSessionsView { private let onSelect: () -> Void - // parent list won't show row if value is nil anyways private var session: SessionInfo { box.value ?? .init() } @@ -38,29 +35,44 @@ extension ActiveSessionsView { private var rowLeading: some View { // TODO: better handling for different poster types Group { - if session.nowPlayingItem?.type == .audio { - ZStack { - Color.clear - - ImageView(session.nowPlayingItem?.squareImageSources(maxWidth: 60) ?? []) - .failure { - SystemImageContentView(systemName: session.nowPlayingItem?.systemImage) - } + if let nowPlayingItem = session.nowPlayingItem { + if nowPlayingItem.type == .audio { + ZStack { + Color.clear + + ImageView(nowPlayingItem.squareImageSources(maxWidth: 60)) + .failure { + SystemImageContentView(systemName: nowPlayingItem.systemImage) + } + } + .squarePosterStyle() + .frame(width: 60, height: 60) + } else { + ZStack { + Color.clear + + ImageView(nowPlayingItem.portraitImageSources(maxWidth: 60)) + .failure { + SystemImageContentView(systemName: nowPlayingItem.systemImage) + } + } + .posterStyle(.portrait) + .frame(width: 60, height: 90) } - .squarePosterStyle() } else { ZStack { - Color.clear + session.device.clientColor - ImageView(session.nowPlayingItem?.portraitImageSources(maxWidth: 60) ?? []) - .failure { - SystemImageContentView(systemName: session.nowPlayingItem?.systemImage) - } + Image(session.device.image) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 40) } - .posterStyle(.portrait) + .squarePosterStyle() + .frame(width: 60, height: 60) } } - .frame(width: 60) + .frame(width: 60, height: 90) .posterShadow() .padding(.vertical, 8) }