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: "\\,") } }