UIKit time :yay:

This commit is contained in:
neon443
2025-11-03 20:27:38 +00:00
parent 29a270c2a5
commit 18e1ebc870
4 changed files with 110 additions and 64 deletions

View File

@@ -46,6 +46,7 @@
A9C172DD2EB8C9AC008A7885 /* Trie.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C172DB2EB8C9AC008A7885 /* Trie.swift */; }; A9C172DD2EB8C9AC008A7885 /* Trie.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C172DB2EB8C9AC008A7885 /* Trie.swift */; };
A9C172DE2EB8C9AC008A7885 /* Trie.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C172DB2EB8C9AC008A7885 /* Trie.swift */; }; A9C172DE2EB8C9AC008A7885 /* Trie.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C172DB2EB8C9AC008A7885 /* Trie.swift */; };
A9D15B8B2EB1142C00404792 /* EmojiPack.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D15B892EB1142C00404792 /* EmojiPack.swift */; }; A9D15B8B2EB1142C00404792 /* EmojiPack.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D15B892EB1142C00404792 /* EmojiPack.swift */; };
A9EB72392EB93FDB00658CEB /* EmojiCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9EB72382EB93FDB00658CEB /* EmojiCollectionView.swift */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
@@ -108,6 +109,7 @@
A9C172DB2EB8C9AC008A7885 /* Trie.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Trie.swift; sourceTree = "<group>"; }; A9C172DB2EB8C9AC008A7885 /* Trie.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Trie.swift; sourceTree = "<group>"; };
A9D15B892EB1142C00404792 /* EmojiPack.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiPack.swift; sourceTree = "<group>"; }; A9D15B892EB1142C00404792 /* EmojiPack.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiPack.swift; sourceTree = "<group>"; };
A9E2ECD72EB74CE00038B2D6 /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; }; A9E2ECD72EB74CE00038B2D6 /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; };
A9EB72382EB93FDB00658CEB /* EmojiCollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiCollectionView.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@@ -210,6 +212,7 @@
A9D15B892EB1142C00404792 /* EmojiPack.swift */, A9D15B892EB1142C00404792 /* EmojiPack.swift */,
A935437A2EB2A3C800BB80A4 /* FilterCategory.swift */, A935437A2EB2A3C800BB80A4 /* FilterCategory.swift */,
A9C172DB2EB8C9AC008A7885 /* Trie.swift */, A9C172DB2EB8C9AC008A7885 /* Trie.swift */,
A9EB72382EB93FDB00658CEB /* EmojiCollectionView.swift */,
); );
path = Emoji; path = Emoji;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -395,6 +398,7 @@
A949B1F42EA04E8200215164 /* ContentView.swift in Sources */, A949B1F42EA04E8200215164 /* ContentView.swift in Sources */,
A949B1F52EA04E8200215164 /* StickerSlackApp.swift in Sources */, A949B1F52EA04E8200215164 /* StickerSlackApp.swift in Sources */,
A9104C802EB4022500D160EA /* MSSticker.swift in Sources */, A9104C802EB4022500D160EA /* MSSticker.swift in Sources */,
A9EB72392EB93FDB00658CEB /* EmojiCollectionView.swift in Sources */,
A949B1FB2EA0518800215164 /* SlackResponse.swift in Sources */, A949B1FB2EA0518800215164 /* SlackResponse.swift in Sources */,
A935437B2EB2A3C800BB80A4 /* FilterCategory.swift in Sources */, A935437B2EB2A3C800BB80A4 /* FilterCategory.swift in Sources */,
A9C172DD2EB8C9AC008A7885 /* Trie.swift in Sources */, A9C172DD2EB8C9AC008A7885 /* Trie.swift in Sources */,
@@ -606,17 +610,18 @@
"INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault; "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
IPHONEOS_DEPLOYMENT_TARGET = 15; IPHONEOS_DEPLOYMENT_TARGET = 16;
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 12; MACOSX_DEPLOYMENT_TARGET = 13;
MARKETING_VERSION = "$(VERSION)"; MARKETING_VERSION = "$(VERSION)";
PRODUCT_BUNDLE_IDENTIFIER = com.neon443.StickerSlack; PRODUCT_BUNDLE_IDENTIFIER = com.neon443.StickerSlack;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
REGISTER_APP_GROUPS = YES; REGISTER_APP_GROUPS = YES;
SDKROOT = auto; SDKROOT = auto;
STRING_CATALOG_GENERATE_SYMBOLS = YES; STRING_CATALOG_GENERATE_SYMBOLS = YES;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator xros xrsimulator";
SUPPORTS_MACCATALYST = NO;
SWIFT_APPROACHABLE_CONCURRENCY = YES; SWIFT_APPROACHABLE_CONCURRENCY = YES;
SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor; SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor;
SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_EMIT_LOC_STRINGS = YES;
@@ -652,17 +657,18 @@
"INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault; "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
IPHONEOS_DEPLOYMENT_TARGET = 15; IPHONEOS_DEPLOYMENT_TARGET = 16;
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 12; MACOSX_DEPLOYMENT_TARGET = 13;
MARKETING_VERSION = "$(VERSION)"; MARKETING_VERSION = "$(VERSION)";
PRODUCT_BUNDLE_IDENTIFIER = com.neon443.StickerSlack; PRODUCT_BUNDLE_IDENTIFIER = com.neon443.StickerSlack;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
REGISTER_APP_GROUPS = YES; REGISTER_APP_GROUPS = YES;
SDKROOT = auto; SDKROOT = auto;
STRING_CATALOG_GENERATE_SYMBOLS = YES; STRING_CATALOG_GENERATE_SYMBOLS = YES;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator xros xrsimulator";
SUPPORTS_MACCATALYST = NO;
SWIFT_APPROACHABLE_CONCURRENCY = YES; SWIFT_APPROACHABLE_CONCURRENCY = YES;
SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor; SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor;
SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_EMIT_LOC_STRINGS = YES;
@@ -685,7 +691,7 @@
INFOPLIST_FILE = StickerSlackiMessageApp/Info.plist; INFOPLIST_FILE = StickerSlackiMessageApp/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = StickerSlack; INFOPLIST_KEY_CFBundleDisplayName = StickerSlack;
INFOPLIST_KEY_NSHumanReadableCopyright = ""; INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 15; IPHONEOS_DEPLOYMENT_TARGET = 16;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@@ -717,7 +723,7 @@
INFOPLIST_FILE = StickerSlackiMessageApp/Info.plist; INFOPLIST_FILE = StickerSlackiMessageApp/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = StickerSlack; INFOPLIST_KEY_CFBundleDisplayName = StickerSlack;
INFOPLIST_KEY_NSHumanReadableCopyright = ""; INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 15; IPHONEOS_DEPLOYMENT_TARGET = 16;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",

View File

@@ -0,0 +1,83 @@
//
// EmojiCollectionView.swift
// StickerSlack
//
// Created by neon443 on 03/11/2025.
//
import Foundation
import UIKit
import SwiftUI
import Haptics
struct EmojiCollectionView: UIViewRepresentable {
let hoarder: EmojiHoarder
func makeUIView(context: Context) -> UITableView {
let tableView = UITableView()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
tableView.dataSource = context.coordinator
return tableView
}
func updateUIView(_ uiView: UITableView, context: Context) {
uiView.reloadData()
}
func makeCoordinator() -> Coordinator {
Coordinator(hoarder: hoarder)
}
final class Coordinator: NSObject, UITableViewDataSource {
var hoarder: EmojiHoarder
init(hoarder: EmojiHoarder) {
self.hoarder = hoarder
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return hoarder.searchTerm.isEmpty ? hoarder.emojis.count : hoarder.filteredEmojis.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var emojiName: String
if hoarder.searchTerm.isEmpty {
emojiName = hoarder.emojis[indexPath.row].name
} else {
emojiName = hoarder.filteredEmojis[indexPath.row]
}
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.contentConfiguration = UIHostingConfiguration {
HStack {
EmojiPreview(
hoarder: hoarder,
emoji: hoarder.trie.dict[emojiName]!
)
.frame(maxWidth: 100, maxHeight: 100)
Spacer()
if hoarder.trie.dict[emojiName]!.isLocal {
Button("", systemImage: "trash") {
self.hoarder.trie.dict[emojiName]!.deleteImage()
self.hoarder.trie.dict[emojiName]!.refresh()
Haptic.heavy.trigger()
}
.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()
}
}
}
.buttonStyle(.plain)
}
}
}
return cell
}
}
}

View File

@@ -21,6 +21,7 @@ class EmojiHoarder: ObservableObject {
@Published var trie: Trie = Trie() @Published var trie: Trie = Trie()
@Published var filteredEmojis: [String] = [] @Published var filteredEmojis: [String] = []
@Published var searchTerm: String = ""
init(localOnly: Bool = false) { init(localOnly: Bool = false) {
let localDB = loadLocalDB() let localDB = loadLocalDB()

View File

@@ -11,77 +11,33 @@ import Haptics
struct ContentView: View { struct ContentView: View {
@StateObject var hoarder: EmojiHoarder = EmojiHoarder() @StateObject var hoarder: EmojiHoarder = EmojiHoarder()
@State var searchTerm: String = ""
var body: some View { var body: some View {
NavigationView { // NavigationView {
List { // List {
TextField("", text: $hoarder.searchTerm)
NavigationLink("trieTester") { NavigationLink("trieTester") {
TrieTestingView( TrieTestingView(
hoarder: hoarder, hoarder: hoarder,
) )
} }
Text("\(searchTerm.isEmpty ? hoarder.emojis.count : hoarder.filteredEmojis.count) Emoji") Text("\(hoarder.searchTerm.isEmpty ? hoarder.emojis.count : hoarder.filteredEmojis.count) Emoji")
if searchTerm.isEmpty { EmojiCollectionView(hoarder: hoarder)
ForEach($hoarder.emojis, id: \.self) { $emoji in
HStack {
EmojiPreview(
hoarder: hoarder,
emoji: emoji
)
.frame(maxWidth: 100, maxHeight: 100)
Spacer()
if emoji.isLocal {
Button("", systemImage: "trash") {
emoji.deleteImage()
emoji.refresh()
Haptic.heavy.trigger()
}
.buttonStyle(.plain)
} else {
Button("", systemImage: "arrow.down.circle") {
Task.detached {
try? await emoji.downloadImage()
await MainActor.run {
emoji.refresh()
Haptic.success.trigger()
}
}
}
.buttonStyle(.plain)
}
}
}
} else {
ForEach(hoarder.filteredEmojis, id: \.self) { name in
if let emoji = hoarder.trie.dict[name] {
EmojiPreview(hoarder: hoarder, emoji: emoji)
.onTapGesture {
Task.detached {
try? await hoarder.trie.dict[name]!.downloadImage()
await MainActor.run {
hoarder.trie.dict[name]!.refresh()
}
}
}
}
}
}
}
.navigationTitle("StickerSlack") .navigationTitle("StickerSlack")
.onChange(of: searchTerm) { _ in .onChange(of: hoarder.searchTerm) { _ in
hoarder.filterEmojis(by: searchTerm) hoarder.filterEmojis(by: hoarder.searchTerm)
} }
.refreshable { .refreshable {
Task.detached { Task.detached {
await hoarder.refreshDB() await hoarder.refreshDB()
} }
searchTerm = "" hoarder.searchTerm = ""
} }
} // }
.searchable(text: $searchTerm, placement: .automatic) .searchable(text: $hoarder.searchTerm, placement: .automatic)
} }
} }