Replace Kingfisher with SDWebImage

This commit is contained in:
Justin Mazzocchi 2021-02-22 15:59:33 -08:00
parent 8b2acf1ace
commit 23a7725840
No known key found for this signature in database
GPG key ID: E223E6937AAFB01C
35 changed files with 215 additions and 250 deletions

View file

@ -1,7 +1,7 @@
// Copyright © 2021 Metabolist. All rights reserved. // Copyright © 2021 Metabolist. All rights reserved.
import Foundation import Foundation
import Kingfisher import SDWebImage
import ServiceLayer import ServiceLayer
struct ImageCacheConfiguration { struct ImageCacheConfiguration {
@ -14,19 +14,23 @@ struct ImageCacheConfiguration {
extension ImageCacheConfiguration { extension ImageCacheConfiguration {
func configure() throws { func configure() throws {
KingfisherManager.shared.cache = try ImageCache( SDImageCache.defaultDiskCacheDirectory = Self.imageCacheDirectoryURL?.path
name: Self.name, ImageDiskCache.service = try ImageSerializationService(environment: environment)
cacheDirectoryURL: Self.directoryURL) SDImageCacheConfig.default.diskCacheClass = ImageDiskCache.self
try KingfisherManager.shared.defaultOptions = [
.cacheSerializer(ImageCacheSerializer(service: .init(environment: environment))) if let legacyImageCacheDirectoryURL = Self.legacyImageCacheDirectoryURL,
] FileManager.default.fileExists(atPath: legacyImageCacheDirectoryURL.path) {
try? FileManager.default.removeItem(at: legacyImageCacheDirectoryURL)
}
} }
} }
private extension ImageCacheConfiguration { private extension ImageCacheConfiguration {
static let name = "Images" static let cachesDirectoryURL = FileManager.default.containerURL(
static let directoryURL = FileManager.default.containerURL(
forSecurityApplicationGroupIdentifier: AppEnvironment.appGroup)? forSecurityApplicationGroupIdentifier: AppEnvironment.appGroup)?
.appendingPathComponent("Library") .appendingPathComponent("Library")
.appendingPathComponent("Caches") .appendingPathComponent("Caches")
static let imageCacheDirectoryURL = cachesDirectoryURL?.appendingPathComponent("com.metabolist.metatext.images")
static let legacyImageCacheDirectoryURL =
cachesDirectoryURL?.appendingPathComponent("com.onevcat.Kingfisher.ImageCache.Images")
} }

View file

@ -1,27 +0,0 @@
// Copyright © 2021 Metabolist. All rights reserved.
import Foundation
import Kingfisher
import ServiceLayer
struct ImageCacheSerializer {
private let service: ImageSerializationService
init(service: ImageSerializationService) {
self.service = service
}
}
extension ImageCacheSerializer: CacheSerializer {
func data(with image: KFCrossPlatformImage, original: Data?) -> Data? {
guard let data = image.kf.data(format: original?.kf.imageFormat ?? .unknown) else { return nil }
return try? service.serialize(data: data)
}
func image(with data: Data, options: KingfisherParsedOptionsInfo) -> KFCrossPlatformImage? {
guard let deserialized = try? service.deserialize(data: data) else { return nil }
return KingfisherWrapper.image(data: deserialized, options: .init())
}
}

View file

@ -0,0 +1,39 @@
// Copyright © 2021 Metabolist. All rights reserved.
import Foundation
import SDWebImage
import ServiceLayer
final class ImageDiskCache: SDDiskCache {
static var service: ImageSerializationService?
private let cachePath: String
required init?(cachePath: String, config: SDImageCacheConfig) {
self.cachePath = cachePath
super.init(cachePath: cachePath, config: config)
}
override func data(forKey key: String) -> Data? {
guard let data = super.data(forKey: key) else { return nil }
return try? Self.service?.deserialize(data: data)
}
override func setData(_ data: Data?, forKey key: String) {
guard let data = data else {
super.setData(nil, forKey: key)
return
}
super.setData(try? Self.service?.serialize(data: data), forKey: key)
}
override func cachePath(forKey key: String) -> String? {
guard let service = Self.service else { return super.cachePath(forKey: key) }
return (cachePath as NSString).appendingPathComponent(service.cacheKey(forKey: key))
}
}

View file

@ -1,15 +0,0 @@
// Copyright © 2021 Metabolist. All rights reserved.
import Foundation
import Kingfisher
struct PrefetchRequestModifier: ImageDownloadRequestModifier {
func modified(for request: URLRequest) -> URLRequest? {
var mutableRequest = request
mutableRequest.allowsExpensiveNetworkAccess = false
mutableRequest.allowsConstrainedNetworkAccess = false
return request
}
}

View file

@ -1,6 +1,5 @@
// Copyright © 2020 Metabolist. All rights reserved. // Copyright © 2020 Metabolist. All rights reserved.
import Kingfisher
import Mastodon import Mastodon
import UIKit import UIKit
import ViewModels import ViewModels
@ -12,17 +11,15 @@ extension NSMutableAttributedString {
while let tokenRange = string.range(of: token) { while let tokenRange = string.range(of: token) {
let attachment = AnimatedTextAttachment() let attachment = AnimatedTextAttachment()
let url: URL
if !identityContext.appPreferences.shouldReduceMotion, if !identityContext.appPreferences.shouldReduceMotion,
identityContext.appPreferences.animateCustomEmojis { identityContext.appPreferences.animateCustomEmojis {
url = emoji.url attachment.imageURL = emoji.url
} else { } else {
url = emoji.staticUrl attachment.imageURL = emoji.staticUrl
} }
attachment.accessibilityLabel = emoji.shortcode attachment.accessibilityLabel = emoji.shortcode
attachment.kf.setImage(with: url, attributedView: view)
replaceCharacters(in: NSRange(tokenRange, in: string), with: NSAttributedString(attachment: attachment)) replaceCharacters(in: NSRange(tokenRange, in: string), with: NSAttributedString(attachment: attachment))
} }
} }

View file

@ -35,16 +35,15 @@
D021A69025C3E4B8008A0C0D /* EmojiContentConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07EC7E225B13DD3006DF726 /* EmojiContentConfiguration.swift */; }; D021A69025C3E4B8008A0C0D /* EmojiContentConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07EC7E225B13DD3006DF726 /* EmojiContentConfiguration.swift */; };
D021A69525C3E4C1008A0C0D /* EmojiView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07EC7F125B13E57006DF726 /* EmojiView.swift */; }; D021A69525C3E4C1008A0C0D /* EmojiView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07EC7F125B13E57006DF726 /* EmojiView.swift */; };
D021A6A625C3E584008A0C0D /* EditAttachmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05936E825AA3F3D00754FDF /* EditAttachmentView.swift */; }; D021A6A625C3E584008A0C0D /* EditAttachmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05936E825AA3F3D00754FDF /* EditAttachmentView.swift */; };
D025B14625C4D26B001C69A8 /* ImageCacheSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D025B14525C4D26A001C69A8 /* ImageCacheSerializer.swift */; };
D025B14725C4D26B001C69A8 /* ImageCacheSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D025B14525C4D26A001C69A8 /* ImageCacheSerializer.swift */; };
D025B14D25C4E482001C69A8 /* ImageCacheConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D025B14C25C4E482001C69A8 /* ImageCacheConfiguration.swift */; }; D025B14D25C4E482001C69A8 /* ImageCacheConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D025B14C25C4E482001C69A8 /* ImageCacheConfiguration.swift */; };
D025B14E25C4E482001C69A8 /* ImageCacheConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D025B14C25C4E482001C69A8 /* ImageCacheConfiguration.swift */; }; D025B14E25C4E482001C69A8 /* ImageCacheConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D025B14C25C4E482001C69A8 /* ImageCacheConfiguration.swift */; };
D025B15B25C4EA7D001C69A8 /* ImageCacheConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D025B14C25C4E482001C69A8 /* ImageCacheConfiguration.swift */; }; D025B15B25C4EA7D001C69A8 /* ImageCacheConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D025B14C25C4E482001C69A8 /* ImageCacheConfiguration.swift */; };
D025B16025C4EA81001C69A8 /* ImageCacheSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D025B14525C4D26A001C69A8 /* ImageCacheSerializer.swift */; };
D025B16A25C4EB18001C69A8 /* ServiceLayer in Frameworks */ = {isa = PBXBuildFile; productRef = D025B16925C4EB18001C69A8 /* ServiceLayer */; }; D025B16A25C4EB18001C69A8 /* ServiceLayer in Frameworks */ = {isa = PBXBuildFile; productRef = D025B16925C4EB18001C69A8 /* ServiceLayer */; };
D025B17025C4EB58001C69A8 /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = D025B16F25C4EB58001C69A8 /* Kingfisher */; };
D025B17E25C500BC001C69A8 /* CapsuleButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D025B17D25C500BC001C69A8 /* CapsuleButton.swift */; }; D025B17E25C500BC001C69A8 /* CapsuleButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D025B17D25C500BC001C69A8 /* CapsuleButton.swift */; };
D02E1F95250B13210071AD56 /* SafariView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02E1F94250B13210071AD56 /* SafariView.swift */; }; D02E1F95250B13210071AD56 /* SafariView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02E1F94250B13210071AD56 /* SafariView.swift */; };
D035D8F925E4338D00E597C9 /* ImageDiskCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D035D8F825E4338D00E597C9 /* ImageDiskCache.swift */; };
D035D8FE25E4339800E597C9 /* ImageDiskCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D035D8F825E4338D00E597C9 /* ImageDiskCache.swift */; };
D035D90325E4388800E597C9 /* ImageDiskCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D035D8F825E4338D00E597C9 /* ImageDiskCache.swift */; };
D035F86925B7F2ED00DC75ED /* MainNavigationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D035F86825B7F2ED00DC75ED /* MainNavigationViewController.swift */; }; D035F86925B7F2ED00DC75ED /* MainNavigationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D035F86825B7F2ED00DC75ED /* MainNavigationViewController.swift */; };
D035F86F25B7F30E00DC75ED /* MainNavigationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D035F86E25B7F30E00DC75ED /* MainNavigationView.swift */; }; D035F86F25B7F30E00DC75ED /* MainNavigationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D035F86E25B7F30E00DC75ED /* MainNavigationView.swift */; };
D035F87D25B7F61600DC75ED /* TimelinesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D035F87C25B7F61600DC75ED /* TimelinesViewController.swift */; }; D035F87D25B7F61600DC75ED /* TimelinesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D035F87C25B7F61600DC75ED /* TimelinesViewController.swift */; };
@ -60,9 +59,11 @@
D036EBB8259FE29800EC1CFC /* Status+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0849C7E25903C4900A5EBCC /* Status+Extensions.swift */; }; D036EBB8259FE29800EC1CFC /* Status+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0849C7E25903C4900A5EBCC /* Status+Extensions.swift */; };
D036EBC2259FE2AD00EC1CFC /* UIVIewController+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E7AD3825870B13005F5E2D /* UIVIewController+Extensions.swift */; }; D036EBC2259FE2AD00EC1CFC /* UIVIewController+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E7AD3825870B13005F5E2D /* UIVIewController+Extensions.swift */; };
D03D87F425C23C44004DCBB2 /* SecondaryNavigationTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03D87F325C23C44004DCBB2 /* SecondaryNavigationTitleView.swift */; }; D03D87F425C23C44004DCBB2 /* SecondaryNavigationTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03D87F325C23C44004DCBB2 /* SecondaryNavigationTitleView.swift */; };
D0477F1525C68BAC005C5368 /* PrefetchRequestModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0477F1425C68BAC005C5368 /* PrefetchRequestModifier.swift */; };
D0477F2C25C6EBAD005C5368 /* OpenInDefaultBrowserActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0477F2B25C6EBAD005C5368 /* OpenInDefaultBrowserActivity.swift */; }; D0477F2C25C6EBAD005C5368 /* OpenInDefaultBrowserActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0477F2B25C6EBAD005C5368 /* OpenInDefaultBrowserActivity.swift */; };
D0477F4625C72E50005C5368 /* CapsuleLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0477F4525C72E50005C5368 /* CapsuleLabel.swift */; }; D0477F4625C72E50005C5368 /* CapsuleLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0477F4525C72E50005C5368 /* CapsuleLabel.swift */; };
D04F34B625E42ABE00714251 /* SDWebImage in Frameworks */ = {isa = PBXBuildFile; productRef = D04F34B525E42ABE00714251 /* SDWebImage */; };
D04F34BC25E42ADC00714251 /* SDWebImage in Frameworks */ = {isa = PBXBuildFile; productRef = D04F34BB25E42ADC00714251 /* SDWebImage */; };
D04F34C225E42AE500714251 /* SDWebImage in Frameworks */ = {isa = PBXBuildFile; productRef = D04F34C125E42AE500714251 /* SDWebImage */; };
D04F9E8E259E9C950081B0C9 /* ViewModels in Frameworks */ = {isa = PBXBuildFile; productRef = D04F9E8D259E9C950081B0C9 /* ViewModels */; }; D04F9E8E259E9C950081B0C9 /* ViewModels in Frameworks */ = {isa = PBXBuildFile; productRef = D04F9E8D259E9C950081B0C9 /* ViewModels */; };
D05936CF25A8D79800754FDF /* EditAttachmentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05936CE25A8D79800754FDF /* EditAttachmentViewController.swift */; }; D05936CF25A8D79800754FDF /* EditAttachmentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05936CE25A8D79800754FDF /* EditAttachmentViewController.swift */; };
D05936D025A8D79800754FDF /* EditAttachmentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05936CE25A8D79800754FDF /* EditAttachmentViewController.swift */; }; D05936D025A8D79800754FDF /* EditAttachmentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05936CE25A8D79800754FDF /* EditAttachmentViewController.swift */; };
@ -206,8 +207,6 @@
D0F0B12E251A97E400942152 /* TableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F0B12D251A97E400942152 /* TableViewController.swift */; }; D0F0B12E251A97E400942152 /* TableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F0B12D251A97E400942152 /* TableViewController.swift */; };
D0F0B136251AA12700942152 /* CollectionItem+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F0B135251AA12700942152 /* CollectionItem+Extensions.swift */; }; D0F0B136251AA12700942152 /* CollectionItem+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F0B135251AA12700942152 /* CollectionItem+Extensions.swift */; };
D0F4362D25C10B9600E4F896 /* AddIdentityViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F4362C25C10B9600E4F896 /* AddIdentityViewController.swift */; }; D0F4362D25C10B9600E4F896 /* AddIdentityViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F4362C25C10B9600E4F896 /* AddIdentityViewController.swift */; };
D0F5880525A7E4C500E3A49C /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = D0F5880425A7E4C500E3A49C /* Kingfisher */; };
D0F5880F25A7E6CC00E3A49C /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = D0F5880E25A7E6CC00E3A49C /* Kingfisher */; };
D0FCC105259C4E61000B67DF /* NewStatusViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FCC104259C4E61000B67DF /* NewStatusViewController.swift */; }; D0FCC105259C4E61000B67DF /* NewStatusViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FCC104259C4E61000B67DF /* NewStatusViewController.swift */; };
D0FCC106259C4E62000B67DF /* NewStatusViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FCC104259C4E61000B67DF /* NewStatusViewController.swift */; }; D0FCC106259C4E62000B67DF /* NewStatusViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FCC104259C4E61000B67DF /* NewStatusViewController.swift */; };
D0FE1C8F253686F9003EF1EB /* PlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FE1C8E253686F9003EF1EB /* PlayerView.swift */; }; D0FE1C8F253686F9003EF1EB /* PlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FE1C8E253686F9003EF1EB /* PlayerView.swift */; };
@ -273,10 +272,10 @@
D021A61925C36C1A008A0C0D /* IdentityContentConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentityContentConfiguration.swift; sourceTree = "<group>"; }; D021A61925C36C1A008A0C0D /* IdentityContentConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentityContentConfiguration.swift; sourceTree = "<group>"; };
D021A62B25C38570008A0C0D /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutView.swift; sourceTree = "<group>"; }; D021A62B25C38570008A0C0D /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutView.swift; sourceTree = "<group>"; };
D021A63525C38ADB008A0C0D /* AcknowledgmentsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AcknowledgmentsView.swift; sourceTree = "<group>"; }; D021A63525C38ADB008A0C0D /* AcknowledgmentsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AcknowledgmentsView.swift; sourceTree = "<group>"; };
D025B14525C4D26A001C69A8 /* ImageCacheSerializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageCacheSerializer.swift; sourceTree = "<group>"; };
D025B14C25C4E482001C69A8 /* ImageCacheConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageCacheConfiguration.swift; sourceTree = "<group>"; }; D025B14C25C4E482001C69A8 /* ImageCacheConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageCacheConfiguration.swift; sourceTree = "<group>"; };
D025B17D25C500BC001C69A8 /* CapsuleButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CapsuleButton.swift; sourceTree = "<group>"; }; D025B17D25C500BC001C69A8 /* CapsuleButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CapsuleButton.swift; sourceTree = "<group>"; };
D02E1F94250B13210071AD56 /* SafariView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariView.swift; sourceTree = "<group>"; }; D02E1F94250B13210071AD56 /* SafariView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariView.swift; sourceTree = "<group>"; };
D035D8F825E4338D00E597C9 /* ImageDiskCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageDiskCache.swift; sourceTree = "<group>"; };
D035F86825B7F2ED00DC75ED /* MainNavigationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainNavigationViewController.swift; sourceTree = "<group>"; }; D035F86825B7F2ED00DC75ED /* MainNavigationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainNavigationViewController.swift; sourceTree = "<group>"; };
D035F86E25B7F30E00DC75ED /* MainNavigationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainNavigationView.swift; sourceTree = "<group>"; }; D035F86E25B7F30E00DC75ED /* MainNavigationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainNavigationView.swift; sourceTree = "<group>"; };
D035F87C25B7F61600DC75ED /* TimelinesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelinesViewController.swift; sourceTree = "<group>"; }; D035F87C25B7F61600DC75ED /* TimelinesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelinesViewController.swift; sourceTree = "<group>"; };
@ -289,7 +288,6 @@
D036AA0B254B612B009094DF /* NotificationContentConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationContentConfiguration.swift; sourceTree = "<group>"; }; D036AA0B254B612B009094DF /* NotificationContentConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationContentConfiguration.swift; sourceTree = "<group>"; };
D036AA16254CA823009094DF /* StatusBodyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusBodyView.swift; sourceTree = "<group>"; }; D036AA16254CA823009094DF /* StatusBodyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusBodyView.swift; sourceTree = "<group>"; };
D03D87F325C23C44004DCBB2 /* SecondaryNavigationTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecondaryNavigationTitleView.swift; sourceTree = "<group>"; }; D03D87F325C23C44004DCBB2 /* SecondaryNavigationTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecondaryNavigationTitleView.swift; sourceTree = "<group>"; };
D0477F1425C68BAC005C5368 /* PrefetchRequestModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrefetchRequestModifier.swift; sourceTree = "<group>"; };
D0477F2B25C6EBAD005C5368 /* OpenInDefaultBrowserActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenInDefaultBrowserActivity.swift; sourceTree = "<group>"; }; D0477F2B25C6EBAD005C5368 /* OpenInDefaultBrowserActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenInDefaultBrowserActivity.swift; sourceTree = "<group>"; };
D0477F4525C72E50005C5368 /* CapsuleLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CapsuleLabel.swift; sourceTree = "<group>"; }; D0477F4525C72E50005C5368 /* CapsuleLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CapsuleLabel.swift; sourceTree = "<group>"; };
D047FA8C24C3E21200AF17C5 /* Metatext.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Metatext.app; sourceTree = BUILT_PRODUCTS_DIR; }; D047FA8C24C3E21200AF17C5 /* Metatext.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Metatext.app; sourceTree = BUILT_PRODUCTS_DIR; };
@ -434,8 +432,8 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
D0F5880525A7E4C500E3A49C /* Kingfisher in Frameworks */,
D0E2C1D124FD97F000854680 /* ViewModels in Frameworks */, D0E2C1D124FD97F000854680 /* ViewModels in Frameworks */,
D04F34B625E42ABE00714251 /* SDWebImage in Frameworks */,
D0FE7C8025C4C79F00203957 /* PreviewViewModels in Frameworks */, D0FE7C8025C4C79F00203957 /* PreviewViewModels in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@ -451,7 +449,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
D0F5880F25A7E6CC00E3A49C /* Kingfisher in Frameworks */, D04F34BC25E42ADC00714251 /* SDWebImage in Frameworks */,
D04F9E8E259E9C950081B0C9 /* ViewModels in Frameworks */, D04F9E8E259E9C950081B0C9 /* ViewModels in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@ -460,7 +458,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
D025B17025C4EB58001C69A8 /* Kingfisher in Frameworks */, D04F34C225E42AE500714251 /* SDWebImage in Frameworks */,
D025B16A25C4EB18001C69A8 /* ServiceLayer in Frameworks */, D025B16A25C4EB18001C69A8 /* ServiceLayer in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@ -823,9 +821,8 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
D025B14C25C4E482001C69A8 /* ImageCacheConfiguration.swift */, D025B14C25C4E482001C69A8 /* ImageCacheConfiguration.swift */,
D025B14525C4D26A001C69A8 /* ImageCacheSerializer.swift */,
D0FE1C9725368A9D003EF1EB /* PlayerCache.swift */, D0FE1C9725368A9D003EF1EB /* PlayerCache.swift */,
D0477F1425C68BAC005C5368 /* PrefetchRequestModifier.swift */, D035D8F825E4338D00E597C9 /* ImageDiskCache.swift */,
); );
path = Caches; path = Caches;
sourceTree = "<group>"; sourceTree = "<group>";
@ -852,8 +849,8 @@
name = Metatext; name = Metatext;
packageProductDependencies = ( packageProductDependencies = (
D0E2C1D024FD97F000854680 /* ViewModels */, D0E2C1D024FD97F000854680 /* ViewModels */,
D0F5880425A7E4C500E3A49C /* Kingfisher */,
D0FE7C7F25C4C79F00203957 /* PreviewViewModels */, D0FE7C7F25C4C79F00203957 /* PreviewViewModels */,
D04F34B525E42ABE00714251 /* SDWebImage */,
); );
productName = "Metatext (iOS)"; productName = "Metatext (iOS)";
productReference = D047FA8C24C3E21200AF17C5 /* Metatext.app */; productReference = D047FA8C24C3E21200AF17C5 /* Metatext.app */;
@ -894,7 +891,7 @@
name = "Share Extension"; name = "Share Extension";
packageProductDependencies = ( packageProductDependencies = (
D04F9E8D259E9C950081B0C9 /* ViewModels */, D04F9E8D259E9C950081B0C9 /* ViewModels */,
D0F5880E25A7E6CC00E3A49C /* Kingfisher */, D04F34BB25E42ADC00714251 /* SDWebImage */,
); );
productName = "Share Extension"; productName = "Share Extension";
productReference = D08E526C257C36CA00FA2C5F /* Share Extension.appex */; productReference = D08E526C257C36CA00FA2C5F /* Share Extension.appex */;
@ -915,7 +912,7 @@
name = "Notification Service Extension"; name = "Notification Service Extension";
packageProductDependencies = ( packageProductDependencies = (
D025B16925C4EB18001C69A8 /* ServiceLayer */, D025B16925C4EB18001C69A8 /* ServiceLayer */,
D025B16F25C4EB58001C69A8 /* Kingfisher */, D04F34C125E42AE500714251 /* SDWebImage */,
); );
productName = "Notification Service Extension"; productName = "Notification Service Extension";
productReference = D0E5361924E3EB4D00FB1CE1 /* Notification Service Extension.appex */; productReference = D0E5361924E3EB4D00FB1CE1 /* Notification Service Extension.appex */;
@ -957,7 +954,7 @@
); );
mainGroup = D047FA7F24C3E21000AF17C5; mainGroup = D047FA7F24C3E21000AF17C5;
packageReferences = ( packageReferences = (
D0F5880325A7E4C500E3A49C /* XCRemoteSwiftPackageReference "Kingfisher" */, D04F34B425E42ABE00714251 /* XCRemoteSwiftPackageReference "SDWebImage" */,
); );
productRefGroup = D047FA8D24C3E21200AF17C5 /* Products */; productRefGroup = D047FA8D24C3E21200AF17C5 /* Products */;
projectDirPath = ""; projectDirPath = "";
@ -1060,7 +1057,6 @@
D0477F2C25C6EBAD005C5368 /* OpenInDefaultBrowserActivity.swift in Sources */, D0477F2C25C6EBAD005C5368 /* OpenInDefaultBrowserActivity.swift in Sources */,
D0DD50CB256B1F24004A04F7 /* ReportView.swift in Sources */, D0DD50CB256B1F24004A04F7 /* ReportView.swift in Sources */,
D07F4D9825D493E300F61133 /* MuteView.swift in Sources */, D07F4D9825D493E300F61133 /* MuteView.swift in Sources */,
D0477F1525C68BAC005C5368 /* PrefetchRequestModifier.swift in Sources */,
D097F41B25BE3E1A00859F2C /* SearchScope+Extensions.swift in Sources */, D097F41B25BE3E1A00859F2C /* SearchScope+Extensions.swift in Sources */,
D0CEC10125E337C900FEF5A6 /* AnimatedTextAttachment.swift in Sources */, D0CEC10125E337C900FEF5A6 /* AnimatedTextAttachment.swift in Sources */,
D035F8B325B9616000DC75ED /* Timeline+Extensions.swift in Sources */, D035F8B325B9616000DC75ED /* Timeline+Extensions.swift in Sources */,
@ -1080,6 +1076,7 @@
D021A60A25C36B32008A0C0D /* IdentityTableViewCell.swift in Sources */, D021A60A25C36B32008A0C0D /* IdentityTableViewCell.swift in Sources */,
D0849C7F25903C4900A5EBCC /* Status+Extensions.swift in Sources */, D0849C7F25903C4900A5EBCC /* Status+Extensions.swift in Sources */,
D0F4362D25C10B9600E4F896 /* AddIdentityViewController.swift in Sources */, D0F4362D25C10B9600E4F896 /* AddIdentityViewController.swift in Sources */,
D035D8F925E4338D00E597C9 /* ImageDiskCache.swift in Sources */,
D0625E59250F092900502611 /* StatusTableViewCell.swift in Sources */, D0625E59250F092900502611 /* StatusTableViewCell.swift in Sources */,
D0E569DB2529319100FA1D72 /* LoadMoreView.swift in Sources */, D0E569DB2529319100FA1D72 /* LoadMoreView.swift in Sources */,
D05936FF25AA94EA00754FDF /* MarkAttachmentsSensitiveView.swift in Sources */, D05936FF25AA94EA00754FDF /* MarkAttachmentsSensitiveView.swift in Sources */,
@ -1136,7 +1133,6 @@
D036AA0C254B612B009094DF /* NotificationContentConfiguration.swift in Sources */, D036AA0C254B612B009094DF /* NotificationContentConfiguration.swift in Sources */,
D08B8D3D253F929E00B1EBEF /* ImageViewController.swift in Sources */, D08B8D3D253F929E00B1EBEF /* ImageViewController.swift in Sources */,
D035F86925B7F2ED00DC75ED /* MainNavigationViewController.swift in Sources */, D035F86925B7F2ED00DC75ED /* MainNavigationViewController.swift in Sources */,
D025B14625C4D26B001C69A8 /* ImageCacheSerializer.swift in Sources */,
D0B8510C25259E56004E0744 /* LoadMoreTableViewCell.swift in Sources */, D0B8510C25259E56004E0744 /* LoadMoreTableViewCell.swift in Sources */,
D08E52612579D2E100FA2C5F /* DomainBlocksView.swift in Sources */, D08E52612579D2E100FA2C5F /* DomainBlocksView.swift in Sources */,
D01F41E424F8889700D55A2D /* AttachmentsView.swift in Sources */, D01F41E424F8889700D55A2D /* AttachmentsView.swift in Sources */,
@ -1226,8 +1222,8 @@
D088406E25AFBBE200BB749B /* EmojiPickerViewController.swift in Sources */, D088406E25AFBBE200BB749B /* EmojiPickerViewController.swift in Sources */,
D0E39B8725D9B7FD009C10F8 /* AutocompleteDataSource.swift in Sources */, D0E39B8725D9B7FD009C10F8 /* AutocompleteDataSource.swift in Sources */,
D00CB23325C92F2D008EF267 /* Attachment+Extensions.swift in Sources */, D00CB23325C92F2D008EF267 /* Attachment+Extensions.swift in Sources */,
D035D8FE25E4339800E597C9 /* ImageDiskCache.swift in Sources */,
D0D93ECA25D9C76500C622ED /* AutocompleteItemView.swift in Sources */, D0D93ECA25D9C76500C622ED /* AutocompleteItemView.swift in Sources */,
D025B14725C4D26B001C69A8 /* ImageCacheSerializer.swift in Sources */,
D036EBB8259FE29800EC1CFC /* Status+Extensions.swift in Sources */, D036EBB8259FE29800EC1CFC /* Status+Extensions.swift in Sources */,
D021A6A625C3E584008A0C0D /* EditAttachmentView.swift in Sources */, D021A6A625C3E584008A0C0D /* EditAttachmentView.swift in Sources */,
D0D93ED925D9CBE200C622ED /* AutocompleteItemCollectionViewCell.swift in Sources */, D0D93ED925D9CBE200C622ED /* AutocompleteItemCollectionViewCell.swift in Sources */,
@ -1241,9 +1237,9 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
D035D90325E4388800E597C9 /* ImageDiskCache.swift in Sources */,
D0E5361C24E3EB4D00FB1CE1 /* NotificationService.swift in Sources */, D0E5361C24E3EB4D00FB1CE1 /* NotificationService.swift in Sources */,
D025B15B25C4EA7D001C69A8 /* ImageCacheConfiguration.swift in Sources */, D025B15B25C4EA7D001C69A8 /* ImageCacheConfiguration.swift in Sources */,
D025B16025C4EA81001C69A8 /* ImageCacheSerializer.swift in Sources */,
D059376125ABE2E800754FDF /* XMLUnescaper.swift in Sources */, D059376125ABE2E800754FDF /* XMLUnescaper.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@ -1642,12 +1638,12 @@
/* End XCConfigurationList section */ /* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */ /* Begin XCRemoteSwiftPackageReference section */
D0F5880325A7E4C500E3A49C /* XCRemoteSwiftPackageReference "Kingfisher" */ = { D04F34B425E42ABE00714251 /* XCRemoteSwiftPackageReference "SDWebImage" */ = {
isa = XCRemoteSwiftPackageReference; isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/onevcat/Kingfisher"; repositoryURL = "https://github.com/SDWebImage/SDWebImage";
requirement = { requirement = {
kind = upToNextMajorVersion; kind = upToNextMajorVersion;
minimumVersion = 6.1.0; minimumVersion = 5.10.4;
}; };
}; };
/* End XCRemoteSwiftPackageReference section */ /* End XCRemoteSwiftPackageReference section */
@ -1657,10 +1653,20 @@
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
productName = ServiceLayer; productName = ServiceLayer;
}; };
D025B16F25C4EB58001C69A8 /* Kingfisher */ = { D04F34B525E42ABE00714251 /* SDWebImage */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
package = D0F5880325A7E4C500E3A49C /* XCRemoteSwiftPackageReference "Kingfisher" */; package = D04F34B425E42ABE00714251 /* XCRemoteSwiftPackageReference "SDWebImage" */;
productName = Kingfisher; productName = SDWebImage;
};
D04F34BB25E42ADC00714251 /* SDWebImage */ = {
isa = XCSwiftPackageProductDependency;
package = D04F34B425E42ABE00714251 /* XCRemoteSwiftPackageReference "SDWebImage" */;
productName = SDWebImage;
};
D04F34C125E42AE500714251 /* SDWebImage */ = {
isa = XCSwiftPackageProductDependency;
package = D04F34B425E42ABE00714251 /* XCRemoteSwiftPackageReference "SDWebImage" */;
productName = SDWebImage;
}; };
D04F9E8D259E9C950081B0C9 /* ViewModels */ = { D04F9E8D259E9C950081B0C9 /* ViewModels */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
@ -1670,16 +1676,6 @@
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
productName = ViewModels; productName = ViewModels;
}; };
D0F5880425A7E4C500E3A49C /* Kingfisher */ = {
isa = XCSwiftPackageProductDependency;
package = D0F5880325A7E4C500E3A49C /* XCRemoteSwiftPackageReference "Kingfisher" */;
productName = Kingfisher;
};
D0F5880E25A7E6CC00E3A49C /* Kingfisher */ = {
isa = XCSwiftPackageProductDependency;
package = D0F5880325A7E4C500E3A49C /* XCRemoteSwiftPackageReference "Kingfisher" */;
productName = Kingfisher;
};
D0FE7C7F25C4C79F00203957 /* PreviewViewModels */ = { D0FE7C7F25C4C79F00203957 /* PreviewViewModels */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
productName = PreviewViewModels; productName = PreviewViewModels;

View file

@ -20,12 +20,12 @@
} }
}, },
{ {
"package": "Kingfisher", "package": "SDWebImage",
"repositoryURL": "https://github.com/onevcat/Kingfisher", "repositoryURL": "https://github.com/SDWebImage/SDWebImage",
"state": { "state": {
"branch": null, "branch": null,
"revision": "daebf8ddf974164d1b9a050c8231e263f3106b09", "revision": "a6b6e44eadf0d39250c10a7cc0e3b91d0bdb0e94",
"version": "6.1.0" "version": "5.10.4"
} }
} }
] ]

View file

@ -1,17 +1,15 @@
// Copyright © 2020 Metabolist. All rights reserved. // Copyright © 2020 Metabolist. All rights reserved.
import Kingfisher
import Mastodon import Mastodon
import SDWebImage
import ServiceLayer import ServiceLayer
import UserNotifications import UserNotifications
final class NotificationService: UNNotificationServiceExtension { final class NotificationService: UNNotificationServiceExtension {
private let environment = AppEnvironment.live(
userNotificationCenter: .current(),
reduceMotion: { false })
override init() { override init() {
super.init() super.init()
try? ImageCacheConfiguration(environment: Self.environment).configure()
} }
var contentHandler: ((UNNotificationContent) -> Void)? var contentHandler: ((UNNotificationContent) -> Void)?
@ -25,7 +23,7 @@ final class NotificationService: UNNotificationServiceExtension {
guard let bestAttemptContent = bestAttemptContent else { return } guard let bestAttemptContent = bestAttemptContent else { return }
let parsingService = PushNotificationParsingService(environment: environment) let parsingService = PushNotificationParsingService(environment: Self.environment)
let decryptedJSON: Data let decryptedJSON: Data
let identityId: Identity.Id let identityId: Identity.Id
let pushNotification: PushNotification let pushNotification: PushNotification
@ -43,14 +41,14 @@ final class NotificationService: UNNotificationServiceExtension {
bestAttemptContent.title = pushNotification.title bestAttemptContent.title = pushNotification.title
bestAttemptContent.body = XMLUnescaper(string: pushNotification.body).unescape() bestAttemptContent.body = XMLUnescaper(string: pushNotification.body).unescape()
let appPreferences = AppPreferences(environment: environment) let appPreferences = AppPreferences(environment: Self.environment)
if appPreferences.notificationSounds.contains(pushNotification.notificationType) { if appPreferences.notificationSounds.contains(pushNotification.notificationType) {
bestAttemptContent.sound = .default bestAttemptContent.sound = .default
} }
if appPreferences.notificationAccountName, if appPreferences.notificationAccountName,
let accountName = try? AllIdentitiesService(environment: environment).identity(id: identityId)?.handle { let accountName = try? AllIdentitiesService(environment: Self.environment).identity(id: identityId)?.handle {
bestAttemptContent.subtitle = accountName bestAttemptContent.subtitle = accountName
} }
@ -71,6 +69,10 @@ final class NotificationService: UNNotificationServiceExtension {
} }
private extension NotificationService { private extension NotificationService {
private static let environment = AppEnvironment.live(
userNotificationCenter: .current(),
reduceMotion: { false })
static func addImage(url: URL, static func addImage(url: URL,
bestAttemptContent: UNMutableNotificationContent, bestAttemptContent: UNMutableNotificationContent,
contentHandler: @escaping (UNNotificationContent) -> Void) { contentHandler: @escaping (UNNotificationContent) -> Void) {
@ -78,31 +80,17 @@ private extension NotificationService {
let fileURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true) let fileURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
.appendingPathComponent(fileName) .appendingPathComponent(fileName)
KingfisherManager.shared.retrieveImage(with: url) { SDWebImageManager.shared.loadImage(with: url, options: [], progress: nil) { _, data, _, _, _, _ in
switch $0 { if let data = data {
case let .success(result):
let format: ImageFormat
switch fileURL.pathExtension.lowercased() {
case "jpg", "jpeg":
format = .JPEG
case "gif":
format = .GIF
case "png":
format = .PNG
default:
format = .unknown
}
do { do {
try result.image.kf.data(format: format)?.write(to: fileURL) try data.write(to: fileURL)
bestAttemptContent.attachments = bestAttemptContent.attachments =
[try UNNotificationAttachment(identifier: fileName, url: fileURL)] [try UNNotificationAttachment(identifier: fileName, url: fileURL)]
contentHandler(bestAttemptContent) contentHandler(bestAttemptContent)
} catch { } catch {
contentHandler(bestAttemptContent) contentHandler(bestAttemptContent)
} }
case .failure: } else {
contentHandler(bestAttemptContent) contentHandler(bestAttemptContent)
} }
} }

View file

@ -1,5 +1,6 @@
// Copyright © 2020 Metabolist. All rights reserved. // Copyright © 2020 Metabolist. All rights reserved.
import Base16
import CryptoKit import CryptoKit
import Foundation import Foundation
import Secrets import Secrets
@ -20,4 +21,8 @@ public extension ImageSerializationService {
func deserialize(data: Data) throws -> Data { func deserialize(data: Data) throws -> Data {
try ChaChaPoly.open(.init(combined: data), using: key) try ChaChaPoly.open(.init(combined: data), using: key)
} }
func cacheKey(forKey key: String) -> String {
Data(SHA256.hash(data: Data(key.utf8))).base16EncodedString()
}
} }

View file

@ -1,7 +1,6 @@
// Copyright © 2020 Metabolist. All rights reserved. // Copyright © 2020 Metabolist. All rights reserved.
import AVKit import AVKit
import Kingfisher
import ServiceLayer import ServiceLayer
import SwiftUI import SwiftUI
import ViewModels import ViewModels
@ -30,9 +29,4 @@ private extension MetatextApp {
static let environment = AppEnvironment.live( static let environment = AppEnvironment.live(
userNotificationCenter: .current(), userNotificationCenter: .current(),
reduceMotion: { UIAccessibility.isReduceMotionEnabled }) reduceMotion: { UIAccessibility.isReduceMotionEnabled })
static let imageCacheName = "Images"
static let imageCacheDirectoryURL = FileManager.default.containerURL(
forSecurityApplicationGroupIdentifier: AppEnvironment.appGroup)?
.appendingPathComponent("Library")
.appendingPathComponent("Caches")
} }

View file

@ -1,9 +1,9 @@
// Copyright © 2021 Metabolist. All rights reserved. // Copyright © 2021 Metabolist. All rights reserved.
import Combine import Combine
import Kingfisher
import Mastodon import Mastodon
import SafariServices import SafariServices
import SDWebImage
import SwiftUI import SwiftUI
import ViewModels import ViewModels
@ -18,7 +18,7 @@ final class AddIdentityViewController: UIViewController {
private let welcomeLabel = UILabel() private let welcomeLabel = UILabel()
private let instanceAndButtonsStackView = UIStackView() private let instanceAndButtonsStackView = UIStackView()
private let instanceStackView = UIStackView() private let instanceStackView = UIStackView()
private let instanceImageView = AnimatedImageView() private let instanceImageView = SDAnimatedImageView()
private let instanceTitleLabel = UILabel() private let instanceTitleLabel = UILabel()
private let instanceURLLabel = UILabel() private let instanceURLLabel = UILabel()
private let buttonsStackView = UIStackView() private let buttonsStackView = UIStackView()
@ -110,7 +110,7 @@ private extension AddIdentityViewController {
instanceImageView.contentMode = .scaleAspectFill instanceImageView.contentMode = .scaleAspectFill
instanceImageView.layer.cornerRadius = .defaultCornerRadius instanceImageView.layer.cornerRadius = .defaultCornerRadius
instanceImageView.clipsToBounds = true instanceImageView.clipsToBounds = true
instanceImageView.kf.indicatorType = .activity instanceImageView.sd_imageIndicator = SDWebImageActivityIndicator.large
buttonsStackView.axis = .vertical buttonsStackView.axis = .vertical
buttonsStackView.spacing = .defaultSpacing buttonsStackView.spacing = .defaultSpacing
@ -259,7 +259,7 @@ private extension AddIdentityViewController {
if let instance = instance { if let instance = instance {
self.instanceTitleLabel.text = instance.title self.instanceTitleLabel.text = instance.title
self.instanceURLLabel.text = instance.uri self.instanceURLLabel.text = instance.uri
self.instanceImageView.kf.setImage(with: instance.thumbnail) self.instanceImageView.sd_setImage(with: instance.thumbnail)
self.instanceStackView.isHidden_stackViewSafe = false self.instanceStackView.isHidden_stackViewSafe = false
if instance.registrations { if instance.registrations {

View file

@ -1,14 +1,14 @@
// Copyright © 2020 Metabolist. All rights reserved. // Copyright © 2020 Metabolist. All rights reserved.
import AVFoundation import AVFoundation
import Kingfisher
import Mastodon import Mastodon
import SDWebImage
import UIKit import UIKit
import ViewModels import ViewModels
final class ImageViewController: UIViewController { final class ImageViewController: UIViewController {
let scrollView = UIScrollView() let scrollView = UIScrollView()
let imageView = AnimatedImageView() let imageView = SDAnimatedImageView()
let playerView = PlayerView() let playerView = PlayerView()
private let viewModel: AttachmentViewModel? private let viewModel: AttachmentViewModel?
@ -55,7 +55,8 @@ final class ImageViewController: UIViewController {
contentView.addSubview(imageView) contentView.addSubview(imageView)
imageView.translatesAutoresizingMaskIntoConstraints = false imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFit imageView.contentMode = .scaleAspectFit
imageView.kf.indicatorType = .activity imageView.sd_imageIndicator = SDWebImageActivityIndicator.large
imageView.autoPlayAnimatedImage = false
contentView.addSubview(playerView) contentView.addSubview(playerView)
playerView.translatesAutoresizingMaskIntoConstraints = false playerView.translatesAutoresizingMaskIntoConstraints = false
@ -109,20 +110,11 @@ final class ImageViewController: UIViewController {
case .image: case .image:
imageView.tag = viewModel.tag imageView.tag = viewModel.tag
playerView.isHidden = true playerView.isHidden = true
imageView.kf.setImage(
with: viewModel.attachment.previewUrl,
options: [.onlyFromCache],
completionHandler: { [weak self] in
guard let self = self else { return }
if case .success = $0 { let placeholderKey = viewModel.attachment.previewUrl?.absoluteString
self.imageView.kf.indicatorType = .none let placeholderImage = SDImageCache.shared.imageFromCache(forKey: placeholderKey)
}
self.imageView.kf.setImage( imageView.sd_setImage(with: viewModel.attachment.url, placeholderImage: placeholderImage)
with: viewModel.attachment.url,
options: [.keepCurrentImageWhileLoading])
})
case .gifv: case .gifv:
playerView.tag = viewModel.tag playerView.tag = viewModel.tag
imageView.isHidden = true imageView.isHidden = true
@ -143,7 +135,7 @@ final class ImageViewController: UIViewController {
} else if let imageURL = imageURL { } else if let imageURL = imageURL {
imageView.tag = imageURL.hashValue imageView.tag = imageURL.hashValue
playerView.isHidden = true playerView.isHidden = true
imageView.kf.setImage(with: imageURL) imageView.sd_setImage(with: imageURL)
} }
contentView.accessibilityLabel = viewModel?.attachment.type.accessibilityName contentView.accessibilityLabel = viewModel?.attachment.type.accessibilityName

View file

@ -2,7 +2,6 @@
import AVFoundation import AVFoundation
import Combine import Combine
import Kingfisher
import PhotosUI import PhotosUI
import SwiftUI import SwiftUI
import UniformTypeIdentifiers import UniformTypeIdentifiers

View file

@ -2,9 +2,9 @@
import AVKit import AVKit
import Combine import Combine
import Kingfisher
import Mastodon import Mastodon
import SafariServices import SafariServices
import SDWebImage
import SwiftUI import SwiftUI
import ViewModels import ViewModels
@ -280,13 +280,8 @@ extension TableViewController: UITableViewDataSourcePrefetching {
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) { func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
let urls = indexPaths.compactMap(dataSource.itemIdentifier(for:)) let urls = indexPaths.compactMap(dataSource.itemIdentifier(for:))
.reduce(Set<URL>()) { $0.union($1.mediaPrefetchURLs(identityContext: viewModel.identityContext)) } .reduce(Set<URL>()) { $0.union($1.mediaPrefetchURLs(identityContext: viewModel.identityContext)) }
var imageOptions = KingfisherManager.shared.defaultOptions
imageOptions.append(.requestModifier(PrefetchRequestModifier())) SDWebImagePrefetcher.shared.prefetchURLs(Array(urls))
for url in urls {
KingfisherManager.shared.retrieveImage(with: url, completionHandler: nil)
}
} }
} }

View file

@ -1,6 +1,5 @@
// Copyright © 2020 Metabolist. All rights reserved. // Copyright © 2020 Metabolist. All rights reserved.
import Kingfisher
import SwiftUI import SwiftUI
import ViewModels import ViewModels

View file

@ -1,6 +1,5 @@
// Copyright © 2020 Metabolist. All rights reserved. // Copyright © 2020 Metabolist. All rights reserved.
import Kingfisher
import SwiftUI import SwiftUI
import ViewModels import ViewModels

View file

@ -1,6 +1,5 @@
// Copyright © 2020 Metabolist. All rights reserved. // Copyright © 2020 Metabolist. All rights reserved.
import Kingfisher
import SwiftUI import SwiftUI
import ViewModels import ViewModels

View file

@ -1,16 +1,16 @@
// Copyright © 2020 Metabolist. All rights reserved. // Copyright © 2020 Metabolist. All rights reserved.
import Kingfisher import SDWebImage
import UIKit import UIKit
import ViewModels import ViewModels
// swiftlint:disable file_length // swiftlint:disable file_length
final class AccountHeaderView: UIView { final class AccountHeaderView: UIView {
let headerImageBackgroundView = UIView() let headerImageBackgroundView = UIView()
let headerImageView = AnimatedImageView() let headerImageView = SDAnimatedImageView()
let headerButton = UIButton() let headerButton = UIButton()
let avatarBackgroundView = UIView() let avatarBackgroundView = UIView()
let avatarImageView = AnimatedImageView() let avatarImageView = SDAnimatedImageView()
let avatarButton = UIButton() let avatarButton = UIButton()
let relationshipButtonsStackView = UIStackView() let relationshipButtonsStackView = UIStackView()
let followButton = UIButton(type: .system) let followButton = UIButton(type: .system)
@ -37,8 +37,8 @@ final class AccountHeaderView: UIView {
var viewModel: ProfileViewModel { var viewModel: ProfileViewModel {
didSet { didSet {
if let accountViewModel = viewModel.accountViewModel { if let accountViewModel = viewModel.accountViewModel {
headerImageView.kf.setImage(with: accountViewModel.headerURL) { [weak self] in headerImageView.sd_setImage(with: accountViewModel.headerURL) { [weak self] image, _, _, _ in
if case let .success(result) = $0, result.image.size != Self.missingHeaderImageSize { if let image = image, image.size != Self.missingHeaderImageSize {
self?.headerButton.isEnabled = true self?.headerButton.isEnabled = true
} }
} }
@ -46,7 +46,7 @@ final class AccountHeaderView: UIView {
headerButton.accessibilityLabel = String.localizedStringWithFormat( headerButton.accessibilityLabel = String.localizedStringWithFormat(
NSLocalizedString("account.header.accessibility-label-%@", comment: ""), NSLocalizedString("account.header.accessibility-label-%@", comment: ""),
accountViewModel.displayName) accountViewModel.displayName)
avatarImageView.kf.setImage(with: accountViewModel.avatarURL(profile: true)) avatarImageView.sd_setImage(with: accountViewModel.avatarURL(profile: true))
avatarImageView.tag = accountViewModel.avatarURL(profile: true).hashValue avatarImageView.tag = accountViewModel.avatarURL(profile: true).hashValue
avatarButton.accessibilityLabel = String.localizedStringWithFormat( avatarButton.accessibilityLabel = String.localizedStringWithFormat(
NSLocalizedString("account.avatar.accessibility-label-%@", comment: ""), NSLocalizedString("account.avatar.accessibility-label-%@", comment: ""),

View file

@ -1,6 +1,6 @@
// Copyright © 2021 Metabolist. All rights reserved. // Copyright © 2021 Metabolist. All rights reserved.
import Kingfisher import SDWebImage
import UIKit import UIKit
final class AnimatedAttachmentLabel: UILabel, EmojiInsertable { final class AnimatedAttachmentLabel: UILabel, EmojiInsertable {
@ -18,7 +18,7 @@ final class AnimatedAttachmentLabel: UILabel, EmojiInsertable {
guard let attributedText = attributedText else { return } guard let attributedText = attributedText else { return }
var attachmentImageViews = Set<AnimatedImageView>() var attachmentImageViews = Set<SDAnimatedImageView>()
attributedText.enumerateAttribute( attributedText.enumerateAttribute(
.attachment, .attachment,
@ -29,7 +29,7 @@ final class AnimatedAttachmentLabel: UILabel, EmojiInsertable {
} }
for subview in subviews { for subview in subviews {
guard let attachmentImageView = subview as? AnimatedImageView else { continue } guard let attachmentImageView = subview as? SDAnimatedImageView else { continue }
if !attachmentImageViews.contains(attachmentImageView) { if !attachmentImageViews.contains(attachmentImageView) {
attachmentImageView.removeFromSuperview() attachmentImageView.removeFromSuperview()
@ -49,6 +49,7 @@ final class AnimatedAttachmentLabel: UILabel, EmojiInsertable {
animatedAttachment.imageView.image = animatedAttachment.image animatedAttachment.imageView.image = animatedAttachment.image
animatedAttachment.imageView.contentMode = .scaleAspectFit animatedAttachment.imageView.contentMode = .scaleAspectFit
animatedAttachment.imageView.center.y = center.y animatedAttachment.imageView.center.y = center.y
animatedAttachment.imageView.sd_setImage(with: animatedAttachment.imageURL)
if animatedAttachment.imageView.superview != self { if animatedAttachment.imageView.superview != self {
addSubview(animatedAttachment.imageView) addSubview(animatedAttachment.imageView)

View file

@ -1,10 +1,11 @@
// Copyright © 2021 Metabolist. All rights reserved. // Copyright © 2021 Metabolist. All rights reserved.
import Kingfisher import SDWebImage
import UIKit import UIKit
final class AnimatedTextAttachment: NSTextAttachment { final class AnimatedTextAttachment: NSTextAttachment {
var imageView = AnimatedImageView() var imageURL: URL?
var imageView = SDAnimatedImageView()
var imageBounds: CGRect? var imageBounds: CGRect?
override func image(forBounds imageBounds: CGRect, override func image(forBounds imageBounds: CGRect,

View file

@ -1,6 +1,6 @@
// Copyright © 2021 Metabolist. All rights reserved. // Copyright © 2021 Metabolist. All rights reserved.
import Kingfisher import SDWebImage
import UIKit import UIKit
final class AnimatingLayoutManager: NSLayoutManager { final class AnimatingLayoutManager: NSLayoutManager {
@ -13,7 +13,7 @@ final class AnimatingLayoutManager: NSLayoutManager {
return return
} }
var attachmentImageViews = Set<AnimatedImageView>() var attachmentImageViews = Set<SDAnimatedImageView>()
textStorage.enumerateAttribute( textStorage.enumerateAttribute(
.attachment, .attachment,
@ -24,7 +24,7 @@ final class AnimatingLayoutManager: NSLayoutManager {
} }
for subview in view?.subviews ?? [] { for subview in view?.subviews ?? [] {
guard let attachmentImageView = subview as? AnimatedImageView else { continue } guard let attachmentImageView = subview as? SDAnimatedImageView else { continue }
if !attachmentImageViews.contains(attachmentImageView) { if !attachmentImageViews.contains(attachmentImageView) {
attachmentImageView.removeFromSuperview() attachmentImageView.removeFromSuperview()
@ -42,6 +42,7 @@ final class AnimatingLayoutManager: NSLayoutManager {
animatedAttachment.imageView.frame = boundingRect(forGlyphRange: range, in: textContainer) animatedAttachment.imageView.frame = boundingRect(forGlyphRange: range, in: textContainer)
animatedAttachment.imageView.image = animatedAttachment.image animatedAttachment.imageView.image = animatedAttachment.image
animatedAttachment.imageView.contentMode = .scaleAspectFit animatedAttachment.imageView.contentMode = .scaleAspectFit
animatedAttachment.imageView.sd_setImage(with: animatedAttachment.imageURL)
if animatedAttachment.imageView.superview != view { if animatedAttachment.imageView.superview != view {
view?.addSubview(animatedAttachment.imageView) view?.addSubview(animatedAttachment.imageView)

View file

@ -2,13 +2,13 @@
import AVKit import AVKit
import Combine import Combine
import Kingfisher import SDWebImage
import UIKit import UIKit
import ViewModels import ViewModels
final class AttachmentView: UIView { final class AttachmentView: UIView {
let playerView = PlayerView() let playerView = PlayerView()
let imageView = AnimatedImageView() let imageView = SDAnimatedImageView()
let removeButton = UIButton(type: .close) let removeButton = UIButton(type: .close)
let editIcon = UIImageView() let editIcon = UIImageView()
let selectionButton = UIButton() let selectionButton = UIButton()
@ -105,6 +105,7 @@ private extension AttachmentView {
imageView.translatesAutoresizingMaskIntoConstraints = false imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFill imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true imageView.clipsToBounds = true
imageView.autoPlayAnimatedImage = false
imageView.tag = viewModel.tag imageView.tag = viewModel.tag
let blurEffect = UIBlurEffect(style: .systemUltraThinMaterial) let blurEffect = UIBlurEffect(style: .systemUltraThinMaterial)
@ -168,11 +169,9 @@ private extension AttachmentView {
switch viewModel.attachment.type { switch viewModel.attachment.type {
case .image, .video, .gifv: case .image, .video, .gifv:
imageView.kf.setImage( imageView.sd_setImage(with: viewModel.attachment.previewUrl) { [weak self] _, _, _, _ in
with: viewModel.attachment.previewUrl, self?.layoutSubviews()
completionHandler: { [weak self] _ in }
self?.layoutSubviews()
})
case .audio: case .audio:
playImageView.image = UIImage(systemName: "waveform.circle", playImageView.image = UIImage(systemName: "waveform.circle",
withConfiguration: UIImage.SymbolConfiguration(textStyle: .largeTitle)) withConfiguration: UIImage.SymbolConfiguration(textStyle: .largeTitle))

View file

@ -1,7 +1,7 @@
// Copyright © 2020 Metabolist. All rights reserved. // Copyright © 2020 Metabolist. All rights reserved.
import Kingfisher
import Mastodon import Mastodon
import SDWebImage
import UIKit import UIKit
import ViewModels import ViewModels
@ -20,7 +20,7 @@ final class CardView: UIView {
.appendingWithSeparator(viewModel.title) .appendingWithSeparator(viewModel.title)
imageView.isHidden = viewModel.imageURL == nil imageView.isHidden = viewModel.imageURL == nil
imageView.kf.setImage(with: viewModel.imageURL) imageView.sd_setImage(with: viewModel.imageURL)
titleLabel.text = viewModel.title titleLabel.text = viewModel.title
descriptionLabel.text = viewModel.description descriptionLabel.text = viewModel.description

View file

@ -1,12 +1,12 @@
// Copyright © 2020 Metabolist. All rights reserved. // Copyright © 2020 Metabolist. All rights reserved.
import Combine import Combine
import Kingfisher import SDWebImage
import UIKit import UIKit
import ViewModels import ViewModels
final class CompositionView: UIView { final class CompositionView: UIView {
let avatarImageView = AnimatedImageView() let avatarImageView = SDAnimatedImageView()
let changeIdentityButton = UIButton() let changeIdentityButton = UIButton()
let spoilerTextField = UITextField() let spoilerTextField = UITextField()
let textView = ImagePastableTextView() let textView = ImagePastableTextView()
@ -199,7 +199,7 @@ private extension CompositionView {
? $0.identity.account?.avatar ? $0.identity.account?.avatar
: $0.identity.account?.avatarStatic : $0.identity.account?.avatarStatic
self.avatarImageView.kf.setImage(with: avatarURL) self.avatarImageView.sd_setImage(with: avatarURL)
self.changeIdentityButton.accessibilityLabel = $0.identity.handle self.changeIdentityButton.accessibilityLabel = $0.identity.handle
self.changeIdentityButton.accessibilityHint = self.changeIdentityButton.accessibilityHint =
NSLocalizedString("compose.change-identity-button.accessibility-hint", comment: "") NSLocalizedString("compose.change-identity-button.accessibility-hint", comment: "")
@ -290,10 +290,11 @@ private extension CompositionView {
} }
func changeIdentityMenu(identities: [Identity]) -> UIMenu { func changeIdentityMenu(identities: [Identity]) -> UIMenu {
let processor = RoundCornerImageProcessor(radius: .widthFraction(0.5)) let imageTransformer = SDImageRoundCornerTransformer(
var imageOptions = KingfisherManager.shared.defaultOptions radius: .greatestFiniteMagnitude,
corners: .allCorners,
imageOptions.append(.processor(processor)) borderWidth: 0,
borderColor: nil)
return UIMenu(children: identities.map { identity in return UIMenu(children: identities.map { identity in
UIDeferredMenuElement { completion in UIDeferredMenuElement { completion in
@ -302,10 +303,12 @@ private extension CompositionView {
} }
if let image = identity.image { if let image = identity.image {
KingfisherManager.shared.retrieveImage(with: image, options: imageOptions) { SDWebImageManager.shared.loadImage(
if case let .success(value) = $0 { with: image,
action.image = value.image options: [.transformAnimatedImage],
} context: [.imageTransformer: imageTransformer],
progress: nil) { (image, _, _, _, _, _) in
action.image = image
completion([action]) completion([action])
} }

View file

@ -1,10 +1,10 @@
// Copyright © 2021 Metabolist. All rights reserved. // Copyright © 2021 Metabolist. All rights reserved.
import Kingfisher import SDWebImage
import UIKit import UIKit
final class EmojiView: UIView { final class EmojiView: UIView {
private let imageView = AnimatedImageView() private let imageView = SDAnimatedImageView()
private let emojiLabel = UILabel() private let emojiLabel = UILabel()
private var emojiConfiguration: EmojiContentConfiguration private var emojiConfiguration: EmojiContentConfiguration
@ -74,7 +74,8 @@ private extension EmojiView {
imageView.isHidden = false imageView.isHidden = false
emojiLabel.isHidden = true emojiLabel.isHidden = true
imageView.kf.setImage(with: emoji.url) // TODO: Use static URL if emoji animation preference is false
imageView.sd_setImage(with: emoji.url)
accessibilityLabel = emoji.shortcode accessibilityLabel = emoji.shortcode
} else { } else {
imageView.isHidden = true imageView.isHidden = true

View file

@ -1,12 +1,12 @@
// Copyright © 2020 Metabolist. All rights reserved. // Copyright © 2020 Metabolist. All rights reserved.
import Kingfisher
import Mastodon import Mastodon
import SDWebImage
import UIKit import UIKit
import ViewModels import ViewModels
final class AccountView: UIView { final class AccountView: UIView {
let avatarImageView = AnimatedImageView() let avatarImageView = SDAnimatedImageView()
let displayNameLabel = AnimatedAttachmentLabel() let displayNameLabel = AnimatedAttachmentLabel()
let accountLabel = UILabel() let accountLabel = UILabel()
let noteTextView = TouchFallthroughTextView() let noteTextView = TouchFallthroughTextView()
@ -199,7 +199,7 @@ private extension AccountView {
func applyAccountConfiguration() { func applyAccountConfiguration() {
let viewModel = accountConfiguration.viewModel let viewModel = accountConfiguration.viewModel
avatarImageView.kf.setImage(with: viewModel.avatarURL(profile: false)) avatarImageView.sd_setImage(with: viewModel.avatarURL(profile: false))
let mutableDisplayName = NSMutableAttributedString(string: viewModel.displayName) let mutableDisplayName = NSMutableAttributedString(string: viewModel.displayName)

View file

@ -1,10 +1,10 @@
// Copyright © 2021 Metabolist. All rights reserved. // Copyright © 2021 Metabolist. All rights reserved.
import Kingfisher import SDWebImage
import UIKit import UIKit
final class AutocompleteItemView: UIView { final class AutocompleteItemView: UIView {
private let imageView = AnimatedImageView() private let imageView = SDAnimatedImageView()
private let primaryLabel = AnimatedAttachmentLabel() private let primaryLabel = AnimatedAttachmentLabel()
private let secondaryLabel = UILabel() private let secondaryLabel = UILabel()
private let stackView = UIStackView() private let stackView = UIStackView()
@ -78,7 +78,7 @@ private extension AutocompleteItemView {
? account.avatar ? account.avatar
: account.avatarStatic : account.avatarStatic
imageView.kf.setImage(with: avatarURL) imageView.sd_setImage(with: avatarURL)
imageView.isHidden = false imageView.isHidden = false
let mutableDisplayName = NSMutableAttributedString(string: account.displayName) let mutableDisplayName = NSMutableAttributedString(string: account.displayName)

View file

@ -1,10 +1,10 @@
// Copyright © 2021 Metabolist. All rights reserved. // Copyright © 2021 Metabolist. All rights reserved.
import Kingfisher import SDWebImage
import UIKit import UIKit
final class IdentityView: UIView { final class IdentityView: UIView {
let imageView = AnimatedImageView() let imageView = SDAnimatedImageView()
let nameLabel = AnimatedAttachmentLabel() let nameLabel = AnimatedAttachmentLabel()
let secondaryLabel = UILabel() let secondaryLabel = UILabel()
@ -84,7 +84,7 @@ private extension IdentityView {
func applyIdentityConfiguration() { func applyIdentityConfiguration() {
let viewModel = identityConfiguration.viewModel let viewModel = identityConfiguration.viewModel
imageView.kf.setImage(with: viewModel.identity.image) imageView.sd_setImage(with: viewModel.identity.image)
imageView.autoPlayAnimatedImage = viewModel.identityContext.appPreferences.animateAvatars == .everywhere imageView.autoPlayAnimatedImage = viewModel.identityContext.appPreferences.animateAvatars == .everywhere
if let displayName = viewModel.identity.account?.displayName, if let displayName = viewModel.identity.account?.displayName,

View file

@ -1,10 +1,10 @@
// Copyright © 2021 Metabolist. All rights reserved. // Copyright © 2021 Metabolist. All rights reserved.
import Kingfisher import SDWebImage
import UIKit import UIKit
final class InstanceView: UIView { final class InstanceView: UIView {
private let imageView = AnimatedImageView() private let imageView = SDAnimatedImageView()
private let titleLabel = UILabel() private let titleLabel = UILabel()
private let uriLabel = UILabel() private let uriLabel = UILabel()
private var instanceConfiguration: InstanceContentConfiguration private var instanceConfiguration: InstanceContentConfiguration
@ -77,7 +77,8 @@ private extension InstanceView {
func applyInstanceConfiguration() { func applyInstanceConfiguration() {
let viewModel = instanceConfiguration.viewModel let viewModel = instanceConfiguration.viewModel
imageView.kf.setImage(with: viewModel.instance.thumbnail) imageView.sd_setImage(with: viewModel.instance.thumbnail)
imageView.autoPlayAnimatedImage = !UIAccessibility.isReduceMotionEnabled
titleLabel.text = viewModel.instance.title titleLabel.text = viewModel.instance.title
uriLabel.text = viewModel.instance.uri uriLabel.text = viewModel.instance.uri

View file

@ -1,13 +1,13 @@
// Copyright © 2020 Metabolist. All rights reserved. // Copyright © 2020 Metabolist. All rights reserved.
import Kingfisher
import Mastodon import Mastodon
import SDWebImage
import UIKit import UIKit
import ViewModels import ViewModels
final class NotificationView: UIView { final class NotificationView: UIView {
private let iconImageView = UIImageView() private let iconImageView = UIImageView()
private let avatarImageView = AnimatedImageView() private let avatarImageView = SDAnimatedImageView()
private let avatarButton = UIButton() private let avatarButton = UIButton()
private let typeLabel = AnimatedAttachmentLabel() private let typeLabel = AnimatedAttachmentLabel()
private let timeLabel = UILabel() private let timeLabel = UILabel()
@ -166,7 +166,7 @@ private extension NotificationView {
func applyNotificationConfiguration() { func applyNotificationConfiguration() {
let viewModel = notificationConfiguration.viewModel let viewModel = notificationConfiguration.viewModel
avatarImageView.kf.setImage(with: viewModel.accountViewModel.avatarURL()) avatarImageView.sd_setImage(with: viewModel.accountViewModel.avatarURL())
switch viewModel.type { switch viewModel.type {
case .follow: case .follow:

View file

@ -2,13 +2,13 @@
// swiftlint:disable file_length // swiftlint:disable file_length
import Combine import Combine
import Kingfisher
import Mastodon import Mastodon
import SDWebImage
import UIKit import UIKit
import ViewModels import ViewModels
final class StatusView: UIView { final class StatusView: UIView {
let avatarImageView = AnimatedImageView() let avatarImageView = SDAnimatedImageView()
let avatarButton = UIButton() let avatarButton = UIButton()
let infoIcon = UIImageView() let infoIcon = UIImageView()
let infoLabel = AnimatedAttachmentLabel() let infoLabel = AnimatedAttachmentLabel()
@ -417,7 +417,7 @@ private extension StatusView {
menuButton.menu = menu(viewModel: viewModel) menuButton.menu = menu(viewModel: viewModel)
avatarImageView.kf.setImage(with: viewModel.avatarURL) avatarImageView.sd_setImage(with: viewModel.avatarURL)
avatarButton.accessibilityLabel = String.localizedStringWithFormat( avatarButton.accessibilityLabel = String.localizedStringWithFormat(
NSLocalizedString("account.avatar.accessibility-label-%@", comment: ""), NSLocalizedString("account.avatar.accessibility-label-%@", comment: ""),
viewModel.accountViewModel.displayName) viewModel.accountViewModel.displayName)

View file

@ -1,6 +1,6 @@
// Copyright © 2020 Metabolist. All rights reserved. // Copyright © 2020 Metabolist. All rights reserved.
import Kingfisher import SDWebImage
import UIKit import UIKit
import ViewModels import ViewModels
@ -23,11 +23,11 @@ final class ConversationAvatarsView: UIView {
rightStackView.isHidden = accountCount == 1 rightStackView.isHidden = accountCount == 1
for (index, accountViewModel) in accountViewModels.enumerated() { for (index, accountViewModel) in accountViewModels.enumerated() {
let imageView = AnimatedImageView() let imageView = SDAnimatedImageView()
imageView.contentMode = .scaleAspectFill imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true imageView.clipsToBounds = true
imageView.kf.setImage(with: accountViewModel.avatarURL()) imageView.sd_setImage(with: accountViewModel.avatarURL())
if accountCount == 2 && index == 1 if accountCount == 2 && index == 1
|| accountCount == 3 && index != 0 || accountCount == 3 && index != 0

View file

@ -1,14 +1,14 @@
// Copyright © 2021 Metabolist. All rights reserved. // Copyright © 2021 Metabolist. All rights reserved.
import Combine import Combine
import Kingfisher import SDWebImage
import UIKit import UIKit
import ViewModels import ViewModels
final class EditThumbnailView: UIView { final class EditThumbnailView: UIView {
let playerView = PlayerView() let playerView = PlayerView()
let imageView = UIImageView() let imageView = SDAnimatedImageView()
let previewImageView = UIImageView() let previewImageView = SDAnimatedImageView()
let promptBackgroundView = UIVisualEffectView(effect: UIBlurEffect(style: .systemChromeMaterial)) let promptBackgroundView = UIVisualEffectView(effect: UIBlurEffect(style: .systemChromeMaterial))
let thumbnailPromptLabel = UILabel() let thumbnailPromptLabel = UILabel()
@ -94,7 +94,7 @@ private extension EditThumbnailView {
addSubview(imageView) addSubview(imageView)
imageView.translatesAutoresizingMaskIntoConstraints = false imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFit imageView.contentMode = .scaleAspectFit
imageView.kf.indicatorType = .activity imageView.sd_imageIndicator = SDWebImageActivityIndicator.large
addSubview(playerView) addSubview(playerView)
playerView.translatesAutoresizingMaskIntoConstraints = false playerView.translatesAutoresizingMaskIntoConstraints = false
@ -137,25 +137,16 @@ private extension EditThumbnailView {
previewImageView.contentMode = .scaleAspectFill previewImageView.contentMode = .scaleAspectFill
previewImageView.clipsToBounds = true previewImageView.clipsToBounds = true
previewImageView.layer.cornerRadius = .defaultCornerRadius previewImageView.layer.cornerRadius = .defaultCornerRadius
previewImageView.kf.setImage(with: viewModel.attachment.previewUrl) previewImageView.sd_setImage(with: viewModel.attachment.previewUrl)
switch viewModel.attachment.type { switch viewModel.attachment.type {
case .image: case .image:
playerView.isHidden = true playerView.isHidden = true
imageView.kf.setImage(
with: viewModel.attachment.previewUrl,
options: [.onlyFromCache],
completionHandler: { [weak self] in
guard let self = self else { return }
if case .success = $0 { let placeholderKey = viewModel.attachment.previewUrl?.absoluteString
self.imageView.kf.indicatorType = .none let placeholderImage = SDImageCache.shared.imageFromCache(forKey: placeholderKey)
}
self.imageView.kf.setImage( imageView.sd_setImage(with: viewModel.attachment.url, placeholderImage: placeholderImage)
with: self.viewModel.attachment.url,
options: [.keepCurrentImageWhileLoading])
})
case .gifv: case .gifv:
imageView.isHidden = true imageView.isHidden = true
let player = PlayerCache.shared.player(url: viewModel.attachment.url) let player = PlayerCache.shared.player(url: viewModel.attachment.url)

View file

@ -1,7 +1,7 @@
// Copyright © 2021 Metabolist. All rights reserved. // Copyright © 2021 Metabolist. All rights reserved.
import Combine import Combine
import Kingfisher import SDWebImage
import UIKit import UIKit
import ViewModels import ViewModels
@ -28,17 +28,18 @@ final class SecondaryNavigationButton: UIBarButtonItem {
]) ])
viewModel.identityContext.$identity.sink { viewModel.identityContext.$identity.sink {
button.kf.setImage( button.sd_setImage(
with: $0.image, with: $0.image,
for: .normal, for: .normal,
placeholder: UIImage(systemName: "line.horizontal.3")) placeholderImage: UIImage(systemName: "line.horizontal.3"))
} }
.store(in: &cancellables) .store(in: &cancellables)
let processor = RoundCornerImageProcessor(radius: .widthFraction(0.5)) let imageTransformer = SDImageRoundCornerTransformer(
var imageOptions = KingfisherManager.shared.defaultOptions radius: .greatestFiniteMagnitude,
corners: .allCorners,
imageOptions.append(.processor(processor)) borderWidth: 0,
borderColor: nil)
viewModel.$recentIdentities.sink { identities in viewModel.$recentIdentities.sink { identities in
button.menu = UIMenu(children: identities.map { identity in button.menu = UIMenu(children: identities.map { identity in
@ -48,10 +49,12 @@ final class SecondaryNavigationButton: UIBarButtonItem {
} }
if let image = identity.image { if let image = identity.image {
KingfisherManager.shared.retrieveImage(with: image, options: imageOptions) { SDWebImageManager.shared.loadImage(
if case let .success(value) = $0 { with: image,
action.image = value.image options: [.transformAnimatedImage],
} context: [.imageTransformer: imageTransformer],
progress: nil) { (image, _, _, _, _, _) in
action.image = image
completion([action]) completion([action])
} }

View file

@ -1,12 +1,12 @@
// Copyright © 2021 Metabolist. All rights reserved. // Copyright © 2021 Metabolist. All rights reserved.
import Kingfisher import SDWebImage
import UIKit import UIKit
import ViewModels import ViewModels
final class SecondaryNavigationTitleView: UIView { final class SecondaryNavigationTitleView: UIView {
private let viewModel: NavigationViewModel private let viewModel: NavigationViewModel
private let avatarImageView = AnimatedImageView() private let avatarImageView = SDAnimatedImageView()
private let displayNameLabel = AnimatedAttachmentLabel() private let displayNameLabel = AnimatedAttachmentLabel()
private let accountLabel = UILabel() private let accountLabel = UILabel()
private let stackView = UIStackView() private let stackView = UIStackView()
@ -70,7 +70,7 @@ private extension SecondaryNavigationTitleView {
? viewModel.identityContext.identity.account?.avatar ? viewModel.identityContext.identity.account?.avatar
: viewModel.identityContext.identity.account?.avatarStatic : viewModel.identityContext.identity.account?.avatarStatic
avatarImageView.kf.setImage(with: avatarURL) avatarImageView.sd_setImage(with: avatarURL)
if let displayName = viewModel.identityContext.identity.account?.displayName, if let displayName = viewModel.identityContext.identity.account?.displayName,
!displayName.isEmpty { !displayName.isEmpty {