diff --git a/StickerSlack/Emoji/EmojiHoarder.swift b/StickerSlack/Emoji/EmojiHoarder.swift index f6a6eb5..e270a91 100644 --- a/StickerSlack/Emoji/EmojiHoarder.swift +++ b/StickerSlack/Emoji/EmojiHoarder.swift @@ -9,6 +9,7 @@ import Foundation import SwiftUI import Combine import UniformTypeIdentifiers +import Haptics class EmojiHoarder: ObservableObject { static let container = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.neon443.StickerSlack")!.appendingPathComponent("Library", conformingTo: .directory) @@ -45,17 +46,10 @@ class EmojiHoarder: ObservableObject { } } - func deleteAllStickers() async { - await withTaskGroup { group in - for i in emojis.indices { - group.addTask { - guard await self.emojis[i].isLocal else { return } - await self.emojis[i].deleteImage() - DispatchQueue.main.sync { - self.emojis[i].refresh() - } - } - } + func deleteAllStickers() { + for i in emojis.indices { + guard downloadedEmojis.contains(emojis[i].name) else { continue } + delete(emoji: emojis[i]) } } @@ -150,6 +144,25 @@ class EmojiHoarder: ObservableObject { withAnimation { filteredEmojis = trie.search(prefix: searchTerm) } } + func download(emoji: Emoji) { + Task.detached { + try? await emoji.downloadImage() + await MainActor.run { + self.downloadedEmojis.insert(emoji.name) + self.trie.dict[emoji.name]?.refresh() + Haptic.success.trigger() + } + } + } + + @MainActor + func delete(emoji: Emoji) { + emoji.deleteImage() + downloadedEmojis.remove(emoji.name) + self.trie.dict[emoji.name]?.refresh() + Haptic.heavy.trigger() + } + // func filterEmojis(byCategory category: FilterCategory, searchTerm: String) { // guard category != .none else { // filterEmojis(by: searchTerm) diff --git a/StickerSlack/SwiftUI/ContentView.swift b/StickerSlack/SwiftUI/ContentView.swift index 763cb10..b231902 100644 --- a/StickerSlack/SwiftUI/ContentView.swift +++ b/StickerSlack/SwiftUI/ContentView.swift @@ -13,12 +13,14 @@ struct ContentView: View { @State var searchTerm: String = "" + var col: GridItem = GridItem(.fixed(100), spacing: 0, alignment: .center) var body: some View { TabView { - List { - ForEach(hoarder.downloadedEmojis, id: \.self) { name in + LazyHGrid(rows: Array(repeating: col, count: 4), spacing: 10) { + ForEach(hoarder.downloadedEmojis.sorted(by: <), id: \.self) { name in if let emoji = hoarder.trie.dict[name] { - EmojiRow(hoarder: hoarder, emoji: emoji) + EmojiPreview(hoarder: hoarder, emoji: emoji) + .aspectRatio(1, contentMode: .fit) } } } diff --git a/StickerSlack/SwiftUI/Emoji/EmojiPreview.swift b/StickerSlack/SwiftUI/Emoji/EmojiPreview.swift index 6a7a4a4..e3fb623 100644 --- a/StickerSlack/SwiftUI/Emoji/EmojiPreview.swift +++ b/StickerSlack/SwiftUI/Emoji/EmojiPreview.swift @@ -15,46 +15,43 @@ struct EmojiPreview: View { @State private var id: UUID = UUID() @State private var delay: TimeInterval = 0 - var body: some View { - VStack(alignment: .leading) { - Text(emoji.name) - Group { - if let image = emoji.image { - Image(uiImage: image) - .resizable().scaledToFit() - .border(.orange) - .overlay(alignment: .bottomLeading) { - Image(systemName: "arrow.down.circle.fill") - .foregroundStyle(.gray) - .shadow(radius: 1) - .symbolRenderingMode(.hierarchical) - } - } else { - AsyncImage(url: emoji.remoteImageURL) { phase in - if let image = phase.image { - image - .resizable().scaledToFit() - } else if phase.error != nil { - ImageErrorView() - .onTapGesture { + var body: some View { + Group { + if let image = emoji.image { + Image(uiImage: image) + .resizable().scaledToFit() + .border(.orange) + .overlay(alignment: .bottomLeading) { + Image(systemName: "arrow.down.circle.fill") + .foregroundStyle(.gray) + .shadow(radius: 1) + .symbolRenderingMode(.hierarchical) + } + } else { + AsyncImage(url: emoji.remoteImageURL) { phase in + if let image = phase.image { + image + .resizable().scaledToFit() + } else if phase.error != nil { + ImageErrorView() + .onTapGesture { + id = UUID() + } + .onAppear { + DispatchQueue.main.asyncAfter(deadline: .now()+delay) { id = UUID() + delay+=0.1 } - .onAppear { - DispatchQueue.main.asyncAfter(deadline: .now()+delay) { - id = UUID() - delay+=0.1 - } - } - } else { - ProgressView() - .frame(maxWidth: .infinity, maxHeight: .infinity) - } + } + } else { + ProgressView() + .frame(maxWidth: .infinity, maxHeight: .infinity) } } } - .id(id) } - } + .id(id) + } } #Preview { diff --git a/StickerSlack/SwiftUI/Emoji/EmojiRow.swift b/StickerSlack/SwiftUI/Emoji/EmojiRow.swift index d8fd3a8..7080d1e 100644 --- a/StickerSlack/SwiftUI/Emoji/EmojiRow.swift +++ b/StickerSlack/SwiftUI/Emoji/EmojiRow.swift @@ -14,28 +14,26 @@ struct EmojiRow: View { var body: some View { HStack { - EmojiPreview( - hoarder: hoarder, - emoji: emoji - ) + VStack { + HStack(spacing: .zero) { +// Text + Text(emoji.name) + } + EmojiPreview( + hoarder: hoarder, + emoji: emoji + ) + } .frame(maxWidth: 100, maxHeight: 100) Spacer() if hoarder.downloadedEmojis.contains(emoji.name) { Button("", systemImage: "trash") { - emoji.deleteImage() - emoji.refresh() - Haptic.heavy.trigger() + hoarder.delete(emoji: emoji) } .buttonStyle(.plain) } else { Button("", systemImage: "arrow.down.circle") { - Task.detached { - try? await emoji.downloadImage() - await MainActor.run { - emoji.refresh() - Haptic.success.trigger() - } - } + hoarder.download(emoji: emoji) } .buttonStyle(.plain) } diff --git a/StickerSlack/UIKit/EmojiCollectionView.swift b/StickerSlack/UIKit/EmojiCollectionView.swift index 76f418b..103ba56 100644 --- a/StickerSlack/UIKit/EmojiCollectionView.swift +++ b/StickerSlack/UIKit/EmojiCollectionView.swift @@ -46,32 +46,25 @@ struct EmojiCollectionView: UIViewRepresentable { func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let emojiName = items[indexPath.row] + let emoji = hoarder.trie.dict[emojiName]! let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) cell.contentConfiguration = UIHostingConfiguration { HStack { EmojiPreview( hoarder: hoarder, - emoji: hoarder.trie.dict[emojiName]! + emoji: emoji ) .frame(maxWidth: 100, maxHeight: 100) Spacer() if hoarder.downloadedEmojis.contains(emojiName) { Button("", systemImage: "trash") { - self.hoarder.trie.dict[emojiName]!.deleteImage() - self.hoarder.trie.dict[emojiName]!.refresh() - Haptic.heavy.trigger() + fatalError() } .buttonStyle(.plain) } else { Button("", systemImage: "arrow.down.circle") { - Task.detached { - try? await self.hoarder.trie.dict[emojiName]!.downloadImage() - await MainActor.run { - self.hoarder.trie.dict[emojiName]!.refresh() - Haptic.success.trigger() - } - } + self.hoarder.download(emoji: emoji) } .buttonStyle(.plain) }