blob: f524bf17211d5e08a02d52ed5d18934e0ba4c5b0 [file] [log] [blame]
Kateryna Kostiuk4db61092019-10-17 16:57:40 -04001/*
2 * Copyright (C) 2019 Savoir-faire Linux Inc.
3 * Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20#import "ChooseContactVC.h"
21#import "views/RingTableView.h"
22#import "views/HoverTableRowView.h"
23#import "utils.h"
24#import "delegates/ImageManipulationDelegate.h"
25
26//LRC
27#import <globalinstances.h>
28#import <api/conversationmodel.h>
29#import <api/account.h>
30#import <api/newaccountmodel.h>
31
32//Qt
33#import <QtMacExtras/qmacfunctions.h>
34#import <QPixmap>
35
36@interface ChooseContactVC () {
37 __unsafe_unretained IBOutlet RingTableView* contactsView;
38 __unsafe_unretained IBOutlet RingTableView* callsView;
39 __unsafe_unretained IBOutlet NSSearchField* searchField;
40 __unsafe_unretained IBOutlet NSLayoutConstraint* contactsViewHeightConstraint;
41 __unsafe_unretained IBOutlet NSLayoutConstraint* calsViewHeightConstraint;
42 __unsafe_unretained IBOutlet NSStackView* callsContainer;
43 __unsafe_unretained IBOutlet NSStackView* contactsContainer;
44 __unsafe_unretained IBOutlet NSTextField* contactsLabel;
45}
46
47@end
48
49@implementation ChooseContactVC
50
51lrc::api::ConversationModel* convModel;
Kateryna Kostiukc867eb92020-03-08 13:15:17 -040052QString currentConversation;
Kateryna Kostiuk4db61092019-10-17 16:57:40 -040053
Kateryna Kostiukc867eb92020-03-08 13:15:17 -040054QMap<lrc::api::ConferenceableItem, lrc::api::ConferenceableValue> values;
Kateryna Kostiuk4db61092019-10-17 16:57:40 -040055
56// Tags for views
57NSInteger const IMAGE_TAG = 100;
58NSInteger const DISPLAYNAME_TAG = 200;
59NSInteger const RING_ID_LABEL = 300;
60NSInteger const PRESENCE_TAG = 400;
61
62NSInteger const ROW_HEIGHT = 60;
63NSInteger const MINIMUM_TABLE_SIZE = 0;
64NSInteger const NORMAL_TABLE_SIZE = 120;
65NSInteger const MAXIMUM_TABLE_SIZE = 240;
66
67- (void)controlTextDidChange:(NSNotification *) notification
68{
Kateryna Kostiukc867eb92020-03-08 13:15:17 -040069 values = convModel->getConferenceableConversations(currentConversation, QString::fromNSString(searchField.stringValue));
Kateryna Kostiuk4db61092019-10-17 16:57:40 -040070 [self reloadView];
71}
72
73- (void) reloadView
74{
75 [callsView reloadData];
76 [contactsView reloadData];
77 auto callsSize = [callsView numberOfRows] * ROW_HEIGHT;
78 auto contactsSize = [contactsView numberOfRows] * ROW_HEIGHT;
79 if (callsSize >= NORMAL_TABLE_SIZE) {
80 if (contactsSize >= NORMAL_TABLE_SIZE) {
81 contactsViewHeightConstraint.constant = NORMAL_TABLE_SIZE;
82 calsViewHeightConstraint.constant = NORMAL_TABLE_SIZE;
83 } else {
84 contactsViewHeightConstraint.constant = contactsSize;
85 calsViewHeightConstraint.constant = MAXIMUM_TABLE_SIZE - contactsSize;
86 }
87 } else if (callsSize == MINIMUM_TABLE_SIZE) {
88 // when call stack view is hidden add 35 to avoid controller size changes
89 // 17 - call label height + 8*2 stack view margins
90 contactsViewHeightConstraint.constant = MAXIMUM_TABLE_SIZE + 35;
91 calsViewHeightConstraint.constant = callsSize;
92 } else {
93 contactsViewHeightConstraint.constant = MAXIMUM_TABLE_SIZE - callsSize;
94 calsViewHeightConstraint.constant = callsSize;
95 }
96
97 [callsContainer setHidden: callsSize == 0];
98 [contactsLabel setHidden: contactsSize == 0];
99}
100
101-(void)viewDidLoad {
102 [super viewDidLoad];
103 [self reloadView];
104}
105
106- (void)setConversationModel:(lrc::api::ConversationModel *)conversationModel
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400107 andCurrentConversation:(const QString&)conversation
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400108{
109 convModel = conversationModel;
110 if (convModel == nil) {
111 return;
112 }
113 currentConversation = conversation;
114 values = convModel->getConferenceableConversations(currentConversation, "");
115 [self reloadView];
116}
117
118#pragma mark - NSTableViewDelegate methods
119
120- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row
121{
122 return YES;
123}
124
125- (BOOL)tableView:(NSTableView *)tableView shouldEditTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
126{
127 return NO;
128}
129
130- (void)tableViewSelectionDidChange:(NSNotification *)notification
131{
132 NSInteger row = [notification.object selectedRow];
133 NSTableView *table = notification.object;
134
135 NSInteger rows = [table numberOfRows];
136 for (int i = 0; i< rows; i++) {
137 HoverTableRowView* cellRowView = [table rowViewAtRow:i makeIfNecessary: NO];
138 [cellRowView drawSelection: (i == row)];
139 }
140 if (row == -1 || convModel == nil)
141 return;
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400142 QVector<QVector<lrc::api::AccountConversation>> conversations = table == callsView ? values.value(lrc::api::ConferenceableItem::CALL) : values.value(lrc::api::ConferenceableItem::CONTACT);
143 if (conversations.size() < row) {
144 return;
145 }
146 QVector<lrc::api::AccountConversation> participants = conversations[row];
147 if (participants.isEmpty()) {
148 return;
149 }
150 auto conversation = participants[0];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400151 auto accountID = conversation.accountId;
152 auto convID = conversation.convId;
153 auto convMod = convModel->owner.accountModel->getAccountInfo(accountID).conversationModel.get();
Kateryna Kostiuk534a8a72020-09-02 18:28:35 -0400154 auto conversationInfo = convMod->getConversationForUID(convID);
155 if (conversationInfo.uid.isEmpty()) {
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400156 return;
157 }
158
159 if (table == callsView) {
Kateryna Kostiuk534a8a72020-09-02 18:28:35 -0400160 auto callID = conversationInfo.confId.isEmpty() ? conversationInfo.callId : conversationInfo.confId;
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400161 [self.delegate joinCall: callID];
162 } else if (table == contactsView) {
Kateryna Kostiuk534a8a72020-09-02 18:28:35 -0400163 auto uid = conversationInfo.participants.front();
164 [self.delegate callToContact:uid convUID: convID];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400165 }
166}
167
168- (NSTableRowView *)tableView:(NSTableView *)tableView rowViewForRow:(NSInteger)row
169{
170 HoverTableRowView *howerRow = [tableView makeViewWithIdentifier:@"HoverRowView" owner:nil];
171 [howerRow setBlurType:7];
172 return howerRow;
173}
174
175- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
176{
177 if (convModel == nil)
178 return nil;
179
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400180 QVector<QVector<lrc::api::AccountConversation>> allConversations;
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400181 if (tableView == callsView && convModel != nullptr) {
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400182 allConversations = values.value(lrc::api::ConferenceableItem::CALL);
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400183 } else if (tableView == contactsView && convModel != nullptr) {
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400184 allConversations = values.value(lrc::api::ConferenceableItem::CONTACT);
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400185 }
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400186 if (allConversations.size() < row) {
187 return nil;
188 }
189
190 QVector<lrc::api::AccountConversation> conversations = allConversations[row];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400191 if (conversations.size() < 1) {
192 return nil;
193 }
194
195 NSTableCellView* result = [tableView makeViewWithIdentifier:@"MainCell" owner:tableView];
196
197 NSTextField* displayName = [result viewWithTag:DISPLAYNAME_TAG];
198 NSTextField* displayRingID = [result viewWithTag:RING_ID_LABEL];
199 NSImageView* photoView = [result viewWithTag:IMAGE_TAG];
200 NSView* presenceView = [result viewWithTag:PRESENCE_TAG];
201
202 [displayName setStringValue:@""];
203 [displayRingID setStringValue:@""];
204 [photoView setHidden: YES];
205 [presenceView setHidden:YES];
206
207 // setup conference cell
208 if(conversations.size() > 1) {
209 NSString* displayNameString = @"";
210 for (auto conversation : conversations) {
211 auto accountID = conversation.accountId;
212 auto convID = conversation.convId;
213 auto *convMod = convModel->owner.accountModel->getAccountInfo(accountID).conversationModel.get();
Kateryna Kostiuk534a8a72020-09-02 18:28:35 -0400214 auto conversationInfo = convMod->getConversationForUID(convID);
215 if (conversationInfo.uid.isEmpty()) {
216 return nil;
217 }
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400218 if (displayNameString.length > 0) {
219 displayNameString = [displayNameString stringByAppendingString:@", "];
220 }
Kateryna Kostiuk534a8a72020-09-02 18:28:35 -0400221 displayNameString = [displayNameString stringByAppendingString: bestNameForConversation(conversationInfo, *convMod)];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400222 }
223 [displayName setStringValue:displayNameString];
224 [NSLayoutConstraint deactivateConstraints:[photoView constraints]];
225 NSArray* constraints = [NSLayoutConstraint
226 constraintsWithVisualFormat:@"H:[photoView(0)]"
227 options:0
228 metrics:nil views:NSDictionaryOfVariableBindings(photoView)];
229 [NSLayoutConstraint activateConstraints:constraints];
230 return result;
231 }
232
233 lrc::api::AccountConversation conversation = conversations.front();
234 auto accountID = conversation.accountId;
235 auto convID = conversation.convId;
236 auto *convMod = convModel->owner.accountModel->getAccountInfo(accountID).conversationModel.get();
Kateryna Kostiuk534a8a72020-09-02 18:28:35 -0400237 auto conversationInfo = convMod->getConversationForUID(convID);
238 if (conversationInfo.uid.isEmpty() || conversationInfo.participants.empty()) {
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400239 return nil;
240 }
Kateryna Kostiuk534a8a72020-09-02 18:28:35 -0400241 NSString* displayNameString = bestNameForConversation(conversationInfo, *convMod);
242 NSString* displayIDString = bestIDForConversation(conversationInfo, *convMod);
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400243 if(displayNameString.length == 0 || [displayNameString isEqualToString:displayIDString]) {
244 [displayName setStringValue:displayIDString];
245 [displayRingID setHidden:YES];
246 } else {
247 [displayName setStringValue:displayNameString];
248 [displayRingID setStringValue:displayIDString];
249 [displayRingID setHidden:NO];
250 }
251 auto& imageManip = reinterpret_cast<Interfaces::ImageManipulationDelegate&>(GlobalInstances::pixmapManipulator());
Kateryna Kostiuk534a8a72020-09-02 18:28:35 -0400252 NSImage* image = QtMac::toNSImage(qvariant_cast<QPixmap>(imageManip.conversationPhoto(conversationInfo, convMod->owner)));
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400253 if(image) {
254 [NSLayoutConstraint deactivateConstraints:[photoView constraints]];
255 NSArray* constraints = [NSLayoutConstraint
256 constraintsWithVisualFormat:@"H:[photoView(54)]"
257 options:0
258 metrics:nil views:NSDictionaryOfVariableBindings(photoView)];
259 [NSLayoutConstraint activateConstraints:constraints];
260 } else {
261 [NSLayoutConstraint deactivateConstraints:[photoView constraints]];
262 NSArray* constraints = [NSLayoutConstraint
263 constraintsWithVisualFormat:@"H:[photoView(0)]"
264 options:0
265 metrics:nil views:NSDictionaryOfVariableBindings(photoView)];
266 [NSLayoutConstraint activateConstraints:constraints];
267 }
268 [photoView setHidden: NO];
269 [photoView setImage: image];
270 try {
Kateryna Kostiuk534a8a72020-09-02 18:28:35 -0400271 auto contact = convModel->owner.contactModel->getContact(conversationInfo.participants[0]);
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400272 if (contact.isPresent) {
273 [presenceView setHidden:NO];
274 }
275 } catch (std::out_of_range& e) {
276 NSLog(@"viewForTableColumn: getContact - out of range");
277 }
278 return result;
279}
280
281- (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row
282{
283 return 60.0;
284}
285
286#pragma mark - NSTableDataSource methods
287
288- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
289{
290 if(!convModel) {
291 return 0;
292 }
293 if (tableView == contactsView) {
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400294 return values.count(lrc::api::ConferenceableItem::CONTACT) ? values.value(lrc::api::ConferenceableItem::CONTACT).size() : 0;
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400295 } else if (tableView == callsView) {
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400296 return values.count(lrc::api::ConferenceableItem::CALL) ? values.value(lrc::api::ConferenceableItem::CALL).size() : 0;
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400297 }
298 return 0;
299}
300
301@end