Kateryna Kostiuk | 4db6109 | 2019-10-17 16:57:40 -0400 | [diff] [blame] | 1 | /* |
| 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 | |
| 51 | lrc::api::ConversationModel* convModel; |
Kateryna Kostiuk | c867eb9 | 2020-03-08 13:15:17 -0400 | [diff] [blame] | 52 | QString currentConversation; |
Kateryna Kostiuk | 4db6109 | 2019-10-17 16:57:40 -0400 | [diff] [blame] | 53 | |
Kateryna Kostiuk | c867eb9 | 2020-03-08 13:15:17 -0400 | [diff] [blame] | 54 | QMap<lrc::api::ConferenceableItem, lrc::api::ConferenceableValue> values; |
Kateryna Kostiuk | 4db6109 | 2019-10-17 16:57:40 -0400 | [diff] [blame] | 55 | |
| 56 | // Tags for views |
| 57 | NSInteger const IMAGE_TAG = 100; |
| 58 | NSInteger const DISPLAYNAME_TAG = 200; |
| 59 | NSInteger const RING_ID_LABEL = 300; |
| 60 | NSInteger const PRESENCE_TAG = 400; |
| 61 | |
| 62 | NSInteger const ROW_HEIGHT = 60; |
| 63 | NSInteger const MINIMUM_TABLE_SIZE = 0; |
| 64 | NSInteger const NORMAL_TABLE_SIZE = 120; |
| 65 | NSInteger const MAXIMUM_TABLE_SIZE = 240; |
| 66 | |
| 67 | - (void)controlTextDidChange:(NSNotification *) notification |
| 68 | { |
Kateryna Kostiuk | c867eb9 | 2020-03-08 13:15:17 -0400 | [diff] [blame] | 69 | values = convModel->getConferenceableConversations(currentConversation, QString::fromNSString(searchField.stringValue)); |
Kateryna Kostiuk | 4db6109 | 2019-10-17 16:57:40 -0400 | [diff] [blame] | 70 | [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 Kostiuk | c867eb9 | 2020-03-08 13:15:17 -0400 | [diff] [blame] | 107 | andCurrentConversation:(const QString&)conversation |
Kateryna Kostiuk | 4db6109 | 2019-10-17 16:57:40 -0400 | [diff] [blame] | 108 | { |
| 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 Kostiuk | c867eb9 | 2020-03-08 13:15:17 -0400 | [diff] [blame] | 142 | 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 Kostiuk | 4db6109 | 2019-10-17 16:57:40 -0400 | [diff] [blame] | 151 | auto accountID = conversation.accountId; |
| 152 | auto convID = conversation.convId; |
| 153 | auto convMod = convModel->owner.accountModel->getAccountInfo(accountID).conversationModel.get(); |
Kateryna Kostiuk | 534a8a7 | 2020-09-02 18:28:35 -0400 | [diff] [blame] | 154 | auto conversationInfo = convMod->getConversationForUID(convID); |
| 155 | if (conversationInfo.uid.isEmpty()) { |
Kateryna Kostiuk | 4db6109 | 2019-10-17 16:57:40 -0400 | [diff] [blame] | 156 | return; |
| 157 | } |
| 158 | |
| 159 | if (table == callsView) { |
Kateryna Kostiuk | 534a8a7 | 2020-09-02 18:28:35 -0400 | [diff] [blame] | 160 | auto callID = conversationInfo.confId.isEmpty() ? conversationInfo.callId : conversationInfo.confId; |
Kateryna Kostiuk | 4db6109 | 2019-10-17 16:57:40 -0400 | [diff] [blame] | 161 | [self.delegate joinCall: callID]; |
| 162 | } else if (table == contactsView) { |
Kateryna Kostiuk | 534a8a7 | 2020-09-02 18:28:35 -0400 | [diff] [blame] | 163 | auto uid = conversationInfo.participants.front(); |
| 164 | [self.delegate callToContact:uid convUID: convID]; |
Kateryna Kostiuk | 4db6109 | 2019-10-17 16:57:40 -0400 | [diff] [blame] | 165 | } |
| 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 Kostiuk | c867eb9 | 2020-03-08 13:15:17 -0400 | [diff] [blame] | 180 | QVector<QVector<lrc::api::AccountConversation>> allConversations; |
Kateryna Kostiuk | 4db6109 | 2019-10-17 16:57:40 -0400 | [diff] [blame] | 181 | if (tableView == callsView && convModel != nullptr) { |
Kateryna Kostiuk | c867eb9 | 2020-03-08 13:15:17 -0400 | [diff] [blame] | 182 | allConversations = values.value(lrc::api::ConferenceableItem::CALL); |
Kateryna Kostiuk | 4db6109 | 2019-10-17 16:57:40 -0400 | [diff] [blame] | 183 | } else if (tableView == contactsView && convModel != nullptr) { |
Kateryna Kostiuk | c867eb9 | 2020-03-08 13:15:17 -0400 | [diff] [blame] | 184 | allConversations = values.value(lrc::api::ConferenceableItem::CONTACT); |
Kateryna Kostiuk | 4db6109 | 2019-10-17 16:57:40 -0400 | [diff] [blame] | 185 | } |
Kateryna Kostiuk | c867eb9 | 2020-03-08 13:15:17 -0400 | [diff] [blame] | 186 | if (allConversations.size() < row) { |
| 187 | return nil; |
| 188 | } |
| 189 | |
| 190 | QVector<lrc::api::AccountConversation> conversations = allConversations[row]; |
Kateryna Kostiuk | 4db6109 | 2019-10-17 16:57:40 -0400 | [diff] [blame] | 191 | 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 Kostiuk | 534a8a7 | 2020-09-02 18:28:35 -0400 | [diff] [blame] | 214 | auto conversationInfo = convMod->getConversationForUID(convID); |
| 215 | if (conversationInfo.uid.isEmpty()) { |
| 216 | return nil; |
| 217 | } |
Kateryna Kostiuk | 4db6109 | 2019-10-17 16:57:40 -0400 | [diff] [blame] | 218 | if (displayNameString.length > 0) { |
| 219 | displayNameString = [displayNameString stringByAppendingString:@", "]; |
| 220 | } |
Kateryna Kostiuk | 534a8a7 | 2020-09-02 18:28:35 -0400 | [diff] [blame] | 221 | displayNameString = [displayNameString stringByAppendingString: bestNameForConversation(conversationInfo, *convMod)]; |
Kateryna Kostiuk | 4db6109 | 2019-10-17 16:57:40 -0400 | [diff] [blame] | 222 | } |
| 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 Kostiuk | 534a8a7 | 2020-09-02 18:28:35 -0400 | [diff] [blame] | 237 | auto conversationInfo = convMod->getConversationForUID(convID); |
| 238 | if (conversationInfo.uid.isEmpty() || conversationInfo.participants.empty()) { |
Kateryna Kostiuk | 4db6109 | 2019-10-17 16:57:40 -0400 | [diff] [blame] | 239 | return nil; |
| 240 | } |
Kateryna Kostiuk | 534a8a7 | 2020-09-02 18:28:35 -0400 | [diff] [blame] | 241 | NSString* displayNameString = bestNameForConversation(conversationInfo, *convMod); |
| 242 | NSString* displayIDString = bestIDForConversation(conversationInfo, *convMod); |
Kateryna Kostiuk | 4db6109 | 2019-10-17 16:57:40 -0400 | [diff] [blame] | 243 | 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 Kostiuk | 534a8a7 | 2020-09-02 18:28:35 -0400 | [diff] [blame] | 252 | NSImage* image = QtMac::toNSImage(qvariant_cast<QPixmap>(imageManip.conversationPhoto(conversationInfo, convMod->owner))); |
Kateryna Kostiuk | 4db6109 | 2019-10-17 16:57:40 -0400 | [diff] [blame] | 253 | 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 Kostiuk | 534a8a7 | 2020-09-02 18:28:35 -0400 | [diff] [blame] | 271 | auto contact = convModel->owner.contactModel->getContact(conversationInfo.participants[0]); |
Kateryna Kostiuk | 4db6109 | 2019-10-17 16:57:40 -0400 | [diff] [blame] | 272 | 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 Kostiuk | c867eb9 | 2020-03-08 13:15:17 -0400 | [diff] [blame] | 294 | return values.count(lrc::api::ConferenceableItem::CONTACT) ? values.value(lrc::api::ConferenceableItem::CONTACT).size() : 0; |
Kateryna Kostiuk | 4db6109 | 2019-10-17 16:57:40 -0400 | [diff] [blame] | 295 | } else if (tableView == callsView) { |
Kateryna Kostiuk | c867eb9 | 2020-03-08 13:15:17 -0400 | [diff] [blame] | 296 | return values.count(lrc::api::ConferenceableItem::CALL) ? values.value(lrc::api::ConferenceableItem::CALL).size() : 0; |
Kateryna Kostiuk | 4db6109 | 2019-10-17 16:57:40 -0400 | [diff] [blame] | 297 | } |
| 298 | return 0; |
| 299 | } |
| 300 | |
| 301 | @end |