Commit 883719f5 authored by Alexandre Lision's avatar Alexandre Lision Committed by Stepan Salenikovich

call: add transfer ability

This commit adds attended/unattended transfer capability
It also improves call controls visibility

Tuleap: #56
Change-Id: I66c2bc22f015f12dc58cf98768b8b3c689e6fdcb
parent 61db3557
......@@ -111,7 +111,9 @@ SET(ringclient_CONTROLLERS
src/PersonLinkerVC.mm
src/PersonLinkerVC.h
src/SmartViewVC.mm
src/SmartViewVC.h)
src/SmartViewVC.h
src/BrokerVC.mm
src/BrokerVC.h)
SET(ringclient_BACKENDS
src/backends/AddressBookBackend.mm
......@@ -160,7 +162,8 @@ SET(ringclient_XIBS
PreferencesWindow
RingWizard
CertificateWindow
PersonLinker)
PersonLinker
Broker)
# Icons
# This part tells CMake where to find and install the file itself
......@@ -186,6 +189,7 @@ ${CMAKE_CURRENT_SOURCE_DIR}/data/dark/ic_action_record.png
${CMAKE_CURRENT_SOURCE_DIR}/data/dark/ic_call_received.png
${CMAKE_CURRENT_SOURCE_DIR}/data/dark/ic_call_missed.png
${CMAKE_CURRENT_SOURCE_DIR}/data/dark/ic_call_made.png
${CMAKE_CURRENT_SOURCE_DIR}/data/dark/ic_action_transfer.png
${CMAKE_CURRENT_SOURCE_DIR}/data/dark/ancrage.png
${CMAKE_CURRENT_SOURCE_DIR}/data/dark/audio.png
${CMAKE_CURRENT_SOURCE_DIR}/data/dark/ic_person_add.png
......
/*
* 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.
*/
#import <Cocoa/Cocoa.h>
@interface BrokerVC : NSViewController
enum class BrokerMode {
TRANSFER = 0,
//CONFERENCE
};
- (instancetype)initWithMode:(BrokerMode) m;
@end
/*
* 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.
*/
#import "BrokerVC.h"
#import <QSortFilterProxyModel>
#import <QItemSelectionModel>
#import <QtMacExtras/qmacfunctions.h>
#import <QPixmap>
//LRC
#import <recentmodel.h>
#import <callmodel.h>
#import <call.h>
#import <person.h>
#import <globalinstances.h>
#import <contactmethod.h>
#import <phonedirectorymodel.h>
#import "QNSTreeController.h"
#import "delegates/ImageManipulationDelegate.h"
// Display all items from peopleproxy() except current call
class NotCurrentItemModel : public QSortFilterProxyModel
{
public:
NotCurrentItemModel(QSortFilterProxyModel* parent) : QSortFilterProxyModel(parent)
{
setSourceModel(parent);
}
virtual bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const
{
auto originIdx = ((QSortFilterProxyModel*)sourceModel())->mapToSource(sourceModel()->index(source_row,0,source_parent));
auto c = RecentModel::instance().getActiveCall(originIdx);
return (!c || (c && (c->state() != Call::State::CURRENT))) &&
QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
}
};
@interface BrokerVC ()
@property BrokerMode mode;
@property (unsafe_unretained) IBOutlet NSOutlineView *smartView;
@property (strong) QNSTreeController *treeController;
@property QSortFilterProxyModel* recentFilterModel;
@end
@implementation BrokerVC
// Tags for views
NSInteger const IMAGE_TAG = 100;
NSInteger const DISPLAYNAME_TAG = 200;
NSInteger const DETAILS_TAG = 300;
NSInteger const CALL_BUTTON_TAG = 400;
NSInteger const TXT_BUTTON_TAG = 500;
- (instancetype)initWithMode:(BrokerMode)m {
self = [super init];
if (self) {
[self setMode:m];
}
return self;
}
- (NSString *)nibName
{
return @"Broker";
}
- (void)dealloc
{
delete _recentFilterModel;
}
- (void)loadView
{
[super loadView];
_recentFilterModel = new NotCurrentItemModel(RecentModel::instance().peopleProxy());
_treeController = [[QNSTreeController alloc] initWithQModel:_recentFilterModel];
[_treeController setAvoidsEmptySelection:NO];
[_treeController setChildrenKeyPath:@"children"];
[_smartView bind:@"content" toObject:_treeController withKeyPath:@"arrangedObjects" options:nil];
[_smartView bind:@"sortDescriptors" toObject:_treeController withKeyPath:@"sortDescriptors" options:nil];
[_smartView bind:@"selectionIndexPaths" toObject:_treeController withKeyPath:@"selectionIndexPaths" options:nil];
[_smartView setTarget:self];
[_smartView setDoubleAction:@selector(placeTransfer:)];
}
// -------------------------------------------------------------------------------
// transfer on click on Person or ContactMethod
// -------------------------------------------------------------------------------
- (void)placeTransfer:(id)sender
{
auto current = CallModel::instance().selectedCall();
if (!current || [_treeController selectedNodes].count == 0)
return;
QModelIndex qIdx = [_treeController toQIdx:[_treeController selectedNodes][0]];
auto originIdx = RecentModel::instance().peopleProxy()->mapToSource(_recentFilterModel->mapToSource(qIdx));
auto transfer = RecentModel::instance().getActiveCall(originIdx);
if (transfer) { //realise an attended transfer between the two calls
CallModel::instance().attendedTransfer(current, transfer);
return;
}
ContactMethod* m = nil;
auto contactmethods = RecentModel::instance().getContactMethods(originIdx);
if (contactmethods.size() > 0) { // Before calling check if we properly extracted at least one contact method
m = contactmethods.first();
CallModel::instance().transfer(current, m);
}
}
// -------------------------------------------------------------------------------
// transfer to unknown URI
// -------------------------------------------------------------------------------
- (void) transferTo:(NSString*) uri
{
auto current = CallModel::instance().selectedCall();
if (!current)
return;
auto number = PhoneDirectoryModel::instance().getNumber(QString::fromNSString(uri));
CallModel::instance().transfer(current, number);
}
#pragma mark - NSOutlineViewDelegate methods
// -------------------------------------------------------------------------------
// shouldSelectItem:item
// -------------------------------------------------------------------------------
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item;
{
return YES;
}
// -------------------------------------------------------------------------------
// shouldEditTableColumn:tableColumn:item
//
// Decide to allow the edit of the given outline view "item".
// -------------------------------------------------------------------------------
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
return NO;
}
// -------------------------------------------------------------------------------
// View Based OutlineView: See the delegate method -tableView:viewForTableColumn:row: in NSTableView.
// -------------------------------------------------------------------------------
- (NSView *)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
auto qIdx = [_treeController toQIdx:((NSTreeNode*)item)];
NSTableCellView *result;
if (!qIdx.parent().isValid()) {
result = [outlineView makeViewWithIdentifier:@"MainCell" owner:outlineView];
} else {
result = [outlineView makeViewWithIdentifier:@"CallCell" owner:outlineView];
}
auto finalIdx = RecentModel::instance().peopleProxy()->mapToSource(_recentFilterModel->mapToSource(qIdx));
NSTextField* details = [result viewWithTag:DETAILS_TAG];
if (auto call = RecentModel::instance().getActiveCall(finalIdx)) {
[details setStringValue:call->roleData((int)Ring::Role::FormattedState).toString().toNSString()];
} else {
[details setStringValue:qIdx.data((int)Ring::Role::FormattedLastUsed).toString().toNSString()];
}
NSTextField* displayName = [result viewWithTag:DISPLAYNAME_TAG];
[displayName setStringValue:qIdx.data(Qt::DisplayRole).toString().toNSString()];
NSImageView* photoView = [result viewWithTag:IMAGE_TAG];
Person* p = qvariant_cast<Person*>(qIdx.data((int)Person::Role::Object));
QVariant photo = GlobalInstances::pixmapManipulator().contactPhoto(p, QSize(40,40));
[photoView setImage:QtMac::toNSImage(qvariant_cast<QPixmap>(photo))];
return result;
}
// -------------------------------------------------------------------------------
// View Based OutlineView: See the delegate method -tableView:rowViewForRow: in NSTableView.
// -------------------------------------------------------------------------------
- (NSTableRowView *)outlineView:(NSOutlineView *)outlineView rowViewForItem:(id)item
{
return [outlineView makeViewWithIdentifier:@"HoverRowView" owner:nil];
}
- (CGFloat)outlineView:(NSOutlineView *)outlineView heightOfRowByItem:(id)item
{
QModelIndex qIdx = [_treeController toQIdx:((NSTreeNode*)item)];
return (((NSTreeNode*)item).indexPath.length == 1) ? 60.0 : 45.0;
}
#pragma mark - NSTextFieldDelegate
- (BOOL)control:(NSControl *)control textView:(NSTextView *)fieldEditor doCommandBySelector:(SEL)commandSelector
{
if (commandSelector == @selector(insertNewline:)) {
if([fieldEditor.textStorage.string isNotEqualTo:@""]) {
[self transferTo:fieldEditor.textStorage.string];
return YES;
}
}
return NO;
}
- (void)controlTextDidChange:(NSNotification *) notification
{
NSTextView *textView = notification.userInfo[@"NSFieldEditor"];
_recentFilterModel->setFilterRegExp(QRegExp(QString::fromNSString(textView.textStorage.string), Qt::CaseInsensitive, QRegExp::FixedString));
[_smartView scrollToBeginningOfDocument:nil];
}
@end
......@@ -36,6 +36,7 @@
#import "views/CallView.h"
#import "PersonLinkerVC.h"
#import "ChatVC.h"
#import "BrokerVC.h"
@interface RendererConnectionsHolder : NSObject
......@@ -51,28 +52,30 @@
@interface CurrentCallVC () <NSPopoverDelegate, ContactLinkedDelegate>
@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 NSButton *muteAudioButton;
@property (unsafe_unretained) IBOutlet NSButton *muteVideoButton;
@property (unsafe_unretained) IBOutlet NSButton *addContactButton;
@property (unsafe_unretained) IBOutlet NSView *headerContainer;
@property (unsafe_unretained) IBOutlet NSButton *qualityButton;
@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 NSButton* muteAudioButton;
@property (unsafe_unretained) IBOutlet NSButton* muteVideoButton;
@property (unsafe_unretained) IBOutlet NSButton* addContactButton;
@property (unsafe_unretained) IBOutlet NSButton* qualityButton;
@property (unsafe_unretained) IBOutlet NSButton* transferButton;
@property (unsafe_unretained) IBOutlet NSView* headerContainer;
@property (unsafe_unretained) IBOutlet ITProgressIndicator *loadingIndicator;
@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 (unsafe_unretained) IBOutlet NSTextField* timeSpentLabel;
@property (unsafe_unretained) IBOutlet NSView* controlsPanel;
@property (unsafe_unretained) IBOutlet NSSplitView* splitView;
@property (unsafe_unretained) IBOutlet NSButton* chatButton;
@property (strong) IBOutlet NSPopover *qualityPopOver;
@property (strong) IBOutlet NSPopover* qualityPopOver;
@property (strong) NSPopover* addToContactPopover;
@property (strong) IBOutlet ChatVC *chatVC;
@property (strong) NSPopover* transferPopoverVC;
@property (strong) IBOutlet ChatVC* chatVC;
@property QHash<int, NSButton*> actionHash;
......@@ -92,8 +95,9 @@
@implementation CurrentCallVC
@synthesize personLabel, actionHash, stateLabel, holdOnOffButton, hangUpButton,
recordOnOffButton, pickUpButton, chatButton, timeSpentLabel,
muteVideoButton, muteAudioButton, controlsPanel, headerContainer, videoView, videoLayer, previewLayer, previewView, splitView, loadingIndicator;
recordOnOffButton, pickUpButton, chatButton, transferButton, timeSpentLabel,
muteVideoButton, muteAudioButton, controlsPanel, headerContainer, videoView,
videoLayer, previewLayer, previewView, splitView, loadingIndicator;
@synthesize previewHolder;
@synthesize videoHolder;
......@@ -188,6 +192,7 @@
actionHash[ (int)UserActionModel::Action::HANGUP] = hangUpButton;
actionHash[ (int)UserActionModel::Action::MUTE_AUDIO] = muteAudioButton;
actionHash[ (int)UserActionModel::Action::MUTE_VIDEO] = muteVideoButton;
actionHash[ (int)UserActionModel::Action::SERVER_TRANSFER] = transferButton;
videoLayer = [CALayer layer];
[videoView setWantsLayer:YES];
......@@ -456,6 +461,12 @@
QObject::disconnect(previewHolder.started);
[videoView.layer setContents:nil];
[previewView.layer setContents:nil];
[self.transferPopoverVC performClose:self];
[self.addToContactPopover performClose:self];
[self.qualityPopOver performClose:self];
[self.chatButton setState:NSOffState];
[self collapseRightView];
}
-(void) animateOut
......@@ -538,8 +549,6 @@
if (self.addToContactPopover != nullptr) {
[self.addToContactPopover performClose:self];
self.addToContactPopover = NULL;
[self.addContactButton setState:NSOffState];
} else if (!contactmethod->contact() || contactmethod->contact()->isPlaceHolder()) {
auto* editorVC = [[PersonLinkerVC alloc] initWithNibName:@"PersonLinker" bundle:nil];
[editorVC setMethodToLink:contactmethod];
......@@ -553,6 +562,8 @@
[self.addToContactPopover showRelativeToRect:sender.bounds ofView:sender preferredEdge:NSMaxXEdge];
}
[videoView setCallDelegate:nil];
}
- (IBAction)hangUp:(id)sender {
......@@ -597,22 +608,50 @@
- (IBAction)displayQualityPopUp:(id)sender {
[self.qualityPopOver showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMaxXEdge];
[videoView setCallDelegate:nil];
}
- (IBAction)toggleTransferView:(id)sender {
if (self.transferPopoverVC != nullptr) {
[self.transferPopoverVC performClose:self];
self.transferPopoverVC = NULL;
[self.transferButton setState:NSOffState];
} else {
auto* transferVC = [[BrokerVC alloc] initWithMode:BrokerMode::TRANSFER];
self.transferPopoverVC = [[NSPopover alloc] init];
[self.transferPopoverVC setContentSize:transferVC.view.frame.size];
[self.transferPopoverVC setContentViewController:transferVC];
[self.transferPopoverVC setAnimates:YES];
[self.transferPopoverVC setBehavior:NSPopoverBehaviorTransient];
[self.transferPopoverVC setDelegate:self];
[self.transferPopoverVC showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMinYEdge];
[videoView setCallDelegate:nil];
}
}
#pragma mark - NSPopOverDelegate
- (void)popoverWillClose:(NSNotification *)notification
{
if (self.transferPopoverVC != nullptr) {
[self.transferPopoverVC performClose:self];
self.transferPopoverVC = NULL;
}
if (self.addToContactPopover != nullptr) {
[self.addToContactPopover performClose:self];
self.addToContactPopover = NULL;
}
[self.qualityButton setState:NSOffState];
[self.addContactButton setState:NSOffState];
[self.transferButton setState:NSOffState];
}
- (void)popoverDidClose:(NSNotification *)notification
{
if (self.addToContactPopover != nullptr) {
[self.addToContactPopover performClose:self];
self.addToContactPopover = NULL;
}
[videoView setCallDelegate:self];
}
#pragma mark - ContactLinkedDelegate
......
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="8191" systemVersion="14F27" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="8191"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="BrokerVC">
<connections>
<outlet property="smartView" destination="ged-Fo-NiW" id="zOq-oj-zdQ"/>
<outlet property="view" destination="Hz6-mo-xeY" id="GmP-OL-Nu1"/>
</connections>
</customObject>
<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="290" height="438"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<searchField wantsLayer="YES" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="6Sk-jm-KTk">
<rect key="frame" x="20" y="396" width="250" height="22"/>
<searchFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" borderStyle="bezel" placeholderString="Search or enter number" usesSingleLineMode="YES" bezelStyle="round" id="5vh-ub-Dsq">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="1" alpha="0.0" colorSpace="deviceWhite"/>
</searchFieldCell>
<connections>
<outlet property="delegate" destination="-2" id="Bs5-0w-IAt"/>
</connections>
</searchField>
<scrollView fixedFrame="YES" borderType="none" autohidesScrollers="YES" horizontalLineScroll="62" horizontalPageScroll="10" verticalLineScroll="62" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="A5E-AF-qKC">
<rect key="frame" x="20" y="20" width="250" height="368"/>
<clipView key="contentView" ambiguous="YES" drawsBackground="NO" copiesOnScroll="NO" id="0Vv-ik-q6g">
<rect key="frame" x="0.0" y="0.0" width="250" height="368"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<outlineView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" multipleSelection="NO" autosaveColumns="NO" rowHeight="60" rowSizeStyle="automatic" viewBased="YES" indentationPerLevel="16" outlineTableColumn="pqp-hy-d8y" id="ged-Fo-NiW">
<rect key="frame" x="0.0" y="0.0" width="250" height="368"/>
<autoresizingMask key="autoresizingMask"/>
<size key="intercellSpacing" width="3" height="2"/>
<color key="backgroundColor" white="1" alpha="0.0" colorSpace="deviceWhite"/>
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
<tableColumns>
<tableColumn width="247" minWidth="40" maxWidth="1000" id="pqp-hy-d8y">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="3lU-Go-v0h">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView identifier="MainCell" id="YLQ-KL-wQ3" userLabel="MainCell" customClass="ContextualTableCellView">
<rect key="frame" x="1" y="1" width="247" height="60"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" tag="200" translatesAutoresizingMaskIntoConstraints="NO" id="bsM-kY-9k6">
<rect key="frame" x="57" y="31" width="189" height="23"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Display Role" id="1Rl-Yq-z7r">
<font key="font" size="16" name="HelveticaNeue-Light"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" tag="100" translatesAutoresizingMaskIntoConstraints="NO" id="RkA-HO-2Ad">
<rect key="frame" x="3" y="6" width="48" height="48"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="NSUser" id="mZk-we-i9v"/>
</imageView>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" tag="300" translatesAutoresizingMaskIntoConstraints="NO" id="eaV-2E-ENh">
<rect key="frame" x="57" y="10" width="189" height="20"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="details" id="sQW-4V-hwv">
<font key="font" size="13" name="HelveticaNeue-Light"/>
<color key="textColor" red="0.0" green="0.23137254901960785" blue="0.30588235294117649" alpha="1" colorSpace="calibratedRGB"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button hidden="YES" verticalHuggingPriority="750" misplaced="YES" tag="400" translatesAutoresizingMaskIntoConstraints="NO" id="neN-xV-wb5" userLabel="Call Button" customClass="IconButton">
<rect key="frame" x="288" y="18" width="25" height="25"/>
<constraints>
<constraint firstAttribute="width" constant="25" id="3a4-Cj-CU8"/>
<constraint firstAttribute="height" constant="25" id="8L3-91-Rn2"/>
</constraints>
<buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="ic_action_call" imagePosition="overlaps" alignment="center" allowsMixedState="YES" transparent="YES" imageScaling="proportionallyDown" inset="2" id="c4F-rE-v5i">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="callClickedAtRow:" target="-1" id="hyg-jg-asa"/>
</connections>
</button>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="neN-xV-wb5" secondAttribute="trailing" constant="8" id="MvK-3g-Jh7"/>
<constraint firstItem="neN-xV-wb5" firstAttribute="centerY" secondItem="YLQ-KL-wQ3" secondAttribute="centerY" constant="-0.5" id="T4T-wG-JiS"/>
</constraints>
<connections>
<outlet property="textField" destination="bsM-kY-9k6" id="XaM-Ih-4di"/>
</connections>
</tableCellView>
<customView identifier="HoverRowView" id="gbf-Fl-RiK" customClass="HoverTableRowView">
<rect key="frame" x="1" y="63" width="247" height="55"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
</customView>
</prototypeCellViews>
</tableColumn>
</tableColumns>
<connections>
<outlet property="delegate" destination="-2" id="aSl-td-KL2"/>
</connections>
</outlineView>
</subviews>
<color key="backgroundColor" white="1" alpha="0.0" colorSpace="deviceWhite"/>
</clipView>
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="Maf-69-awc">
<rect key="frame" x="0.0" y="-16" width="0.0" height="16"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="fYr-Sf-2LL">
<rect key="frame" x="-16" y="0.0" width="16" height="0.0"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
</scrollView>
</subviews>
<point key="canvasLocation" x="248" y="367"/>
</customView>
</objects>
<resources>
<image name="NSUser" width="32" height="32"/>
<image name="ic_action_call" width="72" height="72"/>
</resources>
</document>
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment