Compare commits

..

No commits in common. "76268e7a14e43cee97a619bf3d92a8c7108c7cc6" and "474064669db8f9172c566a77907b886f4d3e3f80" have entirely different histories.

4 changed files with 48 additions and 59 deletions

View File

@ -32,38 +32,46 @@ class ImageCache {
} }
func get(_ url: URL, loadOriginal: Bool = false, completion: ((Data?, UIImage?) -> Void)?) -> Request? { func get(_ url: URL, loadOriginal: Bool = false, completion: ((Data?, UIImage?) -> Void)?) -> Request? {
if !ImageCache.disableCaching, let key = url.absoluteString
let entry = try? cache.get(url.absoluteString, loadOriginal: loadOriginal) {
completion?(entry.data, entry.image) let wrappedCompletion: ((Data?, UIImage?) -> Void)?
return nil if let completion = completion {
} else { wrappedCompletion = { (data, image) in
return Task.detached(priority: .userInitiated) { if let image {
let result = await self.fetch(url: url) if !loadOriginal,
switch result { let size = self.desiredPixelSize {
case .data(let data): image.prepareThumbnail(of: size) {
completion?(data, nil) completion(data, $0)
case .dataAndImage(let data, let image): }
completion?(data, image) } else {
case .none: image.prepareForDisplay {
completion?(nil, nil) completion(data, $0)
}
}
} else {
completion(data, image)
} }
} }
} else {
wrappedCompletion = nil
}
if !ImageCache.disableCaching,
let entry = try? cache.get(key, loadOriginal: loadOriginal) {
wrappedCompletion?(entry.data, entry.image)
return nil
} else {
let task = dataTask(url: url, completion: wrappedCompletion)
task.resume()
return task
} }
} }
func get(_ url: URL, loadOriginal: Bool = false) async -> (Data?, UIImage?) { func get(_ url: URL, loadOriginal: Bool = false) async -> (Data?, UIImage?) {
if !ImageCache.disableCaching, // todo: this should integrate with the task cancellation mechanism somehow
let entry = try? cache.get(url.absoluteString, loadOriginal: loadOriginal) { return await withCheckedContinuation { continuation in
return (entry.data, entry.image) _ = get(url, loadOriginal: loadOriginal) { data, image in
} else { continuation.resume(returning: (data, image))
let result = await self.fetch(url: url)
switch result {
case .data(let data):
return (data, nil)
case .dataAndImage(let data, let image):
return (data, image)
case .none:
return (nil, nil)
} }
} }
} }
@ -73,28 +81,21 @@ class ImageCache {
guard !ImageCache.disableCaching else { return } guard !ImageCache.disableCaching else { return }
if !((try? cache.has(url.absoluteString)) ?? false) { if !((try? cache.has(url.absoluteString)) ?? false) {
Task.detached(priority: .medium) { let task = dataTask(url: url, completion: nil)
_ = await self.fetch(url: url) task.resume()
}
} }
} }
private func fetch(url: URL) async -> FetchResult { private func dataTask(url: URL, completion: ((Data?, UIImage?) -> Void)?) -> URLSessionDataTask {
guard let (data, _) = try? await URLSession.shared.data(from: url) else { return URLSession.shared.dataTask(with: url) { data, response, error in
return .none guard error == nil,
let data else {
return
}
let image = UIImage(data: data)
try? self.cache.set(url.absoluteString, data: data, image: image)
completion?(data, image)
} }
guard let image = UIImage(data: data) else {
try? cache.set(url.absoluteString, data: data, image: nil)
return .data(data)
}
let preparedImage: UIImage?
if let desiredPixelSize {
preparedImage = await image.byPreparingThumbnail(ofSize: desiredPixelSize)
} else {
preparedImage = await image.byPreparingForDisplay()
}
try? cache.set(url.absoluteString, data: data, image: preparedImage ?? image)
return .dataAndImage(data, preparedImage ?? image)
} }
func getData(_ url: URL) -> Data? { func getData(_ url: URL) -> Data? {
@ -113,12 +114,6 @@ class ImageCache {
return cache.disk?.getSizeInBytes() return cache.disk?.getSizeInBytes()
} }
typealias Request = Task<Void, Never> typealias Request = URLSessionDataTask
enum FetchResult {
case data(Data)
case dataAndImage(Data, UIImage)
case none
}
} }

View File

@ -219,11 +219,6 @@ class BookmarksViewController: UIViewController, CollectionViewController, Refre
} }
@objc private func managedObjectsDidChange(_ notification: Foundation.Notification) { @objc private func managedObjectsDidChange(_ notification: Foundation.Notification) {
// only perform local updates while the vc is idle
// otherwise loading the bookmarks ends up inserting them out of order
guard case .loaded = state else {
return
}
var snapshot = dataSource.snapshot() var snapshot = dataSource.snapshot()
func prepend(item: Item) { func prepend(item: Item) {
if let first = snapshot.itemIdentifiers.first { if let first = snapshot.itemIdentifiers.first {
@ -242,7 +237,7 @@ class BookmarksViewController: UIViewController, CollectionViewController, Refre
if let updated = notification.userInfo?[NSUpdatedObjectsKey] as? Set<NSManagedObject> { if let updated = notification.userInfo?[NSUpdatedObjectsKey] as? Set<NSManagedObject> {
for case let status as StatusMO in updated { for case let status as StatusMO in updated {
let item = Item.status(id: status.id, state: .unknown, addedLocally: true) let item = Item.status(id: status.id, state: .unknown, addedLocally: true)
let exists = snapshot.itemIdentifiers.contains(item) var exists = snapshot.itemIdentifiers.contains(item)
if status.bookmarked == true && !exists { if status.bookmarked == true && !exists {
prepend(item: item) prepend(item: item)
hasChanges = true hasChanges = true

View File

@ -28,7 +28,7 @@
<view contentMode="scaleToFill" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kHo-B9-R7a"> <view contentMode="scaleToFill" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kHo-B9-R7a">
<rect key="frame" x="0.0" y="0.0" width="375" height="36"/> <rect key="frame" x="0.0" y="0.0" width="375" height="36"/>
</view> </view>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" editable="NO" textAlignment="natural" adjustsFontForContentSizeCategory="YES" translatesAutoresizingMaskIntoConstraints="NO" id="JZk-BO-2Vh"> <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" editable="NO" textAlignment="natural" adjustsFontForContentSizeCategory="YES" selectable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="JZk-BO-2Vh">
<rect key="frame" x="0.0" y="517" width="375" height="150"/> <rect key="frame" x="0.0" y="517" width="375" height="150"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.5" colorSpace="custom" customColorSpace="displayP3"/> <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.5" colorSpace="custom" customColorSpace="displayP3"/>
<constraints> <constraints>

View File

@ -48,7 +48,6 @@ class StatusActionAccountListViewController: UIViewController {
indicator.centerYAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerYAnchor), indicator.centerYAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerYAnchor),
]) ])
case .displaying(let vc): case .displaying(let vc):
vc.view.translatesAutoresizingMaskIntoConstraints = false
embedChild(vc) embedChild(vc)
case .notFound: case .notFound:
showStatusNotFound() showStatusNotFound()