mirror of
git://jb55.com/damus
synced 2024-09-30 00:40:45 +00:00
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>
This commit is contained in:
parent
2c9b280a04
commit
ae2f48484a
@ -36,6 +36,7 @@
|
|||||||
3ACB685F297633BC00C46468 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3ACB685D297633BC00C46468 /* Localizable.strings */; };
|
3ACB685F297633BC00C46468 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3ACB685D297633BC00C46468 /* Localizable.strings */; };
|
||||||
3ACBCB78295FE5C70037388A /* TimeAgoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ACBCB77295FE5C70037388A /* TimeAgoTests.swift */; };
|
3ACBCB78295FE5C70037388A /* TimeAgoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ACBCB77295FE5C70037388A /* TimeAgoTests.swift */; };
|
||||||
3AE45AF6297BB2E700C1D842 /* LibreTranslateServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AE45AF5297BB2E700C1D842 /* LibreTranslateServer.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 */; };
|
3CCD1E6A2A874C4E0099A953 /* Nip98HTTPAuth.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CCD1E692A874C4E0099A953 /* Nip98HTTPAuth.swift */; };
|
||||||
4C06670128FC7C5900038D2A /* RelayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C06670028FC7C5900038D2A /* RelayView.swift */; };
|
4C06670128FC7C5900038D2A /* RelayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C06670028FC7C5900038D2A /* RelayView.swift */; };
|
||||||
4C06670428FC7EC500038D2A /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 4C06670328FC7EC500038D2A /* Kingfisher */; };
|
4C06670428FC7EC500038D2A /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 4C06670328FC7EC500038D2A /* Kingfisher */; };
|
||||||
@ -444,8 +445,6 @@
|
|||||||
BA3759932ABCCEBA0018D73B /* CameraModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA3759902ABCCEBA0018D73B /* CameraModel.swift */; };
|
BA3759932ABCCEBA0018D73B /* CameraModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA3759902ABCCEBA0018D73B /* CameraModel.swift */; };
|
||||||
BA3759942ABCCEBA0018D73B /* CameraService.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA3759912ABCCEBA0018D73B /* CameraService.swift */; };
|
BA3759942ABCCEBA0018D73B /* CameraService.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA3759912ABCCEBA0018D73B /* CameraService.swift */; };
|
||||||
BA3759972ABCCF360018D73B /* CameraPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA3759962ABCCF360018D73B /* CameraPreview.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 */; };
|
BA693074295D649800ADDB87 /* UserSettingsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA693073295D649800ADDB87 /* UserSettingsStore.swift */; };
|
||||||
BAB68BED29543FA3007BA466 /* SelectWalletView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAB68BEC29543FA3007BA466 /* SelectWalletView.swift */; };
|
BAB68BED29543FA3007BA466 /* SelectWalletView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAB68BEC29543FA3007BA466 /* SelectWalletView.swift */; };
|
||||||
D2277EEA2A089BD5006C3807 /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2277EE92A089BD5006C3807 /* Router.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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
D2277EE92A089BD5006C3807 /* Router.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Router.swift; sourceTree = "<group>"; };
|
||||||
@ -1473,6 +1470,7 @@
|
|||||||
4C06670428FC7EC500038D2A /* Kingfisher in Frameworks */,
|
4C06670428FC7EC500038D2A /* Kingfisher in Frameworks */,
|
||||||
4C649881286E0EE300EAE2B3 /* secp256k1 in Frameworks */,
|
4C649881286E0EE300EAE2B3 /* secp256k1 in Frameworks */,
|
||||||
4C27C9322A64766F007DBC75 /* MarkdownUI in Frameworks */,
|
4C27C9322A64766F007DBC75 /* MarkdownUI in Frameworks */,
|
||||||
|
3AFE89C32BD4156F00AD31EF /* MCEmojiPicker in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -1727,8 +1725,6 @@
|
|||||||
4C1A9A2629DDE31900516EAC /* TranslationSettingsView.swift */,
|
4C1A9A2629DDE31900516EAC /* TranslationSettingsView.swift */,
|
||||||
E4FA1C022A24BB7F00482697 /* SearchSettingsView.swift */,
|
E4FA1C022A24BB7F00482697 /* SearchSettingsView.swift */,
|
||||||
5053ACA62A56DF3B00851AE3 /* DeveloperSettingsView.swift */,
|
5053ACA62A56DF3B00851AE3 /* DeveloperSettingsView.swift */,
|
||||||
BA4AB0AD2A63B9270070A32A /* AddEmojiView.swift */,
|
|
||||||
BA4AB0AF2A63B94D0070A32A /* EmojiListItemView.swift */,
|
|
||||||
);
|
);
|
||||||
path = Settings;
|
path = Settings;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -2831,6 +2827,7 @@
|
|||||||
4C649880286E0EE300EAE2B3 /* secp256k1 */,
|
4C649880286E0EE300EAE2B3 /* secp256k1 */,
|
||||||
4C06670328FC7EC500038D2A /* Kingfisher */,
|
4C06670328FC7EC500038D2A /* Kingfisher */,
|
||||||
4C27C9312A64766F007DBC75 /* MarkdownUI */,
|
4C27C9312A64766F007DBC75 /* MarkdownUI */,
|
||||||
|
3AFE89C22BD4156F00AD31EF /* MCEmojiPicker */,
|
||||||
);
|
);
|
||||||
productName = damus;
|
productName = damus;
|
||||||
productReference = 4CE6DEE327F7A08100C66700 /* damus.app */;
|
productReference = 4CE6DEE327F7A08100C66700 /* damus.app */;
|
||||||
@ -2968,6 +2965,7 @@
|
|||||||
4CCF9AB02A1FE80B00E03CFB /* XCRemoteSwiftPackageReference "GSPlayer" */,
|
4CCF9AB02A1FE80B00E03CFB /* XCRemoteSwiftPackageReference "GSPlayer" */,
|
||||||
4C27C9302A64766F007DBC75 /* XCRemoteSwiftPackageReference "swift-markdown-ui" */,
|
4C27C9302A64766F007DBC75 /* XCRemoteSwiftPackageReference "swift-markdown-ui" */,
|
||||||
D7A343EC2AD0D77C00CED48B /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */,
|
D7A343EC2AD0D77C00CED48B /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */,
|
||||||
|
3AFE89C12BD4156F00AD31EF /* XCRemoteSwiftPackageReference "MCEmojiPicker" */,
|
||||||
);
|
);
|
||||||
productRefGroup = 4CE6DEE427F7A08100C66700 /* Products */;
|
productRefGroup = 4CE6DEE427F7A08100C66700 /* Products */;
|
||||||
projectDirPath = "";
|
projectDirPath = "";
|
||||||
@ -3137,7 +3135,6 @@
|
|||||||
F75BA12F29A18EF500E10810 /* BookmarksView.swift in Sources */,
|
F75BA12F29A18EF500E10810 /* BookmarksView.swift in Sources */,
|
||||||
4CB883B6297730E400DC99E7 /* LNUrls.swift in Sources */,
|
4CB883B6297730E400DC99E7 /* LNUrls.swift in Sources */,
|
||||||
4C7FF7D52823313F009601DB /* Mentions.swift in Sources */,
|
4C7FF7D52823313F009601DB /* Mentions.swift in Sources */,
|
||||||
BA4AB0AE2A63B9270070A32A /* AddEmojiView.swift in Sources */,
|
|
||||||
4C32B94D2A9AD44700DC3548 /* Offset.swift in Sources */,
|
4C32B94D2A9AD44700DC3548 /* Offset.swift in Sources */,
|
||||||
4C633350283D40E500B1C9C3 /* HomeModel.swift in Sources */,
|
4C633350283D40E500B1C9C3 /* HomeModel.swift in Sources */,
|
||||||
4C987B57283FD07F0042CE38 /* FollowersModel.swift in Sources */,
|
4C987B57283FD07F0042CE38 /* FollowersModel.swift in Sources */,
|
||||||
@ -3180,7 +3177,6 @@
|
|||||||
4C9BB83429C12D9900FC4E37 /* EventProfileName.swift in Sources */,
|
4C9BB83429C12D9900FC4E37 /* EventProfileName.swift in Sources */,
|
||||||
4C7D09602A098C5D00943473 /* WalletView.swift in Sources */,
|
4C7D09602A098C5D00943473 /* WalletView.swift in Sources */,
|
||||||
4CB8838F296F781C00DC99E7 /* ReactionsView.swift in Sources */,
|
4CB8838F296F781C00DC99E7 /* ReactionsView.swift in Sources */,
|
||||||
BA4AB0B02A63B94D0070A32A /* EmojiListItemView.swift in Sources */,
|
|
||||||
B5C60C202B530D5100C5ECA7 /* MuteItem.swift in Sources */,
|
B5C60C202B530D5100C5ECA7 /* MuteItem.swift in Sources */,
|
||||||
4C75EFB328049D640006080F /* NostrEvent.swift in Sources */,
|
4C75EFB328049D640006080F /* NostrEvent.swift in Sources */,
|
||||||
4C32B9582A9AD44700DC3548 /* VeriferOptions.swift in Sources */,
|
4C32B9582A9AD44700DC3548 /* VeriferOptions.swift in Sources */,
|
||||||
@ -4268,6 +4264,14 @@
|
|||||||
/* End XCConfigurationList section */
|
/* End XCConfigurationList section */
|
||||||
|
|
||||||
/* Begin XCRemoteSwiftPackageReference 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" */ = {
|
4C06670228FC7EC500038D2A /* XCRemoteSwiftPackageReference "Kingfisher" */ = {
|
||||||
isa = XCRemoteSwiftPackageReference;
|
isa = XCRemoteSwiftPackageReference;
|
||||||
repositoryURL = "https://github.com/onevcat/Kingfisher";
|
repositoryURL = "https://github.com/onevcat/Kingfisher";
|
||||||
@ -4311,6 +4315,11 @@
|
|||||||
/* End XCRemoteSwiftPackageReference section */
|
/* End XCRemoteSwiftPackageReference section */
|
||||||
|
|
||||||
/* Begin XCSwiftPackageProductDependency section */
|
/* Begin XCSwiftPackageProductDependency section */
|
||||||
|
3AFE89C22BD4156F00AD31EF /* MCEmojiPicker */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
package = 3AFE89C12BD4156F00AD31EF /* XCRemoteSwiftPackageReference "MCEmojiPicker" */;
|
||||||
|
productName = MCEmojiPicker;
|
||||||
|
};
|
||||||
4C06670328FC7EC500038D2A /* Kingfisher */ = {
|
4C06670328FC7EC500038D2A /* Kingfisher */ = {
|
||||||
isa = XCSwiftPackageProductDependency;
|
isa = XCSwiftPackageProductDependency;
|
||||||
package = 4C06670228FC7EC500038D2A /* XCRemoteSwiftPackageReference "Kingfisher" */;
|
package = 4C06670228FC7EC500038D2A /* XCRemoteSwiftPackageReference "Kingfisher" */;
|
||||||
|
@ -18,6 +18,15 @@
|
|||||||
"version" : "7.6.1"
|
"version" : "7.6.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"identity" : "mcemojipicker",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/izyumkin/MCEmojiPicker",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "e0b4903b75ae1cc418d276d84d1cb946b8a1d73c",
|
||||||
|
"version" : "1.2.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"identity" : "secp256k1.swift",
|
"identity" : "secp256k1.swift",
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
|
@ -6,8 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import UIKit
|
import MCEmojiPicker
|
||||||
|
|
||||||
|
|
||||||
struct EventActionBar: View {
|
struct EventActionBar: View {
|
||||||
let damus_state: DamusState
|
let damus_state: DamusState
|
||||||
@ -20,6 +19,8 @@ struct EventActionBar: View {
|
|||||||
@State var show_share_action: Bool = false
|
@State var show_share_action: Bool = false
|
||||||
@State var show_repost_action: Bool = false
|
@State var show_repost_action: Bool = false
|
||||||
|
|
||||||
|
@State private var isOnTopHalfOfScreen: Bool = false
|
||||||
|
|
||||||
@ObservedObject var bar: ActionBarModel
|
@ObservedObject var bar: ActionBarModel
|
||||||
|
|
||||||
init(damus_state: DamusState, event: NostrEvent, bar: ActionBarModel? = nil) {
|
init(damus_state: DamusState, event: NostrEvent, bar: ActionBarModel? = nil) {
|
||||||
@ -72,7 +73,7 @@ struct EventActionBar: View {
|
|||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
HStack(spacing: 4) {
|
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 {
|
if bar.liked {
|
||||||
//notify(.delete, bar.our_like)
|
//notify(.delete, bar.our_like)
|
||||||
} else {
|
} else {
|
||||||
@ -135,6 +136,20 @@ struct EventActionBar: View {
|
|||||||
self.bar.our_like = liked.event
|
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) {
|
func send_like(emoji: String) {
|
||||||
@ -168,15 +183,17 @@ struct LikeButton: View {
|
|||||||
let damus_state: DamusState
|
let damus_state: DamusState
|
||||||
let liked: Bool
|
let liked: Bool
|
||||||
let liked_emoji: String?
|
let liked_emoji: String?
|
||||||
|
@Binding var isOnTopHalfOfScreen: Bool
|
||||||
let action: (_ emoji: String) -> Void
|
let action: (_ emoji: String) -> Void
|
||||||
|
|
||||||
// For reactions background
|
// For reactions background
|
||||||
@State private var showReactionsBG = 0
|
@State private var showReactionsBG = 0
|
||||||
@State private var showEmojis: [Int] = []
|
|
||||||
@State private var rotateThumb = -45
|
@State private var rotateThumb = -45
|
||||||
|
|
||||||
@State private var isReactionsVisible = false
|
@State private var isReactionsVisible = false
|
||||||
|
|
||||||
|
@State private var selectedEmoji: String = ""
|
||||||
|
|
||||||
// Following four are Shaka animation properties
|
// Following four are Shaka animation properties
|
||||||
let timer = Timer.publish(every: 0.10, on: .main, in: .common).autoconnect()
|
let timer = Timer.publish(every: 0.10, on: .main, in: .common).autoconnect()
|
||||||
@State private var shouldAnimate = false
|
@State private var shouldAnimate = false
|
||||||
@ -228,7 +245,15 @@ struct LikeButton: View {
|
|||||||
amountOfAngleIncrease = 20.0
|
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() {
|
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
|
// 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() {
|
private func reactionLongPressed() {
|
||||||
UIImpactFeedbackGenerator(style: .medium).impactOccurred()
|
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
|
isReactionsVisible = true
|
||||||
showReactionsBG = 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func emojiTapped(_ emoji: String) {
|
private func emojiTapped(_ emoji: String) {
|
||||||
@ -364,9 +290,7 @@ struct LikeButton: View {
|
|||||||
|
|
||||||
withAnimation(.easeOut(duration: 0.2)) {
|
withAnimation(.easeOut(duration: 0.2)) {
|
||||||
isReactionsVisible = false
|
isReactionsVisible = false
|
||||||
showReactionsBG = 0
|
|
||||||
}
|
}
|
||||||
showEmojis = []
|
|
||||||
|
|
||||||
withAnimation(Animation.easeOut(duration: 0.15)) {
|
withAnimation(Animation.easeOut(duration: 0.15)) {
|
||||||
shouldAnimate = true
|
shouldAnimate = true
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,114 +6,31 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import Combine
|
import MCEmojiPicker
|
||||||
|
|
||||||
struct ReactionsSettingsView: View {
|
struct ReactionsSettingsView: View {
|
||||||
@ObservedObject var settings: UserSettingsStore
|
@ObservedObject var settings: UserSettingsStore
|
||||||
|
@State private var isReactionsVisible: Bool = false
|
||||||
@State var new_emoji: String = ""
|
|
||||||
@State private var showActionButtons = false
|
|
||||||
|
|
||||||
@Environment(\.dismiss) var dismiss
|
|
||||||
|
|
||||||
var recommended: [String] {
|
|
||||||
return getMissingRecommendedEmojis(added: settings.emoji_reactions)
|
|
||||||
}
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Form {
|
Form {
|
||||||
Section {
|
Section {
|
||||||
AddEmojiView(emoji: $new_emoji)
|
Text(settings.default_emoji_reaction)
|
||||||
|
.emojiPicker(
|
||||||
|
isPresented: $isReactionsVisible,
|
||||||
|
selectedEmoji: $settings.default_emoji_reaction,
|
||||||
|
arrowDirection: .up,
|
||||||
|
isDismissAfterChoosing: true
|
||||||
|
)
|
||||||
|
.onTapGesture {
|
||||||
|
isReactionsVisible = true
|
||||||
|
}
|
||||||
} header: {
|
} header: {
|
||||||
Text(NSLocalizedString("Add Emoji", comment: "Label for section for adding an emoji to the reactions list."))
|
Text(NSLocalizedString("Select default emoji", comment: "Prompt selection of user's default emoji reaction"))
|
||||||
.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)
|
|
||||||
}
|
|
||||||
.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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.navigationTitle(NSLocalizedString("Reactions", comment: "Title of emoji reactions view"))
|
.navigationTitle(NSLocalizedString("Reactions", comment: "Title of emoji reactions view"))
|
||||||
.navigationBarTitleDisplayMode(.large)
|
.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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user