From 2841bc21094e3fc388db9b04f1b3f8b4a4e18f1d Mon Sep 17 00:00:00 2001 From: neon443 <69979447+neon443@users.noreply.github.com> Date: Wed, 22 Oct 2025 15:20:18 +0100 Subject: [PATCH] add Emoji and old one is now ApiEmoji added async code to Emoji to load image added app groups to share files --- StickerSlack.xcodeproj/project.pbxproj | 26 +++++-- .../StickerSlackiMessageExtension.xcscheme | 1 + StickerSlack/Emoji/ApiEmoji.swift | 55 +++++++++++++++ StickerSlack/Emoji/Emoji.swift | 70 +++++++++++-------- StickerSlack/EmojiHoarder.swift | 12 +++- StickerSlack/StickerSlack.entitlements | 10 +++ StickerSlack/Views/EmojiPreview.swift | 11 ++- ...StickerSlackiMessageExtension.entitlements | 10 +++ 8 files changed, 156 insertions(+), 39 deletions(-) create mode 100644 StickerSlack/Emoji/ApiEmoji.swift create mode 100644 StickerSlack/StickerSlack.entitlements create mode 100644 StickerSlackiMessageExtension/StickerSlackiMessageExtension.entitlements diff --git a/StickerSlack.xcodeproj/project.pbxproj b/StickerSlack.xcodeproj/project.pbxproj index edfb0b5..ab1de96 100644 --- a/StickerSlack.xcodeproj/project.pbxproj +++ b/StickerSlack.xcodeproj/project.pbxproj @@ -7,7 +7,9 @@ objects = { /* Begin PBXBuildFile section */ - A940FE3D2EA232590016870B /* Emoji.swift in Sources */ = {isa = PBXBuildFile; fileRef = A940FE3C2EA232590016870B /* Emoji.swift */; }; + A924C3722EA9127200F20781 /* Emoji.swift in Sources */ = {isa = PBXBuildFile; fileRef = A924C3712EA9127200F20781 /* Emoji.swift */; }; + A924C3732EA9127200F20781 /* Emoji.swift in Sources */ = {isa = PBXBuildFile; fileRef = A924C3712EA9127200F20781 /* Emoji.swift */; }; + A940FE3D2EA232590016870B /* ApiEmoji.swift in Sources */ = {isa = PBXBuildFile; fileRef = A940FE3C2EA232590016870B /* ApiEmoji.swift */; }; A949B1F32EA04E8200215164 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A949B1EF2EA04E8200215164 /* Assets.xcassets */; }; A949B1F42EA04E8200215164 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949B1F02EA04E8200215164 /* ContentView.swift */; }; A949B1F52EA04E8200215164 /* StickerSlackApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949B1F12EA04E8200215164 /* StickerSlackApp.swift */; }; @@ -21,7 +23,7 @@ A969D6AF2EA3F1AF00399C05 /* MessagesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A969D6AA2EA3F1AF00399C05 /* MessagesViewController.swift */; }; A9773C2F2EA54AF000F3B753 /* EmojiPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9773C2E2EA54AF000F3B753 /* EmojiPreview.swift */; }; A9BE06DB2EA656B80033B213 /* EmojiHoarder.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949B1F72EA04F2300215164 /* EmojiHoarder.swift */; }; - A9BE06DC2EA657C70033B213 /* Emoji.swift in Sources */ = {isa = PBXBuildFile; fileRef = A940FE3C2EA232590016870B /* Emoji.swift */; }; + A9BE06DC2EA657C70033B213 /* ApiEmoji.swift in Sources */ = {isa = PBXBuildFile; fileRef = A940FE3C2EA232590016870B /* ApiEmoji.swift */; }; A9BE06DD2EA657CF0033B213 /* SlackResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949B1FA2EA0518800215164 /* SlackResponse.swift */; }; /* End PBXBuildFile section */ @@ -50,7 +52,10 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - A940FE3C2EA232590016870B /* Emoji.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Emoji.swift; sourceTree = ""; }; + A924C3712EA9127200F20781 /* Emoji.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Emoji.swift; sourceTree = ""; }; + A924C3742EA9134C00F20781 /* StickerSlack.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = StickerSlack.entitlements; sourceTree = ""; }; + A924C3752EA9137A00F20781 /* StickerSlackiMessageExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = StickerSlackiMessageExtension.entitlements; sourceTree = ""; }; + A940FE3C2EA232590016870B /* ApiEmoji.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiEmoji.swift; sourceTree = ""; }; A949B1DF2EA04C0B00215164 /* StickerSlack.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = StickerSlack.app; sourceTree = BUILT_PRODUCTS_DIR; }; A949B1EF2EA04E8200215164 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; A949B1F02EA04E8200215164 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; @@ -117,6 +122,7 @@ A949B1F22EA04E8200215164 /* StickerSlack */ = { isa = PBXGroup; children = ( + A924C3742EA9134C00F20781 /* StickerSlack.entitlements */, A949B1F12EA04E8200215164 /* StickerSlackApp.swift */, A949B1F72EA04F2300215164 /* EmojiHoarder.swift */, A949B1F92EA0517800215164 /* Emoji */, @@ -139,7 +145,8 @@ isa = PBXGroup; children = ( A949B1FA2EA0518800215164 /* SlackResponse.swift */, - A940FE3C2EA232590016870B /* Emoji.swift */, + A940FE3C2EA232590016870B /* ApiEmoji.swift */, + A924C3712EA9127200F20781 /* Emoji.swift */, ); path = Emoji; sourceTree = ""; @@ -155,6 +162,7 @@ A969D6AB2EA3F1AF00399C05 /* StickerSlackiMessageExtension */ = { isa = PBXGroup; children = ( + A924C3752EA9137A00F20781 /* StickerSlackiMessageExtension.entitlements */, A969D6A62EA3F1AF00399C05 /* Assets.xcassets */, A969D6A72EA3F1AF00399C05 /* Info.plist */, A969D6A92EA3F1AF00399C05 /* MainInterface.storyboard */, @@ -270,10 +278,11 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - A940FE3D2EA232590016870B /* Emoji.swift in Sources */, + A940FE3D2EA232590016870B /* ApiEmoji.swift in Sources */, A949B1F42EA04E8200215164 /* ContentView.swift in Sources */, A949B1F52EA04E8200215164 /* StickerSlackApp.swift in Sources */, A949B1FB2EA0518800215164 /* SlackResponse.swift in Sources */, + A924C3732EA9127200F20781 /* Emoji.swift in Sources */, A949B1F82EA04F2300215164 /* EmojiHoarder.swift in Sources */, A9773C2F2EA54AF000F3B753 /* EmojiPreview.swift in Sources */, ); @@ -283,7 +292,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - A9BE06DC2EA657C70033B213 /* Emoji.swift in Sources */, + A924C3722EA9127200F20781 /* Emoji.swift in Sources */, + A9BE06DC2EA657C70033B213 /* ApiEmoji.swift in Sources */, A9BE06DB2EA656B80033B213 /* EmojiHoarder.swift in Sources */, A969D6AF2EA3F1AF00399C05 /* MessagesViewController.swift in Sources */, A9BE06DD2EA657CF0033B213 /* SlackResponse.swift in Sources */, @@ -433,6 +443,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = StickerSlack/StickerSlack.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 8JGND254B7; @@ -477,6 +488,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = StickerSlack/StickerSlack.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 8JGND254B7; @@ -520,6 +532,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "iMessage App Icon"; + CODE_SIGN_ENTITLEMENTS = StickerSlackiMessageExtension/StickerSlackiMessageExtension.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 8JGND254B7; @@ -551,6 +564,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "iMessage App Icon"; + CODE_SIGN_ENTITLEMENTS = StickerSlackiMessageExtension/StickerSlackiMessageExtension.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 8JGND254B7; diff --git a/StickerSlack.xcodeproj/xcshareddata/xcschemes/StickerSlackiMessageExtension.xcscheme b/StickerSlack.xcodeproj/xcshareddata/xcschemes/StickerSlackiMessageExtension.xcscheme index 84b7469..67d4b9b 100644 --- a/StickerSlack.xcodeproj/xcshareddata/xcschemes/StickerSlackiMessageExtension.xcscheme +++ b/StickerSlack.xcodeproj/xcshareddata/xcschemes/StickerSlackiMessageExtension.xcscheme @@ -74,6 +74,7 @@ savedToolIdentifier = "" useCustomWorkingDirectory = "NO" debugDocumentVersioning = "YES" + askForAppToLaunch = "Yes" launchAutomaticallySubstyle = "2"> Emoji { + return Emoji(apiEmoji: self) + } + + func encode(to encoder: any Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(self.name, forKey: .name) + try container.encode(self.urlString, forKey: .urlString) + } +} + diff --git a/StickerSlack/Emoji/Emoji.swift b/StickerSlack/Emoji/Emoji.swift index a43e06f..81ce506 100644 --- a/StickerSlack/Emoji/Emoji.swift +++ b/StickerSlack/Emoji/Emoji.swift @@ -6,46 +6,60 @@ // import Foundation -import SwiftUI +import UIKit +import UniformTypeIdentifiers -protocol EmojiProtocol: Codable, Hashable { - var name: String { get set } - var urlString: String { get set } -} - -struct Emoji: EmojiProtocol { +struct Emoji: Codable, Identifiable, Hashable { + var id: UUID var name: String - var urlString: String + var localImageURL: URL + var remoteImageURL: URL - var url: URL { - return URL(string: urlString) ?? URL(string: "https://")! + var image: UIImage? + + enum CodingKeys: String, CodingKey { + case id = "id" + case name = "name" + case localImageURL = "localImageURL" + case remoteImageURL = "remoteImageURL" } init(from decoder: any Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) - self.init( - name: try container.decode(String.self, forKey: .name), - url: try container.decode(String.self, forKey: .urlString) - ) + self.id = try container.decode(UUID.self, forKey: .id) + self.name = try container.decode(String.self, forKey: .name) + self.localImageURL = try container.decode(URL.self, forKey: .localImageURL) + self.remoteImageURL = try container.decode(URL.self, forKey: .remoteImageURL) + + if let data = try? Data(contentsOf: localImageURL), + let img = UIImage(data: data) { + self.image = img + } else { + self.image = nil + } } init( - name: String, - url: String, + apiEmoji: ApiEmoji, + id: UUID = UUID() ) { - self.name = name - self.urlString = url + self.id = id + self.name = apiEmoji.name + self.remoteImageURL = apiEmoji.url + self.localImageURL = EmojiHoarder.container.appendingPathComponent(id.uuidString, conformingTo: .image) + + +// Task { [weak self] in +// let (data, response) = try await URLSession.shared.data(from: apiEmoji.url) +// self.image = UIImage(data: data) +// } +// let image = try! Data(contentsOf: apiEmoji.url) +// try! image.write(to: localImageURL) +// self.image = UIImage(data: image) ?? UIImage() } - enum CodingKeys: CodingKey { - case name - case urlString - } - - func encode(to encoder: any Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(self.name, forKey: .name) - try container.encode(self.urlString, forKey: .urlString) + func loadImage() async throws -> UIImage { + let (data, _) = try await URLSession.shared.data(from: remoteImageURL) + return UIImage(data: data)! } } - diff --git a/StickerSlack/EmojiHoarder.swift b/StickerSlack/EmojiHoarder.swift index 454e61f..a998677 100644 --- a/StickerSlack/EmojiHoarder.swift +++ b/StickerSlack/EmojiHoarder.swift @@ -10,13 +10,21 @@ import SwiftUI import Combine class EmojiHoarder: ObservableObject { + static let container = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.neon443.StickerSlack")! private let endpoint: URL = URL(string: "https://cachet.dunkirk.sh/emojis")! @Published var emojis: [Emoji] init() { - let data = try! Data(contentsOf: endpoint) + guard let data = try? Data(contentsOf: endpoint) else { fatalError("cachet unreachable") } let decoded: [SlackResponse] = try! JSONDecoder().decode([SlackResponse].self, from: data) - self.emojis = decoded.map { Emoji(name: $0.name, url: $0.imageUrl) } + self.emojis = decoded.map { ApiEmoji(name: $0.name, url: $0.imageUrl).toEmoji() } +// Task { +// for i in emojis.indices { +// emojis[i].image = try? await emojis[i].loadImage() +// } +// } } + +// func storeStickers } diff --git a/StickerSlack/StickerSlack.entitlements b/StickerSlack/StickerSlack.entitlements new file mode 100644 index 0000000..f5e052f --- /dev/null +++ b/StickerSlack/StickerSlack.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.application-groups + + group.com.neon443.StickerSlack + + + diff --git a/StickerSlack/Views/EmojiPreview.swift b/StickerSlack/Views/EmojiPreview.swift index 834fbcc..8dd8f3f 100644 --- a/StickerSlack/Views/EmojiPreview.swift +++ b/StickerSlack/Views/EmojiPreview.swift @@ -15,7 +15,12 @@ struct EmojiPreview: View { var body: some View { VStack { Text(emoji.name) - AsyncImage(url: emoji.url) { phase in + if let image = emoji.image { + Image(uiImage: image) + } else { + ProgressView() + } + AsyncImage(url: emoji.remoteImageURL) { phase in if let image = phase.image { image .resizable().scaledToFit() @@ -38,9 +43,9 @@ struct EmojiPreview: View { #Preview { EmojiPreview( - emoji: Emoji( + emoji: ApiEmoji( name: "s?", url: "https://neon443.github.io/images/fav.ico" - ) + ).toEmoji() ) } diff --git a/StickerSlackiMessageExtension/StickerSlackiMessageExtension.entitlements b/StickerSlackiMessageExtension/StickerSlackiMessageExtension.entitlements new file mode 100644 index 0000000..f5e052f --- /dev/null +++ b/StickerSlackiMessageExtension/StickerSlackiMessageExtension.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.application-groups + + group.com.neon443.StickerSlack + + +