Skip to content

Commit

Permalink
Add reaction send support for internal
Browse files Browse the repository at this point in the history
  • Loading branch information
marissa-signal committed Apr 23, 2024
1 parent 7ee4a1e commit 4412a47
Show file tree
Hide file tree
Showing 7 changed files with 369 additions and 36 deletions.
4 changes: 4 additions & 0 deletions Signal.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1909,6 +1909,7 @@
E14EDF6E2A71AFDF00F0FD7C /* RecipientContextMenuHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = E14EDF6D2A71AFDF00F0FD7C /* RecipientContextMenuHelper.swift */; };
E16B440E2BBF242C00D2583E /* ReactionsModelTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16B440D2BBF242C00D2583E /* ReactionsModelTest.swift */; };
E17283DE2B2A713C00302DC7 /* CallControlsConfirmationToast.swift in Sources */ = {isa = PBXBuildFile; fileRef = E17283DD2B2A713C00302DC7 /* CallControlsConfirmationToast.swift */; };
E173F7032BC9E61D000BCDB3 /* CallControlsOverflowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E173F7022BC9E61D000BCDB3 /* CallControlsOverflowView.swift */; };
E18C4A7729EF2ECC007534D4 /* SignalAccountTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18C4A7629EF2ECC007534D4 /* SignalAccountTest.swift */; };
E1A090382A4B909B00F2BE8B /* RecipientHidingManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1A090372A4B909B00F2BE8B /* RecipientHidingManager.swift */; };
E1C2A54B2A8FCB0D00AEC4DA /* DeleteSystemContactViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1C2A54A2A8FCB0D00AEC4DA /* DeleteSystemContactViewController.swift */; };
Expand Down Expand Up @@ -4883,6 +4884,7 @@
E14EDF6D2A71AFDF00F0FD7C /* RecipientContextMenuHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipientContextMenuHelper.swift; sourceTree = "<group>"; };
E16B440D2BBF242C00D2583E /* ReactionsModelTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReactionsModelTest.swift; sourceTree = "<group>"; };
E17283DD2B2A713C00302DC7 /* CallControlsConfirmationToast.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallControlsConfirmationToast.swift; sourceTree = "<group>"; };
E173F7022BC9E61D000BCDB3 /* CallControlsOverflowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallControlsOverflowView.swift; sourceTree = "<group>"; };
E18C4A7629EF2ECC007534D4 /* SignalAccountTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignalAccountTest.swift; sourceTree = "<group>"; };
E1A090372A4B909B00F2BE8B /* RecipientHidingManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipientHidingManager.swift; sourceTree = "<group>"; };
E1A0AD8B16E13FDD0071E604 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
Expand Down Expand Up @@ -8894,6 +8896,7 @@
88238EA324E9DDE900F28079 /* CallButton.swift */,
88588D1A252D3DFF00405414 /* CallControls.swift */,
E17283DD2B2A713C00302DC7 /* CallControlsConfirmationToast.swift */,
E173F7022BC9E61D000BCDB3 /* CallControlsOverflowView.swift */,
88ABB8B42534070400229EAA /* CallHeader.swift */,
88D23D1B23CEC0C700B0E74B /* CallKitCallUIAdaptee.swift */,
E1E78CAE2B573BD100B6FC2D /* CallMemberCameraOffView.swift */,
Expand Down Expand Up @@ -12873,6 +12876,7 @@
88238EA424E9DDE900F28079 /* CallButton.swift in Sources */,
88588D1B252D3DFF00405414 /* CallControls.swift in Sources */,
E17283DE2B2A713C00302DC7 /* CallControlsConfirmationToast.swift in Sources */,
E173F7032BC9E61D000BCDB3 /* CallControlsOverflowView.swift in Sources */,
88ABB8B52534070400229EAA /* CallHeader.swift in Sources */,
88D23D2423CEC0C700B0E74B /* CallKitCallManager.swift in Sources */,
88D23D2523CEC0C700B0E74B /* CallKitCallUIAdaptee.swift in Sources */,
Expand Down
3 changes: 2 additions & 1 deletion Signal/Calls/UserInterface/CallControls.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ protocol CallControlsDelegate: AnyObject {
func didPressRing()
func didPressJoin()
func didPressHangup()
func didPressMore()
}

class CallControls: UIView {
Expand Down Expand Up @@ -658,7 +659,7 @@ extension CallControlsViewModel {

@objc
func didPressMore() {
// TODO: Display reaction picker and raise hand option.
delegate?.didPressMore()
}
}

Expand Down
171 changes: 171 additions & 0 deletions Signal/Calls/UserInterface/CallControlsOverflowView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
//
// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//

import SignalRingRTC
import SignalServiceKit

class CallControlsOverflowView: UIView {
private lazy var reactionPicker: MessageReactionPicker = {
let picker = MessageReactionPicker(
selectedEmoji: nil,
delegate: self,
style: .contextMenu,
forceDarkTheme: true
)
picker.isHidden = true
return picker
}()

private var reactionSender: ReactionSender?
private var reactionReceiver: ReactionReceiver?

private weak var emojiPickerSheetPresenter: EmojiPickerSheetPresenter?

private weak var callControlsOverflowPresenter: CallControlsOverflowPresenter?

private override init(frame: CGRect) {
super.init(frame: frame)

if FeatureFlags.callReactionSendSupport {
self.addSubview(reactionPicker)
reactionPicker.autoPinEdgesToSuperviewEdges()
}

// TODO: Add Raise Hand button
}

convenience init(
reactionSender: ReactionSender,
reactionReceiver: ReactionReceiver,
emojiPickerSheetPresenter: EmojiPickerSheetPresenter,
callControlsOverflowPresenter: CallControlsOverflowPresenter
) {
self.init(frame: .zero)
self.reactionSender = reactionSender
self.reactionReceiver = reactionReceiver
self.emojiPickerSheetPresenter = emojiPickerSheetPresenter
self.callControlsOverflowPresenter = callControlsOverflowPresenter
}

// MARK: - Animations

private var isAnimating = false

func animateIn() {
self.isHidden = false
guard !isAnimating else {
return
}
isAnimating = true

self.callControlsOverflowPresenter?.callControlsOverflowWillAppear()

self.reactionPicker.isHidden = false
// `playPresentationAnimation` is built to be called on new, rather
// than reused, reaction pickers. Since we're reusing here, we need
// to reset the alpha.
self.reactionPicker.alpha = 1
self.reactionPicker.playPresentationAnimation(duration: 0.2) { [weak self] in
self?.isAnimating = false
}

// TODO: Animate Raise Hand menu item
}

func animateOut() {
guard !isAnimating else {
return
}
isAnimating = true

self.reactionPicker.isHidden = true
self.reactionPicker.playDismissalAnimation(
duration: 0.2,
completion: { [weak self] in
self?.isAnimating = false
self?.isHidden = true
self?.callControlsOverflowPresenter?.callControlsOverflowDidDisappear()
}
)

// TODO: Animate Raise Hand menu item
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

// MARK: - MessageReactionPickerDelegate

extension CallControlsOverflowView: MessageReactionPickerDelegate {
func didSelectReaction(reaction: String, isRemoving: Bool, inPosition position: Int) {
self.react(with: reaction)
}

func didSelectAnyEmoji() {
let sheet = EmojiPickerSheet(
message: nil,
allowReactionConfiguration: false,
forceDarkTheme: true
) { [weak self] selectedEmoji in
guard let selectedEmoji else { return }
self?.react(with: selectedEmoji.rawValue)
}
emojiPickerSheetPresenter?.present(
sheet: sheet,
animated: true
)
}

private func react(with reaction: String) {
self.callControlsOverflowPresenter?.willSendReaction()
self.reactionSender?.react(value: reaction)
// Locally-sent reactions do not come in via the API, so we add them here.
self.reactionReceiver?.addReactions(
reactions: [
Reaction(
emoji: reaction,
name: CommonStrings.you,
timestamp: Date.timeIntervalSinceReferenceDate
)
]
)
}
}

// MARK: ReactionSender

protocol ReactionSender {
func react(value: String)
}

extension GroupCall: ReactionSender {}

// MARK: ReactionReceiver

protocol ReactionReceiver {
func addReactions(reactions: [Reaction])
}

// MARK: - EmojiPickerSheetPresenter

protocol EmojiPickerSheetPresenter: AnyObject {
func present(sheet: EmojiPickerSheet, animated: Bool)
}

extension GroupCallViewController: EmojiPickerSheetPresenter {
func present(sheet: EmojiPickerSheet, animated: Bool) {
self.present(sheet, animated: animated)
}
}

// MARK: - CallControlsOverflowPresenter

protocol CallControlsOverflowPresenter: AnyObject {
func callControlsOverflowWillAppear()
func callControlsOverflowDidDisappear()
func willSendReaction()
}

0 comments on commit 4412a47

Please sign in to comment.