Enable/update group call action based on current call and thread

This commit is contained in:
Michelle Linington 2020-11-18 23:08:11 -08:00 committed by Nora Trapp
parent 485e12e6c4
commit d93c19abe7
7 changed files with 56 additions and 13 deletions

View File

@ -7,6 +7,7 @@ import SignalRingRTC
import PromiseKit
// All Observer methods will be invoked from the main thread.
@objc(OWSCallServiceObserver)
protocol CallServiceObserver: class {
/**
* Fired whenever the call changes.
@ -138,6 +139,7 @@ public final class CallService: NSObject {
private var observers = WeakArray<CallServiceObserver>()
// The observer-related methods should be invoked on the main thread.
@objc
func addObserverAndSyncState(observer: CallServiceObserver) {
AssertIsOnMainThread()
@ -148,6 +150,7 @@ public final class CallService: NSObject {
}
// The observer-related methods should be invoked on the main thread.
@objc
func removeObserver(_ observer: CallServiceObserver) {
AssertIsOnMainThread()
observers.removeAll { $0 === observer }

View File

@ -92,6 +92,7 @@ public class SignalCall: NSObject, CallManagerCallReference {
didSet { AssertIsOnMainThread() }
}
@objc
public let thread: TSThread?
public var error: CallError?

View File

@ -44,6 +44,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)conversationCell:(ConversationViewCell *)cell didEndLongpress:(id<ConversationViewItem>)viewItem;
- (void)conversationCell:(ConversationViewCell *)cell didTapReactions:(id<ConversationViewItem>)viewItem;
- (BOOL)conversationCellHasPendingMessageRequest:(ConversationViewCell *)cell;
@property (nonatomic, readonly) BOOL isCallingSupported;
#pragma mark - Selection

View File

@ -791,6 +791,7 @@ typedef void (^SystemMessageActionBlock)(void);
case RPRecentCallTypeIncomingAnsweredElsewhere:
case RPRecentCallTypeIncomingDeclinedElsewhere:
case RPRecentCallTypeIncomingBusyElsewhere:
// If delegate is nil, include the action. This way we always oversize instead of undersize.
if ([self.delegate conversationCellHasPendingMessageRequest:self]) {
return nil;
}
@ -800,6 +801,7 @@ typedef void (^SystemMessageActionBlock)(void);
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"call_back")];
case RPRecentCallTypeOutgoing:
case RPRecentCallTypeOutgoingMissed:
// If delegate is nil, include the action. This way we always oversize instead of undersize.
if ([self.delegate conversationCellHasPendingMessageRequest:self]) {
return nil;
}
@ -815,21 +817,20 @@ typedef void (^SystemMessageActionBlock)(void);
- (nullable SystemMessageAction *)actionForGroupCall:(OWSGroupCallMessage *)groupCallMessage
{
// TODO: Check if the current call belongs to this thread.
if (self.callService.currentCall != nil) {
return nil;
}
// Assume the current thread supports calling if we have no delegate. This ensures we always
// overestimate cell measurement in cases where the current thread doesn't support calling.
BOOL isCallingSupported = !self.delegate || self.delegate.isCallingSupported;
BOOL isCallActive = (!groupCallMessage.hasEnded && groupCallMessage.joinedMemberAddresses.count > 0);
// TODO: Respect -canCall from ConversationViewController
// TODO: "Return to call" if for the current thread. Hide the action is currently in a call
// For now we'll just check the feature flag
BOOL canCall = SSKFeatureFlags.groupCalling;
if (isCallingSupported && isCallActive) {
NSString *currentCallThreadId = self.callService.currentCall.thread.uniqueId;
BOOL isCurrentCallForThread = [currentCallThreadId isEqualToString:self.viewItem.thread.uniqueId];
NSString *joinTitle = NSLocalizedString(@"GROUP_CALL_JOIN_BUTTON", "Button to join an ongoing group call");
NSString *returnTitle = NSLocalizedString(@"CALL_RETURN_BUTTON", "Button to return to the current call");
NSString *actionTitle = isCurrentCallForThread ? returnTitle : joinTitle;
if (isCallActive && canCall) {
__weak typeof(self) wSelf = self;
NSString *actionTitle = NSLocalizedString(@"GROUP_CALL_JOIN_BUTTON", "Button to join an ongoing group call");
return [SystemMessageAction actionWithTitle:actionTitle
block:^{ [wSelf.delegate handleGroupCallTap]; }
accessibilityIdentifier:actionTitle];

View File

@ -1935,7 +1935,11 @@ typedef enum : NSUInteger {
- (void)handleGroupCallTap
{
[self showGroupCallLobby];
if ([self.callService.currentCall.thread.uniqueId isEqualToString:self.thread.uniqueId]) {
// TODO
} else {
[self showGroupCallLobby];
}
}
- (void)updateSystemContactWithAddress:(SignalServiceAddress *)address
@ -2281,6 +2285,11 @@ typedef enum : NSUInteger {
return self.threadViewModel.hasPendingMessageRequest;
}
- (BOOL)isCallingSupported
{
return [self canCall];
}
- (BOOL)isShowingSelectionUI
{
return self.uiMode == ConversationUIMode_Selection;

View File

@ -144,7 +144,7 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark -
@interface ConversationViewModel () <UIDatabaseSnapshotDelegate>
@interface ConversationViewModel () <UIDatabaseSnapshotDelegate, OWSCallServiceObserver>
@property (nonatomic, weak) id<ConversationViewModelDelegate> delegate;
@ -241,6 +241,11 @@ NS_ASSUME_NONNULL_BEGIN
return [OWSProfileManager shared];
}
- (CallService *)callService
{
return AppEnvironment.shared.callService;
}
#pragma mark -
- (void)addNotificationListeners
@ -265,6 +270,7 @@ NS_ASSUME_NONNULL_BEGIN
selector:@selector(localProfileDidChange:)
name:kNSNotificationNameLocalProfileDidChange
object:nil];
[self.callService addObserverAndSyncStateWithObserver:self];
}
- (void)profileWhitelistDidChange:(NSNotification *)notification
@ -326,6 +332,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)dealloc
{
[self.callService removeObserver:self];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
@ -1279,6 +1286,12 @@ NS_ASSUME_NONNULL_BEGIN
viewItem.senderProfileName = [self.profileManager fullNameForAddress:infoMessage.profileChangeAddress
transaction:transaction];
}
} else if (interactionType == OWSInteractionType_Call) {
NSString *activeCallThreadId = self.callService.currentCall.thread.uniqueId;
BOOL isAnotherThreadInCall = activeCallThreadId && ![self.thread.uniqueId isEqualToString:activeCallThreadId];
BOOL wasCollapsed = viewItem.shouldCollapseSystemMessageAction;
viewItem.shouldCollapseSystemMessageAction = wasCollapsed || isAnotherThreadInCall;
}
uint64_t collapseCutoffTimestamp = [NSDate ows_millisecondsSince1970ForDate:self.collapseCutoffDate];
@ -1494,6 +1507,18 @@ NS_ASSUME_NONNULL_BEGIN
return !self.canLoadOlderItems;
}
#pragma mark - <OWSCallServiceObserver>
- (void)didUpdateCallFrom:(nullable SignalCall *)oldValue to:(nullable SignalCall *)newValue
{
// If the call state changed for the current thread, we may want to hide the Call action.
// When registering, CallObserver sends the currentCall synchronously. Since we register
// during -viewDidLoad, ordering gets a bit messed up. It's okay if we async for a bit later.
dispatch_async(dispatch_get_main_queue(), ^{
[self updateForTransientItems];
});
}
@end
NS_ASSUME_NONNULL_END

View File

@ -481,6 +481,9 @@
/* notification body */
"CALL_MISSED_BECAUSE_OF_IDENTITY_CHANGE_NOTIFICATION_BODY" = "☎️ Missed call because the caller's safety number changed.";
/* Button to return to the current call */
"CALL_RETURN_BUTTON" = "Return To Call";
/* Call setup status label after outgoing call times out */
"CALL_SCREEN_STATUS_NO_ANSWER" = "No Answer";