Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 84c388044b |
@@ -9,6 +9,7 @@
|
||||
import UserNotifications
|
||||
import CoreLocation
|
||||
import Shogun
|
||||
import UIKit
|
||||
|
||||
class NotificationService: UNNotificationServiceExtension {
|
||||
|
||||
@@ -119,13 +120,26 @@ class NotificationService: UNNotificationServiceExtension {
|
||||
}
|
||||
|
||||
// add the icon as notification attachment
|
||||
if !iconName.isEmpty {
|
||||
iconName = iconName.replacingOccurrences(of: ".png", with: "")
|
||||
|
||||
if let imageUrl = Bundle(for: NotificationService.self).url(forResource: iconName, withExtension: "png"),
|
||||
let attachment = try? UNNotificationAttachment(identifier: iconName, url: imageUrl) {
|
||||
bestAttemptContent.attachments = [ attachment ]
|
||||
}
|
||||
// if !iconName.isEmpty {
|
||||
// iconName = iconName.replacingOccurrences(of: ".png", with: "")
|
||||
//
|
||||
// if let imageUrl = Bundle(for: NotificationService.self).url(forResource: iconName, withExtension: "png"),
|
||||
// let attachment = try? UNNotificationAttachment(identifier: iconName, url: imageUrl) {
|
||||
// bestAttemptContent.attachments = [ attachment ]
|
||||
// }
|
||||
// }
|
||||
|
||||
do {
|
||||
let image = createImage(for: "M2.3")
|
||||
let imageData = try NotificationServiceImageDownloader.shared.storeImage(image)
|
||||
let imageAttachment = try UNNotificationAttachment(
|
||||
identifier: "image",
|
||||
url: imageData.localUrl,
|
||||
options: nil)
|
||||
bestAttemptContent.attachments = [imageAttachment]
|
||||
bestAttemptContent.title = bestAttemptContent.title + " [IMG]"
|
||||
} catch {
|
||||
bestAttemptContent.title = bestAttemptContent.title + " [ROTTO]"
|
||||
}
|
||||
|
||||
// remove same type posted notification
|
||||
@@ -209,4 +223,145 @@ class NotificationService: UNNotificationServiceExtension {
|
||||
default: return ""
|
||||
}
|
||||
}
|
||||
|
||||
private func createImage(
|
||||
for magnitude: String
|
||||
) -> UIImage {
|
||||
let frame = CGRect(x: 0, y: 0, width: 200, height: 200)
|
||||
let renderer = UIGraphicsImageRenderer(size: frame.size)
|
||||
let image = renderer.image { ctx in
|
||||
ctx.cgContext.setFillColor(UIColor.white.cgColor)
|
||||
ctx.cgContext.setStrokeColor(UIColor.black.cgColor) // dark
|
||||
ctx.cgContext.setLineWidth(1.0)
|
||||
|
||||
let rectXPadding: CGFloat = 5.0
|
||||
let rectYPadding: CGFloat = 40.0
|
||||
let rectWidth = frame.width - 2*rectXPadding
|
||||
let rectHeight = frame.height - 2*rectYPadding
|
||||
let rectFrame = CGRect(x: rectXPadding, y: rectYPadding, width: rectWidth, height: rectHeight)
|
||||
ctx.cgContext.addRect(rectFrame)
|
||||
ctx.cgContext.drawPath(using: .fillStroke)
|
||||
|
||||
// text
|
||||
let paragraphStyle = NSMutableParagraphStyle()
|
||||
paragraphStyle.alignment = .center
|
||||
let attrs = [
|
||||
NSAttributedString.Key.font: UIFont.systemFont(ofSize: 60.0, weight: .bold),
|
||||
NSAttributedString.Key.paragraphStyle: paragraphStyle,
|
||||
NSAttributedString.Key.foregroundColor: UIColor.blue
|
||||
]
|
||||
|
||||
ctx.cgContext.setStrokeColor(UIColor.blue.cgColor)
|
||||
|
||||
let textMargin: CGFloat = 5.0
|
||||
let textWidth = rectFrame.width - 2*textMargin
|
||||
let textHeight: CGFloat = 60.0
|
||||
let xPos = rectFrame.minX + textMargin
|
||||
let yPos = rectFrame.minY + (rectFrame.height - textHeight) / 2.0
|
||||
let textFrame = CGRect(x: xPos, y: yPos, width: textWidth, height: textHeight)
|
||||
magnitude.draw(with: textFrame, options: .usesLineFragmentOrigin, attributes: attrs, context: nil)
|
||||
}
|
||||
return image
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class NotificationServiceImageDownloader {
|
||||
|
||||
enum DownloadError: Error {
|
||||
case invalidUrl
|
||||
case emptyData
|
||||
case invalidImage
|
||||
}
|
||||
|
||||
struct Image {
|
||||
let data: Data
|
||||
let png: UIImage
|
||||
let localUrl: URL
|
||||
}
|
||||
|
||||
|
||||
static let shared = NotificationServiceImageDownloader()
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
func downloadAndStoreImage(
|
||||
for stringUrl: String
|
||||
) async throws -> Image {
|
||||
guard let url = URL(string: stringUrl) else {
|
||||
throw DownloadError.invalidUrl
|
||||
}
|
||||
return try await downloadAndStoreImage(for: url)
|
||||
}
|
||||
|
||||
func downloadAndStoreImage(
|
||||
for url: URL
|
||||
) async throws -> Image {
|
||||
// download image from URL
|
||||
let (data, _) = try await URLSession.shared.data(from: url)
|
||||
guard let image = UIImage(data: data) else {
|
||||
throw DownloadError.invalidImage
|
||||
}
|
||||
|
||||
let identifier = "\(UUID().uuidString).\(url.pathExtension)"
|
||||
let localUrl = try saveImageLocally(image: image, with: identifier)
|
||||
return .init(data: data, png: image, localUrl: localUrl)
|
||||
|
||||
}
|
||||
|
||||
func storeImage(
|
||||
_ image: UIImage
|
||||
) throws -> Image {
|
||||
let identifier = "\(UUID().uuidString).png"
|
||||
let localUrl = try saveImageLocally(image: image, with: identifier)
|
||||
return .init(data: Data(), png: image, localUrl: localUrl)
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func saveImageLocally(
|
||||
image: UIImage,
|
||||
with identifier: String
|
||||
) throws -> URL {
|
||||
guard let imageData = image.pngData() else {
|
||||
throw DownloadError.invalidImage
|
||||
}
|
||||
// create a subfolder in Caches directory and
|
||||
// store the given image
|
||||
let cacheDirectory = try FileManager.default.createSubfolder(in: .cachesDirectory, name: "NotificationImages")
|
||||
let fileURL = cacheDirectory.appendingPathComponent(identifier)
|
||||
|
||||
try imageData.write(to: fileURL)
|
||||
return fileURL
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public extension FileManager {
|
||||
|
||||
/// Check if a subfolder already exists in a search path directory. If the folder does not exists, it will be created.
|
||||
/// - Parameters:
|
||||
/// - directory: The search path directory
|
||||
/// - name: Name of the subfolder
|
||||
/// - Returns: URL that specifies the directory
|
||||
func createSubfolder(in directory: FileManager.SearchPathDirectory, name: String) throws -> URL {
|
||||
let searchPathDirectory = urls(for: directory, in: .userDomainMask).first!
|
||||
return try createSubfolder(at: searchPathDirectory, name: name)
|
||||
}
|
||||
|
||||
/// Check if a subfolder already exists at a given URL. If the folder does not exists, it will be created.
|
||||
/// - Parameters:
|
||||
/// - directory: The search path directory
|
||||
/// - name: Name of the subfolder
|
||||
/// - Returns: URL that specifies the directory
|
||||
func createSubfolder(at url: URL, name: String) throws -> URL {
|
||||
let directoryUrl = url.appendingPathComponent(name)
|
||||
|
||||
var isDirectory: ObjCBool = false
|
||||
if !fileExists(atPath: directoryUrl.path, isDirectory: &isDirectory) {
|
||||
try createDirectory(at: directoryUrl, withIntermediateDirectories: false)
|
||||
}
|
||||
|
||||
return directoryUrl
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user