Utils.swift 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. import Foundation
  2. import UIKit
  3. import AVFoundation
  4. struct Utils {
  5. static func getInitials(inputName: String) -> String {
  6. if let firstLetter = inputName.first {
  7. return firstLetter.uppercased()
  8. } else {
  9. return ""
  10. }
  11. }
  12. static func copyAndFreeArray(inputArray: OpaquePointer?) -> [Int] {
  13. var acc: [Int] = []
  14. let len = dc_array_get_cnt(inputArray)
  15. for i in 0 ..< len {
  16. let e = dc_array_get_id(inputArray, i)
  17. acc.append(Int(e))
  18. }
  19. dc_array_unref(inputArray)
  20. return acc
  21. }
  22. static func copyAndFreeArrayWithLen(inputArray: OpaquePointer?, len: Int = 0) -> [Int] {
  23. var acc: [Int] = []
  24. let arrayLen = dc_array_get_cnt(inputArray)
  25. let start = max(0, arrayLen - len)
  26. for i in start ..< arrayLen {
  27. let e = dc_array_get_id(inputArray, i)
  28. acc.append(Int(e))
  29. }
  30. dc_array_unref(inputArray)
  31. return acc
  32. }
  33. static func copyAndFreeArrayWithOffset(inputArray: OpaquePointer?, len: Int = 0, from: Int = 0, skipEnd: Int = 0) -> [Int] {
  34. let lenArray = dc_array_get_cnt(inputArray)
  35. if lenArray <= skipEnd || lenArray == 0 {
  36. dc_array_unref(inputArray)
  37. return []
  38. }
  39. let start = lenArray - 1 - skipEnd
  40. let end = max(0, start - len)
  41. let finalLen = start - end + (len > 0 ? 0 : 1)
  42. var acc: [Int] = [Int](repeating: 0, count: finalLen)
  43. for i in stride(from: start, to: end, by: -1) {
  44. let index = finalLen - (start - i) - 1
  45. acc[index] = Int(dc_array_get_id(inputArray, i))
  46. }
  47. dc_array_unref(inputArray)
  48. DcContext.shared.logger?.info("got: \(from) \(len) \(lenArray) - \(acc)")
  49. return acc
  50. }
  51. /* static func formatAddressForQuery(address: [String: String]) -> String {
  52. // Open address in Apple Maps app.
  53. var addressParts = [String]()
  54. let addAddressPart: ((String?) -> Void) = { part in
  55. guard let part = part else {
  56. return
  57. }
  58. guard !part.isEmpty else {
  59. return
  60. }
  61. addressParts.append(part)
  62. }
  63. addAddressPart(address["Street"])
  64. addAddressPart(address["Neighborhood"])
  65. addAddressPart(address["City"])
  66. addAddressPart(address["Region"])
  67. addAddressPart(address["Postcode"])
  68. addAddressPart(address["Country"])
  69. return addressParts.joined(separator: ", ")
  70. }
  71. // compression needs to be done before in UIImage.dcCompress()
  72. static func saveImage(image: UIImage) -> String? {
  73. guard let directory = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask,
  74. appropriateFor: nil, create: false) as NSURL else {
  75. return nil
  76. }
  77. guard let data = image.isTransparent() ? image.pngData() : image.jpegData(compressionQuality: 1.0) else {
  78. return nil
  79. }
  80. do {
  81. let timestamp = Double(Date().timeIntervalSince1970)
  82. let path = directory.appendingPathComponent("\(timestamp).jpg")
  83. try data.write(to: path!)
  84. return path?.relativePath
  85. } catch {
  86. logger.info(error.localizedDescription)
  87. return nil
  88. }
  89. }
  90. */
  91. static func hasAudioSuffix(url: URL) -> Bool {
  92. ///TODO: add more file suffixes
  93. return url.absoluteString.hasSuffix("wav")
  94. }
  95. static func generateThumbnailFromVideo(url: URL?) -> UIImage? {
  96. guard let url = url else {
  97. return nil
  98. }
  99. do {
  100. let asset = AVURLAsset(url: url)
  101. let imageGenerator = AVAssetImageGenerator(asset: asset)
  102. imageGenerator.appliesPreferredTrackTransform = true
  103. let cgImage = try imageGenerator.copyCGImage(at: .zero, actualTime: nil)
  104. return UIImage(cgImage: cgImage)
  105. } catch {
  106. print(error.localizedDescription)
  107. return nil
  108. }
  109. }
  110. /*
  111. static func getDeviceLanguage() -> String? {
  112. // some device languages have suffixes (like en-aus etc.) so we want to cut suffixes off
  113. guard let lang = Locale.preferredLanguages.first?.split(separator: "-").first else {
  114. return nil
  115. }
  116. return String(lang)
  117. }
  118. */
  119. }
  120. class DateUtils {
  121. typealias DtU = DateUtils
  122. static let minute: Double = 60
  123. static let hour: Double = 3600
  124. static let day: Double = 86400
  125. static let year: Double = 365 * day
  126. static func getRelativeTimeInSeconds(timeStamp: Double) -> Double {
  127. let unixTime = Double(Date().timeIntervalSince1970)
  128. return unixTime - timeStamp
  129. }
  130. private static func is24hDefault() -> Bool {
  131. let dateString: String = DateFormatter.dateFormat(fromTemplate: "j", options: 0, locale: Locale.current) ?? ""
  132. return !dateString.contains("a")
  133. }
  134. private static func getLocalDateFormatter() -> DateFormatter {
  135. let formatter = DateFormatter()
  136. formatter.timeZone = .current
  137. formatter.locale = .current
  138. return formatter
  139. }
  140. static func getExtendedRelativeTimeSpanString(timeStamp: Double) -> String {
  141. let seconds = getRelativeTimeInSeconds(timeStamp: timeStamp)
  142. let date = Date(timeIntervalSince1970: timeStamp)
  143. let formatter = getLocalDateFormatter()
  144. let is24h = is24hDefault()
  145. if seconds < DtU.minute {
  146. return String.localized("now")
  147. } else if seconds < DtU.hour {
  148. let mins = seconds / DtU.minute
  149. return String.localized(stringID: "n_minutes", count: Int(mins))
  150. } else if seconds < DtU.day {
  151. formatter.dateFormat = is24h ? "HH:mm" : "hh:mm a"
  152. return formatter.string(from: date)
  153. } else if seconds < 6 * DtU.day {
  154. formatter.dateFormat = is24h ? "EEE, HH:mm" : "EEE, hh:mm a"
  155. return formatter.string(from: date)
  156. } else if seconds < DtU.year {
  157. formatter.dateFormat = is24h ? "MMM d, HH:mm" : "MMM d, hh:mm a"
  158. return formatter.string(from: date)
  159. } else {
  160. formatter.dateFormat = is24h ? "MMM d, yyyy, HH:mm" : "MMM d, yyyy, hh:mm a"
  161. return formatter.string(from: date)
  162. }
  163. }
  164. static func getBriefRelativeTimeSpanString(timeStamp: Double) -> String {
  165. let seconds = getRelativeTimeInSeconds(timeStamp: timeStamp)
  166. let date = Date(timeIntervalSince1970: timeStamp)
  167. let formatter = getLocalDateFormatter()
  168. if seconds < DtU.minute {
  169. return String.localized("now") // under one minute
  170. } else if seconds < DtU.hour {
  171. let mins = seconds / DtU.minute
  172. return String.localized(stringID: "n_minutes", count: Int(mins))
  173. } else if seconds < DtU.day {
  174. let hours = seconds / DtU.hour
  175. return String.localized(stringID: "n_hours", count: Int(hours))
  176. } else if seconds < DtU.day * 6 {
  177. formatter.dateFormat = "EEE"
  178. return formatter.string(from: date)
  179. } else if seconds < DtU.year {
  180. formatter.dateFormat = "MMM d"
  181. return formatter.string(from: date)
  182. } else {
  183. formatter.dateFormat = "MMM d, yyyy"
  184. let localDate = formatter.string(from: date)
  185. return localDate
  186. }
  187. }
  188. }