You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

125 lines
4.5 KiB

  1. //
  2. // ExtensionHelpers.swift
  3. // Kingfisher
  4. //
  5. // Created by onevcat on 2018/09/28.
  6. //
  7. // Copyright (c) 2019 Wei Wang <onevcat@gmail.com>
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining a copy
  10. // of this software and associated documentation files (the "Software"), to deal
  11. // in the Software without restriction, including without limitation the rights
  12. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. // copies of the Software, and to permit persons to whom the Software is
  14. // furnished to do so, subject to the following conditions:
  15. //
  16. // The above copyright notice and this permission notice shall be included in
  17. // all copies or substantial portions of the Software.
  18. //
  19. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. // THE SOFTWARE.
  26. import Foundation
  27. extension Float {
  28. var isEven: Bool {
  29. return truncatingRemainder(dividingBy: 2.0) == 0
  30. }
  31. }
  32. #if canImport(AppKit)
  33. import AppKit
  34. extension NSBezierPath {
  35. convenience init(roundedRect rect: NSRect, topLeftRadius: CGFloat, topRightRadius: CGFloat,
  36. bottomLeftRadius: CGFloat, bottomRightRadius: CGFloat)
  37. {
  38. self.init()
  39. let maxCorner = min(rect.width, rect.height) / 2
  40. let radiusTopLeft = min(maxCorner, max(0, topLeftRadius))
  41. let radiusTopRight = min(maxCorner, max(0, topRightRadius))
  42. let radiusBottomLeft = min(maxCorner, max(0, bottomLeftRadius))
  43. let radiusBottomRight = min(maxCorner, max(0, bottomRightRadius))
  44. guard !rect.isEmpty else {
  45. return
  46. }
  47. let topLeft = NSPoint(x: rect.minX, y: rect.maxY)
  48. let topRight = NSPoint(x: rect.maxX, y: rect.maxY)
  49. let bottomRight = NSPoint(x: rect.maxX, y: rect.minY)
  50. move(to: NSPoint(x: rect.midX, y: rect.maxY))
  51. appendArc(from: topLeft, to: rect.origin, radius: radiusTopLeft)
  52. appendArc(from: rect.origin, to: bottomRight, radius: radiusBottomLeft)
  53. appendArc(from: bottomRight, to: topRight, radius: radiusBottomRight)
  54. appendArc(from: topRight, to: topLeft, radius: radiusTopRight)
  55. close()
  56. }
  57. convenience init(roundedRect rect: NSRect, byRoundingCorners corners: RectCorner, radius: CGFloat) {
  58. let radiusTopLeft = corners.contains(.topLeft) ? radius : 0
  59. let radiusTopRight = corners.contains(.topRight) ? radius : 0
  60. let radiusBottomLeft = corners.contains(.bottomLeft) ? radius : 0
  61. let radiusBottomRight = corners.contains(.bottomRight) ? radius : 0
  62. self.init(roundedRect: rect, topLeftRadius: radiusTopLeft, topRightRadius: radiusTopRight,
  63. bottomLeftRadius: radiusBottomLeft, bottomRightRadius: radiusBottomRight)
  64. }
  65. }
  66. extension Image {
  67. // macOS does not support scale. This is just for code compatibility across platforms.
  68. convenience init?(data: Data, scale: CGFloat) {
  69. self.init(data: data)
  70. }
  71. }
  72. #endif
  73. #if canImport(UIKit)
  74. import UIKit
  75. extension RectCorner {
  76. var uiRectCorner: UIRectCorner {
  77. var result: UIRectCorner = []
  78. if contains(.topLeft) { result.insert(.topLeft) }
  79. if contains(.topRight) { result.insert(.topRight) }
  80. if contains(.bottomLeft) { result.insert(.bottomLeft) }
  81. if contains(.bottomRight) { result.insert(.bottomRight) }
  82. return result
  83. }
  84. }
  85. #endif
  86. extension Date {
  87. var isPast: Bool {
  88. return isPast(referenceDate: Date())
  89. }
  90. var isFuture: Bool {
  91. return !isPast
  92. }
  93. func isPast(referenceDate: Date) -> Bool {
  94. return timeIntervalSince(referenceDate) <= 0
  95. }
  96. func isFuture(referenceDate: Date) -> Bool {
  97. return !isPast(referenceDate: referenceDate)
  98. }
  99. // `Date` in memory is a wrap for `TimeInterval`. But in file attribute it can only accept `Int` number.
  100. // By default the system will `round` it. But it is not friendly for testing purpose.
  101. // So we always `ceil` the value when used for file attributes.
  102. var fileAttributeDate: Date {
  103. return Date(timeIntervalSince1970: ceil(timeIntervalSince1970))
  104. }
  105. }