WallpaperManager.swift

3.1 KB · raw

1import AppKit23@MainActor4protocol WallpaperManaging {5  func download(from url: URL) async throws -> URL6  func setDesktopImage(from fileURL: URL, screen: NSScreen?) throws7  func saveToFolder(from sourceURL: URL, to folderURL: URL) throws8}910@MainActor11protocol DesktopImageSetting {12  func setDesktopImageURL(13    _ url: URL, for screen: NSScreen, options: [NSWorkspace.DesktopImageOptionKey: Any]14  ) throws15}1617extension NSWorkspace: DesktopImageSetting {}1819class WallpaperManager: WallpaperManaging {20  static let shared = WallpaperManager()2122  private let session: URLSession23  private let desktopSetter: @MainActor (URL, NSScreen) throws -> Void2425  init(26    session: URLSession = .shared,27    desktopSetter: (@MainActor (URL, NSScreen) throws -> Void)? = nil,28    workspace: DesktopImageSetting = NSWorkspace.shared29  ) {30    self.session = session31    self.desktopSetter =32      desktopSetter ?? { url, screen in33        try workspace.setDesktopImageURL(34          url, for: screen, options: [:]35        )36      }37  }3839  /// Downloads the file to a temporary location and returns the local URL.40  func download(from url: URL) async throws -> URL {41    let (data, response) = try await session.data(from: url)42    guard let response = response as? HTTPURLResponse,43      (200...299).contains(response.statusCode)44    else {45      throw WallhavenError.apiError("Wallpaper download failed")46    }4748    let filename = url.lastPathComponent49    let tempDir = FileManager.default.temporaryDirectory50    let fileURL = tempDir.appendingPathComponent(filename)5152    try data.write(to: fileURL)53    return fileURL54  }5556  /// Sets the desktop image from a local file URL.57  @MainActor58  func setDesktopImage(from fileURL: URL, screen: NSScreen? = nil) throws {59    if let screen = screen {60      try desktopSetter(fileURL, screen)61    } else {62      // Set for all screens or just main? Let's default to main for safety,63      // but the UI will likely drive this.64      // If no screen specified, maybe set for the 'active' one.65      let targetScreen = NSScreen.main ?? NSScreen.screens.first!66      try desktopSetter(fileURL, targetScreen)67    }68  }6970  /// Copies the file to the specified destination directory.71  func saveToFolder(from sourceURL: URL, to folderURL: URL) throws {72    // Ensure folder exists73    try FileManager.default.createDirectory(at: folderURL, withIntermediateDirectories: true)7475    let destinationURL = folderURL.appendingPathComponent(sourceURL.lastPathComponent)7677    // If file exists, maybe don't overwrite or handle gracefully?78    // For now, we'll remove it if it exists to ensure we have the fresh one, or just skip.79    if FileManager.default.fileExists(atPath: destinationURL.path) {80      try FileManager.default.removeItem(at: destinationURL)81    }8283    try FileManager.default.copyItem(at: sourceURL, to: destinationURL)84  }8586  // Legacy support wrapper (optional, but cleaner to update call sites)87  @MainActor88  func setWallpaper(from url: URL, screen: NSScreen? = nil) async throws {89    let localURL = try await download(from: url)90    try setDesktopImage(from: localURL, screen: screen)91  }92}