mirror of
https://github.com/neon443/StickerSlack.git
synced 2026-03-11 05:19:13 +00:00
updated downloadImage()
- to use cached local version if available - now writes to disk if not already saved rewrote toEmojis() just a simple map of ApiEmoji($0).toEmoji() use the new toEmojis in emojiHoarder now the emojiDB gets stored locally, need to make it fetch it if it can cos cache cant be valid forever yk using neon443/Haptics for haptics lol added a download button on EmojiPreview, if downloaded a lil download icon shows up, and will show that one instead of AsyncImage
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
/* Begin PBXBuildFile section */
|
||||
A924C3722EA9127200F20781 /* Emoji.swift in Sources */ = {isa = PBXBuildFile; fileRef = A924C3712EA9127200F20781 /* Emoji.swift */; };
|
||||
A924C3732EA9127200F20781 /* Emoji.swift in Sources */ = {isa = PBXBuildFile; fileRef = A924C3712EA9127200F20781 /* Emoji.swift */; };
|
||||
A924C3782EA9225800F20781 /* Haptics in Frameworks */ = {isa = PBXBuildFile; productRef = A924C3772EA9225800F20781 /* Haptics */; };
|
||||
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 */; };
|
||||
@@ -77,6 +78,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
A924C3782EA9225800F20781 /* Haptics in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -190,6 +192,7 @@
|
||||
);
|
||||
name = StickerSlack;
|
||||
packageProductDependencies = (
|
||||
A924C3772EA9225800F20781 /* Haptics */,
|
||||
);
|
||||
productName = StickerSlack;
|
||||
productReference = A949B1DF2EA04C0B00215164 /* StickerSlack.app */;
|
||||
@@ -241,6 +244,9 @@
|
||||
);
|
||||
mainGroup = A949B1D62EA04C0B00215164;
|
||||
minimizedProjectReferenceProxies = 1;
|
||||
packageReferences = (
|
||||
A924C3762EA9225800F20781 /* XCLocalSwiftPackageReference "../Haptics" */,
|
||||
);
|
||||
preferredProjectObjectVersion = 77;
|
||||
productRefGroup = A949B1E02EA04C0B00215164 /* Products */;
|
||||
projectDirPath = "";
|
||||
@@ -624,6 +630,20 @@
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCLocalSwiftPackageReference section */
|
||||
A924C3762EA9225800F20781 /* XCLocalSwiftPackageReference "../Haptics" */ = {
|
||||
isa = XCLocalSwiftPackageReference;
|
||||
relativePath = ../Haptics;
|
||||
};
|
||||
/* End XCLocalSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
A924C3772EA9225800F20781 /* Haptics */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = Haptics;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
};
|
||||
rootObject = A949B1D72EA04C0B00215164 /* Project object */;
|
||||
}
|
||||
|
||||
@@ -48,7 +48,6 @@ struct Emoji: Codable, Identifiable, Hashable {
|
||||
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)
|
||||
@@ -58,8 +57,13 @@ struct Emoji: Codable, Identifiable, Hashable {
|
||||
// self.image = UIImage(data: image) ?? UIImage()
|
||||
}
|
||||
|
||||
func loadImage() async throws -> UIImage {
|
||||
func downloadImage() async throws -> UIImage {
|
||||
if let data = try? Data(contentsOf: localImageURL),
|
||||
let uiimage = UIImage(data: data) {
|
||||
return uiimage
|
||||
}
|
||||
let (data, _) = try await URLSession.shared.data(from: remoteImageURL)
|
||||
try! data.write(to: localImageURL)
|
||||
return UIImage(data: data)!
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,20 +12,8 @@ struct SlackResponse: Codable {
|
||||
var imageUrl: String
|
||||
var alias: String?
|
||||
|
||||
// func toEmojis() -> [Emoji] {
|
||||
// let initialMap = emoji.map {
|
||||
// Emoji(name: $0.key, url: $0.value)
|
||||
// }
|
||||
// return initialMap.map {
|
||||
// var ret = $0
|
||||
// if ret.urlString.prefix(6) == "alias:" {
|
||||
// if let orig = initialMap.first(where: {
|
||||
// $0.name == "\(ret.urlString.dropFirst(6))"
|
||||
// }) {
|
||||
// ret.urlString = orig.urlString
|
||||
// }
|
||||
// }
|
||||
// return ret
|
||||
// }
|
||||
// }
|
||||
|
||||
static func toEmojis(from: [SlackResponse]) -> [Emoji] {
|
||||
return from.map { ApiEmoji(name: $0.name, url: $0.imageUrl).toEmoji() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,22 +8,28 @@
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import Combine
|
||||
import UniformTypeIdentifiers
|
||||
|
||||
class EmojiHoarder: ObservableObject {
|
||||
static let container = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.neon443.StickerSlack")!
|
||||
static let container = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.neon443.StickerSlack")!.appendingPathComponent("Library", conformingTo: .directory)
|
||||
static let localEmojiDB: URL = EmojiHoarder.container.appendingPathExtension("localEmojiDB.json")
|
||||
private let endpoint: URL = URL(string: "https://cachet.dunkirk.sh/emojis")!
|
||||
|
||||
@Published var emojis: [Emoji]
|
||||
|
||||
init() {
|
||||
if let localEmojiDB = try? Data(contentsOf: EmojiHoarder.localEmojiDB) {
|
||||
let decoded = try! JSONDecoder().decode([Emoji].self, from: localEmojiDB)
|
||||
self.emojis = decoded
|
||||
return
|
||||
}
|
||||
|
||||
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 { ApiEmoji(name: $0.name, url: $0.imageUrl).toEmoji() }
|
||||
// Task {
|
||||
// for i in emojis.indices {
|
||||
// emojis[i].image = try? await emojis[i].loadImage()
|
||||
// }
|
||||
// }
|
||||
self.emojis = SlackResponse.toEmojis(from: decoded)
|
||||
|
||||
try! JSONEncoder().encode(emojis).write(to: EmojiHoarder.localEmojiDB)
|
||||
}
|
||||
|
||||
// func storeStickers
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Haptics
|
||||
|
||||
struct ContentView: View {
|
||||
@StateObject var hoarder: EmojiHoarder = EmojiHoarder()
|
||||
@@ -15,8 +16,18 @@ struct ContentView: View {
|
||||
TabView {
|
||||
List {
|
||||
ForEach(hoarder.emojis, id: \.self) { emoji in
|
||||
EmojiPreview(emoji: emoji)
|
||||
.frame(maxWidth: 100)
|
||||
HStack {
|
||||
EmojiPreview(emoji: emoji)
|
||||
.frame(maxWidth: 100)
|
||||
Spacer()
|
||||
Button("", systemImage: "arrow.down.circle") {
|
||||
Task {
|
||||
let _ = try? await emoji.downloadImage()
|
||||
Haptic.success.trigger()
|
||||
}
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
}
|
||||
}
|
||||
}
|
||||
.tabItem {
|
||||
|
||||
@@ -6,34 +6,55 @@
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Haptics
|
||||
|
||||
struct EmojiPreview: View {
|
||||
@State var emoji: Emoji
|
||||
|
||||
@State private var id: UUID = UUID()
|
||||
@State private var image: UIImage?
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
Text(emoji.name)
|
||||
if let image = emoji.image {
|
||||
Image(uiImage: image)
|
||||
} else {
|
||||
ProgressView()
|
||||
}
|
||||
AsyncImage(url: emoji.remoteImageURL) { phase in
|
||||
if let image = phase.image {
|
||||
image
|
||||
|
||||
Group {
|
||||
if let localImage = try? Data(contentsOf: emoji.localImageURL),
|
||||
let image = UIImage(data: localImage) {
|
||||
Image(uiImage: image)
|
||||
.resizable().scaledToFit()
|
||||
} else if phase.error != nil {
|
||||
Image(systemName: "xmark.app.fill")
|
||||
.resizable().scaledToFit()
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.foregroundStyle(.red)
|
||||
.onTapGesture {
|
||||
id = UUID()
|
||||
.border(.orange)
|
||||
.overlay(alignment: .bottomLeading) {
|
||||
Image(systemName: "arrow.down.circle.fill")
|
||||
.resizable().scaledToFit()
|
||||
.frame(width: 20, height: 20)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
// .foregroundStyle(.gray)
|
||||
}
|
||||
} else {
|
||||
ProgressView()
|
||||
AsyncImage(url: emoji.remoteImageURL) { phase in
|
||||
if let image = phase.image {
|
||||
image
|
||||
.resizable().scaledToFit()
|
||||
} else if phase.error != nil {
|
||||
Image(systemName: "xmark.app.fill")
|
||||
.resizable().scaledToFit()
|
||||
.padding()
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.foregroundStyle(.red)
|
||||
.onTapGesture {
|
||||
id = UUID()
|
||||
}
|
||||
} else {
|
||||
ProgressView()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.onTapGesture {
|
||||
Task {
|
||||
image = try? await emoji.downloadImage()
|
||||
Haptic.success.trigger()
|
||||
}
|
||||
}
|
||||
.id(id)
|
||||
|
||||
Reference in New Issue
Block a user