Basic SVG Support (#1010)
This commit is contained in:
parent
bda46325b3
commit
8c9c86713d
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// 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 SVGKit
|
||||
import SwiftUI
|
||||
|
||||
// Note: SVGKit does not support the simulator and will appear blank.
|
||||
|
||||
// This seemed necessary because using SwiftUI `Image(uiImage:)` would cause severe lag.
|
||||
struct FastSVGView: UIViewRepresentable {
|
||||
|
||||
let data: Data
|
||||
|
||||
func makeUIView(context: Context) -> some UIView {
|
||||
let imageView = SVGKFastImageView(svgkImage: SVGKImage(data: data))!
|
||||
imageView.contentMode = .scaleAspectFit
|
||||
imageView.clipsToBounds = true
|
||||
|
||||
imageView.setContentHuggingPriority(.defaultLow, for: .vertical)
|
||||
imageView.setContentHuggingPriority(.defaultLow, for: .horizontal)
|
||||
imageView.setContentCompressionResistancePriority(.defaultLow, for: .vertical)
|
||||
imageView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
||||
|
||||
return imageView
|
||||
}
|
||||
|
||||
func updateUIView(_ uiView: UIViewType, context: Context) {}
|
||||
}
|
|
@ -7,16 +7,24 @@
|
|||
//
|
||||
|
||||
import BlurHashKit
|
||||
import JellyfinAPI
|
||||
import Nuke
|
||||
import NukeUI
|
||||
import SwiftUI
|
||||
import UIKit
|
||||
|
||||
private let imagePipeline = ImagePipeline(configuration: .withDataCache)
|
||||
private let imagePipeline = {
|
||||
|
||||
ImageDecoderRegistry.shared.register { context in
|
||||
guard let mimeType = context.urlResponse?.mimeType else { return nil }
|
||||
return mimeType.contains("svg") ? ImageDecoders.Empty() : nil
|
||||
}
|
||||
|
||||
return ImagePipeline(configuration: .withDataCache)
|
||||
}()
|
||||
|
||||
// TODO: Binding inits?
|
||||
// - instead of removing first source on failure, just safe index into sources
|
||||
// TODO: currently SVGs are only supported for logos, which are only used in a few places.
|
||||
// make it so when displaying an SVG there is a unified `image` caller modifier
|
||||
struct ImageView: View {
|
||||
|
||||
@State
|
||||
|
@ -42,8 +50,12 @@ struct ImageView: View {
|
|||
if state.isLoading {
|
||||
_placeholder(currentSource)
|
||||
} else if let _image = state.image {
|
||||
image(_image.resizable())
|
||||
.eraseToAnyView()
|
||||
if let data = state.imageContainer?.data {
|
||||
FastSVGView(data: data)
|
||||
} else {
|
||||
image(_image.resizable())
|
||||
.eraseToAnyView()
|
||||
}
|
||||
} else if state.error != nil {
|
||||
failure()
|
||||
.eraseToAnyView()
|
||||
|
@ -103,7 +115,7 @@ extension ImageView {
|
|||
}
|
||||
}
|
||||
|
||||
// MARK: Extensions
|
||||
// MARK: Modifiers
|
||||
|
||||
extension ImageView {
|
||||
|
||||
|
|
|
@ -221,6 +221,10 @@
|
|||
E1153DAF2BBA734200424D36 /* CollectionHStack in Frameworks */ = {isa = PBXBuildFile; productRef = E1153DAE2BBA734200424D36 /* CollectionHStack */; };
|
||||
E1153DB12BBA734C00424D36 /* CollectionHStack in Frameworks */ = {isa = PBXBuildFile; productRef = E1153DB02BBA734C00424D36 /* CollectionHStack */; };
|
||||
E1153DB42BBA80FB00424D36 /* EmptyCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1153DB22BBA80B400424D36 /* EmptyCard.swift */; };
|
||||
E1153DCC2BBB633B00424D36 /* FastSVGView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1153DCB2BBB633B00424D36 /* FastSVGView.swift */; };
|
||||
E1153DCD2BBB633B00424D36 /* FastSVGView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1153DCB2BBB633B00424D36 /* FastSVGView.swift */; };
|
||||
E1153DD02BBB634F00424D36 /* SVGKit in Frameworks */ = {isa = PBXBuildFile; productRef = E1153DCF2BBB634F00424D36 /* SVGKit */; };
|
||||
E1153DD22BBB649C00424D36 /* SVGKit in Frameworks */ = {isa = PBXBuildFile; productRef = E1153DD12BBB649C00424D36 /* SVGKit */; };
|
||||
E1171A1928A2212600FA1AF5 /* QuickConnectView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1171A1828A2212600FA1AF5 /* QuickConnectView.swift */; };
|
||||
E118959D289312020042947B /* BaseItemPerson+Poster.swift in Sources */ = {isa = PBXBuildFile; fileRef = E118959C289312020042947B /* BaseItemPerson+Poster.swift */; };
|
||||
E118959E289312020042947B /* BaseItemPerson+Poster.swift in Sources */ = {isa = PBXBuildFile; fileRef = E118959C289312020042947B /* BaseItemPerson+Poster.swift */; };
|
||||
|
@ -973,6 +977,7 @@
|
|||
E1153D992BBA3E9800424D36 /* ErrorCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorCard.swift; sourceTree = "<group>"; };
|
||||
E1153D9B2BBA3E9D00424D36 /* LoadingCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingCard.swift; sourceTree = "<group>"; };
|
||||
E1153DB22BBA80B400424D36 /* EmptyCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyCard.swift; sourceTree = "<group>"; };
|
||||
E1153DCB2BBB633B00424D36 /* FastSVGView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FastSVGView.swift; sourceTree = "<group>"; };
|
||||
E1171A1828A2212600FA1AF5 /* QuickConnectView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickConnectView.swift; sourceTree = "<group>"; };
|
||||
E118959C289312020042947B /* BaseItemPerson+Poster.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BaseItemPerson+Poster.swift"; sourceTree = "<group>"; };
|
||||
E11895A8289383BC0042947B /* ScrollViewOffsetModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollViewOffsetModifier.swift; sourceTree = "<group>"; };
|
||||
|
@ -1361,6 +1366,7 @@
|
|||
E13DD3CD27164CA7009D4DAF /* CoreStore in Frameworks */,
|
||||
E1A7B1652B9A9F7800152546 /* PreferencesView in Frameworks */,
|
||||
E1153DA92BBA642A00424D36 /* CollectionVGrid in Frameworks */,
|
||||
E1153DD22BBB649C00424D36 /* SVGKit in Frameworks */,
|
||||
62666E1527E501C800EC0ECD /* AVFoundation.framework in Frameworks */,
|
||||
E13AF3BC28A0C59E009093AB /* BlurHashKit in Frameworks */,
|
||||
E1153DB12BBA734C00424D36 /* CollectionHStack in Frameworks */,
|
||||
|
@ -1402,6 +1408,7 @@
|
|||
62666E0C27E501A500EC0ECD /* OpenGLES.framework in Frameworks */,
|
||||
E19E6E0A28A0BEFF005C10C8 /* BlurHashKit in Frameworks */,
|
||||
E1FAD1C62A0375BA007F5521 /* UDPBroadcast in Frameworks */,
|
||||
E1153DD02BBB634F00424D36 /* SVGKit in Frameworks */,
|
||||
E18D6AA62BAA96F000A0D167 /* CollectionHStack in Frameworks */,
|
||||
62666E0127E5016900EC0ECD /* CoreFoundation.framework in Frameworks */,
|
||||
E14CB6862A9FF62A001586C6 /* JellyfinAPI in Frameworks */,
|
||||
|
@ -2639,6 +2646,7 @@
|
|||
children = (
|
||||
E104DC952B9E7E29008F506D /* AssertionFailureView.swift */,
|
||||
E18E0203288749200022598C /* BlurView.swift */,
|
||||
E1153DCB2BBB633B00424D36 /* FastSVGView.swift */,
|
||||
531AC8BE26750DE20091C7EB /* ImageView.swift */,
|
||||
E1D37F472B9C648E00343D2B /* MaxHeightText.swift */,
|
||||
531690F9267AD6EC005D8AB9 /* PlainNavigationLinkButton.swift */,
|
||||
|
@ -2990,6 +2998,7 @@
|
|||
E1392FEC2BA218A80034110D /* SwiftUIIntrospect */,
|
||||
E1153DA82BBA642A00424D36 /* CollectionVGrid */,
|
||||
E1153DB02BBA734C00424D36 /* CollectionHStack */,
|
||||
E1153DD12BBB649C00424D36 /* SVGKit */,
|
||||
);
|
||||
productName = "JellyfinPlayer tvOS";
|
||||
productReference = 535870602669D21600D05A09 /* Swiftfin tvOS.app */;
|
||||
|
@ -3043,6 +3052,7 @@
|
|||
E1153DA62BBA641000424D36 /* CollectionVGrid */,
|
||||
E1153DAB2BBA6AD200424D36 /* CollectionHStack */,
|
||||
E1153DAE2BBA734200424D36 /* CollectionHStack */,
|
||||
E1153DCF2BBB634F00424D36 /* SVGKit */,
|
||||
);
|
||||
productName = JellyfinPlayer;
|
||||
productReference = 5377CBF1263B596A003A4E83 /* Swiftfin iOS.app */;
|
||||
|
@ -3114,6 +3124,7 @@
|
|||
E15D4F032B1B0C3C00442DB8 /* XCLocalSwiftPackageReference "PreferencesView" */,
|
||||
E1153DA52BBA641000424D36 /* XCRemoteSwiftPackageReference "CollectionVGrid" */,
|
||||
E1153DAD2BBA734200424D36 /* XCRemoteSwiftPackageReference "CollectionHStack" */,
|
||||
E1153DCE2BBB634F00424D36 /* XCRemoteSwiftPackageReference "SVGKit" */,
|
||||
);
|
||||
productRefGroup = 5377CBF2263B596A003A4E83 /* Products */;
|
||||
projectDirPath = "";
|
||||
|
@ -3435,6 +3446,7 @@
|
|||
E12E30F5296392EC0022FAC9 /* EnumPickerView.swift in Sources */,
|
||||
E1575E72293E77B5001665B1 /* Utilities.swift in Sources */,
|
||||
E1575E84293E7A00001665B1 /* PrimaryAppIcon.swift in Sources */,
|
||||
E1153DCD2BBB633B00424D36 /* FastSVGView.swift in Sources */,
|
||||
E1E6C45129B104850064123F /* Button.swift in Sources */,
|
||||
E1DC981A296DD1CD00982F06 /* CinematicBackgroundView.swift in Sources */,
|
||||
E1A1528B28FD22F600600579 /* TextPairView.swift in Sources */,
|
||||
|
@ -3678,6 +3690,7 @@
|
|||
E139CC1D28EC836F00688DE2 /* ChapterOverlay.swift in Sources */,
|
||||
E168BD14289A4162001A6922 /* LatestInLibraryView.swift in Sources */,
|
||||
E1E6C45029B104840064123F /* Button.swift in Sources */,
|
||||
E1153DCC2BBB633B00424D36 /* FastSVGView.swift in Sources */,
|
||||
E1E5D5492783CDD700692DFE /* VideoPlayerSettingsView.swift in Sources */,
|
||||
E14EDEC52B8FB64E000F00A4 /* AnyItemFilter.swift in Sources */,
|
||||
E11245B728D97ED200D8A977 /* TopBarView.swift in Sources */,
|
||||
|
@ -4398,6 +4411,14 @@
|
|||
kind = branch;
|
||||
};
|
||||
};
|
||||
E1153DCE2BBB634F00424D36 /* XCRemoteSwiftPackageReference "SVGKit" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/SVGKit/SVGKit";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 3.0.0;
|
||||
};
|
||||
};
|
||||
E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/JohnEstropia/CoreStore.git";
|
||||
|
@ -4595,6 +4616,16 @@
|
|||
package = E1153DAD2BBA734200424D36 /* XCRemoteSwiftPackageReference "CollectionHStack" */;
|
||||
productName = CollectionHStack;
|
||||
};
|
||||
E1153DCF2BBB634F00424D36 /* SVGKit */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = E1153DCE2BBB634F00424D36 /* XCRemoteSwiftPackageReference "SVGKit" */;
|
||||
productName = SVGKit;
|
||||
};
|
||||
E1153DD12BBB649C00424D36 /* SVGKit */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = E1153DCE2BBB634F00424D36 /* XCRemoteSwiftPackageReference "SVGKit" */;
|
||||
productName = SVGKit;
|
||||
};
|
||||
E12186DD2718F1C50010884C /* Defaults */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = E13DD3D127168E65009D4DAF /* XCRemoteSwiftPackageReference "Defaults" */;
|
||||
|
|
|
@ -9,6 +9,15 @@
|
|||
"version" : "1.2.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "cocoalumberjack",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/CocoaLumberjack/CocoaLumberjack.git",
|
||||
"state" : {
|
||||
"revision" : "4b8714a7fb84d42393314ce897127b3939885ec3",
|
||||
"version" : "3.8.5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "collectionhstack",
|
||||
"kind" : "remoteSourceControl",
|
||||
|
@ -135,6 +144,15 @@
|
|||
"revision" : "6dda57096e16020342b36ebea86dc4bdf6783426"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "svgkit",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/SVGKit/SVGKit",
|
||||
"state" : {
|
||||
"revision" : "58152b9f7c85eab239160b36ffdfd364aa43d666",
|
||||
"version" : "3.0.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-algorithms",
|
||||
"kind" : "remoteSourceControl",
|
||||
|
|
Loading…
Reference in New Issue