Skip to content

Commit b3ead7b

Browse files
author
Rover Release Bot 🤖
committed
Releasing 4.11.5
1 parent 8ae0aab commit b3ead7b

File tree

3 files changed

+92
-43
lines changed

3 files changed

+92
-43
lines changed

Sources/Experiences/ClassicExperiences/Services/ImageStore.swift

Lines changed: 91 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// copy, modify, and distribute this software in source code or binary form for use
44
// in connection with the web services and APIs provided by Rover.
55
//
6-
// This copyright notice shall be included in all copies or substantial portions of
6+
// This copyright notice shall be included in all copies or substantial portions of
77
// the software.
88
//
99
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
@@ -23,11 +23,11 @@ class ImageStore {
2323
// MARK: Cache
2424

2525
fileprivate enum Optimization: Equatable, Hashable {
26-
case fill(bounds: CGRect)
27-
case fit(bounds: CGRect)
28-
case stretch(bounds: CGRect, originalSize: CGSize)
29-
case original(bounds: CGRect, originalSize: CGSize, originalScale: CGFloat)
30-
case tile(bounds: CGRect, originalSize: CGSize, originalScale: CGFloat)
26+
case fill(bounds: HashableCGRect)
27+
case fit(bounds: HashableCGRect)
28+
case stretch(bounds: HashableCGRect, originalSize: HashableCGSize)
29+
case original(bounds: HashableCGRect, originalSize: HashableCGSize, originalScale: CGFloat)
30+
case tile(bounds: HashableCGRect, originalSize: HashableCGSize, originalScale: CGFloat)
3131
}
3232

3333
fileprivate struct Configuration: Equatable, Hashable {
@@ -74,8 +74,9 @@ class ImageStore {
7474
let configuration = Configuration(image: image, frame: frame)
7575
return self.image(for: configuration)
7676
}
77-
77+
7878
func image(for image: ClassicImage, filledInFrame frame: CGRect) -> UIImage? {
79+
let frame = HashableCGRect(frame)
7980
let optimization: ImageStore.Optimization = .fill(bounds: frame)
8081
let configuration = Configuration(url: image.url, optimization: optimization)
8182
return self.image(for: configuration)
@@ -115,6 +116,7 @@ class ImageStore {
115116
}
116117

117118
func fetchImage(for image: ClassicImage, filledInFrame frame: CGRect, completionHandler: ((UIImage?) -> Void)? = nil) {
119+
let frame = HashableCGRect(frame)
118120
let optimization: ImageStore.Optimization = .fill(bounds: frame)
119121
let configuration = Configuration(url: image.url, optimization: optimization)
120122
fetchImage(for: configuration, completionHandler: completionHandler)
@@ -193,11 +195,12 @@ extension ImageStore.Configuration {
193195
guard let image = background.image else {
194196
return nil
195197
}
196-
198+
199+
let frame = HashableCGRect(frame)
197200
let optimization: ImageStore.Optimization?
198201
if image.isURLOptimizationEnabled {
199-
let originalSize = CGSize(width: CGFloat(image.width), height: CGFloat(image.height))
200-
202+
let originalSize = HashableCGSize(width: CGFloat(image.width), height: CGFloat(image.height))
203+
201204
let originalScale: CGFloat
202205
switch background.scale {
203206
case .x1:
@@ -228,7 +231,8 @@ extension ImageStore.Configuration {
228231
}
229232

230233
init(image: ClassicImage, frame: CGRect) {
231-
let originalSize = CGSize(width: CGFloat(image.width), height: CGFloat(image.height))
234+
let frame = HashableCGRect(frame)
235+
let originalSize = HashableCGSize(width: CGFloat(image.width), height: CGFloat(image.height))
232236
let optimization = ImageStore.Optimization.stretch(bounds: frame, originalSize: originalSize)
233237
self.init(url: image.url, optimization: optimization)
234238
}
@@ -292,24 +296,92 @@ extension ImageStore.Optimization {
292296
}
293297
}
294298

295-
fileprivate extension CGFloat {
296-
var paramValue: String {
299+
extension CGFloat {
300+
fileprivate var paramValue: String {
297301
let rounded = self.rounded()
298302
let int = Int(rounded)
299303
return int.description
300304
}
301305
}
302306

303-
extension CGSize: Hashable {
304-
public func hash(into hasher: inout Hasher) {
305-
hasher.combine(width)
306-
hasher.combine(height)
307+
/// Wrapper type providing Hashable and Sendable conformance for CGSize without extending public CoreGraphics types (to avoid public extension conflicts and ABI/compatibility issues). Offers conversion helper (cgSize) for interop.
308+
fileprivate struct HashableCGSize: Hashable, Sendable {
309+
var width: CGFloat
310+
var height: CGFloat
311+
312+
init(_ size: CGSize) {
313+
self.init(width: size.width, height: size.height)
314+
}
315+
316+
init(width: CGFloat, height: CGFloat) {
317+
self.width = width
318+
self.height = height
319+
}
320+
321+
var cgSize: CGSize {
322+
CGSize(width: width, height: height)
323+
}
324+
325+
func hash(into hasher: inout Hasher) {
326+
hasher.combine(Double(width))
327+
hasher.combine(Double(height))
328+
}
329+
330+
static func == (lhs: HashableCGSize, rhs: HashableCGSize) -> Bool {
331+
lhs.width == rhs.width && lhs.height == rhs.height
307332
}
308333
}
309334

310-
extension CGRect: Hashable {
311-
public func hash(into hasher: inout Hasher) {
335+
/// Wrapper type providing Hashable and Sendable conformance for CGRect without extending public CoreGraphics types (to avoid public extension conflicts and ABI/compatibility issues). Offers conversion helper (cgRect) for interop.
336+
fileprivate struct HashableCGRect: Hashable, Sendable {
337+
var origin: HashableCGPoint
338+
var size: HashableCGSize
339+
340+
init(_ rect: CGRect) {
341+
self.origin = HashableCGPoint(rect.origin)
342+
self.size = HashableCGSize(rect.size)
343+
}
344+
345+
var cgRect: CGRect {
346+
CGRect(origin: origin.cgPoint, size: size.cgSize)
347+
}
348+
349+
var width: CGFloat {
350+
size.width
351+
}
352+
353+
var height: CGFloat {
354+
size.height
355+
}
356+
357+
func hash(into hasher: inout Hasher) {
312358
hasher.combine(origin)
313359
hasher.combine(size)
314360
}
361+
362+
static func == (lhs: Self, rhs: Self) -> Bool {
363+
lhs.origin == rhs.origin && lhs.size == rhs.size
364+
}
365+
}
366+
367+
/// Wrapper type providing Hashable and Sendable conformance for CGPoint without extending public CoreGraphics types (to avoid public extension conflicts and ABI/compatibility issues). Offers conversion helper (cgPoint) for interop.
368+
fileprivate struct HashableCGPoint: Hashable, Sendable {
369+
var x: CGFloat
370+
var y: CGFloat
371+
372+
init(_ point: CGPoint) {
373+
self.x = point.x
374+
self.y = point.y
375+
}
376+
377+
var cgPoint: CGPoint { CGPoint(x: x, y: y) }
378+
379+
func hash(into hasher: inout Hasher) {
380+
hasher.combine(Double(x))
381+
hasher.combine(Double(y))
382+
}
383+
384+
static func == (lhs: Self, rhs: Self) -> Bool {
385+
lhs.x == rhs.x && lhs.y == rhs.y
386+
}
315387
}

Sources/Experiences/Extensions/CGPoint+Hashable.swift

Lines changed: 0 additions & 23 deletions
This file was deleted.

Sources/Foundation/Meta.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,5 @@ import Foundation
1717

1818
public enum Meta {
1919
public static let APIVersion: Int = 2
20-
public static let SDKVersion: String = "4.11.4"
20+
public static let SDKVersion: String = "4.11.5"
2121
}

0 commit comments

Comments
 (0)