Skip to content
This repository has been archived by the owner on Nov 10, 2020. It is now read-only.

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
Hassan Shahbazi committed Apr 2, 2020
2 parents 0000863 + 7a4ff05 commit 4d2807b
Show file tree
Hide file tree
Showing 15 changed files with 130 additions and 44 deletions.
4 changes: 2 additions & 2 deletions NinchatSDK.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ Pod::Spec.new do |s|
s.static_framework = true

# Cocoapods dependencies
s.dependency "AFNetworking", "~> 3.0"
s.dependency "AFNetworking"
s.dependency "NinchatLowLevelClient"
s.dependency "GoogleWebRTC", "~> 1.1"
s.dependency "GoogleWebRTC", "~> 1.0"

s.module_name = "NinchatSDK"
s.requires_arc = true
Expand Down
4 changes: 2 additions & 2 deletions NinchatSDK.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1237,7 +1237,7 @@
"-framework",
"\"CoreGraphics\"",
"-framework",
"\"MobileCoreServices\"",
"\"CoreServices\"",
"-framework",
"\"NinchatLowLevelClient\"",
"-framework",
Expand Down Expand Up @@ -1292,7 +1292,7 @@
"-framework",
"\"CoreGraphics\"",
"-framework",
"\"MobileCoreServices\"",
"\"CoreServices\"",
"-framework",
"\"NinchatLowLevelClient\"",
"-framework",
Expand Down
22 changes: 18 additions & 4 deletions NinchatSDK/ManagersAndServices/SessionManager/NINSessionManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,14 @@ -(void) realmQueuesFound:(NINLowLevelClientProps*)params {
return;
}

[_queues addObject:[NINQueue queueWithId:queueId andName:queueName]];
BOOL isClosed;
[queueAttrs getBool:@"closed" val:&isClosed error:&error];
if (error != nil) {
postNotification(kActionNotification, @{@"action_id": @(actionId), @"error": error});
return;
}

[_queues addObject:[NINQueue queueWithId:queueId andName:queueName isClosed:isClosed]];
}

// Form the list of audience queues; if audienceQueues is specified in siteConfig, we use those;
Expand Down Expand Up @@ -893,7 +900,9 @@ -(void) handleInboundMessage:(NINLowLevelClientProps*)params payload:(NINLowLeve
NINChannelUser* messageUser = _channelUsers[messageUserID];
if (messageUser == nil) {
NSLog(@"Message from unknown user: %@", messageUserID);
//TODO how big a problem is this?
/// This can result in crashes such as the one described in https://github.com/somia/ninchat-sdk-ios/issues/104
/// The solution is to either return with the appropriate error
/// Or trying to handle the situation in the rest of the function where the user is injected
}

if ([messageType isEqualToString:kNINMessageTypeWebRTCIceCandidate] ||
Expand All @@ -911,12 +920,17 @@ -(void) handleInboundMessage:(NINLowLevelClientProps*)params payload:(NINLowLeve
for (int i = 0; i < payload.length; i++) {
// Handle a WebRTC signaling message
NSDictionary* payloadDict = [NSJSONSerialization JSONObjectWithData:[payload get:i] options:0 error:&error];
if (error != nil) {
if (error != nil || payloadDict == nil) {
NSLog(@"Failed to deserialize message JSON: %@", error);
return;
}

postNotification(kNINWebRTCSignalNotification, @{@"messageType": messageType, @"payload": payloadDict, @"messageUser": messageUser});
/// For now, since only https://github.com/somia/ninchat-sdk-ios/issues/104 is reported by customers, the easiest way is to handle the "null" exception here
/// Later, if we get more crashes or reports, we might think to make a permanent solution for all.
if (messageUser == nil)
postNotification(kNINWebRTCSignalNotification, @{@"messageType": messageType, @"payload": payloadDict});
else
postNotification(kNINWebRTCSignalNotification, @{@"messageType": messageType, @"payload": payloadDict, @"messageUser": messageUser});
}
return;
}
Expand Down
16 changes: 14 additions & 2 deletions NinchatSDK/UI/Chat.storyboard
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15705" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16096" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15706"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16086"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
Expand Down Expand Up @@ -765,15 +765,26 @@ you are next.</string>
<action selector="closeWindowButtonPressed:" destination="YpM-11-QhB" eventType="touchUpInside" id="0qF-MX-afk"/>
</connections>
</button>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" scrollEnabled="NO" editable="NO" text="Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed " textAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="fX8-AZ-l16">
<rect key="frame" x="67.5" y="5" width="240" height="60"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<fontDescription key="fontDescription" name="SourceSansPro-Regular" family="Source Sans Pro" pointSize="16"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
<dataDetectorType key="dataDetectorTypes" phoneNumber="YES" link="YES"/>
</textView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="ign-ZR-Zu6" secondAttribute="bottom" constant="40" id="2BR-nD-ycT"/>
<constraint firstItem="ign-ZR-Zu6" firstAttribute="top" secondItem="kgP-Ty-5vY" secondAttribute="bottom" constant="15" id="6eV-mB-lOO"/>
<constraint firstItem="fX8-AZ-l16" firstAttribute="trailing" secondItem="kgP-Ty-5vY" secondAttribute="trailing" id="FfG-3t-bJX"/>
<constraint firstItem="kgP-Ty-5vY" firstAttribute="top" secondItem="MP0-uv-PXT" secondAttribute="top" constant="5" id="Omj-9X-SYY"/>
<constraint firstItem="kgP-Ty-5vY" firstAttribute="centerX" secondItem="MP0-uv-PXT" secondAttribute="centerX" id="P6s-Kh-uKE"/>
<constraint firstItem="ign-ZR-Zu6" firstAttribute="width" secondItem="kgP-Ty-5vY" secondAttribute="width" id="QCe-t8-Ez4"/>
<constraint firstItem="fX8-AZ-l16" firstAttribute="bottom" secondItem="kgP-Ty-5vY" secondAttribute="bottom" id="e20-P9-eWo"/>
<constraint firstItem="ign-ZR-Zu6" firstAttribute="centerX" secondItem="MP0-uv-PXT" secondAttribute="centerX" id="er1-fp-enb"/>
<constraint firstItem="fX8-AZ-l16" firstAttribute="top" secondItem="kgP-Ty-5vY" secondAttribute="top" id="pwh-1g-Xal"/>
<constraint firstItem="fX8-AZ-l16" firstAttribute="leading" secondItem="kgP-Ty-5vY" secondAttribute="leading" id="raD-IG-ZHO"/>
</constraints>
</view>
</subviews>
Expand Down Expand Up @@ -829,6 +840,7 @@ you are next.</string>
<outlet property="bottomContainerView" destination="3xg-1C-FCR" id="bTt-tN-u3D"/>
<outlet property="closeWindowButton" destination="ign-ZR-Zu6" id="jyw-cP-AxW"/>
<outlet property="motdTextView" destination="D4q-k8-gpN" id="mvn-0f-RPQ"/>
<outlet property="noQueueTextView" destination="fX8-AZ-l16" id="E10-tU-8bt"/>
<outlet property="queueButtonsStackView" destination="kgP-Ty-5vY" id="0f1-eC-IFe"/>
<outlet property="topContainerView" destination="Wa1-0U-Lj7" id="o2l-78-drn"/>
<outlet property="welcomeTextView" destination="sio-TM-FLm" id="On2-aa-gGH"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ typedef void (^consentDialogClosedBlock)(NINConsentDialogResult result);
@interface NINVideoCallConsentDialog : UIView

/** Displays the dialog on top of another view. */
+(instancetype) showOnView:(UIView*)view forRemoteUser:(NINChannelUser*)user sessionManager:(NINSessionManager*)sessionManager closedBlock:(consentDialogClosedBlock)closedBlock;
+(instancetype _Nonnull) showOnView:(UIView* _Nonnull)view forRemoteUser:(NINChannelUser* _Nullable)user sessionManager:(NINSessionManager* _Nonnull)sessionManager closedBlock:(consentDialogClosedBlock _Nullable)closedBlock;

@end
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ +(NINVideoCallConsentDialog*) loadViewFromNib {

#pragma mark - Public methods

+(instancetype) showOnView:(UIView*)view forRemoteUser:(NINChannelUser*)user sessionManager:(NINSessionManager*)sessionManager closedBlock:(consentDialogClosedBlock)closedBlock {
+(instancetype _Nonnull) showOnView:(UIView* _Nonnull)view forRemoteUser:(NINChannelUser* _Nullable)user sessionManager:(NINSessionManager* _Nonnull)sessionManager closedBlock:(consentDialogClosedBlock _Nullable)closedBlock {
NINVideoCallConsentDialog* d = [NINVideoCallConsentDialog loadViewFromNib];
d.translatesAutoresizingMaskIntoConstraints = NO;
d.closedBlock = closedBlock;
Expand All @@ -95,15 +95,19 @@ +(instancetype) showOnView:(UIView*)view forRemoteUser:(NINChannelUser*)user ses
// Caller's Avatar image
if (agentAvatarConfig.imageOverrideUrl != nil) {
[d.avatarImageView setImageWithURL:[NSURL URLWithString:agentAvatarConfig.imageOverrideUrl]];
} else {
} else if (user != nil) {
[d.avatarImageView setImageWithURL:[NSURL URLWithString:user.iconURL]];
} else {
d.avatarImageView.image = [UIImage imageNamed:@"icon_avatar_other" inBundle:findResourceBundle() compatibleWithTraitCollection:nil];
}

// Caller's name
if (agentAvatarConfig.nameOverride != nil) {
d.usernameLabel.text = agentAvatarConfig.nameOverride;
} else {
} else if (user != nil) {
d.usernameLabel.text = user.displayName;
} else {
d.usernameLabel.text = NSLocalizedStringFromTableInBundle(@"Guest", @"Localizable", findResourceBundle(), @"");
}

[d applyAssetOverrides:sessionManager.ninchatSession];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// Copyright © 2018 Somia Reality Oy. All rights reserved.
//

@import MobileCoreServices;
@import CoreServices;
@import AVFoundation;
@import AVKit;
@import Photos;
Expand Down Expand Up @@ -952,7 +952,12 @@ -(void) viewDidLoad {
fetchNotification(kNINChannelClosedNotification, ^BOOL(NSNotification* notification) {
[weakSelf stopObserverChatEvents];
[weakSelf disableInputControls];


/// Ending the conversation must remove the video
/// As described in https://github.com/somia/ninchat-sdk-ios/issues/105
[weakSelf disconnectWebRTC];
[weakSelf adjustConstraintsForSize:weakSelf.view.bounds.size animate:YES];

return YES;
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

// UI strings
static NSString* const kJoinQueueText = @"Join audience queue {{audienceQueue.queue_attrs.name}}";
static NSString* const kJoinClosedQueueText = @"Join audience queue {{audienceQueue.queue_attrs.name}} (Closed)";
static NSString* const kNoQueueText = @"noQueuesText";
static NSString* const kCloseWindowText = @"Close window";

// Segue id to open queue view
Expand All @@ -31,6 +33,7 @@ @interface NINInitialViewController ()
@property (nonatomic, strong) IBOutlet UIStackView* queueButtonsStackView;
@property (nonatomic, strong) IBOutlet UIButton* closeWindowButton;
@property (nonatomic, strong) IBOutlet UITextView* motdTextView;
@property (nonatomic, strong) IBOutlet UITextView* noQueueTextView;

@end

Expand Down Expand Up @@ -107,15 +110,40 @@ -(void) viewDidAppear:(BOOL)animated {
}
}

/// The function determines if there is at least one open queue to join
/// According to https://github.com/somia/ninchat-sdk-ios/issues/68
- (BOOL) canJoinAtLeastOneQueue {
for (NINQueue *queue in self.sessionManager.audienceQueues) {
if (!queue.isClosed) {
return YES;
}
}
return NO;
}

- (NSArray<NINQueue*>*) queueList {
NSMutableArray *list = [NSMutableArray new];
for (NINQueue *queue in self.sessionManager.audienceQueues) {
if (!queue.isClosed) {
[list addObject:queue];
}
}
return list;
}

-(void) createQueueButtons {
const NSInteger maxButtons = 3;

[self.queueButtonsStackView setHidden:NO];
[self.noQueueTextView setHidden:YES];

// Remote any existing buttons in the stack view
for (UIView* view in self.queueButtonsStackView.subviews) {
[view removeFromSuperview];
}

NSInteger numButtons = MIN(maxButtons, self.sessionManager.audienceQueues.count);
NSArray<NINQueue*>* queues = [self queueList];
NSInteger numButtons = MIN(maxButtons, queues.count);
CGFloat buttonHeight = (numButtons > 2) ? 40.0 : 60.0;

UIColor* defaultBgColor = [UIColor colorWithRed:73.0/255 green:172.0/255 blue:253.0/255 alpha:1];
Expand All @@ -124,8 +152,8 @@ -(void) createQueueButtons {

__weak typeof(self) weakSelf = self;

for (NSInteger i = 0; i < numButtons; i++) {
NINQueue* queue = self.sessionManager.audienceQueues[i];
for (NSUInteger i = 0; i < numButtons; i++) {
NINQueue* queue = queues[i];
UIButton* button = [UIButton buttonWithPressedCallback:^{
[weakSelf performSegueWithIdentifier:kSegueIdInitialToQueue sender:queue];
}];
Expand All @@ -136,19 +164,29 @@ -(void) createQueueButtons {
button.layer.cornerRadius = buttonHeight / 2;
button.backgroundColor = defaultBgColor;
[button setTitleColor:defaultTextColor forState:UIControlStateNormal];
[button setTitle:[self.sessionManager translation:kJoinQueueText formatParams:@{@"audienceQueue.queue_attrs.name": queue.name}] forState:UIControlStateNormal];
[button overrideAssetsWithSession:self.sessionManager.ninchatSession isPrimaryButton:YES];

// Check if the queue is open to join, according to https://github.com/somia/ninchat-sdk-ios/issues/68
[button setEnabled:!queue.isClosed];
[button setAlpha: (queue.isClosed) ? 0.5 : 1.0];
[button setTitle:[self.sessionManager translation:(queue.isClosed) ? kJoinClosedQueueText : kJoinQueueText formatParams:@{@"audienceQueue.queue_attrs.name": queue.name}] forState:UIControlStateNormal];

// Add the button to the stack view
[self.queueButtonsStackView addArrangedSubview:button];

// Set button height via constraint
[constraints addObject:[button.heightAnchor constraintEqualToConstant:buttonHeight]];
}

[NSLayoutConstraint activateConstraints:constraints];
}

- (void) createNoQueueText {
[self.queueButtonsStackView setHidden:YES];
[self.noQueueTextView setHidden:NO];

[self.noQueueTextView setFormattedText:[self.sessionManager.siteConfiguration valueForKey:kNoQueueText]];
}

-(void) viewDidLoad {
[super viewDidLoad];

Expand All @@ -160,8 +198,12 @@ -(void) viewDidLoad {
[self.motdTextView setFormattedText:[self.sessionManager.siteConfiguration valueForKey:@"motd"]];
self.motdTextView.delegate = self;

// Create queue buttons
[self createQueueButtons];
/// if there are open queues to join
if ([self canJoinAtLeastOneQueue])
[self createQueueButtons]; /// Create queue buttons
else
[self createNoQueueText]; /// Let the user knows there is no open queue to join.


// Rounded button corners
self.closeWindowButton.layer.cornerRadius = self.closeWindowButton.bounds.size.height / 2;
Expand Down
23 changes: 16 additions & 7 deletions NinchatSDK/UI/ViewControllers/QueueView/NINQueueViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#import "UIButton+Ninchat.h"

// UI strings
static NSString* const kNoQueueText = @"noQueuesText";
static NSString* const kQueuePositionN = @"Joined audience queue {{audienceQueue.queue_attrs.name}}, you are at position {{audienceQueue.queue_position}}.";
static NSString* const kQueuePositionNext = @"Joined audience queue {{audienceQueue.queue_attrs.name}}, you are next.";
static NSString* const kCloseChatText = @"Close chat";
Expand Down Expand Up @@ -75,22 +76,30 @@ -(void) applyAssetOverrides {
[self.closeChatButton overrideAssetsWithSession:self.sessionManager.ninchatSession];
}

-(void) connectToQueueWithId:(NSString*)queueId {
/// https://github.com/somia/ninchat-sdk-ios/issues/68
-(void) connectToQueue:(NINQueue*)queue {
if (queue.isClosed) {
[self.queueInfoTextView setFormattedText:[self.sessionManager.siteConfiguration valueForKey:kNoQueueText]];
return;
}
[self connectToQueueWithId:queue.queueID];
}

- (void)connectToQueueWithId:(NSString*)queueID {
__weak typeof(self) weakSelf = self;

[self.sessionManager joinQueueWithId:queueId progress:^(NSError * _Nullable error, NSInteger queuePosition) {

[self.sessionManager joinQueueWithId:queueID progress:^(NSError * _Nullable error, NSInteger queuePosition) {

if (error != nil) {
// Failed to join the queue
[self.sessionManager.ninchatSession sdklog:@"Failed to join the queue: %@", error];
}

if (queuePosition == 1) {
[weakSelf.queueInfoTextView setFormattedText:[weakSelf.sessionManager translation:kQueuePositionNext formatParams:@{@"audienceQueue.queue_attrs.name": weakSelf.queueToJoin.name}]];
} else {
[weakSelf.queueInfoTextView setFormattedText:[weakSelf.sessionManager translation:kQueuePositionN formatParams:@{@"audienceQueue.queue_position": @(queuePosition).stringValue, @"audienceQueue.queue_attrs.name": weakSelf.queueToJoin.name}]];
}

// Apply color override
UIColor* textTopColor = [weakSelf.sessionManager.ninchatSession overrideColorAssetForKey:NINColorAssetTextTop];
if (textTopColor != nil) {
Expand Down Expand Up @@ -170,7 +179,7 @@ -(void) viewDidLoad {

// Connect to the queue
[[NSNotificationCenter defaultCenter] removeObserver:self name:kNINQueuedNotification object:nil];
[self connectToQueueWithId:self.queueToJoin.queueID];
[self connectToQueue:self.queueToJoin];
}

@end
3 changes: 2 additions & 1 deletion NinchatSDK/Utils/Entities/NINQueue.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@

@property (nonatomic, strong, readonly) NSString* queueID;
@property (nonatomic, strong, readonly) NSString* name;
@property (nonatomic, assign, readonly) BOOL isClosed;

+(NINQueue*) queueWithId:(NSString*)queueId andName:(NSString*)name;
+(NINQueue*) queueWithId:(NSString*)queueId andName:(NSString*)name isClosed:(BOOL)isClosed;

@end
4 changes: 3 additions & 1 deletion NinchatSDK/Utils/Entities/NINQueue.m
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ @interface NINQueue ()
// Private writable versions of the properties
@property (nonatomic, strong) NSString* queueID;
@property (nonatomic, strong) NSString* name;
@property (nonatomic, assign) BOOL isClosed;

@end

Expand All @@ -37,10 +38,11 @@ -(NSString*) description {
return [NSString stringWithFormat:@"Queue ID: %@, Name: %@", self.queueID, self.name];
}

+(NINQueue*) queueWithId:(NSString*)queueId andName:(NSString*)name {
+(NINQueue*) queueWithId:(NSString*)queueId andName:(NSString*)name isClosed:(BOOL)isClosed {
NINQueue* queue = [NINQueue new];
queue.queueID = queueId;
queue.name = name;
queue.isClosed = isClosed;

return queue;
}
Expand Down
Loading

0 comments on commit 4d2807b

Please sign in to comment.