Make categorized emoji picker (#1680)

Signed-off-by: Euigyom Kim <egkim@dehol.kr>
This commit is contained in:
Euigyom Kim 2023-11-19 16:09:41 +09:00 committed by GitHub
parent 1e35ffb82b
commit d3b52b3206
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 64 additions and 23 deletions

View file

@ -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?
} }

View file

@ -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) {

View file

@ -0,0 +1,8 @@
import Foundation
import Models
struct StatusEditorCategorizedEmojiContainer: Identifiable, Equatable {
let id = UUID().uuidString
let categoryName: String
var emojis: [Emoji]
}

View file

@ -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 {}
} }
} }