Basic SVG Support (#1010)

This commit is contained in:
Ethan Pippin 2024-04-02 08:56:09 -06:00 committed by GitHub
parent bda46325b3
commit 8c9c86713d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 100 additions and 6 deletions

View File

@ -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) {}
}

View File

@ -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 {

View File

@ -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" */;

View File

@ -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",