Compare commits
No commits in common. "76268e7a14e43cee97a619bf3d92a8c7108c7cc6" and "474064669db8f9172c566a77907b886f4d3e3f80" have entirely different histories.
76268e7a14
...
474064669d
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in New Issue