mirror of
https://github.com/neon443/StickerSlack.git
synced 2026-03-11 05:19:13 +00:00
add welcome view with how to use steps
add listrow for reusability added stats like total, downloaded emojis added letterstats to count how many emojis there are starting with each letter fix lag when opening settigns cos we were initing a new hoarder in trietestingview fix downloaded view using screen width instead of window width now its good on mac and ipad split screen added designed for ipad support
This commit is contained in:
@@ -14,6 +14,8 @@
|
||||
A9104C7C2EB3AE6300D160EA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A949B1EF2EA04E8200215164 /* Assets.xcassets */; };
|
||||
A9104C7F2EB4022500D160EA /* MSSticker.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9104C7D2EB4022500D160EA /* MSSticker.swift */; };
|
||||
A9104C802EB4022500D160EA /* MSSticker.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9104C7D2EB4022500D160EA /* MSSticker.swift */; };
|
||||
A921C2DF2ED067BB00E57B1A /* WelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A921C2DE2ED067BB00E57B1A /* WelcomeView.swift */; };
|
||||
A921C2E02ED067BB00E57B1A /* WelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A921C2DE2ED067BB00E57B1A /* WelcomeView.swift */; };
|
||||
A924C3732EA9127200F20781 /* Emoji.swift in Sources */ = {isa = PBXBuildFile; fileRef = A924C3712EA9127200F20781 /* Emoji.swift */; };
|
||||
A924C3782EA9225800F20781 /* Haptics in Frameworks */ = {isa = PBXBuildFile; productRef = A924C3772EA9225800F20781 /* Haptics */; };
|
||||
A931D4082EBC9646007BC75B /* Haptics in Frameworks */ = {isa = PBXBuildFile; productRef = A931D4072EBC9646007BC75B /* Haptics */; };
|
||||
@@ -107,6 +109,7 @@
|
||||
A9104C722EB3AE4700D160EA /* Icon.pxd */ = {isa = PBXFileReference; lastKnownFileType = file; path = Icon.pxd; sourceTree = "<group>"; };
|
||||
A9104C732EB3AE4700D160EA /* StickerSlack.icon */ = {isa = PBXFileReference; lastKnownFileType = folder.iconcomposer.icon; path = StickerSlack.icon; sourceTree = "<group>"; };
|
||||
A9104C7D2EB4022500D160EA /* MSSticker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSSticker.swift; sourceTree = "<group>"; };
|
||||
A921C2DE2ED067BB00E57B1A /* WelcomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeView.swift; sourceTree = "<group>"; };
|
||||
A924C3712EA9127200F20781 /* Emoji.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Emoji.swift; sourceTree = "<group>"; };
|
||||
A924C3742EA9134C00F20781 /* StickerSlack.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = StickerSlack.entitlements; sourceTree = "<group>"; };
|
||||
A935437A2EB2A3C800BB80A4 /* FilterCategory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterCategory.swift; sourceTree = "<group>"; };
|
||||
@@ -237,6 +240,7 @@
|
||||
A955B3F02EC22E9700E1732D /* BrowseView.swift */,
|
||||
A955B3F42EC22EE900E1732D /* SearchView.swift */,
|
||||
A957C1732ECCE2CE00EA3EE9 /* SettingsView.swift */,
|
||||
A921C2DE2ED067BB00E57B1A /* WelcomeView.swift */,
|
||||
);
|
||||
path = SwiftUI;
|
||||
sourceTree = "<group>";
|
||||
@@ -495,6 +499,7 @@
|
||||
A9EB724F2EB94A6B00658CEB /* TrieTestingView.swift in Sources */,
|
||||
A924C3732EA9127200F20781 /* Emoji.swift in Sources */,
|
||||
A9D15B8B2EB1142C00404792 /* EmojiPack.swift in Sources */,
|
||||
A921C2DF2ED067BB00E57B1A /* WelcomeView.swift in Sources */,
|
||||
A949B1F82EA04F2300215164 /* EmojiHoarder.swift in Sources */,
|
||||
A9BBC5182EB8FA4500FFE82F /* ViewModifiers.swift in Sources */,
|
||||
A9EB72492EB948C400658CEB /* EmojiRow.swift in Sources */,
|
||||
@@ -538,6 +543,7 @@
|
||||
A955B3F62EC22EE900E1732D /* SearchView.swift in Sources */,
|
||||
A9B9A8322EB2CD29004C9245 /* SlackResponse.swift in Sources */,
|
||||
A957C1782ECD008E00EA3EE9 /* Bundle.swift in Sources */,
|
||||
A921C2E02ED067BB00E57B1A /* WelcomeView.swift in Sources */,
|
||||
A9B9A82E2EB2CCBE004C9245 /* StickerSlackTests.swift in Sources */,
|
||||
A9B9A8312EB2CD14004C9245 /* FilterCategory.swift in Sources */,
|
||||
A957C1802ECFAA1100EA3EE9 /* GifView.swift in Sources */,
|
||||
@@ -727,6 +733,7 @@
|
||||
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator xros xrsimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
|
||||
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||
SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
@@ -774,6 +781,7 @@
|
||||
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator xros xrsimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
|
||||
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||
SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
|
||||
@@ -26,8 +26,13 @@ class EmojiHoarder: ObservableObject {
|
||||
@Published var downloadedEmojis: Set<String> = []
|
||||
@Published var downloadedEmojisArr: [String] = []
|
||||
@Published var searchTerm: String = ""
|
||||
@Published var letterStats: [EmojiHoarder.LetterStat] = []
|
||||
|
||||
@Published var showWelcome: Bool = true
|
||||
|
||||
init(localOnly: Bool = false, skipIndex: Bool = false) {
|
||||
self.showWelcome = !UserDefaults.standard.bool(forKey: "showWelcome")
|
||||
|
||||
let localDB = loadLocalDB()
|
||||
withAnimation { self.emojis = localDB }
|
||||
loadTrie()
|
||||
@@ -196,6 +201,26 @@ class EmojiHoarder: ObservableObject {
|
||||
Haptic.heavy.trigger()
|
||||
}
|
||||
|
||||
func setShowWelcome(to newValue: Bool) {
|
||||
UserDefaults.standard.set(!newValue, forKey: "shownWelcome")
|
||||
self.showWelcome = newValue
|
||||
}
|
||||
|
||||
func generateLetterStats() -> [EmojiHoarder.LetterStat] {
|
||||
var result: [EmojiHoarder.LetterStat] = []
|
||||
for child in trie.root.children {
|
||||
let count = trie.collectWords(startingWith: child.key, from: child.value).count
|
||||
let stat = LetterStat(char: child.key, count: count)
|
||||
result.append(stat)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
struct LetterStat: Hashable {
|
||||
var char: String
|
||||
var count: Int
|
||||
}
|
||||
|
||||
// func filterEmojis(byCategory category: FilterCategory, searchTerm: String) {
|
||||
// guard category != .none else {
|
||||
// filterEmojis(by: searchTerm)
|
||||
|
||||
@@ -12,40 +12,48 @@ struct ContentView: View {
|
||||
@ObservedObject var hoarder: EmojiHoarder = EmojiHoarder()
|
||||
|
||||
var body: some View {
|
||||
if #available(iOS 18, *) {
|
||||
TabView {
|
||||
Tab("Browse", systemImage: "square.grid.2x2.fill") {
|
||||
BrowseView(hoarder: hoarder)
|
||||
Group {
|
||||
if #available(iOS 18, *) {
|
||||
TabView {
|
||||
Tab("Browse", systemImage: "square.grid.2x2.fill") {
|
||||
BrowseView(hoarder: hoarder)
|
||||
}
|
||||
|
||||
Tab("Downloaded", systemImage: "arrow.down.circle.fill") {
|
||||
DownloadedView(hoarder: hoarder)
|
||||
}
|
||||
|
||||
Tab("Settings", systemImage: "gear") {
|
||||
SettingsView(hoarder: hoarder)
|
||||
}
|
||||
|
||||
Tab(role: .search) {
|
||||
SearchView(hoarder: hoarder)
|
||||
}
|
||||
}
|
||||
|
||||
Tab("Downloaded", systemImage: "arrow.down.circle.fill") {
|
||||
} else {
|
||||
TabView {
|
||||
DownloadedView(hoarder: hoarder)
|
||||
}
|
||||
|
||||
Tab("Settings", systemImage: "gear") {
|
||||
SettingsView(hoarder: hoarder)
|
||||
}
|
||||
|
||||
Tab(role: .search) {
|
||||
.tabItem {
|
||||
Label("Downloaded", systemImage: "arrow.down.circle.fill")
|
||||
}
|
||||
BrowseView(hoarder: hoarder)
|
||||
.tabItem {
|
||||
Label("Browse", systemImage: "square.grid.2x2.fill")
|
||||
}
|
||||
SearchView(hoarder: hoarder)
|
||||
.tabItem {
|
||||
Label("Search", systemImage: "magnifyingglass")
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
TabView {
|
||||
DownloadedView(hoarder: hoarder)
|
||||
.tabItem {
|
||||
Label("Downloaded", systemImage: "arrow.down.circle.fill")
|
||||
}
|
||||
BrowseView(hoarder: hoarder)
|
||||
.tabItem {
|
||||
Label("Browse", systemImage: "square.grid.2x2.fill")
|
||||
}
|
||||
SearchView(hoarder: hoarder)
|
||||
.tabItem {
|
||||
Label("Search", systemImage: "magnifyingglass")
|
||||
}
|
||||
}
|
||||
}
|
||||
.sheet(isPresented: $hoarder.showWelcome) {
|
||||
print("hi")
|
||||
} content: {
|
||||
WelcomeView()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,40 +24,42 @@ struct DownloadedView: View {
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ScrollView {
|
||||
let columns: Int = max(1, Int((UIScreen.main.bounds.width - 2*spacing) / (minColWidth + spacing)))
|
||||
let layout = Array(repeating: col, count: columns)
|
||||
LazyVGrid(columns: layout, spacing: spacing) {
|
||||
ForEach(hoarder.downloadedEmojisArr, id: \.self) { name in
|
||||
if let emoji = hoarder.trie.dict[name] {
|
||||
ZStack {
|
||||
Rectangle()
|
||||
.foregroundStyle(isDark ? .black : .white)
|
||||
EmojiPreview(hoarder: hoarder, emoji: emoji)
|
||||
RoundedRectangle(cornerRadius: 15)
|
||||
.stroke(.gray, lineWidth: 1)
|
||||
}
|
||||
.aspectRatio(1, contentMode: .fit)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 15))
|
||||
.contextMenu {
|
||||
Text(emoji.name)
|
||||
Button("Copy Name", systemImage: "doc.on.clipboard") {
|
||||
UIPasteboard.general.string = emoji.name
|
||||
GeometryReader { geo in
|
||||
ScrollView {
|
||||
let columns: Int = max(1, Int((geo.size.width - 2*spacing) / (minColWidth + spacing)))
|
||||
let layout = Array(repeating: col, count: columns)
|
||||
LazyVGrid(columns: layout, spacing: spacing) {
|
||||
ForEach(hoarder.downloadedEmojisArr, id: \.self) { name in
|
||||
if let emoji = hoarder.trie.dict[name] {
|
||||
ZStack {
|
||||
Rectangle()
|
||||
.foregroundStyle(isDark ? .black : .white)
|
||||
EmojiPreview(hoarder: hoarder, emoji: emoji)
|
||||
RoundedRectangle(cornerRadius: 15)
|
||||
.stroke(.gray, lineWidth: 1)
|
||||
}
|
||||
Button("Copy Image", systemImage: "photo.fill.on.rectangle.fill") {
|
||||
UIPasteboard.general.image = emoji.image
|
||||
}
|
||||
Divider()
|
||||
ShareLink("Share", item: emoji.remoteImageURL, subject: nil, message: nil)
|
||||
Divider()
|
||||
Button("Delete", systemImage: "trash.fill", role: .destructive) {
|
||||
hoarder.delete(emoji: emoji)
|
||||
.aspectRatio(1, contentMode: .fit)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 15))
|
||||
.contextMenu {
|
||||
Text(emoji.name)
|
||||
Button("Copy Name", systemImage: "doc.on.clipboard") {
|
||||
UIPasteboard.general.string = emoji.name
|
||||
}
|
||||
Button("Copy Image", systemImage: "photo.fill.on.rectangle.fill") {
|
||||
UIPasteboard.general.image = emoji.image
|
||||
}
|
||||
Divider()
|
||||
ShareLink("Share", item: emoji.remoteImageURL, subject: nil, message: nil)
|
||||
Divider()
|
||||
Button("Delete", systemImage: "trash.fill", role: .destructive) {
|
||||
hoarder.delete(emoji: emoji)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, spacing)
|
||||
}
|
||||
.padding(.horizontal, spacing)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,16 +25,36 @@ struct SettingsView: View {
|
||||
.font(.title)
|
||||
.monospaced()
|
||||
.bold()
|
||||
HStack(alignment: .center, spacing: 5) {
|
||||
Text(Bundle.main.appVersion)
|
||||
.bold()
|
||||
Text(Bundle.main.appBuild)
|
||||
.foregroundStyle(.gray)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Section {
|
||||
Text("")
|
||||
Text("\(hoarder.emojis.count) total Emoji")
|
||||
Text("\(hoarder.downloadedEmojis.count) downloaded Emoji")
|
||||
NavigationLink {
|
||||
List {
|
||||
ForEach(hoarder.generateLetterStats(), id: \.self) { stat in
|
||||
Text("\(stat.count) Emoji starting with \(stat.char)")
|
||||
}
|
||||
}
|
||||
} label: {
|
||||
Label("Letter Stats", systemImage: "textformat")
|
||||
}
|
||||
}
|
||||
|
||||
Button("Show Welcome", systemImage: "arrow.trianglehead.clockwise") {
|
||||
hoarder.setShowWelcome(to: true)
|
||||
}
|
||||
|
||||
Section("Debug") {
|
||||
NavigationLink {
|
||||
TrieTestingView()
|
||||
TrieTestingView(hoarder: hoarder)
|
||||
} label: {
|
||||
Label("Tree", systemImage: "tree")
|
||||
}
|
||||
|
||||
49
StickerSlack/SwiftUI/WelcomeView.swift
Normal file
49
StickerSlack/SwiftUI/WelcomeView.swift
Normal file
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// WelcomeView.swift
|
||||
// StickerSlack
|
||||
//
|
||||
// Created by neon443 on 21/11/2025.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct WelcomeView: View {
|
||||
var body: some View {
|
||||
VStack {
|
||||
Text("StickerSlack")
|
||||
.bold()
|
||||
.font(.title)
|
||||
.monospaced()
|
||||
.padding()
|
||||
List {
|
||||
Section("How to use") {
|
||||
ListRow(number: 1, text: "Browse or search for an emoji")
|
||||
ListRow(number: 2, text: "Download it")
|
||||
ListRow(number: 3, text: "Open iMessage")
|
||||
ListRow(number: 4, text: "Press the +")
|
||||
ListRow(number: 5, text: "Choose StickerSlack")
|
||||
ListRow(number: 6, text: "Tap an emoji to use it!")
|
||||
}
|
||||
}
|
||||
.scrollContentBackground(.hidden)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ListRow: View {
|
||||
@State var number: Int
|
||||
@State var text: String
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
Text("\(number)")
|
||||
.padding(.trailing, 10)
|
||||
.foregroundStyle(.gray)
|
||||
Text(text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
WelcomeView()
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
import SwiftUI
|
||||
|
||||
struct TrieTestingView: View {
|
||||
@ObservedObject var hoarder: EmojiHoarder = EmojiHoarder(localOnly: true)
|
||||
@ObservedObject var hoarder: EmojiHoarder
|
||||
|
||||
@State var searchTerm: String = ""
|
||||
@State var searchStatus: Bool? = nil
|
||||
@@ -99,5 +99,5 @@ struct TrieNodeView: View {
|
||||
}
|
||||
|
||||
#Preview {
|
||||
TrieTestingView()
|
||||
TrieTestingView(hoarder: EmojiHoarder(localOnly: true))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user