You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
session-ios/Session/Emoji/EmojiWithSkinTones.swift

74 lines
3.0 KiB
Swift

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

//
// Copyright (c) 2022 Open Whisper Systems. All rights reserved.
//
public struct EmojiWithSkinTones: Hashable {
let baseEmoji: Emoji
let skinTones: [Emoji.SkinTone]?
init(baseEmoji: Emoji, skinTones: [Emoji.SkinTone]? = nil) {
self.baseEmoji = baseEmoji
// Deduplicate skin tones, while preserving order. This allows for
// multi-skin tone emoji, where if you have for example the permutation
// [.dark, .dark], it is consolidated to just [.dark], to be initialized
// with either variant and result in the correct emoji.
self.skinTones = skinTones?.reduce(into: [Emoji.SkinTone]()) { result, skinTone in
guard !result.contains(skinTone) else { return }
result.append(skinTone)
}
}
var rawValue: String {
if let skinTones = skinTones {
return baseEmoji.emojiPerSkinTonePermutation?[skinTones] ?? baseEmoji.rawValue
} else {
return baseEmoji.rawValue
}
}
}
extension Emoji {
private static let emojiWithPreferredSkinToneCollection = "Emoji+PreferredSkinTonePermutation"
static func allSendableEmojiByCategoryWithPreferredSkinTones(transaction: YapDatabaseReadTransaction) -> [Category: [EmojiWithSkinTones]] {
return Category.allCases.reduce(into: [Category: [EmojiWithSkinTones]]()) { result, category in
result[category] = category.normalizedEmoji.filter { $0.available }.map { $0.withPreferredSkinTones(transaction: transaction) }
}
}
func withPreferredSkinTones(transaction: YapDatabaseReadTransaction) -> EmojiWithSkinTones {
guard let rawSkinTones = transaction.object(forKey: rawValue, inCollection: Self.emojiWithPreferredSkinToneCollection) as? [String] else {
return EmojiWithSkinTones(baseEmoji: self, skinTones: nil)
}
return EmojiWithSkinTones(baseEmoji: self, skinTones: rawSkinTones.compactMap { SkinTone(rawValue: $0) })
}
func setPreferredSkinTones(_ preferredSkinTonePermutation: [SkinTone]?, transaction: YapDatabaseReadWriteTransaction) {
if let preferredSkinTonePermutation = preferredSkinTonePermutation {
transaction.setObject(preferredSkinTonePermutation.map { $0.rawValue }, forKey: rawValue, inCollection: Self.emojiWithPreferredSkinToneCollection)
} else {
transaction.removeObject(forKey: rawValue, inCollection: Self.emojiWithPreferredSkinToneCollection)
}
}
init?(_ string: String) {
guard let emojiWithSkinTonePermutation = EmojiWithSkinTones(rawValue: string) else { return nil }
self = emojiWithSkinTonePermutation.baseEmoji
}
}
// MARK: -
extension String {
// This is slightly more accurate than String.isSingleEmoji,
// but slower.
//
// * This will reject "lone modifiers".
// * This will reject certain edge cases such as 🌈.
var isSingleEmojiUsingEmojiWithSkinTones: Bool {
EmojiWithSkinTones(rawValue: self) != nil
}
}