mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 01:20:12 +00:00
Automatically try reloading failed images on network changes (#3170)
* Add the networkMonitor to the NSE and delete the old MockMediaLoader * Generate a MediaLoaderMock through AutoMockable and use it in the MediaProviderTests * Implement an ImageProvider mechanism that automatically tries reloading images when connectivity is established again and use it for LoadableImages * Merge the ImageProvider protocol back into the MediaProvider * Address PR review comments * Provide a default sdk client request configuration * Address tasks not automatically cancelling themselves when views get deallocated
This commit is contained in:
@@ -14,17 +14,21 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Combine
|
||||
import Kingfisher
|
||||
import UIKit
|
||||
|
||||
struct MediaProvider: MediaProviderProtocol {
|
||||
private let mediaLoader: MediaLoaderProtocol
|
||||
private let imageCache: Kingfisher.ImageCache
|
||||
private let networkMonitor: NetworkMonitorProtocol?
|
||||
|
||||
init(mediaLoader: MediaLoaderProtocol,
|
||||
imageCache: Kingfisher.ImageCache) {
|
||||
imageCache: Kingfisher.ImageCache,
|
||||
networkMonitor: NetworkMonitorProtocol?) {
|
||||
self.mediaLoader = mediaLoader
|
||||
self.imageCache = imageCache
|
||||
self.networkMonitor = networkMonitor
|
||||
}
|
||||
|
||||
// MARK: Images
|
||||
@@ -71,6 +75,45 @@ struct MediaProvider: MediaProviderProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
func loadImageRetryingOnReconnection(_ source: MediaSourceProxy, size: CGSize?) -> Task<UIImage, any Error> {
|
||||
guard let networkMonitor else {
|
||||
fatalError("This method shouldn't be invoked without a NetworkMonitor set.")
|
||||
}
|
||||
|
||||
return Task {
|
||||
if case let .success(image) = await loadImageFromSource(source, size: size) {
|
||||
return image
|
||||
}
|
||||
|
||||
guard !Task.isCancelled else {
|
||||
throw MediaProviderError.cancelled
|
||||
}
|
||||
|
||||
for await reachability in networkMonitor.reachabilityPublisher.values {
|
||||
guard !Task.isCancelled else {
|
||||
throw MediaProviderError.cancelled
|
||||
}
|
||||
|
||||
guard reachability == .reachable else {
|
||||
continue
|
||||
}
|
||||
|
||||
switch await loadImageFromSource(source, size: size) {
|
||||
case .success(let image):
|
||||
return image
|
||||
case .failure:
|
||||
// If it fails after a retry with the network available
|
||||
// then something else must be wrong. Bail out.
|
||||
if reachability == .reachable {
|
||||
throw MediaProviderError.cancelled
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw MediaProviderError.cancelled
|
||||
}
|
||||
}
|
||||
|
||||
func loadImageDataFromSource(_ source: MediaSourceProxy) async -> Result<Data, MediaProviderError> {
|
||||
do {
|
||||
let imageData = try await mediaLoader.loadMediaContentForSource(source)
|
||||
|
||||
Reference in New Issue
Block a user