async let to parallelise stuff

fix crash when the fetched db doesnt exist
added loadremoteDB to asyncly fetch remotedb
fixed Tasks not running on background threads
remove expiration from slackresponse
emoji.uiid starts out as emoji.id
added filtering emojis test
hopefully optimised the display of images checking if its local
imessage extension ios 15+
remove the "hii!!" and "hello world" from the emojji picker
This commit is contained in:
neon443
2025-10-30 19:44:59 +00:00
parent b738a06835
commit c974e8136b
8 changed files with 44 additions and 46 deletions

View File

@@ -663,7 +663,7 @@
INFOPLIST_FILE = StickerSlackiMessageExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = StickerSlackiMessageExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 26.0;
IPHONEOS_DEPLOYMENT_TARGET = 15;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -695,7 +695,7 @@
INFOPLIST_FILE = StickerSlackiMessageExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = StickerSlackiMessageExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 26.0;
IPHONEOS_DEPLOYMENT_TARGET = 15;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",

View File

@@ -13,13 +13,12 @@ import UniformTypeIdentifiers
struct Emoji: Codable, Identifiable, Hashable {
var id: UUID
var uiID: UUID = UUID()
var uiID: UUID
var name: String
var localImageURL: URL {
let urlString = remoteImageURL.absoluteString
let split = urlString.split(separator: ".")
let fileExtension = ".\(split.last ?? "png")"
// return EmojiHoarder.container.appendingPathComponent(id.uuidString+fileExtension, conformingTo: .image)
return URL(string: EmojiHoarder.container.absoluteString+id.uuidString+fileExtension)!
}
var remoteImageURL: URL
@@ -53,6 +52,7 @@ struct Emoji: Codable, Identifiable, Hashable {
init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.id = try container.decode(UUID.self, forKey: .id)
self.uiID = id
self.name = try container.decode(String.self, forKey: .name)
self.remoteImageURL = try container.decode(URL.self, forKey: .remoteImageURL)
}
@@ -62,6 +62,7 @@ struct Emoji: Codable, Identifiable, Hashable {
id: UUID = UUID()
) {
self.id = id
self.uiID = id
self.name = apiEmoji.name
self.remoteImageURL = apiEmoji.url
}

View File

@@ -13,7 +13,6 @@ struct SlackResponse: Identifiable, Codable {
var name: String
var imageUrl: String
var alias: String?
var expiration: Date
static func toEmojis(from response: [SlackResponse]?) -> [Emoji]? {
guard let response else { return nil }

View File

@@ -25,11 +25,9 @@ class EmojiHoarder: ObservableObject {
withAnimation { self.emojis = loadLocalDB() }
withAnimation { self.filteredEmojis = self.emojis }
Task(priority: .high) {
if let fetched = await self.fetchRemoteDB() {
withAnimation { self.emojis = fetched }
withAnimation { self.filteredEmojis = fetched }
}
Task.detached {
print(Thread.current)
await self.loadRemoteDB()
}
}
@@ -55,12 +53,20 @@ class EmojiHoarder: ObservableObject {
return []
}
func loadRemoteDB() async {
async let fetched = self.fetchRemoteDB()
if let fetched = await fetched {
withAnimation { self.emojis = fetched }
withAnimation { self.filteredEmojis = fetched }
}
}
func fetchRemoteDB() async -> [Emoji]? {
do {
let (data, _) = try await URLSession.shared.data(from: endpoint)
async let (data, _) = try URLSession.shared.data(from: endpoint)
decoder.dateDecodingStrategy = .iso8601
let decoded: [SlackResponse] = try! decoder.decode([SlackResponse].self, from: data)
storeDB(data: data)
let decoded: [SlackResponse] = try decoder.decode([SlackResponse].self, from: await data)
try storeDB(data: await data)
return SlackResponse.toEmojis(from: decoded)
} catch {
print(error.localizedDescription)
@@ -69,12 +75,14 @@ class EmojiHoarder: ObservableObject {
}
func refreshDB(withCallback callback: (() -> Void)? = nil) {
Task {
guard let fetched = try? await fetchRemoteDB() else { return }
withAnimation { self.emojis = fetched }
withAnimation { self.filteredEmojis = fetched }
if let callback {
callback()
Task.detached {
guard let fetched = await self.fetchRemoteDB() else { return }
DispatchQueue.main.async {
withAnimation { self.emojis = fetched }
withAnimation { self.filteredEmojis = fetched }
if let callback {
callback()
}
}
}
}
@@ -84,8 +92,8 @@ class EmojiHoarder: ObservableObject {
withAnimation(.interactiveSpring) { self.filteredEmojis = emojis }
return
}
Task {
let filtered = emojis.filter { $0.name.localizedCaseInsensitiveContains(searchTerm) }
Task.detached {
let filtered = await self.emojis.filter { $0.name.localizedCaseInsensitiveContains(searchTerm) }
DispatchQueue.main.async {
withAnimation(.interactiveSpring) { self.filteredEmojis = filtered }
}
@@ -97,15 +105,15 @@ class EmojiHoarder: ObservableObject {
filterEmojis(by: searchTerm)
return
}
Task {
filterEmojis(by: searchTerm)
self.filterEmojis(by: searchTerm)
DispatchQueue.main.async {
switch category {
case .none:
fallthrough
case .downloaded:
withAnimation(.interactiveSpring) { filteredEmojis = filteredEmojis.filter { $0.isLocal } }
withAnimation(.interactiveSpring) { self.filteredEmojis = self.filteredEmojis.filter { $0.isLocal } }
case .notDownloaded:
withAnimation(.interactiveSpring) { filteredEmojis = filteredEmojis.filter { !$0.isLocal } }
withAnimation(.interactiveSpring) { self.filteredEmojis = self.filteredEmojis.filter { !$0.isLocal } }
}
}
}

View File

@@ -17,9 +17,8 @@ struct EmojiPreview: View {
VStack(alignment: .leading) {
Text(emoji.name)
Group {
if let localImage = try? Data(contentsOf: emoji.localImageURL),
let image = UIImage(data: localImage) {
Image(uiImage: image)
if emoji.isLocal {
Image(uiImage: emoji.image!)
.resizable().scaledToFit()
.border(.orange)
.overlay(alignment: .bottomLeading) {

View File

@@ -23,4 +23,13 @@ struct StickerSlackTests {
}
}
@Test func filteringEmojis() async throws {
let searchQueries = ["heavysob", "yay", "afsdjk", "afhjskf", "g4", "aqua-osx", "neotunes", "", "", ""]
for query in searchQueries {
print(query)
hoarder.filteredEmojis = []
hoarder.filterEmojis(by: query)
print(hoarder.filteredEmojis.count)
}
}
}

View File

@@ -15,19 +15,8 @@
<view key="view" contentMode="scaleToFill" id="zMn-AG-sqS">
<rect key="frame" x="0.0" y="0.0" width="320" height="528"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Hello World" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="d1e-fi-ked">
<rect key="frame" x="116" y="254.00000000000003" width="88" height="20.333333333333343"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<viewLayoutGuide key="safeArea" id="LDy-ih-0nr"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstAttribute="centerY" secondItem="d1e-fi-ked" secondAttribute="centerY" id="H0s-hz-dDP"/>
<constraint firstAttribute="centerX" secondItem="d1e-fi-ked" secondAttribute="centerX" id="wFy-hW-Bib"/>
</constraints>
</view>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<size key="freeformSize" width="320" height="528"/>

View File

@@ -20,13 +20,6 @@ class MessagesViewController: MSMessagesAppViewController {
// MARK: - Conversation Handling
override func willBecomeActive(with conversation: MSConversation) {
let l = UILabel()
l.frame = CGRect(x: 20, y: 20, width: 200, height: 40)
l.textColor = .systemOrange
l.text = "hii!"
view.addSubview(l)
view.bringSubviewToFront(l)
let stickerBrowser = MSStickerBrowserView(frame: .zero, stickerSize: .regular)
stickerBrowser.frame = CGRect(x: 60, y: 20, width: 200, height: 600)
stickerBrowser.dataSource = dataSource