mirror of
https://github.com/neon443/StickerSlack.git
synced 2026-03-11 05:19:13 +00:00
adding gifs
added sticker.swift to add a protocol for stickers and an extension that has shared default implementations of functions and computed properties added stickertype enum
This commit is contained in:
@@ -63,6 +63,17 @@
|
||||
A9BBC5182EB8FA4500FFE82F /* ViewModifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BBC5172EB8FA4500FFE82F /* ViewModifiers.swift */; };
|
||||
A9BBC5192EB8FA4500FFE82F /* ViewModifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BBC5172EB8FA4500FFE82F /* ViewModifiers.swift */; };
|
||||
A9BBC51A2EB8FA4500FFE82F /* ViewModifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BBC5172EB8FA4500FFE82F /* ViewModifiers.swift */; };
|
||||
A9BE30EC2F5AFE1E00A57668 /* StickerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BE30EB2F5AFE1E00A57668 /* StickerType.swift */; };
|
||||
A9BE30EF2F5B004800A57668 /* GifHoarder.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BE30EE2F5B004800A57668 /* GifHoarder.swift */; };
|
||||
A9BE30F02F5B004800A57668 /* GifHoarder.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BE30EE2F5B004800A57668 /* GifHoarder.swift */; };
|
||||
A9BE30F22F5B004E00A57668 /* Gif.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BE30F12F5B004E00A57668 /* Gif.swift */; };
|
||||
A9BE30F32F5B004E00A57668 /* Gif.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BE30F12F5B004E00A57668 /* Gif.swift */; };
|
||||
A9BE30F62F5B011A00A57668 /* StickerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BE30F52F5B011A00A57668 /* StickerProtocol.swift */; };
|
||||
A9BE30F72F5B011A00A57668 /* StickerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BE30F52F5B011A00A57668 /* StickerProtocol.swift */; };
|
||||
A9BE30F82F5B02BF00A57668 /* StickerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BE30F52F5B011A00A57668 /* StickerProtocol.swift */; };
|
||||
A9BE30FA2F5B03F400A57668 /* Sticker.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BE30F92F5B03F400A57668 /* Sticker.swift */; };
|
||||
A9BE30FB2F5B03F400A57668 /* Sticker.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BE30F92F5B03F400A57668 /* Sticker.swift */; };
|
||||
A9BE30FC2F5B03F400A57668 /* Sticker.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BE30F92F5B03F400A57668 /* Sticker.swift */; };
|
||||
A9C172DC2EB8C9AC008A7885 /* Trie.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C172DB2EB8C9AC008A7885 /* Trie.swift */; };
|
||||
A9C172DD2EB8C9AC008A7885 /* Trie.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C172DB2EB8C9AC008A7885 /* Trie.swift */; };
|
||||
A9CD6C352EDDE22800B7F421 /* EmojiPackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9CD6C342EDDE22800B7F421 /* EmojiPackView.swift */; };
|
||||
@@ -148,6 +159,11 @@
|
||||
A9B9A8232EB2CCB5004C9245 /* StickerSlackTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = StickerSlackTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
A9B9A82C2EB2CCBE004C9245 /* StickerSlackTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StickerSlackTests.swift; sourceTree = "<group>"; };
|
||||
A9BBC5172EB8FA4500FFE82F /* ViewModifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewModifiers.swift; sourceTree = "<group>"; };
|
||||
A9BE30EB2F5AFE1E00A57668 /* StickerType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StickerType.swift; sourceTree = "<group>"; };
|
||||
A9BE30EE2F5B004800A57668 /* GifHoarder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GifHoarder.swift; sourceTree = "<group>"; };
|
||||
A9BE30F12F5B004E00A57668 /* Gif.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gif.swift; sourceTree = "<group>"; };
|
||||
A9BE30F52F5B011A00A57668 /* StickerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StickerProtocol.swift; sourceTree = "<group>"; };
|
||||
A9BE30F92F5B03F400A57668 /* Sticker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sticker.swift; sourceTree = "<group>"; };
|
||||
A9C172DB2EB8C9AC008A7885 /* Trie.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Trie.swift; sourceTree = "<group>"; };
|
||||
A9CD6C342EDDE22800B7F421 /* EmojiPackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiPackView.swift; sourceTree = "<group>"; };
|
||||
A9CD6C372EDDE37500B7F421 /* EmojiPackManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiPackManager.swift; sourceTree = "<group>"; };
|
||||
@@ -295,6 +311,9 @@
|
||||
children = (
|
||||
A924C3742EA9134C00F20781 /* StickerSlack.entitlements */,
|
||||
A949B1F12EA04E8200215164 /* StickerSlackApp.swift */,
|
||||
A9BE30EB2F5AFE1E00A57668 /* StickerType.swift */,
|
||||
A9BE30F42F5B011400A57668 /* Stickers */,
|
||||
A9BE30ED2F5B003A00A57668 /* Gifs */,
|
||||
A949B1F92EA0517800215164 /* Emoji */,
|
||||
A91C09892EBBD75A00210C34 /* Trie */,
|
||||
A9104C812EB4022E00D160EA /* Extensions */,
|
||||
@@ -347,6 +366,24 @@
|
||||
path = StickerSlackTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A9BE30ED2F5B003A00A57668 /* Gifs */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A9BE30F12F5B004E00A57668 /* Gif.swift */,
|
||||
A9BE30EE2F5B004800A57668 /* GifHoarder.swift */,
|
||||
);
|
||||
path = Gifs;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A9BE30F42F5B011400A57668 /* Stickers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A9BE30F52F5B011A00A57668 /* StickerProtocol.swift */,
|
||||
A9BE30F92F5B03F400A57668 /* Sticker.swift */,
|
||||
);
|
||||
path = Stickers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@@ -515,12 +552,17 @@
|
||||
A9EB724F2EB94A6B00658CEB /* TrieTestingView.swift in Sources */,
|
||||
A924C3732EA9127200F20781 /* Emoji.swift in Sources */,
|
||||
A9D15B8B2EB1142C00404792 /* EmojiPack.swift in Sources */,
|
||||
A9BE30FB2F5B03F400A57668 /* Sticker.swift in Sources */,
|
||||
A9BE30F62F5B011A00A57668 /* StickerProtocol.swift in Sources */,
|
||||
A921C2DF2ED067BB00E57B1A /* WelcomeView.swift in Sources */,
|
||||
A949B1F82EA04F2300215164 /* EmojiHoarder.swift in Sources */,
|
||||
A9BBC5182EB8FA4500FFE82F /* ViewModifiers.swift in Sources */,
|
||||
A9EB72492EB948C400658CEB /* EmojiRow.swift in Sources */,
|
||||
A921C2E22ED071C900E57B1A /* ListRow.swift in Sources */,
|
||||
A9773C2F2EA54AF000F3B753 /* EmojiPreview.swift in Sources */,
|
||||
A9BE30F02F5B004800A57668 /* GifHoarder.swift in Sources */,
|
||||
A9BE30F22F5B004E00A57668 /* Gif.swift in Sources */,
|
||||
A9BE30EC2F5AFE1E00A57668 /* StickerType.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -529,9 +571,11 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
A957C17B2ECE542D00EA3EE9 /* GifManager.swift in Sources */,
|
||||
A9BE30F82F5B02BF00A57668 /* StickerProtocol.swift in Sources */,
|
||||
A986A6C32EB6598100B6E0FA /* FilterCategory.swift in Sources */,
|
||||
A9CD6C3A2EDDE6B500B7F421 /* EmojiPack.swift in Sources */,
|
||||
A9EB724B2EB94A5700658CEB /* Trie.swift in Sources */,
|
||||
A9BE30FA2F5B03F400A57668 /* Sticker.swift in Sources */,
|
||||
A986A6CD2EB659E000B6E0FA /* MessagesViewController.swift in Sources */,
|
||||
A986A6CE2EB659E000B6E0FA /* StickerBrowserDataSource.swift in Sources */,
|
||||
A957C17E2ECFAA1100EA3EE9 /* GifView.swift in Sources */,
|
||||
@@ -550,9 +594,12 @@
|
||||
A9104C7F2EB4022500D160EA /* MSSticker.swift in Sources */,
|
||||
A9B9A8302EB2CD0B004C9245 /* Emoji.swift in Sources */,
|
||||
A955B3F12EC22E9700E1732D /* BrowseView.swift in Sources */,
|
||||
A9BE30F72F5B011A00A57668 /* StickerProtocol.swift in Sources */,
|
||||
A9BE30FC2F5B03F400A57668 /* Sticker.swift in Sources */,
|
||||
A9B9A82F2EB2CCED004C9245 /* EmojiHoarder.swift in Sources */,
|
||||
A9CD6C3B2EDDE6B500B7F421 /* EmojiPack.swift in Sources */,
|
||||
A921C2E32ED071C900E57B1A /* ListRow.swift in Sources */,
|
||||
A9BE30EF2F5B004800A57668 /* GifHoarder.swift in Sources */,
|
||||
A9EB724A2EB948E000658CEB /* EmojiCollectionView.swift in Sources */,
|
||||
A9EB724D2EB94A6B00658CEB /* TrieTestingView.swift in Sources */,
|
||||
A9BBC51A2EB8FA4500FFE82F /* ViewModifiers.swift in Sources */,
|
||||
@@ -567,6 +614,7 @@
|
||||
A957C1782ECD008E00EA3EE9 /* Bundle.swift in Sources */,
|
||||
A921C2E02ED067BB00E57B1A /* WelcomeView.swift in Sources */,
|
||||
A9B9A82E2EB2CCBE004C9245 /* StickerSlackTests.swift in Sources */,
|
||||
A9BE30F32F5B004E00A57668 /* Gif.swift in Sources */,
|
||||
A9B9A8312EB2CD14004C9245 /* FilterCategory.swift in Sources */,
|
||||
A957C1802ECFAA1100EA3EE9 /* GifView.swift in Sources */,
|
||||
A9EB72502EB94FAD00658CEB /* EmojiPreview.swift in Sources */,
|
||||
|
||||
@@ -11,7 +11,7 @@ import SwiftUI
|
||||
import Messages
|
||||
import UniformTypeIdentifiers
|
||||
|
||||
struct Emoji: Codable, Identifiable, Hashable {
|
||||
struct Emoji: StickerProtocol {
|
||||
var id: UUID
|
||||
var uiID: UUID
|
||||
var name: String
|
||||
@@ -21,31 +21,8 @@ struct Emoji: Codable, Identifiable, Hashable {
|
||||
let fileExtension = ".\(split.last ?? "png")"
|
||||
return EmojiHoarder.container.absoluteString+id.uuidString+fileExtension
|
||||
}
|
||||
var localImageURL: URL {
|
||||
return URL(string: localImageURLString)!
|
||||
}
|
||||
var remoteImageURL: URL
|
||||
|
||||
var isLocal: Bool {
|
||||
return (try? Data(contentsOf: localImageURL)) != nil
|
||||
}
|
||||
|
||||
var sticker: MSSticker? {
|
||||
guard isLocal else {
|
||||
return nil
|
||||
}
|
||||
return try? MSSticker(contentsOfFileURL: localImageURL, localizedDescription: name)
|
||||
}
|
||||
|
||||
var image: UIImage? {
|
||||
if let data = try? Data(contentsOf: localImageURL),
|
||||
let img = UIImage(data: data) {
|
||||
return img
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id = "id"
|
||||
case name = "name"
|
||||
@@ -90,47 +67,11 @@ struct Emoji: Codable, Identifiable, Hashable {
|
||||
return
|
||||
}
|
||||
|
||||
func deleteImage() {
|
||||
try? FileManager.default.removeItem(at: localImageURL)
|
||||
return
|
||||
}
|
||||
|
||||
@MainActor
|
||||
mutating func refresh() {
|
||||
withAnimation { self.uiID = UUID() }
|
||||
}
|
||||
|
||||
func resize(image: UIImage, to targetSize: CGSize) -> UIImage {
|
||||
let oldSize = image.size
|
||||
let ratio: (x: CGFloat, y: CGFloat)
|
||||
ratio.x = targetSize.width / oldSize.width
|
||||
ratio.y = targetSize.height / oldSize.height
|
||||
|
||||
var newSize: CGSize
|
||||
if ratio.x > ratio.y {
|
||||
newSize = CGSize(width: oldSize.width * ratio.y, height: oldSize.height * ratio.y)
|
||||
} else {
|
||||
newSize = CGSize(width: oldSize.width * ratio.x, height: oldSize.height * ratio.x)
|
||||
}
|
||||
|
||||
let rect = CGRect(origin: .zero, size: newSize)
|
||||
|
||||
if let frames = image.images {
|
||||
var result: [UIImage] = []
|
||||
for frame in frames {
|
||||
UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
|
||||
frame.draw(in: rect)
|
||||
result.append(UIGraphicsGetImageFromCurrentImageContext() ?? UIImage())
|
||||
UIGraphicsEndImageContext()
|
||||
}
|
||||
return UIImage.animatedImage(with: result, duration: image.duration) ?? UIImage()
|
||||
}
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
|
||||
image.draw(in: rect)
|
||||
return UIGraphicsGetImageFromCurrentImageContext() ?? UIImage()
|
||||
}
|
||||
|
||||
static var test: Emoji = Emoji(
|
||||
name: "s?",
|
||||
url: URL(string: "https://neon443.github.io/images/fav.ico")!
|
||||
|
||||
25
StickerSlack/Gifs/Gif.swift
Normal file
25
StickerSlack/Gifs/Gif.swift
Normal file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// Gif.swift
|
||||
// StickerSlack
|
||||
//
|
||||
// Created by neon443 on 06/03/2026.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
//struct Gif: StickerProtocol {
|
||||
// var id: UUID
|
||||
// var uiID: UUID
|
||||
// var name: String
|
||||
// var localImageURLString: String {
|
||||
//
|
||||
// }
|
||||
// var localImageURL: URL {
|
||||
// return URL(string: localImageURLString)!
|
||||
// }
|
||||
// var remoteImageURL: URL
|
||||
//
|
||||
// var isLocal: Bool {
|
||||
//
|
||||
// }
|
||||
//}
|
||||
8
StickerSlack/Gifs/GifHoarder.swift
Normal file
8
StickerSlack/Gifs/GifHoarder.swift
Normal file
@@ -0,0 +1,8 @@
|
||||
//
|
||||
// GifHoarder.swift
|
||||
// StickerSlack
|
||||
//
|
||||
// Created by neon443 on 06/03/2026.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
24
StickerSlack/StickerType.swift
Normal file
24
StickerSlack/StickerType.swift
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// StickerType.swift
|
||||
// StickerSlack
|
||||
//
|
||||
// Created by neon443 on 06/03/2026.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum StickerType: CustomStringConvertible, CaseIterable, Identifiable {
|
||||
case slackEmoji
|
||||
case giphyGif
|
||||
|
||||
var id: String { self.description }
|
||||
|
||||
var description: String {
|
||||
switch self {
|
||||
case .slackEmoji:
|
||||
return "Slack Emoji"
|
||||
case .giphyGif:
|
||||
return "Giphy GIF"
|
||||
}
|
||||
}
|
||||
}
|
||||
71
StickerSlack/Stickers/Sticker.swift
Normal file
71
StickerSlack/Stickers/Sticker.swift
Normal file
@@ -0,0 +1,71 @@
|
||||
//
|
||||
// Sticker.swift
|
||||
// StickerSlack
|
||||
//
|
||||
// Created by neon443 on 06/03/2026.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Messages
|
||||
|
||||
extension StickerProtocol {
|
||||
var localImageURL: URL {
|
||||
return URL(string: localImageURLString)!
|
||||
}
|
||||
|
||||
var isLocal: Bool {
|
||||
return (try? Data(contentsOf: localImageURL)) != nil
|
||||
}
|
||||
|
||||
var msSticker: MSSticker? {
|
||||
guard isLocal else {
|
||||
return nil
|
||||
}
|
||||
return try? MSSticker(contentsOfFileURL: localImageURL, localizedDescription: name)
|
||||
}
|
||||
|
||||
var image: UIImage? {
|
||||
if let data = try? Data(contentsOf: localImageURL),
|
||||
let img = UIImage(data: data) {
|
||||
return img
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func deleteImage() {
|
||||
try? FileManager.default.removeItem(at: localImageURL)
|
||||
return
|
||||
}
|
||||
|
||||
func resize(image: UIImage, to targetSize: CGSize) -> UIImage {
|
||||
let oldSize = image.size
|
||||
let ratio: (x: CGFloat, y: CGFloat)
|
||||
ratio.x = targetSize.width / oldSize.width
|
||||
ratio.y = targetSize.height / oldSize.height
|
||||
|
||||
var newSize: CGSize
|
||||
if ratio.x > ratio.y {
|
||||
newSize = CGSize(width: oldSize.width * ratio.y, height: oldSize.height * ratio.y)
|
||||
} else {
|
||||
newSize = CGSize(width: oldSize.width * ratio.x, height: oldSize.height * ratio.x)
|
||||
}
|
||||
|
||||
let rect = CGRect(origin: .zero, size: newSize)
|
||||
|
||||
if let frames = image.images {
|
||||
var result: [UIImage] = []
|
||||
for frame in frames {
|
||||
UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
|
||||
frame.draw(in: rect)
|
||||
result.append(UIGraphicsGetImageFromCurrentImageContext() ?? UIImage())
|
||||
UIGraphicsEndImageContext()
|
||||
}
|
||||
return UIImage.animatedImage(with: result, duration: image.duration) ?? UIImage()
|
||||
}
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
|
||||
image.draw(in: rect)
|
||||
return UIGraphicsGetImageFromCurrentImageContext() ?? UIImage()
|
||||
}
|
||||
}
|
||||
30
StickerSlack/Stickers/StickerProtocol.swift
Normal file
30
StickerSlack/Stickers/StickerProtocol.swift
Normal file
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// StickerProtocol.swift
|
||||
// StickerSlack
|
||||
//
|
||||
// Created by neon443 on 06/03/2026.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Messages
|
||||
|
||||
protocol StickerProtocol: Codable, Identifiable, Hashable {
|
||||
var id: UUID { get set }
|
||||
var uiID: UUID { get set }
|
||||
var name: String { get set }
|
||||
|
||||
var localImageURL: URL { get }
|
||||
var localImageURLString: String { get }
|
||||
var remoteImageURL: URL { get set }
|
||||
|
||||
var isLocal: Bool { get }
|
||||
|
||||
var msSticker: MSSticker? { get }
|
||||
var image: UIImage? { get }
|
||||
|
||||
func downloadImage() async throws
|
||||
func deleteImage()
|
||||
mutating func refresh()
|
||||
func resize(image: UIImage, to targetSize: CGSize) -> UIImage
|
||||
static var test: Self { get }
|
||||
}
|
||||
@@ -12,6 +12,12 @@ struct BrowseView: View {
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
Picker("", selection: .constant(StickerType.giphyGif)) {
|
||||
ForEach(StickerType.allCases, id: \.self) { type in
|
||||
Text(type.description)
|
||||
}
|
||||
}
|
||||
.pickerStyle(.segmented)
|
||||
ForEach(hoarder.emojis, id: \.self) { emoji in
|
||||
EmojiRow(hoarder: hoarder, emoji: emoji)
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import Haptics
|
||||
|
||||
struct ContentView: View {
|
||||
@ObservedObject var hoarder: EmojiHoarder = EmojiHoarder()
|
||||
// @ObservedObject var hoarder: = EmojiHoarder()
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
|
||||
@@ -16,7 +16,7 @@ class StickerBrowserDataSource: NSObject, MSStickerBrowserViewDataSource {
|
||||
func numberOfStickers(in stickerBrowserView: MSStickerBrowserView) -> Int {
|
||||
guard emojis.isEmpty else { return emojis.count }
|
||||
for emoji in hoarder.emojis {
|
||||
guard let sticker = emoji.sticker else { continue }
|
||||
guard let sticker = emoji.msSticker else { continue }
|
||||
emojis.append(sticker)
|
||||
}
|
||||
return emojis.count
|
||||
|
||||
Reference in New Issue
Block a user