From 918af3baa35b98736dd961dcca9a7b9385688aea Mon Sep 17 00:00:00 2001 From: leminlimez <59540996+leminlimez@users.noreply.github.com> Date: Sun, 22 Jun 2025 15:59:01 -0400 Subject: [PATCH] get wallpapers in order --- .../Controllers/CarPlayWallpaper.swift | 23 +++++++++ .../Controllers/PosterBoardManager.swift | 50 +++++++++++++++++-- Pocket Poster/Extensions/Reorderable.swift | 30 +++++++++++ .../Extensions/{ => Views}/Alert++.swift | 0 Pocket Poster/Localizable.xcstrings | 3 ++ .../Views/NavigatorViews/CarPlayView.swift | 18 +++---- 6 files changed, 108 insertions(+), 16 deletions(-) create mode 100644 Pocket Poster/Controllers/CarPlayWallpaper.swift create mode 100644 Pocket Poster/Extensions/Reorderable.swift rename Pocket Poster/Extensions/{ => Views}/Alert++.swift (100%) diff --git a/Pocket Poster/Controllers/CarPlayWallpaper.swift b/Pocket Poster/Controllers/CarPlayWallpaper.swift new file mode 100644 index 0000000..c1d90de --- /dev/null +++ b/Pocket Poster/Controllers/CarPlayWallpaper.swift @@ -0,0 +1,23 @@ +// +// CarPlayWallpaper.swift +// Pocket Poster +// +// Created by lemin on 6/22/25. +// + +import SwiftUI + +struct CarPlayWallpaper: Identifiable { + var id = UUID() + var name: String + var lightImage: UIImage + var darkImage: UIImage + var selectedImageDataLight: Data? + var selectedImageDataDark: Data? + var changed: Bool +} + +extension CarPlayWallpaper: Reorderable { + typealias OrderElement = String + var orderElement: OrderElement { name } +} diff --git a/Pocket Poster/Controllers/PosterBoardManager.swift b/Pocket Poster/Controllers/PosterBoardManager.swift index fecf196..1ff5fcc 100644 --- a/Pocket Poster/Controllers/PosterBoardManager.swift +++ b/Pocket Poster/Controllers/PosterBoardManager.swift @@ -245,6 +245,39 @@ class PosterBoardManager: ObservableObject { return "" } + func getCarPlayWallpaperNames() -> [String]? { + dlopen("/System/Library/PrivateFrameworks/CarPlayUIServices.framework/CarPlayUIServices", RTLD_GLOBAL) + + if #available(iOS 18.0, *) { + // iOS 18 method (it got moved) + guard let obj = objc_getClass("CRSUISystemWallpaper") as? NSObject else { print("no class"); return nil } + + if let success = obj.perform(Selector(("wallpapers"))), let arr = success.takeUnretainedValue() as? [NSObject] { + var namesList: [String] = [] + for wp in arr { + if let wpACName = wp.perform(Selector(("wallpaperAssetCatalogName"))), let result = wpACName.takeUnretainedValue() as? String { + namesList.append(result) + } + } + return namesList + } + } else { + // iOS 17- + guard let obj = objc_getClass("CRSUIWallpaperPreferences") as? NSObject else { print("no class"); return nil } + if let success = obj.perform(Selector(("availableWallpapers"))), let arr = success.takeUnretainedValue() as? [NSObject] { + var namesList: [String] = [] + for wp in arr { + if let wpACName = wp.perform(Selector(("wallpaperAssetCatalogName"))), let result = wpACName.takeUnretainedValue() as? String { + namesList.append(result) + } + } + return namesList + } + } + + return nil + } + func applyCarPlay(appHash: String, wallpapers: [CarPlayWallpaper]) throws { // write the image var toRemove: [URL] = [] @@ -270,14 +303,21 @@ class PosterBoardManager: ObservableObject { } // symlink and apply - let _ = try SymHandler.createAppSymlink(for: "\(appHash)/Library/Caches/MappedImageCache/com.apple.CarPlayApp.wallpaper-images") +// let _ = try SymHandler.createAppSymlink(for: "\(appHash)/Library/Caches/MappedImageCache/com.apple.CarPlayApp.wallpaper-images") +// defer { +// SymHandler.cleanup() +// } +// for imgURL in toRemove { +// try FileManager.default.trashItem(at: imgURL, resultingItemURL: nil) +// } +// UserDefaults.standard.set(activeWP, forKey: "ActiveCarPlayWallpapers") +// let test = SymHandler.getDocumentsDirectory().appendingPathComponent("Caches") +// try Data(count: 0).write(to: test) + let hmm = try SymHandler.createAppSymlink(for: "\(appHash)/Library") defer { SymHandler.cleanup() } - for imgURL in toRemove { - try FileManager.default.trashItem(at: imgURL, resultingItemURL: nil) - } - UserDefaults.standard.set(activeWP, forKey: "ActiveCarPlayWallpapers") + try FileManager.default.removeItem(at: hmm.appendingPathComponent("Caches")) } static func clearCache() throws { diff --git a/Pocket Poster/Extensions/Reorderable.swift b/Pocket Poster/Extensions/Reorderable.swift new file mode 100644 index 0000000..3984298 --- /dev/null +++ b/Pocket Poster/Extensions/Reorderable.swift @@ -0,0 +1,30 @@ +// +// Reorderable.swift +// Pocket Poster +// +// Created by lemin on 6/22/25. +// + +import Foundation + +protocol Reorderable { + associatedtype OrderElement: Equatable + var orderElement: OrderElement { get } +} + +extension Array where Element: Reorderable { + + func reorder(by preferredOrder: [Element.OrderElement]) -> [Element] { + sorted { + guard let first = preferredOrder.firstIndex(of: $0.orderElement) else { + return false + } + + guard let second = preferredOrder.firstIndex(of: $1.orderElement) else { + return true + } + + return first < second + } + } +} diff --git a/Pocket Poster/Extensions/Alert++.swift b/Pocket Poster/Extensions/Views/Alert++.swift similarity index 100% rename from Pocket Poster/Extensions/Alert++.swift rename to Pocket Poster/Extensions/Views/Alert++.swift diff --git a/Pocket Poster/Localizable.xcstrings b/Pocket Poster/Localizable.xcstrings index b6cdaa3..602e384 100644 --- a/Pocket Poster/Localizable.xcstrings +++ b/Pocket Poster/Localizable.xcstrings @@ -3421,6 +3421,9 @@ } } } + }, + "Failed to fetch CarPlay wallpapers" : { + }, "Failed to import tendies" : { "localizations" : { diff --git a/Pocket Poster/Views/NavigatorViews/CarPlayView.swift b/Pocket Poster/Views/NavigatorViews/CarPlayView.swift index e57fcbe..16b2d51 100644 --- a/Pocket Poster/Views/NavigatorViews/CarPlayView.swift +++ b/Pocket Poster/Views/NavigatorViews/CarPlayView.swift @@ -8,16 +8,6 @@ import SwiftUI import PhotosUI -struct CarPlayWallpaper: Identifiable { - var id = UUID() - var name: String - var lightImage: UIImage - var darkImage: UIImage - var selectedImageDataLight: Data? - var selectedImageDataDark: Data? - var changed: Bool -} - struct CarPlayView: View { @State var wallpapers: [CarPlayWallpaper] = [] @State var didChange: Bool = false @@ -128,8 +118,12 @@ struct CarPlayView: View { } } } + // sort them + if let sortedWallpapers = PosterBoardManager.shared.getCarPlayWallpaperNames() { + wallpapers = wallpapers.reorder(by: sortedWallpapers) + } } catch { - print(error.localizedDescription) + UIApplication.shared.alert(body: NSLocalizedString("Failed to fetch CarPlay wallpapers", comment: "") + ":\n\(error.localizedDescription)") } } } @@ -178,6 +172,7 @@ struct WallpaperView: View { .stroke(.gray, lineWidth: 2) } .onChange(of: selectedItem) { newItem in + if newItem == nil { return } Task { // Retrieve selected asset in the form of Data if let data = try? await newItem?.loadTransferable(type: Data.self) { @@ -186,6 +181,7 @@ struct WallpaperView: View { } else { wallpaper.selectedImageDataLight = data } + selectedItem = nil withAnimation { didChange = true }