Fix #1934 - Hook reaction pickers into the system's recently used keyboard emojis (#3453)

This commit is contained in:
Stefan Ceriu
2024-10-25 19:58:56 +03:00
committed by GitHub
parent 35cbc84a99
commit 7a47e37d38
35 changed files with 274 additions and 133 deletions
@@ -7,31 +7,38 @@
import Emojibase
import Foundation
@MainActor
protocol EmojiProviderProtocol {
func categories(searchString: String?) async -> [EmojiCategory]
}
private enum EmojiProviderState {
case notLoaded
case inProgress(Task<[EmojiCategory], Never>)
case loaded([EmojiCategory])
}
import OrderedCollections
class EmojiProvider: EmojiProviderProtocol {
private let loader: EmojiLoaderProtocol
private var state: EmojiProviderState = .notLoaded
private let appSettings: AppSettings
init(loader: EmojiLoaderProtocol = EmojibaseDatasource()) {
private(set) var state: EmojiProviderState = .notLoaded
init(loader: EmojiLoaderProtocol = EmojibaseDatasource(), appSettings: AppSettings) {
self.loader = loader
self.appSettings = appSettings
Task {
await loadIfNeeded()
}
}
func categories(searchString: String? = nil) async -> [EmojiCategory] {
let emojiCategories = await loadIfNeeded()
var emojiCategories = await loadIfNeeded()
let allEmojis = emojiCategories.reduce([]) { partialResult, category in
partialResult + category.emojis
}
// Map frequently used system unicode emojis to our emoji provider ones
let frequentlyUsedEmojis = frequentlyUsedSystemEmojis().prefix(20)
let emojis = allEmojis.filter { frequentlyUsedEmojis.contains($0.unicode) }
if !emojis.isEmpty {
emojiCategories.insert(.init(id: EmojiCategory.frequentlyUsedCategoryIdentifier, emojis: emojis), at: 0)
}
if let searchString, searchString.isEmpty == false {
return search(searchString: searchString, emojiCategories: emojiCategories)
} else {
@@ -39,6 +46,40 @@ class EmojiProvider: EmojiProviderProtocol {
}
}
func frequentlyUsedSystemEmojis() -> [String] {
guard appSettings.frequentEmojisEnabled, !ProcessInfo.processInfo.isiOSAppOnMac else {
return []
}
guard let preferences = UserDefaults(suiteName: "com.apple.EmojiPreferences"),
let defaults = preferences.dictionary(forKey: "EMFDefaultsKey"),
let recents = defaults["EMFRecentsKey"] as? [String]
else {
return []
}
return recents
}
func markEmojiAsFrequentlyUsed(_ emoji: String) {
guard appSettings.frequentEmojisEnabled else {
return
}
guard let preferences = UserDefaults(suiteName: "com.apple.EmojiPreferences"),
let defaults = preferences.dictionary(forKey: "EMFDefaultsKey"),
let recents = defaults["EMFRecentsKey"] as? [String] else {
return
}
var uniqueOrderedRecents = OrderedSet(recents)
uniqueOrderedRecents.insert(emoji, at: 0)
preferences.setValue(["EMFRecentsKey": Array(uniqueOrderedRecents)], forKey: "EMFDefaultsKey")
}
// MARK: - Private
private func search(searchString: String, emojiCategories: [EmojiCategory]) -> [EmojiCategory] {
emojiCategories.compactMap { category in
let emojis = category.emojis.filter { emoji in