mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2024-11-26 02:01:02 +00:00
Make categorized emoji picker (#1680)
Signed-off-by: Euigyom Kim <egkim@dehol.kr>
This commit is contained in:
parent
1e35ffb82b
commit
d3b52b3206
4 changed files with 64 additions and 23 deletions
|
@ -13,4 +13,5 @@ public struct Emoji: Codable, Hashable, Identifiable, Equatable, Sendable {
|
||||||
public let url: URL
|
public let url: URL
|
||||||
public let staticUrl: URL
|
public let staticUrl: URL
|
||||||
public let visibleInPicker: Bool
|
public let visibleInPicker: Bool
|
||||||
|
public let category: String?
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,7 +120,7 @@ struct StatusEditorAccessoryView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !viewModel.customEmojis.isEmpty {
|
if !viewModel.customEmojiContainer.isEmpty {
|
||||||
Button {
|
Button {
|
||||||
isCustomEmojisSheetDisplay = true
|
isCustomEmojisSheetDisplay = true
|
||||||
} label: {
|
} label: {
|
||||||
|
@ -283,29 +283,37 @@ struct StatusEditorAccessoryView: View {
|
||||||
private var customEmojisSheet: some View {
|
private var customEmojisSheet: some View {
|
||||||
NavigationStack {
|
NavigationStack {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
LazyVGrid(columns: [GridItem(.adaptive(minimum: 40))], spacing: 9) {
|
ForEach(viewModel.customEmojiContainer) { container in
|
||||||
ForEach(viewModel.customEmojis) { emoji in
|
VStack(alignment: .leading) {
|
||||||
LazyImage(url: emoji.url) { state in
|
Text(container.categoryName)
|
||||||
if let image = state.image {
|
.font(.scaledFootnote)
|
||||||
image
|
LazyVGrid(columns: [GridItem(.adaptive(minimum: 40))], spacing: 9) {
|
||||||
.resizable()
|
ForEach(container.emojis) { emoji in
|
||||||
.aspectRatio(contentMode: .fill)
|
LazyImage(url: emoji.url) { state in
|
||||||
.frame(width: 40, height: 40)
|
if let image = state.image {
|
||||||
.accessibilityLabel(emoji.shortcode.replacingOccurrences(of: "_", with: " "))
|
image
|
||||||
.accessibilityAddTraits(.isButton)
|
.resizable()
|
||||||
} else if state.isLoading {
|
.aspectRatio(contentMode: .fill)
|
||||||
Rectangle()
|
.frame(width: 40, height: 40)
|
||||||
.fill(Color.gray)
|
.accessibilityLabel(emoji.shortcode.replacingOccurrences(of: "_", with: " "))
|
||||||
.frame(width: 40, height: 40)
|
.accessibilityAddTraits(.isButton)
|
||||||
.accessibility(hidden: true)
|
} else if state.isLoading {
|
||||||
.shimmering()
|
Rectangle()
|
||||||
|
.fill(Color.gray)
|
||||||
|
.frame(width: 40, height: 40)
|
||||||
|
.accessibility(hidden: true)
|
||||||
|
.shimmering()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.onTapGesture {
|
||||||
|
viewModel.insertStatusText(text: " :\(emoji.shortcode): ")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onTapGesture {
|
|
||||||
viewModel.insertStatusText(text: " :\(emoji.shortcode): ")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
|
.padding(.bottom)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.toolbar {
|
.toolbar {
|
||||||
ToolbarItem(placement: .navigationBarLeading) {
|
ToolbarItem(placement: .navigationBarLeading) {
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
import Foundation
|
||||||
|
import Models
|
||||||
|
|
||||||
|
struct StatusEditorCategorizedEmojiContainer: Identifiable, Equatable {
|
||||||
|
let id = UUID().uuidString
|
||||||
|
let categoryName: String
|
||||||
|
var emojis: [Emoji]
|
||||||
|
}
|
|
@ -100,7 +100,7 @@ import SwiftUI
|
||||||
var replyToStatus: Status?
|
var replyToStatus: Status?
|
||||||
var embeddedStatus: Status?
|
var embeddedStatus: Status?
|
||||||
|
|
||||||
var customEmojis: [Emoji] = []
|
var customEmojiContainer: [StatusEditorCategorizedEmojiContainer] = []
|
||||||
|
|
||||||
var postingError: String?
|
var postingError: String?
|
||||||
var showPostingErrorAlert: Bool = false
|
var showPostingErrorAlert: Bool = false
|
||||||
|
@ -726,9 +726,33 @@ import SwiftUI
|
||||||
// MARK: - Custom emojis
|
// MARK: - Custom emojis
|
||||||
|
|
||||||
func fetchCustomEmojis() async {
|
func fetchCustomEmojis() async {
|
||||||
|
typealias EmojiContainer = StatusEditorCategorizedEmojiContainer
|
||||||
|
|
||||||
guard let client else { return }
|
guard let client else { return }
|
||||||
do {
|
do {
|
||||||
customEmojis = try await client.get(endpoint: CustomEmojis.customEmojis) ?? []
|
let customEmojis: [Emoji] = try await client.get(endpoint: CustomEmojis.customEmojis) ?? []
|
||||||
|
var emojiContainers: [EmojiContainer] = []
|
||||||
|
|
||||||
|
customEmojis.reduce([String: [Emoji]]()) { currentDict, emoji in
|
||||||
|
var dict = currentDict
|
||||||
|
let category = emoji.category ?? "Uncategorized"
|
||||||
|
|
||||||
|
if let emojis = dict[category] {
|
||||||
|
dict[category] = emojis + [emoji]
|
||||||
|
} else {
|
||||||
|
dict[category] = [emoji]
|
||||||
|
}
|
||||||
|
|
||||||
|
return dict
|
||||||
|
}.sorted(by: { lhs, rhs in
|
||||||
|
if rhs.key == "Uncategorized" { return false }
|
||||||
|
else if lhs.key == "Uncategorized" { return true }
|
||||||
|
else { return lhs.key < rhs.key }
|
||||||
|
}).forEach { key, value in
|
||||||
|
emojiContainers.append(.init(categoryName: key, emojis: value))
|
||||||
|
}
|
||||||
|
|
||||||
|
customEmojiContainer = emojiContainers
|
||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue