commit ae2f48484acfe55c2851e39ba2c7b486135c1b21
parent 2c9b280a04bd476be4bc39180fd0346dd6490110
Author: Terry Yiu <git@tyiu.xyz>
Date: Sat, 20 Apr 2024 14:27:24 -0400
Change reactions to use a native looking emoji picker
Changelog-Changed: Change reactions to use a native looking emoji picker
Signed-off-by: William Casarin <jb55@jb55.com>
Diffstat:
6 files changed, 70 insertions(+), 340 deletions(-)
diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj
@@ -36,6 +36,7 @@
3ACB685F297633BC00C46468 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3ACB685D297633BC00C46468 /* Localizable.strings */; };
3ACBCB78295FE5C70037388A /* TimeAgoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ACBCB77295FE5C70037388A /* TimeAgoTests.swift */; };
3AE45AF6297BB2E700C1D842 /* LibreTranslateServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AE45AF5297BB2E700C1D842 /* LibreTranslateServer.swift */; };
+ 3AFE89C32BD4156F00AD31EF /* MCEmojiPicker in Frameworks */ = {isa = PBXBuildFile; productRef = 3AFE89C22BD4156F00AD31EF /* MCEmojiPicker */; };
3CCD1E6A2A874C4E0099A953 /* Nip98HTTPAuth.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CCD1E692A874C4E0099A953 /* Nip98HTTPAuth.swift */; };
4C06670128FC7C5900038D2A /* RelayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C06670028FC7C5900038D2A /* RelayView.swift */; };
4C06670428FC7EC500038D2A /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 4C06670328FC7EC500038D2A /* Kingfisher */; };
@@ -444,8 +445,6 @@
BA3759932ABCCEBA0018D73B /* CameraModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA3759902ABCCEBA0018D73B /* CameraModel.swift */; };
BA3759942ABCCEBA0018D73B /* CameraService.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA3759912ABCCEBA0018D73B /* CameraService.swift */; };
BA3759972ABCCF360018D73B /* CameraPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA3759962ABCCF360018D73B /* CameraPreview.swift */; };
- BA4AB0AE2A63B9270070A32A /* AddEmojiView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4AB0AD2A63B9270070A32A /* AddEmojiView.swift */; };
- BA4AB0B02A63B94D0070A32A /* EmojiListItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4AB0AF2A63B94D0070A32A /* EmojiListItemView.swift */; };
BA693074295D649800ADDB87 /* UserSettingsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA693073295D649800ADDB87 /* UserSettingsStore.swift */; };
BAB68BED29543FA3007BA466 /* SelectWalletView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAB68BEC29543FA3007BA466 /* SelectWalletView.swift */; };
D2277EEA2A089BD5006C3807 /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2277EE92A089BD5006C3807 /* Router.swift */; };
@@ -1368,8 +1367,6 @@
BA3759902ABCCEBA0018D73B /* CameraModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraModel.swift; sourceTree = "<group>"; };
BA3759912ABCCEBA0018D73B /* CameraService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraService.swift; sourceTree = "<group>"; };
BA3759962ABCCF360018D73B /* CameraPreview.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraPreview.swift; sourceTree = "<group>"; };
- BA4AB0AD2A63B9270070A32A /* AddEmojiView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddEmojiView.swift; sourceTree = "<group>"; };
- BA4AB0AF2A63B94D0070A32A /* EmojiListItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiListItemView.swift; sourceTree = "<group>"; };
BA693073295D649800ADDB87 /* UserSettingsStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSettingsStore.swift; sourceTree = "<group>"; };
BAB68BEC29543FA3007BA466 /* SelectWalletView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectWalletView.swift; sourceTree = "<group>"; };
D2277EE92A089BD5006C3807 /* Router.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Router.swift; sourceTree = "<group>"; };
@@ -1473,6 +1470,7 @@
4C06670428FC7EC500038D2A /* Kingfisher in Frameworks */,
4C649881286E0EE300EAE2B3 /* secp256k1 in Frameworks */,
4C27C9322A64766F007DBC75 /* MarkdownUI in Frameworks */,
+ 3AFE89C32BD4156F00AD31EF /* MCEmojiPicker in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1727,8 +1725,6 @@
4C1A9A2629DDE31900516EAC /* TranslationSettingsView.swift */,
E4FA1C022A24BB7F00482697 /* SearchSettingsView.swift */,
5053ACA62A56DF3B00851AE3 /* DeveloperSettingsView.swift */,
- BA4AB0AD2A63B9270070A32A /* AddEmojiView.swift */,
- BA4AB0AF2A63B94D0070A32A /* EmojiListItemView.swift */,
);
path = Settings;
sourceTree = "<group>";
@@ -2831,6 +2827,7 @@
4C649880286E0EE300EAE2B3 /* secp256k1 */,
4C06670328FC7EC500038D2A /* Kingfisher */,
4C27C9312A64766F007DBC75 /* MarkdownUI */,
+ 3AFE89C22BD4156F00AD31EF /* MCEmojiPicker */,
);
productName = damus;
productReference = 4CE6DEE327F7A08100C66700 /* damus.app */;
@@ -2968,6 +2965,7 @@
4CCF9AB02A1FE80B00E03CFB /* XCRemoteSwiftPackageReference "GSPlayer" */,
4C27C9302A64766F007DBC75 /* XCRemoteSwiftPackageReference "swift-markdown-ui" */,
D7A343EC2AD0D77C00CED48B /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */,
+ 3AFE89C12BD4156F00AD31EF /* XCRemoteSwiftPackageReference "MCEmojiPicker" */,
);
productRefGroup = 4CE6DEE427F7A08100C66700 /* Products */;
projectDirPath = "";
@@ -3137,7 +3135,6 @@
F75BA12F29A18EF500E10810 /* BookmarksView.swift in Sources */,
4CB883B6297730E400DC99E7 /* LNUrls.swift in Sources */,
4C7FF7D52823313F009601DB /* Mentions.swift in Sources */,
- BA4AB0AE2A63B9270070A32A /* AddEmojiView.swift in Sources */,
4C32B94D2A9AD44700DC3548 /* Offset.swift in Sources */,
4C633350283D40E500B1C9C3 /* HomeModel.swift in Sources */,
4C987B57283FD07F0042CE38 /* FollowersModel.swift in Sources */,
@@ -3180,7 +3177,6 @@
4C9BB83429C12D9900FC4E37 /* EventProfileName.swift in Sources */,
4C7D09602A098C5D00943473 /* WalletView.swift in Sources */,
4CB8838F296F781C00DC99E7 /* ReactionsView.swift in Sources */,
- BA4AB0B02A63B94D0070A32A /* EmojiListItemView.swift in Sources */,
B5C60C202B530D5100C5ECA7 /* MuteItem.swift in Sources */,
4C75EFB328049D640006080F /* NostrEvent.swift in Sources */,
4C32B9582A9AD44700DC3548 /* VeriferOptions.swift in Sources */,
@@ -4268,6 +4264,14 @@
/* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */
+ 3AFE89C12BD4156F00AD31EF /* XCRemoteSwiftPackageReference "MCEmojiPicker" */ = {
+ isa = XCRemoteSwiftPackageReference;
+ repositoryURL = "https://github.com/izyumkin/MCEmojiPicker";
+ requirement = {
+ kind = upToNextMajorVersion;
+ minimumVersion = 1.2.3;
+ };
+ };
4C06670228FC7EC500038D2A /* XCRemoteSwiftPackageReference "Kingfisher" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/onevcat/Kingfisher";
@@ -4311,6 +4315,11 @@
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
+ 3AFE89C22BD4156F00AD31EF /* MCEmojiPicker */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = 3AFE89C12BD4156F00AD31EF /* XCRemoteSwiftPackageReference "MCEmojiPicker" */;
+ productName = MCEmojiPicker;
+ };
4C06670328FC7EC500038D2A /* Kingfisher */ = {
isa = XCSwiftPackageProductDependency;
package = 4C06670228FC7EC500038D2A /* XCRemoteSwiftPackageReference "Kingfisher" */;
diff --git a/damus.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/damus.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -19,6 +19,15 @@
}
},
{
+ "identity" : "mcemojipicker",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/izyumkin/MCEmojiPicker",
+ "state" : {
+ "revision" : "e0b4903b75ae1cc418d276d84d1cb946b8a1d73c",
+ "version" : "1.2.3"
+ }
+ },
+ {
"identity" : "secp256k1.swift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/jb55/secp256k1.swift",
diff --git a/damus/Views/ActionBar/EventActionBar.swift b/damus/Views/ActionBar/EventActionBar.swift
@@ -6,8 +6,7 @@
//
import SwiftUI
-import UIKit
-
+import MCEmojiPicker
struct EventActionBar: View {
let damus_state: DamusState
@@ -20,6 +19,8 @@ struct EventActionBar: View {
@State var show_share_action: Bool = false
@State var show_repost_action: Bool = false
+ @State private var isOnTopHalfOfScreen: Bool = false
+
@ObservedObject var bar: ActionBarModel
init(damus_state: DamusState, event: NostrEvent, bar: ActionBarModel? = nil) {
@@ -72,7 +73,7 @@ struct EventActionBar: View {
Spacer()
HStack(spacing: 4) {
- LikeButton(damus_state: damus_state, liked: bar.liked, liked_emoji: bar.our_like != nil ? to_reaction_emoji(ev: bar.our_like!) : nil) { emoji in
+ LikeButton(damus_state: damus_state, liked: bar.liked, liked_emoji: bar.our_like != nil ? to_reaction_emoji(ev: bar.our_like!) : nil, isOnTopHalfOfScreen: $isOnTopHalfOfScreen) { emoji in
if bar.liked {
//notify(.delete, bar.our_like)
} else {
@@ -135,8 +136,22 @@ struct EventActionBar: View {
self.bar.our_like = liked.event
}
}
+ .background(
+ GeometryReader { geometry in
+ EmptyView()
+ .onAppear {
+ let eventActionBarY = geometry.frame(in: .global).midY
+ let screenMidY = UIScreen.main.bounds.midY
+ self.isOnTopHalfOfScreen = eventActionBarY > screenMidY
+ }
+ .onChange(of: geometry.frame(in: .global).midY) { newY in
+ let screenMidY = UIScreen.main.bounds.midY
+ self.isOnTopHalfOfScreen = newY > screenMidY
+ }
+ }
+ )
}
-
+
func send_like(emoji: String) {
guard let keypair = damus_state.keypair.to_full(),
let like_ev = make_like_event(keypair: keypair, liked: event, content: emoji) else {
@@ -168,15 +183,17 @@ struct LikeButton: View {
let damus_state: DamusState
let liked: Bool
let liked_emoji: String?
+ @Binding var isOnTopHalfOfScreen: Bool
let action: (_ emoji: String) -> Void
// For reactions background
@State private var showReactionsBG = 0
- @State private var showEmojis: [Int] = []
@State private var rotateThumb = -45
@State private var isReactionsVisible = false
+ @State private var selectedEmoji: String = ""
+
// Following four are Shaka animation properties
let timer = Timer.publish(every: 0.10, on: .main, in: .common).autoconnect()
@State private var shouldAnimate = false
@@ -228,7 +245,15 @@ struct LikeButton: View {
amountOfAngleIncrease = 20.0
}
})
- .overlay(reactionsOverlay())
+ .emojiPicker(
+ isPresented: $isReactionsVisible,
+ selectedEmoji: $selectedEmoji,
+ arrowDirection: isOnTopHalfOfScreen ? .down : .up,
+ isDismissAfterChoosing: true
+ )
+ .onChange(of: selectedEmoji) { newSelectedEmoji in
+ self.action(newSelectedEmoji)
+ }
}
func shakaAnimationLogic() {
@@ -251,110 +276,11 @@ struct LikeButton: View {
}
}
- func reactionsOverlay() -> some View {
- Group {
- if isReactionsVisible {
- ZStack {
- RoundedRectangle(cornerRadius: 20)
- .frame(width: calculateOverlayWidth(), height: 50)
- .foregroundColor(DamusColors.black)
- .scaleEffect(Double(showReactionsBG), anchor: .topTrailing)
- .animation(
- .interpolatingSpring(stiffness: 170, damping: 15).delay(0.05),
- value: showReactionsBG
- )
- .overlay(
- Rectangle()
- .foregroundColor(Color.white.opacity(0.2))
- .frame(width: calculateOverlayWidth(), height: 50)
- .clipShape(
- RoundedRectangle(cornerRadius: 20)
- )
- )
- .overlay(reactions())
- }
- .offset(y: -40)
- .onTapGesture {
- withAnimation(.easeOut(duration: 0.2)) {
- isReactionsVisible = false
- showReactionsBG = 0
- }
- showEmojis = []
- }
- } else {
- EmptyView()
- }
- }
- }
-
- func calculateOverlayWidth() -> CGFloat {
- let maxWidth: CGFloat = 250
- let numberOfEmojis = emojis.count
- let minimumWidth: CGFloat = 75
-
- if numberOfEmojis > 0 {
- let emojiWidth: CGFloat = 25
- let padding: CGFloat = 15
- let buttonWidth: CGFloat = 18
- let buttonPadding: CGFloat = 20
-
- let totalWidth = CGFloat(numberOfEmojis) * (emojiWidth + padding) + buttonWidth + buttonPadding
- return min(maxWidth, max(minimumWidth, totalWidth))
- } else {
- return minimumWidth
- }
- }
-
- func reactions() -> some View {
- HStack {
- ScrollView(.horizontal, showsIndicators: false) {
- HStack(spacing: 15) {
- ForEach(emojis, id: \.self) { emoji in
- if let index = emojis.firstIndex(of: emoji) {
- let scale = index < showEmojis.count ? showEmojis[index] : 0
- Text(emoji)
- .font(.system(size: 25))
- .scaleEffect(Double(scale))
- .onTapGesture {
- emojiTapped(emoji)
- }
- }
- }
- }
- .padding(.leading, 10)
- }
- Button(action: {
- withAnimation(.easeOut(duration: 0.2)) {
- isReactionsVisible = false
- showReactionsBG = 0
- }
- showEmojis = []
- }) {
- Image(systemName: "xmark.circle.fill")
- .font(.system(size: 18))
- .foregroundColor(.gray)
- }
- .padding(.trailing, 7.5)
- }
- }
-
// When reaction button is long pressed, it displays the multiple emojis overlay and displays the user's selected emojis with an animation
private func reactionLongPressed() {
UIImpactFeedbackGenerator(style: .medium).impactOccurred()
- showEmojis = Array(repeating: 0, count: emojis.count) // Initialize the showEmojis array
-
- for (index, _) in emojis.enumerated() {
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.1 * Double(index)) {
- withAnimation(.interpolatingSpring(stiffness: 170, damping: 8)) {
- if index < showEmojis.count {
- showEmojis[index] = 1
- }
- }
- }
- }
isReactionsVisible = true
- showReactionsBG = 1
}
private func emojiTapped(_ emoji: String) {
@@ -364,9 +290,7 @@ struct LikeButton: View {
withAnimation(.easeOut(duration: 0.2)) {
isReactionsVisible = false
- showReactionsBG = 0
}
- showEmojis = []
withAnimation(Animation.easeOut(duration: 0.15)) {
shouldAnimate = true
diff --git a/damus/Views/Settings/AddEmojiView.swift b/damus/Views/Settings/AddEmojiView.swift
@@ -1,48 +0,0 @@
-//
-// AddEmojiView.swift
-// damus
-//
-// Created by Suhail Saqan on 7/16/23.
-//
-
-import SwiftUI
-
-struct AddEmojiView: View {
- @Binding var emoji: String
-
- var body: some View {
- ZStack(alignment: .leading) {
- HStack{
- TextField(NSLocalizedString("⚡", comment: "Placeholder example for an emoji reaction"), text: $emoji)
- .padding(2)
- .padding(.leading, 25)
- .opacity(emoji == "" ? 0.5 : 1)
- .autocorrectionDisabled(true)
- .textInputAutocapitalization(.never)
- .onChange(of: emoji) { newEmoji in
- if let lastEmoji = newEmoji.last.map(String.init), isValidEmoji(lastEmoji) {
- self.emoji = lastEmoji
- } else {
- self.emoji = ""
- }
- }
-
- Label("", image: "close-circle")
- .foregroundColor(.accentColor)
- .padding(.trailing, -25.0)
- .opacity((emoji == "") ? 0.0 : 1.0)
- .onTapGesture {
- self.emoji = ""
- }
- }
-
- Label("", image: "copy2")
- .padding(.leading, -10)
- .onTapGesture {
- if let pastedEmoji = UIPasteboard.general.string {
- self.emoji = pastedEmoji
- }
- }
- }
- }
-}
diff --git a/damus/Views/Settings/EmojiListItemView.swift b/damus/Views/Settings/EmojiListItemView.swift
@@ -1,81 +0,0 @@
-//
-// EmojiListItemView.swift
-// damus
-//
-// Created by Suhail Saqan on 7/16/23.
-//
-
-import SwiftUI
-
-struct EmojiListItemView: View {
- @ObservedObject var settings: UserSettingsStore
-
- let emoji: String
- let recommended: Bool
-
- @Binding var showActionButtons: Bool
-
- var body: some View {
- Group {
- HStack {
- if showActionButtons {
- if recommended {
- AddButton()
- } else {
- RemoveButton()
- }
- }
-
- Text(emoji)
- }
- }
- .swipeActions {
- if !recommended {
- RemoveButton()
- .tint(.red)
- } else {
- AddButton()
- .tint(.green)
- }
- }
- .contextMenu {
- if !showActionButtons {
- CopyAction(emoji: emoji)
- }
- }
- }
-
- func CopyAction(emoji: String) -> some View {
- Button {
- UIPasteboard.general.setValue(emoji, forPasteboardType: "public.plain-text")
- } label: {
- Label(NSLocalizedString("Copy", comment: "Button to copy an emoji reaction"), image: "copy2")
- }
- }
-
- func RemoveButton() -> some View {
- Button(action: {
- if let index = settings.emoji_reactions.firstIndex(of: emoji) {
- settings.emoji_reactions.remove(at: index)
- }
- }) {
- Image(systemName: "minus.circle")
- .resizable()
- .frame(width: 20, height: 20)
- .foregroundColor(.red)
- .padding(.leading, -5)
- }
- }
-
- func AddButton() -> some View {
- Button(action: {
- settings.emoji_reactions.append(emoji)
- }) {
- Image(systemName: "plus.circle")
- .resizable()
- .frame(width: 20, height: 20)
- .foregroundColor(.green)
- .padding(.leading, -5)
- }
- }
-}
diff --git a/damus/Views/Settings/ReactionsSettingsView.swift b/damus/Views/Settings/ReactionsSettingsView.swift
@@ -6,114 +6,31 @@
//
import SwiftUI
-import Combine
+import MCEmojiPicker
struct ReactionsSettingsView: View {
@ObservedObject var settings: UserSettingsStore
-
- @State var new_emoji: String = ""
- @State private var showActionButtons = false
-
- @Environment(\.dismiss) var dismiss
-
- var recommended: [String] {
- return getMissingRecommendedEmojis(added: settings.emoji_reactions)
- }
-
+ @State private var isReactionsVisible: Bool = false
+
var body: some View {
Form {
Section {
- AddEmojiView(emoji: $new_emoji)
- } header: {
- Text(NSLocalizedString("Add Emoji", comment: "Label for section for adding an emoji to the reactions list."))
- .font(.system(size: 18, weight: .heavy))
- .padding(.bottom, 5)
- } footer: {
- HStack {
- Spacer()
- if !new_emoji.isEmpty {
- Button(NSLocalizedString("Cancel", comment: "Button to cancel out of view adding user inputted emoji.")) {
- new_emoji = ""
- }
- .font(.system(size: 14, weight: .bold))
- .frame(width: 80, height: 30)
- .foregroundColor(.white)
- .background(LINEAR_GRADIENT)
- .clipShape(Capsule())
- .padding(EdgeInsets(top: 15, leading: 0, bottom: 0, trailing: 0))
-
- Button(NSLocalizedString("Add", comment: "Button to confirm adding user inputted emoji.")) {
- if isValidEmoji(new_emoji) {
- settings.emoji_reactions.append(new_emoji)
- new_emoji = ""
- }
- }
- .font(.system(size: 14, weight: .bold))
- .frame(width: 80, height: 30)
- .foregroundColor(.white)
- .background(LINEAR_GRADIENT)
- .clipShape(Capsule())
- .padding(EdgeInsets(top: 15, leading: 0, bottom: 0, trailing: 0))
- }
- }
- }
-
- Picker(NSLocalizedString("Select default emoji", comment: "Prompt selection of user's default emoji reaction"),
- selection: $settings.default_emoji_reaction) {
- ForEach(settings.emoji_reactions, id: \.self) { emoji in
- Text(emoji)
- }
- }
-
- Section {
- List {
- ForEach(Array(zip(settings.emoji_reactions, 1...)), id: \.1) { tup in
- EmojiListItemView(settings: settings, emoji: tup.0, recommended: false, showActionButtons: $showActionButtons)
+ Text(settings.default_emoji_reaction)
+ .emojiPicker(
+ isPresented: $isReactionsVisible,
+ selectedEmoji: $settings.default_emoji_reaction,
+ arrowDirection: .up,
+ isDismissAfterChoosing: true
+ )
+ .onTapGesture {
+ isReactionsVisible = true
}
- .onMove(perform: showActionButtons ? move: nil)
- }
} header: {
- Text("Emoji Reactions", comment: "Section title for emoji reactions that are currently added.")
- .font(.system(size: 18, weight: .heavy))
- .padding(.bottom, 5)
- }
-
- if recommended.count > 0 {
- Section {
- List(Array(zip(recommended, 1...)), id: \.1) { tup in
- EmojiListItemView(settings: settings, emoji: tup.0, recommended: true, showActionButtons: $showActionButtons)
- }
- } header: {
- Text("Recommended Emojis", comment: "Section title for recommend emojis")
- .font(.system(size: 18, weight: .heavy))
- .padding(.bottom, 5)
- }
+ Text(NSLocalizedString("Select default emoji", comment: "Prompt selection of user's default emoji reaction"))
}
}
.navigationTitle(NSLocalizedString("Reactions", comment: "Title of emoji reactions view"))
.navigationBarTitleDisplayMode(.large)
- .toolbar {
- if showActionButtons {
- Button("Done") {
- showActionButtons.toggle()
- }
- } else {
- Button("Edit") {
- showActionButtons.toggle()
- }
- }
- }
- }
-
- private func move(from: IndexSet, to: Int) {
- settings.emoji_reactions.move(fromOffsets: from, toOffset: to)
- }
-
- // Returns the emojis that are in the recommended list but the user has not added yet
- func getMissingRecommendedEmojis(added: [String], recommended: [String] = default_emoji_reactions) -> [String] {
- let addedSet = Set(added)
- let missingEmojis = recommended.filter { !addedSet.contains($0) }
- return missingEmojis
}
}