113 lines
3.5 KiB
Swift
113 lines
3.5 KiB
Swift
import Foundation
|
|
import UIKit
|
|
|
|
class ShareService {
|
|
static let shared = ShareService()
|
|
|
|
private init() {}
|
|
|
|
func shareTextFile(content: String, fileName: String) {
|
|
guard let viewController = ShareService.topViewController() else { return }
|
|
|
|
let tempURL = FileManager.default.temporaryDirectory
|
|
.appendingPathComponent(fileName)
|
|
|
|
do {
|
|
try content.write(to: tempURL, atomically: true, encoding: .utf8)
|
|
|
|
let activityVC = UIActivityViewController(
|
|
activityItems: [tempURL],
|
|
applicationActivities: nil
|
|
)
|
|
|
|
if let popover = activityVC.popoverPresentationController {
|
|
popover.sourceView = viewController.view
|
|
popover.sourceRect = CGRect(
|
|
x: viewController.view.bounds.midX,
|
|
y: viewController.view.bounds.midY,
|
|
width: 0,
|
|
height: 0
|
|
)
|
|
}
|
|
|
|
DispatchQueue.main.async {
|
|
viewController.present(activityVC, animated: true)
|
|
}
|
|
} catch {
|
|
print("Share file error: \(error)")
|
|
}
|
|
}
|
|
|
|
func shareCalendarEvent(
|
|
title: String,
|
|
notes: String,
|
|
startDate: Date,
|
|
durationMinutes: Int = 60
|
|
) {
|
|
let endDate = startDate.addingTimeInterval(TimeInterval(durationMinutes * 60))
|
|
let icsContent = calendarICS(
|
|
title: title,
|
|
notes: notes,
|
|
startDate: startDate,
|
|
endDate: endDate
|
|
)
|
|
shareTextFile(content: icsContent, fileName: "PortfolioJournal-CheckIn.ics")
|
|
}
|
|
|
|
private static func topViewController(
|
|
base: UIViewController? = UIApplication.shared.connectedScenes
|
|
.compactMap { $0 as? UIWindowScene }
|
|
.flatMap { $0.windows }
|
|
.first(where: { $0.isKeyWindow })?.rootViewController
|
|
) -> UIViewController? {
|
|
if let nav = base as? UINavigationController {
|
|
return topViewController(base: nav.visibleViewController)
|
|
}
|
|
if let tab = base as? UITabBarController {
|
|
return topViewController(base: tab.selectedViewController)
|
|
}
|
|
if let presented = base?.presentedViewController {
|
|
return topViewController(base: presented)
|
|
}
|
|
return base
|
|
}
|
|
|
|
private func calendarICS(
|
|
title: String,
|
|
notes: String,
|
|
startDate: Date,
|
|
endDate: Date
|
|
) -> String {
|
|
let uid = UUID().uuidString
|
|
let formatter = DateFormatter()
|
|
formatter.dateFormat = "yyyyMMdd'T'HHmmss'Z'"
|
|
formatter.timeZone = TimeZone(secondsFromGMT: 0)
|
|
let stamp = formatter.string(from: Date())
|
|
let start = formatter.string(from: startDate)
|
|
let end = formatter.string(from: endDate)
|
|
|
|
return """
|
|
BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:-//PortfolioJournal//MonthlyCheckIn//EN
|
|
BEGIN:VEVENT
|
|
UID:\(uid)
|
|
DTSTAMP:\(stamp)
|
|
DTSTART:\(start)
|
|
DTEND:\(end)
|
|
SUMMARY:\(escapeICS(title))
|
|
DESCRIPTION:\(escapeICS(notes))
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
"""
|
|
}
|
|
|
|
private func escapeICS(_ value: String) -> String {
|
|
value
|
|
.replacingOccurrences(of: "\\", with: "\\\\")
|
|
.replacingOccurrences(of: "\n", with: "\\n")
|
|
.replacingOccurrences(of: ";", with: "\\;")
|
|
.replacingOccurrences(of: ",", with: "\\,")
|
|
}
|
|
}
|