osx: add chat support
This commit adds a collapsible right panel for incall chatting
Refs #74037
Change-Id: I82c53174c1dbdeb1cfdb4ab8a773256aa182b70c
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c619bc2..fadcc7c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -68,7 +68,9 @@
src/HistoryVC.mm
src/HistoryVC.h
src/PersonsVC.mm
- src/PersonsVC.h)
+ src/PersonsVC.h
+ src/ChatVC.mm
+ src/ChatVC.h)
SET(ringclient_BACKENDS
src/backends/AddressBookBackend.mm
diff --git a/src/ChatVC.h b/src/ChatVC.h
new file mode 100644
index 0000000..f07f5af
--- /dev/null
+++ b/src/ChatVC.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 Savoir-Faire Linux Inc.
+ * Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Additional permission under GNU GPL version 3 section 7:
+ *
+ * If you modify this program, or any covered work, by linking or
+ * combining it with the OpenSSL project's OpenSSL library (or a
+ * modified version of that library), containing parts covered by the
+ * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
+ * grants you additional permission to convey the resulting work.
+ * Corresponding Source for a non-source form of such a combination
+ * shall include the source code for the parts of OpenSSL used as well
+ * as that of the covered work.
+ */
+#import <Cocoa/Cocoa.h>
+
+@interface ChatVC : NSViewController <NSTextFieldDelegate>
+
+/**
+ * Message contained in messageField TextField.
+ * This is a KVO method to bind the text with the send Button
+ * if message.length is > 0, button is enabled, otherwise disabled
+ */
+@property (retain) NSString* message;
+
+@end
diff --git a/src/ChatVC.mm b/src/ChatVC.mm
new file mode 100644
index 0000000..bedbdd2
--- /dev/null
+++ b/src/ChatVC.mm
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2015 Savoir-Faire Linux Inc.
+ * Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Additional permission under GNU GPL version 3 section 7:
+ *
+ * If you modify this program, or any covered work, by linking or
+ * combining it with the OpenSSL project's OpenSSL library (or a
+ * modified version of that library), containing parts covered by the
+ * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
+ * grants you additional permission to convey the resulting work.
+ * Corresponding Source for a non-source form of such a combination
+ * shall include the source code for the parts of OpenSSL used as well
+ * as that of the covered work.
+ */
+
+#import "ChatVC.h"
+
+#import <QItemSelectionModel>
+#import <qstring.h>
+
+#import <media/media.h>
+#import <media/text.h>
+#import <media/textrecording.h>
+#import <callmodel.h>
+
+@interface MediaConnectionsHolder : NSObject
+
+@property QMetaObject::Connection newMediaAdded;
+@property QMetaObject::Connection newMessage;
+
+@end
+
+@implementation MediaConnectionsHolder
+
+@end
+
+@interface ChatVC ()
+
+@property (unsafe_unretained) IBOutlet NSTextView *chatView;
+@property (unsafe_unretained) IBOutlet NSTextField *messageField;
+@property (unsafe_unretained) IBOutlet NSButton *sendButton;
+
+@property MediaConnectionsHolder* mediaHolder;
+
+@end
+
+@implementation ChatVC
+@synthesize messageField,chatView,sendButton, mediaHolder;
+
+- (void)awakeFromNib
+{
+ NSLog(@"Init ChatVC");
+
+ [self.view setWantsLayer:YES];
+ [self.view setLayer:[CALayer layer]];
+ [self.view.layer setBackgroundColor:[NSColor blackColor].CGColor];
+
+ mediaHolder = [[MediaConnectionsHolder alloc] init];
+
+ QObject::connect(CallModel::instance()->selectionModel(),
+ &QItemSelectionModel::currentChanged,
+ [=](const QModelIndex ¤t, const QModelIndex &previous) {
+ [self setupChat];
+ });
+}
+
+- (void) setupChat
+{
+ QObject::disconnect(mediaHolder.newMediaAdded);
+ QObject::disconnect(mediaHolder.newMessage);
+
+ QModelIndex callIdx = CallModel::instance()->selectionModel()->currentIndex();
+
+ if (!callIdx.isValid())
+ return;
+
+ Call* call = CallModel::instance()->getCall(callIdx);
+
+ /* check if text media is already present */
+ if (call->hasMedia(Media::Media::Type::TEXT, Media::Media::Direction::IN)) {
+ Media::Text *text = call->firstMedia<Media::Text>(Media::Media::Direction::IN);
+ [self parseChatModel:text->recording()->instantMessagingModel()];
+ } else if (call->hasMedia(Media::Media::Type::TEXT, Media::Media::Direction::OUT)) {
+ Media::Text *text = call->firstMedia<Media::Text>(Media::Media::Direction::OUT);
+ [self parseChatModel:text->recording()->instantMessagingModel()];
+ } else {
+ /* monitor media for messaging text messaging */
+ mediaHolder.newMediaAdded = QObject::connect(call,
+ &Call::mediaAdded,
+ [self] (Media::Media* media) {
+ if (media->type() == Media::Media::Type::TEXT) {
+ QObject::disconnect(mediaHolder.newMediaAdded);
+ [self parseChatModel:((Media::Text*)media)->recording()->instantMessagingModel()];
+
+ }
+ });
+ }
+}
+
+- (void) parseChatModel:(QAbstractItemModel *)model
+{
+ QObject::disconnect(mediaHolder.newMessage);
+ [self.messageField setStringValue:@""];
+ self.message = @"";
+ [self.chatView.textStorage.mutableString setString:@""];
+
+ /* put all the messages in the im model into the text view */
+ for (int row = 0; row < model->rowCount(); ++row) {
+ [self appendNewMessage:model->index(row, 0)];
+ }
+
+ /* append new messages */
+ mediaHolder.newMessage = QObject::connect(model,
+ &QAbstractItemModel::rowsInserted,
+ [self, model] (const QModelIndex &parent, int first, int last) {
+ for (int row = first; row <= last; ++row) {
+ QModelIndex idx = model->index(row, 0, parent);
+ [self appendNewMessage:idx];
+ }
+ }
+ );
+}
+
+- (void) appendNewMessage:(const QModelIndex&) msgIdx
+{
+ if (!msgIdx.isValid())
+ return;
+
+ QVariant message = msgIdx.data();
+ NSAttributedString* attr = [[NSAttributedString alloc] initWithString:
+ [NSString stringWithFormat:@"%@\n",message.value<QString>().toNSString()]];
+ [[chatView textStorage] appendAttributedString:attr];
+ [chatView scrollRangeToVisible:NSMakeRange([[chatView string] length], 0)];
+
+}
+
+- (IBAction)sendMessage:(id)sender {
+
+ QModelIndex callIdx = CallModel::instance()->selectionModel()->currentIndex();
+ Call* call = CallModel::instance()->getCall(callIdx);
+
+ /* make sure there is text to send */
+ NSString* text = self.message;
+ if (text && text.length > 0) {
+ call->addOutgoingMedia<Media::Text>()->send(QString::fromNSString(text));
+ // Empty the text after sending it
+ [self.messageField setStringValue:@""];
+ self.message = @"";
+ }
+}
+
+#pragma mark - NSTextFieldDelegate
+
+- (BOOL)control:(NSControl *)control textView:(NSTextView *)fieldEditor doCommandBySelector:(SEL)commandSelector
+{
+ if (commandSelector == @selector(insertNewline:) && self.message.length > 0) {
+ [self sendMessage:nil];
+ return YES;
+ }
+ return NO;
+}
+
+@end
diff --git a/src/ConversationsVC.mm b/src/ConversationsVC.mm
index c7dabad..13aa12f 100644
--- a/src/ConversationsVC.mm
+++ b/src/ConversationsVC.mm
@@ -32,14 +32,10 @@
#import <callmodel.h>
#import <QtCore/qitemselectionmodel.h>
-#import "CurrentCallVC.h"
-
#define COLUMNID_CONVERSATIONS @"ConversationsColumn" // the single column name in our outline view
@interface ConversationsVC ()
-@property CurrentCallVC* currentVC;
-@property (assign) IBOutlet NSView *currentCallView;
@property QNSTreeController *treeController;
@property (assign) IBOutlet NSOutlineView *conversationsView;
@@ -48,9 +44,6 @@
@implementation ConversationsVC
@synthesize conversationsView;
@synthesize treeController;
-@synthesize currentVC;
-@synthesize currentCallView;
-
- (void)awakeFromNib
{
NSLog(@"INIT Conversations VC");
@@ -73,15 +66,7 @@
[conversationsView reloadDataForRowIndexes:
[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(topLeft.row(), bottomRight.row() + 1)]
columnIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, conversationsView.tableColumns.count)]];
-
});
-
- currentVC = [[CurrentCallVC alloc] initWithNibName:@"CurrentCall" bundle:nil];
- [currentCallView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
- [[currentVC view] setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
-
- [currentCallView addSubview:[self.currentVC view]];
- [currentVC initFrame];
}
#pragma mark - NSOutlineViewDelegate methods
diff --git a/src/CurrentCallVC.h b/src/CurrentCallVC.h
index e24cf01..7000c55 100644
--- a/src/CurrentCallVC.h
+++ b/src/CurrentCallVC.h
@@ -32,9 +32,11 @@
#import <Cocoa/Cocoa.h>
+#import "views/CallView.h"
+
class Call;
-@interface CurrentCallVC : NSViewController {
+@interface CurrentCallVC : NSViewController <NSSplitViewDelegate, FullScreenDelegate> {
}
diff --git a/src/CurrentCallVC.mm b/src/CurrentCallVC.mm
index aa853cb..0035a15 100644
--- a/src/CurrentCallVC.mm
+++ b/src/CurrentCallVC.mm
@@ -40,11 +40,10 @@
#import <QItemSelection>
#import <video/previewmanager.h>
#import <video/renderer.h>
+#import <media/text.h>
#import "views/CallView.h"
-/** FrameReceiver class - delegate for AVCaptureSession
- */
@interface RendererConnectionsHolder : NSObject
@property QMetaObject::Connection frameUpdated;
@@ -59,21 +58,23 @@
@interface CurrentCallVC ()
-@property (assign) IBOutlet NSTextField *personLabel;
-@property (assign) IBOutlet NSTextField *stateLabel;
-@property (assign) IBOutlet NSButton *holdOnOffButton;
-@property (assign) IBOutlet NSButton *hangUpButton;
-@property (assign) IBOutlet NSButton *recordOnOffButton;
-@property (assign) IBOutlet NSButton *pickUpButton;
-@property (assign) IBOutlet NSTextField *timeSpentLabel;
-@property (assign) IBOutlet NSView *controlsPanel;
+@property (unsafe_unretained) IBOutlet NSTextField *personLabel;
+@property (unsafe_unretained) IBOutlet NSTextField *stateLabel;
+@property (unsafe_unretained) IBOutlet NSButton *holdOnOffButton;
+@property (unsafe_unretained) IBOutlet NSButton *hangUpButton;
+@property (unsafe_unretained) IBOutlet NSButton *recordOnOffButton;
+@property (unsafe_unretained) IBOutlet NSButton *pickUpButton;
+@property (unsafe_unretained) IBOutlet NSTextField *timeSpentLabel;
+@property (unsafe_unretained) IBOutlet NSView *controlsPanel;
+@property (unsafe_unretained) IBOutlet NSSplitView *splitView;
+@property (unsafe_unretained) IBOutlet NSButton *chatButton;
@property QHash<int, NSButton*> actionHash;
// Video
-@property (assign) IBOutlet CallView *videoView;
+@property (unsafe_unretained) IBOutlet CallView *videoView;
@property CALayer* videoLayer;
-@property (assign) IBOutlet NSView *previewView;
+@property (unsafe_unretained) IBOutlet NSView *previewView;
@property CALayer* previewLayer;
@property RendererConnectionsHolder* previewHolder;
@@ -90,12 +91,14 @@
@synthesize hangUpButton;
@synthesize recordOnOffButton;
@synthesize pickUpButton;
+@synthesize chatButton;
@synthesize timeSpentLabel;
@synthesize controlsPanel;
@synthesize videoView;
@synthesize videoLayer;
@synthesize previewLayer;
@synthesize previewView;
+@synthesize splitView;
@synthesize previewHolder;
@synthesize videoHolder;
@@ -128,10 +131,10 @@
-(void) updateCall
{
QModelIndex callIdx = CallModel::instance()->selectionModel()->currentIndex();
- [personLabel setStringValue:CallModel::instance()->data(callIdx, Qt::DisplayRole).toString().toNSString()];
- [timeSpentLabel setStringValue:CallModel::instance()->data(callIdx, (int)Call::Role::Length).toString().toNSString()];
+ [personLabel setStringValue:callIdx.data(Qt::DisplayRole).toString().toNSString()];
+ [timeSpentLabel setStringValue:callIdx.data((int)Call::Role::Length).toString().toNSString()];
- Call::State state = CallModel::instance()->data(callIdx, (int)Call::Role::State).value<Call::State>();
+ Call::State state = callIdx.data((int)Call::Role::State).value<Call::State>();
switch (state) {
case Call::State::DIALING:
@@ -221,6 +224,8 @@
previewHolder = [[RendererConnectionsHolder alloc] init];
videoHolder = [[RendererConnectionsHolder alloc] init];
+ [self.videoView setFullScreenDelegate:self];
+
[self connect];
}
@@ -233,6 +238,7 @@
[self animateOut];
return;
}
+ [self collapseRightView];
[self updateCall];
[self updateAllActions];
[self animateOut];
@@ -264,7 +270,7 @@
{
QModelIndex idx = CallModel::instance()->selectionModel()->currentIndex();
Call* call = CallModel::instance()->getCall(idx);
- QObject::connect(call,
+ self.videoStarted = QObject::connect(call,
&Call::videoStarted,
[=](Video::Renderer* renderer) {
NSLog(@"Video started!");
@@ -453,8 +459,37 @@
NSLog(@"frame %@ : %f %f %f %f \n\n",name ,frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
}
+-(void)collapseRightView
+{
+ NSView *right = [[splitView subviews] objectAtIndex:1];
+ NSView *left = [[splitView subviews] objectAtIndex:0];
+ NSRect leftFrame = [left frame];
+ [right setHidden:YES];
+ [splitView display];
+}
-#pragma button methods
+-(void)uncollapseRightView
+{
+ NSView *left = [[splitView subviews] objectAtIndex:0];
+ NSView *right = [[splitView subviews] objectAtIndex:1];
+ [right setHidden:NO];
+
+ CGFloat dividerThickness = [splitView dividerThickness];
+
+ // get the different frames
+ NSRect leftFrame = [left frame];
+ NSRect rightFrame = [right frame];
+
+ leftFrame.size.width = (leftFrame.size.width - rightFrame.size.width - dividerThickness);
+ rightFrame.origin.x = leftFrame.size.width + dividerThickness;
+ [left setFrameSize:leftFrame.size];
+ [right setFrame:rightFrame];
+ [splitView display];
+}
+
+
+#pragma mark - Button methods
+
- (IBAction)hangUp:(id)sender {
CallModel::instance()->getCall(CallModel::instance()->selectionModel()->currentIndex()) << Call::Action::REFUSE;
}
@@ -471,4 +506,50 @@
CallModel::instance()->getCall(CallModel::instance()->selectionModel()->currentIndex()) << Call::Action::HOLD;
}
+-(IBAction)toggleChat:(id)sender;
+{
+ BOOL rightViewCollapsed = [[self splitView] isSubviewCollapsed:[[[self splitView] subviews] objectAtIndex: 1]];
+ if (rightViewCollapsed) {
+ [self uncollapseRightView];
+ CallModel::instance()->getCall(CallModel::instance()->selectionModel()->currentIndex())->addOutgoingMedia<Media::Text>();
+ } else {
+ [self collapseRightView];
+ }
+ [chatButton setState:rightViewCollapsed];
+}
+
+#pragma mark - NSSplitViewDelegate
+
+/* Return YES if the subview should be collapsed because the user has double-clicked on an adjacent divider. If a split view has a delegate, and the delegate responds to this message, it will be sent once for the subview before a divider when the user double-clicks on that divider, and again for the subview after the divider, but only if the delegate returned YES when sent -splitView:canCollapseSubview: for the subview in question. When the delegate indicates that both subviews should be collapsed NSSplitView's behavior is undefined.
+ */
+- (BOOL)splitView:(NSSplitView *)splitView shouldCollapseSubview:(NSView *)subview forDoubleClickOnDividerAtIndex:(NSInteger)dividerIndex;
+{
+ NSView* rightView = [[splitView subviews] objectAtIndex:1];
+ return ([subview isEqual:rightView]);
+}
+
+
+- (BOOL)splitView:(NSSplitView *)splitView canCollapseSubview:(NSView *)subview;
+{
+ NSView* rightView = [[splitView subviews] objectAtIndex:1];
+ return ([subview isEqual:rightView]);
+}
+
+
+# pragma mark - FullScreenDelegate
+
+- (void) callShouldToggleFullScreen
+{
+ if(self.splitView.isInFullScreenMode)
+ [self.splitView exitFullScreenModeWithOptions:nil];
+ else {
+ NSApplicationPresentationOptions options = NSApplicationPresentationDefault +NSApplicationPresentationAutoHideDock +
+ NSApplicationPresentationAutoHideMenuBar + NSApplicationPresentationAutoHideToolbar;
+ NSDictionary *opts = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithUnsignedInt:options],
+ NSFullScreenModeApplicationPresentationOptions, nil];
+
+ [self.splitView enterFullScreenMode:[NSScreen mainScreen] withOptions:opts];
+ }
+}
+
@end
diff --git a/src/RingWindowController.mm b/src/RingWindowController.mm
index f708f7c..7559041 100644
--- a/src/RingWindowController.mm
+++ b/src/RingWindowController.mm
@@ -36,15 +36,22 @@
#import "AppDelegate.h"
#import "Constants.h"
+#import "CurrentCallVC.h"
@interface RingWindowController ()
@property NSSearchField* callField;
+@property CurrentCallVC* currentVC;
+@property (unsafe_unretained) IBOutlet NSView *callView;
+
@end
@implementation RingWindowController
@synthesize callField;
+@synthesize currentVC;
+@synthesize callView;
+
static NSString* const kSearchViewIdentifier = @"SearchViewIdentifier";
static NSString* const kPreferencesIdentifier = @"PreferencesIdentifier";
static NSString* const kCallButtonIdentifer = @"CallButtonIdentifier";
@@ -53,6 +60,13 @@
[super windowDidLoad];
[self.window setReleasedWhenClosed:FALSE];
[self displayMainToolBar];
+
+ currentVC = [[CurrentCallVC alloc] initWithNibName:@"CurrentCall" bundle:nil];
+ [callView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
+ [[currentVC view] setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
+
+ [callView addSubview:[self.currentVC view]];
+ [currentVC initFrame];
}
- (IBAction)openPreferences:(id)sender
diff --git a/src/views/CallView.h b/src/views/CallView.h
index 06b4590..b15d525 100644
--- a/src/views/CallView.h
+++ b/src/views/CallView.h
@@ -29,6 +29,15 @@
*/
#import <Cocoa/Cocoa.h>
+@protocol FullScreenDelegate;
+@protocol FullScreenDelegate
+
+@optional
+
+-(void) callShouldToggleFullScreen;
+
+@end
+
@interface CallView : NSView <NSDraggingDestination, NSOpenSavePanelDelegate>
{
//highlight the drop zone
@@ -42,4 +51,9 @@
*/
@property BOOL shouldAcceptInteractions;
+/**
+ * Delegate to inform about desire to move
+ */
+@property (nonatomic) id <FullScreenDelegate> fullScreenDelegate;
+
@end
diff --git a/src/views/CallView.mm b/src/views/CallView.mm
index 8831db2..43a5d80 100644
--- a/src/views/CallView.mm
+++ b/src/views/CallView.mm
@@ -186,15 +186,8 @@
else if([theEvent clickCount] == 2)
{
[NSObject cancelPreviousPerformRequestsWithTarget:self]; // cancel showContextualMenu
- if(self.isInFullScreenMode)
- [self exitFullScreenModeWithOptions:nil];
- else {
- NSApplicationPresentationOptions options = NSApplicationPresentationDefault + NSApplicationPresentationAutoHideDock +
- NSApplicationPresentationAutoHideMenuBar + NSApplicationPresentationAutoHideToolbar;
- NSDictionary *opts = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithUnsignedInt:options], NSFullScreenModeApplicationPresentationOptions, nil];
-
- [self enterFullScreenMode:[NSScreen mainScreen] withOptions:opts];
- }
+ if(self.fullScreenDelegate)
+ [self.fullScreenDelegate callShouldToggleFullScreen];
}
}
diff --git a/ui/CurrentCall.xib b/ui/CurrentCall.xib
index 1d6538e..02a15e2 100644
--- a/ui/CurrentCall.xib
+++ b/ui/CurrentCall.xib
@@ -1,11 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="6751" systemVersion="14C1510" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="7706" systemVersion="14D2134" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
- <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="6751"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="7706"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="CurrentCallVC">
<connections>
+ <outlet property="chatButton" destination="fmp-x4-Pef" id="ARt-dr-TRo"/>
<outlet property="controlsPanel" destination="Eoi-B8-iL6" id="4xn-3b-SNn"/>
<outlet property="hangUpButton" destination="Kjq-iM-NBL" id="Puz-4L-Okl"/>
<outlet property="holdOnOffButton" destination="anb-Y8-JQi" id="HSl-pE-Kwg"/>
@@ -13,6 +14,7 @@
<outlet property="pickUpButton" destination="qgD-3D-nD5" id="mkD-IT-22E"/>
<outlet property="previewView" destination="6y6-RH-qOp" id="1PY-sd-mh4"/>
<outlet property="recordOnOffButton" destination="oRa-pS-HN2" id="N7C-wn-0le"/>
+ <outlet property="splitView" destination="GIJ-gB-FZo" id="PM0-az-Q8X"/>
<outlet property="stateLabel" destination="kFD-FB-vig" id="SSO-14-q2t"/>
<outlet property="timeSpentLabel" destination="cIU-M7-xpN" id="9Rl-t3-gjY"/>
<outlet property="videoView" destination="2wf-Py-l6B" id="dEF-Gx-w6x"/>
@@ -22,170 +24,289 @@
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customView id="Hz6-mo-xeY">
- <rect key="frame" x="0.0" y="0.0" width="608" height="493"/>
+ <rect key="frame" x="0.0" y="0.0" width="1014" height="509"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
- <customView translatesAutoresizingMaskIntoConstraints="NO" id="2wf-Py-l6B" customClass="CallView">
- <rect key="frame" x="0.0" y="0.0" width="608" height="493"/>
+ <splitView dividerStyle="thin" vertical="YES" translatesAutoresizingMaskIntoConstraints="NO" id="GIJ-gB-FZo">
+ <rect key="frame" x="0.0" y="0.0" width="1014" height="509"/>
<subviews>
- <customView translatesAutoresizingMaskIntoConstraints="NO" id="6y6-RH-qOp" userLabel="Preview">
- <rect key="frame" x="413" y="20" width="175" height="120"/>
- <constraints>
- <constraint firstAttribute="height" constant="120" id="BvU-kV-0uD"/>
- <constraint firstAttribute="width" constant="175" id="aEv-Tt-tSD"/>
- </constraints>
- </customView>
- <customView translatesAutoresizingMaskIntoConstraints="NO" id="Eoi-B8-iL6" userLabel="Controls">
- <rect key="frame" x="20" y="20" width="385" height="77"/>
+ <customView id="2wf-Py-l6B" customClass="CallView">
+ <rect key="frame" x="0.0" y="0.0" width="675" height="509"/>
+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
- <button horizontalHuggingPriority="750" verticalHuggingPriority="750" ambiguous="YES" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Kjq-iM-NBL">
- <rect key="frame" x="187" y="8" width="80" height="60"/>
+ <customView translatesAutoresizingMaskIntoConstraints="NO" id="d0X-cW-Xgz">
+ <rect key="frame" x="20" y="438" width="635" height="71"/>
+ <subviews>
+ <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="bg3-hB-nE8">
+ <rect key="frame" x="18" y="40" width="85" height="17"/>
+ <constraints>
+ <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="81" id="gT7-Wu-XtU"/>
+ </constraints>
+ <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" title="Person name" id="osk-LS-0Qg">
+ <font key="font" metaFont="system"/>
+ <color key="textColor" name="highlightColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="kFD-FB-vig">
+ <rect key="frame" x="18" y="20" width="37" height="17"/>
+ <constraints>
+ <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="29" id="pft-oc-ZNh"/>
+ </constraints>
+ <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="State" id="ugy-uK-901">
+ <font key="font" metaFont="system"/>
+ <color key="textColor" name="highlightColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="highlightColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="cIU-M7-xpN">
+ <rect key="frame" x="513" y="23" width="104" height="24"/>
+ <constraints>
+ <constraint firstAttribute="width" constant="100" id="9vz-kb-6L6"/>
+ </constraints>
+ <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="Time" id="zsO-T7-9yi">
+ <font key="font" size="20" name="HelveticaNeue"/>
+ <color key="textColor" name="alternateSelectedControlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="highlightColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ <userDefinedRuntimeAttributes>
+ <userDefinedRuntimeAttribute type="string" keyPath="layer.cornerRadius" value="15"/>
+ </userDefinedRuntimeAttributes>
+ </textField>
+ </subviews>
<constraints>
- <constraint firstAttribute="width" constant="76" id="7Ja-wI-kLL"/>
- <constraint firstAttribute="height" constant="55" id="E2W-LK-NfM"/>
+ <constraint firstItem="kFD-FB-vig" firstAttribute="leading" secondItem="bg3-hB-nE8" secondAttribute="leading" id="LXG-QI-oPf"/>
+ <constraint firstItem="cIU-M7-xpN" firstAttribute="top" secondItem="d0X-cW-Xgz" secondAttribute="top" constant="24" id="Qc7-qp-qSV"/>
+ <constraint firstAttribute="trailing" secondItem="cIU-M7-xpN" secondAttribute="trailing" constant="20" id="RXf-xZ-4f9"/>
+ <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="568" id="Xeq-Aa-f1W"/>
+ <constraint firstItem="kFD-FB-vig" firstAttribute="top" secondItem="bg3-hB-nE8" secondAttribute="bottom" constant="3" id="Z06-5v-81Q"/>
+ <constraint firstItem="kFD-FB-vig" firstAttribute="top" secondItem="bg3-hB-nE8" secondAttribute="bottom" constant="3" id="gRn-E6-o6O"/>
+ <constraint firstItem="kFD-FB-vig" firstAttribute="leading" secondItem="d0X-cW-Xgz" secondAttribute="leading" constant="20" id="i5C-8o-qKp"/>
+ <constraint firstAttribute="bottom" secondItem="kFD-FB-vig" secondAttribute="bottom" constant="20" id="l71-7V-oLx"/>
+ <constraint firstItem="bg3-hB-nE8" firstAttribute="leading" secondItem="d0X-cW-Xgz" secondAttribute="leading" constant="20" id="nV4-Vy-vqK"/>
+ <constraint firstAttribute="centerY" secondItem="cIU-M7-xpN" secondAttribute="centerY" id="yvc-8B-cEu"/>
</constraints>
- <buttonCell key="cell" type="bevel" bezelStyle="regularSquare" image="64F5804D-D61F-4A20-A8D3-6F9E71A72A27" imagePosition="overlaps" alignment="left" borderStyle="border" imageScaling="proportionallyDown" id="kR5-bV-2KY">
- <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
- <font key="font" metaFont="system"/>
- </buttonCell>
- <connections>
- <action selector="hangUp:" target="-2" id="1Fj-b8-nfh"/>
- </connections>
- </button>
- <button horizontalHuggingPriority="750" verticalHuggingPriority="750" ambiguous="YES" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="qgD-3D-nD5">
- <rect key="frame" x="103" y="8" width="80" height="60"/>
+ </customView>
+ <customView translatesAutoresizingMaskIntoConstraints="NO" id="Eoi-B8-iL6" userLabel="Controls">
+ <rect key="frame" x="20" y="20" width="452" height="77"/>
+ <subviews>
+ <button horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Kjq-iM-NBL">
+ <rect key="frame" x="186" y="8" width="80" height="60"/>
+ <constraints>
+ <constraint firstAttribute="width" constant="76" id="7Ja-wI-kLL"/>
+ <constraint firstAttribute="height" constant="55" id="E2W-LK-NfM"/>
+ </constraints>
+ <buttonCell key="cell" type="bevel" bezelStyle="regularSquare" image="536D2CB3-F984-4261-A185-5FD010473380" imagePosition="overlaps" alignment="left" borderStyle="border" imageScaling="proportionallyDown" id="kR5-bV-2KY">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ </buttonCell>
+ <connections>
+ <action selector="hangUp:" target="-2" id="1Fj-b8-nfh"/>
+ </connections>
+ </button>
+ <button horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="qgD-3D-nD5">
+ <rect key="frame" x="102" y="8" width="80" height="60"/>
+ <constraints>
+ <constraint firstAttribute="width" constant="76" id="9Aq-GM-wT2"/>
+ <constraint firstAttribute="height" constant="55" id="mnN-fs-Rr6"/>
+ </constraints>
+ <buttonCell key="cell" type="bevel" bezelStyle="regularSquare" image="365E0BA1-E8E9-417C-9637-69685AEF3D44" imagePosition="overlaps" alignment="left" borderStyle="border" imageScaling="proportionallyDown" id="CoO-HS-nEB">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ </buttonCell>
+ <connections>
+ <action selector="accept:" target="-2" id="maS-G8-eY7"/>
+ </connections>
+ </button>
+ <button horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="oRa-pS-HN2">
+ <rect key="frame" x="18" y="8" width="80" height="60"/>
+ <constraints>
+ <constraint firstAttribute="width" constant="76" id="Afw-2T-aY9"/>
+ <constraint firstAttribute="height" constant="55" id="t21-HC-Wvs"/>
+ </constraints>
+ <buttonCell key="cell" type="bevel" title="Record" bezelStyle="regularSquare" imagePosition="overlaps" alignment="center" borderStyle="border" imageScaling="proportionallyDown" id="rhz-4Z-avV">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ </buttonCell>
+ <connections>
+ <action selector="toggleRecording:" target="-2" id="gAc-ZJ-9PN"/>
+ </connections>
+ </button>
+ <button horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="anb-Y8-JQi">
+ <rect key="frame" x="270" y="8" width="80" height="60"/>
+ <constraints>
+ <constraint firstAttribute="width" constant="76" id="QBx-uC-sub"/>
+ <constraint firstAttribute="height" constant="55" id="nPV-iA-aaw"/>
+ </constraints>
+ <buttonCell key="cell" type="bevel" title="Hold" bezelStyle="regularSquare" imagePosition="overlaps" alignment="center" borderStyle="border" imageScaling="proportionallyDown" id="7w5-d1-mNe">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ </buttonCell>
+ <connections>
+ <action selector="toggleHold:" target="-2" id="O18-nN-hHE"/>
+ </connections>
+ </button>
+ <button horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="fmp-x4-Pef">
+ <rect key="frame" x="354" y="8" width="80" height="60"/>
+ <constraints>
+ <constraint firstAttribute="width" constant="76" id="eC5-B4-omb"/>
+ <constraint firstAttribute="height" constant="55" id="wYS-TH-4rc"/>
+ </constraints>
+ <buttonCell key="cell" type="bevel" title="Chat" bezelStyle="regularSquare" imagePosition="overlaps" alignment="center" borderStyle="border" imageScaling="proportionallyDown" id="1fJ-X6-Rza">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES" changeBackground="YES" changeGray="YES"/>
+ <font key="font" metaFont="system"/>
+ </buttonCell>
+ <connections>
+ <action selector="toggleChat:" target="-2" id="7HN-HS-oqT"/>
+ </connections>
+ </button>
+ </subviews>
<constraints>
- <constraint firstAttribute="width" constant="76" id="9Aq-GM-wT2"/>
- <constraint firstAttribute="height" constant="55" id="mnN-fs-Rr6"/>
+ <constraint firstItem="qgD-3D-nD5" firstAttribute="top" secondItem="Eoi-B8-iL6" secondAttribute="top" constant="11" id="1lr-kB-A5h"/>
+ <constraint firstItem="Kjq-iM-NBL" firstAttribute="leading" secondItem="qgD-3D-nD5" secondAttribute="trailing" constant="8" id="3iK-1x-F2q"/>
+ <constraint firstItem="anb-Y8-JQi" firstAttribute="top" secondItem="Eoi-B8-iL6" secondAttribute="top" constant="11" id="4C3-og-43v"/>
+ <constraint firstAttribute="bottom" secondItem="fmp-x4-Pef" secondAttribute="bottom" constant="11" id="4qt-Sw-3oV"/>
+ <constraint firstAttribute="bottom" secondItem="Kjq-iM-NBL" secondAttribute="bottom" constant="11" id="IPS-1V-PVm"/>
+ <constraint firstAttribute="bottom" secondItem="qgD-3D-nD5" secondAttribute="bottom" constant="11" id="KYy-za-dDq"/>
+ <constraint firstItem="anb-Y8-JQi" firstAttribute="leading" secondItem="Kjq-iM-NBL" secondAttribute="trailing" constant="8" id="Mcj-US-rZq"/>
+ <constraint firstAttribute="bottom" secondItem="anb-Y8-JQi" secondAttribute="bottom" constant="11" id="MwL-3I-lJv"/>
+ <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="385" id="TSJ-9A-brf"/>
+ <constraint firstItem="fmp-x4-Pef" firstAttribute="top" secondItem="Eoi-B8-iL6" secondAttribute="top" constant="11" id="Wmf-0A-jba"/>
+ <constraint firstItem="Kjq-iM-NBL" firstAttribute="top" secondItem="Eoi-B8-iL6" secondAttribute="top" constant="11" id="a1R-g8-5gl"/>
+ <constraint firstAttribute="bottom" secondItem="oRa-pS-HN2" secondAttribute="bottom" constant="11" id="aOv-xQ-1pk"/>
+ <constraint firstItem="fmp-x4-Pef" firstAttribute="leading" secondItem="anb-Y8-JQi" secondAttribute="trailing" constant="8" id="bSy-yw-J5C"/>
+ <constraint firstItem="oRa-pS-HN2" firstAttribute="top" secondItem="Eoi-B8-iL6" secondAttribute="top" constant="11" id="faC-l8-iCU"/>
+ <constraint firstItem="oRa-pS-HN2" firstAttribute="leading" secondItem="Eoi-B8-iL6" secondAttribute="leading" constant="20" id="htl-he-rlg"/>
+ <constraint firstItem="fmp-x4-Pef" firstAttribute="leading" secondItem="anb-Y8-JQi" secondAttribute="trailing" constant="8" id="jfN-xU-POX"/>
+ <constraint firstItem="qgD-3D-nD5" firstAttribute="leading" secondItem="oRa-pS-HN2" secondAttribute="trailing" constant="8" id="wQF-FD-dbj"/>
</constraints>
- <buttonCell key="cell" type="bevel" bezelStyle="regularSquare" image="234C9BC9-A500-43C5-873E-78EC0E1D8ED1" imagePosition="overlaps" alignment="left" borderStyle="border" imageScaling="proportionallyDown" id="CoO-HS-nEB">
- <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
- <font key="font" metaFont="system"/>
- </buttonCell>
- <connections>
- <action selector="accept:" target="-2" id="maS-G8-eY7"/>
- </connections>
- </button>
- <button horizontalHuggingPriority="750" verticalHuggingPriority="750" ambiguous="YES" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="anb-Y8-JQi">
- <rect key="frame" x="269" y="7" width="84" height="62"/>
+ </customView>
+ <customView translatesAutoresizingMaskIntoConstraints="NO" id="6y6-RH-qOp" userLabel="Preview">
+ <rect key="frame" x="480" y="20" width="175" height="120"/>
<constraints>
- <constraint firstAttribute="width" constant="76" id="QBx-uC-sub"/>
- <constraint firstAttribute="height" constant="55" id="nPV-iA-aaw"/>
+ <constraint firstAttribute="height" constant="120" id="BvU-kV-0uD"/>
+ <constraint firstAttribute="width" constant="175" id="aEv-Tt-tSD"/>
</constraints>
- <buttonCell key="cell" type="bevel" title="Hold" bezelStyle="regularSquare" imagePosition="overlaps" alignment="center" borderStyle="border" imageScaling="proportionallyDown" id="7w5-d1-mNe">
- <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
- <font key="font" metaFont="system"/>
- </buttonCell>
- <connections>
- <action selector="toggleHold:" target="-2" id="O18-nN-hHE"/>
- </connections>
- </button>
- <button horizontalHuggingPriority="750" verticalHuggingPriority="750" ambiguous="YES" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="oRa-pS-HN2">
- <rect key="frame" x="18" y="8" width="80" height="60"/>
- <constraints>
- <constraint firstAttribute="width" constant="76" id="Afw-2T-aY9"/>
- <constraint firstAttribute="height" constant="55" id="t21-HC-Wvs"/>
- </constraints>
- <buttonCell key="cell" type="bevel" title="Record" bezelStyle="regularSquare" imagePosition="overlaps" alignment="center" borderStyle="border" imageScaling="proportionallyDown" id="rhz-4Z-avV">
- <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
- <font key="font" metaFont="system"/>
- </buttonCell>
- <connections>
- <action selector="toggleRecording:" target="-2" id="gAc-ZJ-9PN"/>
- </connections>
- </button>
+ </customView>
</subviews>
<constraints>
- <constraint firstItem="qgD-3D-nD5" firstAttribute="top" secondItem="Eoi-B8-iL6" secondAttribute="top" constant="11" id="1lr-kB-A5h"/>
- <constraint firstItem="anb-Y8-JQi" firstAttribute="top" secondItem="Eoi-B8-iL6" secondAttribute="top" constant="11" id="4C3-og-43v"/>
- <constraint firstAttribute="bottom" secondItem="Kjq-iM-NBL" secondAttribute="bottom" constant="11" id="IPS-1V-PVm"/>
- <constraint firstAttribute="bottom" secondItem="qgD-3D-nD5" secondAttribute="bottom" constant="11" id="KYy-za-dDq"/>
- <constraint firstAttribute="bottom" secondItem="anb-Y8-JQi" secondAttribute="bottom" constant="11" id="MwL-3I-lJv"/>
- <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="385" id="TSJ-9A-brf"/>
- <constraint firstItem="Kjq-iM-NBL" firstAttribute="top" secondItem="Eoi-B8-iL6" secondAttribute="top" constant="11" id="a1R-g8-5gl"/>
- <constraint firstAttribute="bottom" secondItem="oRa-pS-HN2" secondAttribute="bottom" constant="11" id="aOv-xQ-1pk"/>
- <constraint firstItem="oRa-pS-HN2" firstAttribute="top" secondItem="Eoi-B8-iL6" secondAttribute="top" constant="11" id="faC-l8-iCU"/>
+ <constraint firstItem="6y6-RH-qOp" firstAttribute="leading" secondItem="Eoi-B8-iL6" secondAttribute="trailing" constant="8" id="7wV-uh-Xb7"/>
+ <constraint firstAttribute="trailing" secondItem="d0X-cW-Xgz" secondAttribute="trailing" constant="20" id="G79-Jv-EYw"/>
+ <constraint firstAttribute="bottom" secondItem="6y6-RH-qOp" secondAttribute="bottom" constant="20" id="HOt-7O-FU2"/>
+ <constraint firstAttribute="trailing" secondItem="6y6-RH-qOp" secondAttribute="trailing" constant="20" id="KTx-SN-RUg"/>
+ <constraint firstItem="d0X-cW-Xgz" firstAttribute="top" secondItem="2wf-Py-l6B" secondAttribute="top" id="MKB-zm-C75"/>
+ <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="675" id="ciq-ed-2FK"/>
+ <constraint firstItem="d0X-cW-Xgz" firstAttribute="leading" secondItem="2wf-Py-l6B" secondAttribute="leading" constant="20" id="efy-70-qsJ"/>
+ <constraint firstAttribute="bottom" secondItem="Eoi-B8-iL6" secondAttribute="bottom" constant="20" id="glQ-Is-Pk6"/>
+ <constraint firstItem="Eoi-B8-iL6" firstAttribute="leading" secondItem="2wf-Py-l6B" secondAttribute="leading" constant="20" id="sHw-xg-QAo"/>
</constraints>
</customView>
- <customView ambiguous="YES" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="d0X-cW-Xgz">
- <rect key="frame" x="20" y="422" width="568" height="71"/>
+ <customView id="TdD-3L-553">
+ <rect key="frame" x="676" y="0.0" width="338" height="509"/>
+ <autoresizingMask key="autoresizingMask"/>
<subviews>
- <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="bg3-hB-nE8">
- <rect key="frame" x="18" y="40" width="139" height="17"/>
+ <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="kW2-Cx-fNv">
+ <rect key="frame" x="274" y="13" width="50" height="32"/>
<constraints>
- <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="81" id="gT7-Wu-XtU"/>
+ <constraint firstAttribute="width" constant="38" id="0Qx-5g-ThL"/>
</constraints>
- <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" title="Person name" id="osk-LS-0Qg">
+ <buttonCell key="cell" type="push" bezelStyle="rounded" image="NSGoRightTemplate" imagePosition="overlaps" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="5Nl-aV-9kl">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
- <color key="textColor" name="highlightColor" catalog="System" colorSpace="catalog"/>
+ </buttonCell>
+ <connections>
+ <action selector="sendMessage:" target="LWe-df-dS6" id="Hlj-og-5rV"/>
+ <binding destination="LWe-df-dS6" name="enabled" keyPath="self.message.length" id="ec2-s1-Hpt"/>
+ </connections>
+ </button>
+ <textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="OBX-o0-u1k">
+ <rect key="frame" x="20" y="20" width="252" height="22"/>
+ <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" state="on" borderStyle="bezel" bezelStyle="round" id="QW9-Ty-ZEe">
+ <font key="font" metaFont="system"/>
+ <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
+ <connections>
+ <binding destination="LWe-df-dS6" name="value" keyPath="self.message" id="suS-k6-ypU">
+ <dictionary key="options">
+ <bool key="NSContinuouslyUpdatesValue" value="YES"/>
+ </dictionary>
+ </binding>
+ <outlet property="delegate" destination="LWe-df-dS6" id="9by-zr-IW0"/>
+ </connections>
</textField>
- <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="kFD-FB-vig">
- <rect key="frame" x="18" y="20" width="37" height="17"/>
- <constraints>
- <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="29" id="pft-oc-ZNh"/>
- </constraints>
- <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="State" id="ugy-uK-901">
- <font key="font" metaFont="system"/>
- <color key="textColor" name="highlightColor" catalog="System" colorSpace="catalog"/>
- <color key="backgroundColor" name="highlightColor" catalog="System" colorSpace="catalog"/>
- </textFieldCell>
- </textField>
- <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" ambiguous="YES" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="cIU-M7-xpN">
- <rect key="frame" x="446" y="23" width="104" height="24"/>
- <constraints>
- <constraint firstAttribute="width" constant="100" id="9vz-kb-6L6"/>
- </constraints>
- <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="Time" id="zsO-T7-9yi">
- <font key="font" size="20" name="HelveticaNeue"/>
- <color key="textColor" name="alternateSelectedControlTextColor" catalog="System" colorSpace="catalog"/>
- <color key="backgroundColor" name="highlightColor" catalog="System" colorSpace="catalog"/>
- </textFieldCell>
- <userDefinedRuntimeAttributes>
- <userDefinedRuntimeAttribute type="string" keyPath="layer.cornerRadius" value="15"/>
- </userDefinedRuntimeAttributes>
- </textField>
+ <scrollView borderType="none" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" horizontalScrollElasticity="none" translatesAutoresizingMaskIntoConstraints="NO" id="i3X-6S-mKF">
+ <rect key="frame" x="0.0" y="50" width="338" height="459"/>
+ <clipView key="contentView" id="Tbz-Bj-Y3K">
+ <rect key="frame" x="1" y="1" width="223" height="133"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <textView editable="NO" importsGraphics="NO" findStyle="panel" continuousSpellChecking="YES" allowsUndo="YES" usesRuler="YES" usesFontPanel="YES" verticallyResizable="YES" allowsNonContiguousLayout="YES" quoteSubstitution="YES" dataDetection="YES" dashSubstitution="YES" spellingCorrection="YES" smartInsertDelete="YES" id="9jD-8j-lXO">
+ <rect key="frame" x="0.0" y="0.0" width="223" height="439"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+ <size key="minSize" width="338" height="459"/>
+ <size key="maxSize" width="463" height="10000000"/>
+ <color key="insertionPointColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <size key="minSize" width="338" height="459"/>
+ <size key="maxSize" width="463" height="10000000"/>
+ </textView>
+ </subviews>
+ <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
+ </clipView>
+ <scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="YES" id="Uo5-G8-d2s">
+ <rect key="frame" x="-100" y="-100" width="87" height="18"/>
+ <autoresizingMask key="autoresizingMask"/>
+ </scroller>
+ <scroller key="verticalScroller" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="eno-qS-nJm">
+ <rect key="frame" x="224" y="1" width="15" height="133"/>
+ <autoresizingMask key="autoresizingMask"/>
+ </scroller>
+ </scrollView>
</subviews>
<constraints>
- <constraint firstItem="kFD-FB-vig" firstAttribute="leading" secondItem="bg3-hB-nE8" secondAttribute="leading" id="LXG-QI-oPf"/>
- <constraint firstAttribute="trailing" secondItem="cIU-M7-xpN" secondAttribute="trailing" constant="20" id="RXf-xZ-4f9"/>
- <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="568" id="Xeq-Aa-f1W"/>
- <constraint firstItem="kFD-FB-vig" firstAttribute="top" secondItem="bg3-hB-nE8" secondAttribute="bottom" constant="3" id="Z06-5v-81Q"/>
- <constraint firstItem="kFD-FB-vig" firstAttribute="top" secondItem="bg3-hB-nE8" secondAttribute="bottom" constant="3" id="gRn-E6-o6O"/>
- <constraint firstItem="kFD-FB-vig" firstAttribute="leading" secondItem="d0X-cW-Xgz" secondAttribute="leading" constant="20" id="i5C-8o-qKp"/>
- <constraint firstAttribute="bottom" secondItem="kFD-FB-vig" secondAttribute="bottom" constant="20" id="l71-7V-oLx"/>
- <constraint firstItem="bg3-hB-nE8" firstAttribute="leading" secondItem="d0X-cW-Xgz" secondAttribute="leading" constant="20" id="nV4-Vy-vqK"/>
- <constraint firstAttribute="centerY" secondItem="cIU-M7-xpN" secondAttribute="centerY" id="yvc-8B-cEu"/>
+ <constraint firstItem="kW2-Cx-fNv" firstAttribute="leading" secondItem="OBX-o0-u1k" secondAttribute="trailing" constant="8" id="5sg-0N-YSw"/>
+ <constraint firstAttribute="bottom" secondItem="kW2-Cx-fNv" secondAttribute="bottom" constant="20" id="EeC-o1-xNE"/>
+ <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="250" id="KI6-XT-afu"/>
+ <constraint firstItem="i3X-6S-mKF" firstAttribute="top" secondItem="TdD-3L-553" secondAttribute="top" id="LoI-gZ-Gp6"/>
+ <constraint firstItem="i3X-6S-mKF" firstAttribute="leading" secondItem="TdD-3L-553" secondAttribute="leading" id="NVH-57-1Yw"/>
+ <constraint firstAttribute="width" relation="lessThanOrEqual" constant="400" id="Szn-hz-Zcv"/>
+ <constraint firstAttribute="bottom" secondItem="OBX-o0-u1k" secondAttribute="bottom" constant="20" id="eOH-Wv-Zuo"/>
+ <constraint firstAttribute="trailing" secondItem="kW2-Cx-fNv" secondAttribute="trailing" constant="20" id="g3z-YY-hyn"/>
+ <constraint firstItem="OBX-o0-u1k" firstAttribute="leading" secondItem="TdD-3L-553" secondAttribute="leading" constant="20" id="wTD-wE-axZ"/>
+ <constraint firstItem="OBX-o0-u1k" firstAttribute="top" secondItem="i3X-6S-mKF" secondAttribute="bottom" constant="8" id="yKJ-bq-2wk"/>
+ <constraint firstAttribute="trailing" secondItem="i3X-6S-mKF" secondAttribute="trailing" id="zdl-DO-8e8"/>
</constraints>
</customView>
</subviews>
- <constraints>
- <constraint firstItem="6y6-RH-qOp" firstAttribute="leading" secondItem="Eoi-B8-iL6" secondAttribute="trailing" constant="8" id="7wV-uh-Xb7"/>
- <constraint firstAttribute="trailing" secondItem="d0X-cW-Xgz" secondAttribute="trailing" constant="20" id="G79-Jv-EYw"/>
- <constraint firstAttribute="bottom" secondItem="6y6-RH-qOp" secondAttribute="bottom" constant="20" id="HOt-7O-FU2"/>
- <constraint firstAttribute="trailing" secondItem="6y6-RH-qOp" secondAttribute="trailing" constant="20" id="KTx-SN-RUg"/>
- <constraint firstItem="d0X-cW-Xgz" firstAttribute="top" secondItem="2wf-Py-l6B" secondAttribute="top" id="MKB-zm-C75"/>
- <constraint firstItem="d0X-cW-Xgz" firstAttribute="leading" secondItem="2wf-Py-l6B" secondAttribute="leading" constant="20" id="efy-70-qsJ"/>
- <constraint firstAttribute="bottom" secondItem="Eoi-B8-iL6" secondAttribute="bottom" constant="20" id="glQ-Is-Pk6"/>
- <constraint firstItem="Eoi-B8-iL6" firstAttribute="leading" secondItem="2wf-Py-l6B" secondAttribute="leading" constant="20" id="sHw-xg-QAo"/>
- </constraints>
- </customView>
+ <holdingPriorities>
+ <real value="250"/>
+ <real value="250"/>
+ </holdingPriorities>
+ <connections>
+ <outlet property="delegate" destination="-2" id="Srr-ek-32R"/>
+ </connections>
+ </splitView>
</subviews>
<constraints>
- <constraint firstAttribute="trailing" secondItem="2wf-Py-l6B" secondAttribute="trailing" id="55Z-0g-5TN"/>
- <constraint firstItem="2wf-Py-l6B" firstAttribute="leading" secondItem="Hz6-mo-xeY" secondAttribute="leading" id="X7p-et-pnn"/>
- <constraint firstAttribute="trailing" secondItem="2wf-Py-l6B" secondAttribute="trailing" id="YzN-ww-GnM"/>
- <constraint firstAttribute="bottom" secondItem="2wf-Py-l6B" secondAttribute="bottom" id="a7w-Ws-Gv9"/>
- <constraint firstItem="2wf-Py-l6B" firstAttribute="top" secondItem="Hz6-mo-xeY" secondAttribute="top" id="fQz-Y7-SMk"/>
- <constraint firstAttribute="bottom" secondItem="2wf-Py-l6B" secondAttribute="bottom" id="iMg-yV-adv"/>
- <constraint firstItem="2wf-Py-l6B" firstAttribute="leading" secondItem="Hz6-mo-xeY" secondAttribute="leading" id="mf8-S2-fcv"/>
+ <constraint firstAttribute="trailing" secondItem="GIJ-gB-FZo" secondAttribute="trailing" id="0em-qy-QDF"/>
+ <constraint firstItem="GIJ-gB-FZo" firstAttribute="top" secondItem="Hz6-mo-xeY" secondAttribute="top" id="BMA-1U-7qS"/>
+ <constraint firstAttribute="bottom" secondItem="GIJ-gB-FZo" secondAttribute="bottom" id="cSp-R2-2P7"/>
+ <constraint firstItem="GIJ-gB-FZo" firstAttribute="leading" secondItem="Hz6-mo-xeY" secondAttribute="leading" id="gYP-xn-tdT"/>
</constraints>
- <point key="canvasLocation" x="1225" y="13.5"/>
+ <point key="canvasLocation" x="1428" y="21.5"/>
</customView>
+ <viewController id="LWe-df-dS6" customClass="ChatVC">
+ <connections>
+ <outlet property="chatView" destination="9jD-8j-lXO" id="nRK-qZ-xex"/>
+ <outlet property="messageField" destination="OBX-o0-u1k" id="MS2-Hl-as4"/>
+ <outlet property="sendButton" destination="kW2-Cx-fNv" id="7iO-d1-LsM"/>
+ <outlet property="view" destination="TdD-3L-553" id="HQf-B1-D8b"/>
+ </connections>
+ </viewController>
</objects>
<resources>
- <image name="234C9BC9-A500-43C5-873E-78EC0E1D8ED1" width="48" height="48">
+ <image name="365E0BA1-E8E9-417C-9637-69685AEF3D44" width="48" height="48">
<mutableData key="keyedArchiveRepresentation">
YnBsaXN0MDDUAQIDBAUGOzxYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoK0HCBEW
GxwgISksLzU4VSRudWxs1AkKCwwNDg8QViRjbGFzc1xOU0ltYWdlRmxhZ3NWTlNSZXBzV05TQ29sb3KA
@@ -409,7 +530,7 @@
AAAyug
</mutableData>
</image>
- <image name="64F5804D-D61F-4A20-A8D3-6F9E71A72A27" width="48" height="48">
+ <image name="536D2CB3-F984-4261-A185-5FD010473380" width="48" height="48">
<mutableData key="keyedArchiveRepresentation">
YnBsaXN0MDDUAQIDBAUGOzxYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoK0HCBEW
GxwgISksLzU4VSRudWxs1AkKCwwNDg8QViRjbGFzc1xOU0ltYWdlRmxhZ3NWTlNSZXBzV05TQ29sb3KA
@@ -633,5 +754,6 @@
AAAyug
</mutableData>
</image>
+ <image name="NSGoRightTemplate" width="9" height="12"/>
</resources>
</document>
diff --git a/ui/RingWindow.xib b/ui/RingWindow.xib
index fdd2c01..af920b8 100644
--- a/ui/RingWindow.xib
+++ b/ui/RingWindow.xib
@@ -1,11 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="6751" systemVersion="13F1066" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="7706" systemVersion="14D2134" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
- <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="6751"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="7706"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="RingWindowController">
<connections>
+ <outlet property="callView" destination="tSW-YT-asL" id="NRy-rM-XW4"/>
<outlet property="currentView" destination="se5-gp-TjO" id="Sae-7F-MB3"/>
<outlet property="window" destination="F0z-JX-Cv5" id="gIp-Ho-8D9"/>
</connections>
@@ -32,7 +33,7 @@
<rect key="frame" x="0.0" y="0.0" width="293" height="19"/>
<autoresizingMask key="autoresizingMask"/>
<size key="intercellSpacing" width="3" height="2"/>
- <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+ <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
<tableColumns>
<tableColumn identifier="ConversationsColumn" width="290" minWidth="40" maxWidth="1000" id="VDO-Cu-h8f">
@@ -92,7 +93,7 @@
<rect key="frame" x="0.0" y="0.0" width="226" height="19"/>
<autoresizingMask key="autoresizingMask"/>
<size key="intercellSpacing" width="3" height="2"/>
- <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+ <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
<tableColumns>
<tableColumn identifier="DayColumn" width="87.5703125" minWidth="40" maxWidth="1000" id="pTT-gU-NVa">
@@ -169,7 +170,7 @@
</tabViewItem>
<tabViewItem label="Contacts" identifier="" id="Zbi-X6-DLT">
<view key="view" id="sag-tS-7Jw">
- <rect key="frame" x="10" y="7" width="289" height="405"/>
+ <rect key="frame" x="10" y="7" width="295" height="405"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView focusRingType="none" misplaced="YES" autohidesScrollers="YES" horizontalLineScroll="48" horizontalPageScroll="10" verticalLineScroll="48" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rJv-ju-DFe">
@@ -182,7 +183,7 @@
<rect key="frame" x="0.0" y="0.0" width="293" height="48"/>
<autoresizingMask key="autoresizingMask"/>
<size key="intercellSpacing" width="3" height="2"/>
- <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+ <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
<tableColumns>
<tableColumn identifier="NameColumn" width="289.7734375" minWidth="40" maxWidth="1000" id="8Ve-L0-o7V">
@@ -229,8 +230,8 @@
</tabViewItem>
</tabViewItems>
</tabView>
- <customView focusRingType="none" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="tSW-YT-asL">
- <rect key="frame" x="323" y="0.0" width="725" height="626"/>
+ <customView focusRingType="none" translatesAutoresizingMaskIntoConstraints="NO" id="tSW-YT-asL">
+ <rect key="frame" x="323" y="0.0" width="730" height="626"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="626" id="5yo-rb-X1O"/>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="725" id="ccX-uq-zuj"/>
@@ -263,8 +264,7 @@
<viewController id="txt-J3-pzW" customClass="ConversationsVC">
<connections>
<outlet property="conversationsView" destination="zcl-pp-rGb" id="YXp-WN-UmC"/>
- <outlet property="currentCallView" destination="tSW-YT-asL" id="r2r-Q3-clc"/>
- <outlet property="view" destination="tSW-YT-asL" id="fv5-ly-rk8"/>
+ <outlet property="view" destination="bqQ-DB-Z0g" id="nJI-EM-4z2"/>
</connections>
</viewController>
<viewController id="9RF-6W-vEW" customClass="PersonsVC">