blob: 252605b6c5f7b5d27cc39f7edf9ea7f694190414 [file] [log] [blame]
Kateryna Kostiuk13b76882017-03-30 09:18:44 -04001/*
2 * Copyright (C) 2015-2017 Savoir-faire Linux Inc.
3 * Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
Anthony Léonard49cb2912017-11-13 16:15:39 -05004 * Author: Olivier Soldano <olivier.soldano@savoirfairelinux.com>
5 * Author: Anthony Léonard <anthony.leonard@savoirfairelinux.com>
Kateryna Kostiuk13b76882017-03-30 09:18:44 -04006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22#import "ChooseAccountVC.h"
23
24//Qt
25#import <QSize>
26#import <QtMacExtras/qmacfunctions.h>
27#import <QPixmap>
28
29//LRC
Kateryna Kostiuk13b76882017-03-30 09:18:44 -040030#import <globalinstances.h>
Kateryna Kostiuk13b76882017-03-30 09:18:44 -040031#import <QItemSelectionModel.h>
32#import <interfaces/pixmapmanipulatori.h>
Anthony Léonard49cb2912017-11-13 16:15:39 -050033#import <api/newaccountmodel.h>
34#import <api/account.h>
Kateryna Kostiuk312f9132017-04-18 12:09:06 -040035
Kateryna Kostiuk13b76882017-03-30 09:18:44 -040036//RING
37#import "views/AccountMenuItemView.h"
Kateryna Kostiuka16c9862017-05-03 13:30:14 -040038#import "AccountSelectionManager.h"
Anthony Léonard9bebf1d2017-12-21 14:33:51 -050039#import "RingWindowController.h"
Kateryna Kostiuk13b76882017-03-30 09:18:44 -040040
41@interface ChooseAccountVC () <NSMenuDelegate>
42
43@end
44
45@implementation ChooseAccountVC {
Kateryna Kostiuk312f9132017-04-18 12:09:06 -040046
Kateryna Kostiuk13b76882017-03-30 09:18:44 -040047 __unsafe_unretained IBOutlet NSImageView* profileImage;
48 __unsafe_unretained IBOutlet NSPopUpButton* accountSelectionButton;
Anthony Léonard49cb2912017-11-13 16:15:39 -050049 const lrc::api::NewAccountModel* accMdl_;
50 AccountSelectionManager* accountSelectionManager_;
Anthony Léonard9bebf1d2017-12-21 14:33:51 -050051 RingWindowController* delegate;
Kateryna Kostiuk312f9132017-04-18 12:09:06 -040052
Kateryna Kostiuk13b76882017-03-30 09:18:44 -040053}
54Boolean menuIsOpen;
55Boolean menuNeedsUpdate;
56NSMenu* accountsMenu;
57NSMenuItem* selectedMenuItem;
Anthony Léonard49cb2912017-11-13 16:15:39 -050058
Anthony Léonard9bebf1d2017-12-21 14:33:51 -050059-(id) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil model:(const lrc::api::NewAccountModel*) accMdl delegate:(RingWindowController *)mainWindow
Anthony Léonard49cb2912017-11-13 16:15:39 -050060{
61 accMdl_ = accMdl;
62 accountSelectionManager_ = [[AccountSelectionManager alloc] initWithAccountModel:accMdl_];
Anthony Léonard9bebf1d2017-12-21 14:33:51 -050063 delegate = mainWindow;
Anthony Léonard49cb2912017-11-13 16:15:39 -050064 return [self initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
65}
Kateryna Kostiuk13b76882017-03-30 09:18:44 -040066
67- (void)awakeFromNib
68{
69 [profileImage setWantsLayer: YES];
70 profileImage.layer.cornerRadius = profileImage.frame.size.width / 2;
71 profileImage.layer.masksToBounds = YES;
Kateryna Kostiuk065aaf22017-07-07 13:04:23 -040072
Kateryna Kostiuk13b76882017-03-30 09:18:44 -040073 accountsMenu = [[NSMenu alloc] initWithTitle:@""];
74 [accountsMenu setDelegate:self];
75 accountSelectionButton.menu = accountsMenu;
76 [self update];
77
Anthony Léonard49cb2912017-11-13 16:15:39 -050078 QObject::connect(accMdl_,
79 &lrc::api::NewAccountModel::accountAdded,
Kateryna Kostiukab499f42018-04-16 12:27:33 -040080 [self] (const std::string& accountID) {
Kateryna Kostiuk312f9132017-04-18 12:09:06 -040081 [self update];
Kateryna Kostiukab499f42018-04-16 12:27:33 -040082 @try {
83 auto& account = [self selectedAccount];
84 [delegate selectAccount:account];
85 }
86 @catch (NSException * e) {
87 NSLog(@"account selection failed");
88 }
Kateryna Kostiuk312f9132017-04-18 12:09:06 -040089 });
Anthony Léonard49cb2912017-11-13 16:15:39 -050090 QObject::connect(accMdl_,
91 &lrc::api::NewAccountModel::accountRemoved,
Kateryna Kostiukab499f42018-04-16 12:27:33 -040092 [self] (const std::string& accountID) {
93 if ([self selectedAccount].id.compare(accountID) == 0) {
94 [accountSelectionManager_ clearSelectedAccount];
95 }
96 @try {
97 auto& account = [self selectedAccount];
98 [delegate selectAccount:account];
99 }
100 @catch (NSException * e) {
101 [delegate allAccountsDeleted];
102 }
Kateryna Kostiuk312f9132017-04-18 12:09:06 -0400103 [self update];
104 });
Anthony Léonard49cb2912017-11-13 16:15:39 -0500105 QObject::connect(accMdl_,
106 &lrc::api::NewAccountModel::profileUpdated,
Kateryna Kostiukab499f42018-04-16 12:27:33 -0400107 [self] (const std::string& accountID) {
Kateryna Kostiuk312f9132017-04-18 12:09:06 -0400108 [self update];
109 });
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400110}
111
Anthony Léonard49cb2912017-11-13 16:15:39 -0500112-(const lrc::api::account::Info&) selectedAccount
113{
Anthony Léonard72128c92017-12-26 16:48:39 -0500114 try {
115 return [accountSelectionManager_ savedAccount];
Kateryna Kostiukab499f42018-04-16 12:27:33 -0400116 } catch (NSException *ex) {
Anthony Léonard72128c92017-12-26 16:48:39 -0500117 auto accountList = accMdl_->getAccountList();
118 if (!accountList.empty()) {
119 const auto& fallbackAccount = accMdl_->getAccountInfo(accountList.at(0));
Kateryna Kostiukab499f42018-04-16 12:27:33 -0400120 if (accountList.size() == 1) {
121 [accountSelectionManager_ setSavedAccount:fallbackAccount];
122 }
Anthony Léonard49cb2912017-11-13 16:15:39 -0500123 return fallbackAccount;
Anthony Léonard72128c92017-12-26 16:48:39 -0500124 } else {
125 NSException* noAccEx = [NSException
126 exceptionWithName:@"NoAccountException"
127 reason:@"No account in AccountModel"
128 userInfo:nil];
129 @throw noAccEx;
Anthony Léonard49cb2912017-11-13 16:15:39 -0500130 }
131 }
Anthony Léonard49cb2912017-11-13 16:15:39 -0500132}
133
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400134-(void) updateMenu {
135 [accountsMenu removeAllItems];
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400136
Anthony Léonard49cb2912017-11-13 16:15:39 -0500137 auto accList = accMdl_->getAccountList();
138
139 for (std::string accId : accList) {
140 auto& account = accMdl_->getAccountInfo(accId);
141
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400142 NSMenuItem* menuBarItem = [[NSMenuItem alloc]
Kateryna Kostiuk312f9132017-04-18 12:09:06 -0400143 initWithTitle:[self itemTitleForAccount:account]
144 action:NULL
145 keyEquivalent:@""];
146
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400147 menuBarItem.attributedTitle = [self attributedItemTitleForAccount:account];
148 AccountMenuItemView *itemView = [[AccountMenuItemView alloc] initWithFrame:CGRectZero];
Anthony Léonard49cb2912017-11-13 16:15:39 -0500149 [itemView.accountLabel setStringValue:@(account.profileInfo.alias.c_str())];
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400150 NSString* userNameString = [self nameForAccount: account];
151 [itemView.userNameLabel setStringValue:userNameString];
Anthony Léonard49cb2912017-11-13 16:15:39 -0500152 switch (account.profileInfo.type) {
153 case lrc::api::profile::Type::SIP:
Kateryna Kostiuka7248462017-04-18 16:15:31 -0400154 [itemView.accountTypeLabel setStringValue:@"SIP"];
155 break;
Anthony Léonard49cb2912017-11-13 16:15:39 -0500156 case lrc::api::profile::Type::RING:
Kateryna Kostiuka7248462017-04-18 16:15:31 -0400157 [itemView.accountTypeLabel setStringValue:@"RING"];
158 break;
159 default:
160 break;
161 }
Anthony Léonard49cb2912017-11-13 16:15:39 -0500162
Anthony Léonard48079de2018-02-15 17:00:50 -0500163 bool isAccountAlone = accList.size() == 1;
164
165 [[accountSelectionButton cell] setArrowPosition: (isAccountAlone)?NSPopUpNoArrow:NSPopUpArrowAtBottom];
166 [accountSelectionButton setEnabled:!isAccountAlone];
167
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400168 [menuBarItem setView:itemView];
169 [accountsMenu addItem:menuBarItem];
170 [accountsMenu addItem:[NSMenuItem separatorItem]];
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400171 }
172}
173
Anthony Léonard49cb2912017-11-13 16:15:39 -0500174-(void) updatePhoto
175{
Anthony Léonard72128c92017-12-26 16:48:39 -0500176 @try {
177 auto& account = [self selectedAccount];
178 if(account.profileInfo.type == lrc::api::profile::Type::INVALID)
179 return;
Anthony Léonard49cb2912017-11-13 16:15:39 -0500180
Anthony Léonard72128c92017-12-26 16:48:39 -0500181 QByteArray ba = QByteArray::fromStdString(account.profileInfo.avatar);
Anthony Léonard49cb2912017-11-13 16:15:39 -0500182
Anthony Léonard72128c92017-12-26 16:48:39 -0500183 QVariant photo = GlobalInstances::pixmapManipulator().personPhoto(ba);
184 [profileImage setImage:QtMac::toNSImage(qvariant_cast<QPixmap>(photo))];
185 }
186 @catch (NSException *ex) {
187 NSLog(@"Caught exception %@: %@", [ex name], [ex reason]);
188 }
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400189}
190
Anthony Léonard49cb2912017-11-13 16:15:39 -0500191-(NSString*) nameForAccount:(const lrc::api::account::Info&) account {
192 auto name = account.registeredName;
193 return @(name.c_str());
194}
195
196-(NSString*) itemTitleForAccount:(const lrc::api::account::Info&) account {
197 NSString* alias = @(account.profileInfo.alias.c_str());
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400198 NSString* userNameString = [self nameForAccount: account];
Kateryna Kostiuka7248462017-04-18 16:15:31 -0400199 if([userNameString length] > 0) {
200 alias = [NSString stringWithFormat: @"%@\n", alias];
201 }
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400202 return [alias stringByAppendingString:userNameString];
203}
204
Anthony Léonard49cb2912017-11-13 16:15:39 -0500205- (NSAttributedString*) attributedItemTitleForAccount:(const lrc::api::account::Info&) account {
206 NSString* alias = @(account.profileInfo.alias.c_str());
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400207 NSString* userNameString = [self nameForAccount: account];
Kateryna Kostiuka7248462017-04-18 16:15:31 -0400208 if([userNameString length] > 0){
209 alias = [NSString stringWithFormat: @"%@\n", alias];
210 }
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400211 NSFont *fontAlias = [NSFont userFontOfSize:14.0];
212 NSFont *fontUserName = [NSFont userFontOfSize:11.0];
213 NSColor *colorAlias = [NSColor labelColor];
214 NSColor *colorAUserName = [NSColor secondaryLabelColor];
215 NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
216 paragraphStyle.lineBreakMode = NSLineBreakByTruncatingTail;
217 NSDictionary *aliasAttrs = [NSDictionary dictionaryWithObjectsAndKeys:fontAlias,NSFontAttributeName,
218 colorAlias,NSForegroundColorAttributeName,
219 paragraphStyle,NSParagraphStyleAttributeName, nil];
220 NSDictionary *userNameAttrs = [NSDictionary dictionaryWithObjectsAndKeys:fontUserName,NSFontAttributeName,
221 colorAUserName,NSForegroundColorAttributeName,
222 paragraphStyle,NSParagraphStyleAttributeName, nil];
223 NSAttributedString* attributedString = [[NSAttributedString alloc] initWithString:alias attributes:aliasAttrs];
224 NSAttributedString* attributedStringSecond= [[NSAttributedString alloc] initWithString:userNameString attributes:userNameAttrs];
225 NSMutableAttributedString *result = [[NSMutableAttributedString alloc] init];
226 [result appendAttributedString:attributedString];
227 [result appendAttributedString:attributedStringSecond];
228 return result;
229}
230
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400231-(void) update {
232 if(menuIsOpen) {
233 return;
234 }
235 [self updateMenu];
Kateryna Kostiuk312f9132017-04-18 12:09:06 -0400236 [self setPopUpButtonSelection];
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400237}
238
Kateryna Kostiuk312f9132017-04-18 12:09:06 -0400239-(void) setPopUpButtonSelection {
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400240 if(accountsMenu.itemArray.count == 0) {
241 [self.view setHidden:YES];
242 return;
243 }
Kateryna Kostiuk312f9132017-04-18 12:09:06 -0400244 [self.view setHidden:NO];
Anthony Léonard72128c92017-12-26 16:48:39 -0500245 @try {
246 auto& account = [self selectedAccount];
247 if(account.profileInfo.type == lrc::api::profile::Type::INVALID){
248 return;
249 }
250 [accountSelectionButton selectItemWithTitle:[self itemTitleForAccount:account]];
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400251 }
Anthony Léonard72128c92017-12-26 16:48:39 -0500252 @catch (NSException *ex) {
253 NSLog(@"Caught exception %@: %@", [ex name], [ex reason]);
254 }
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400255}
256
257#pragma mark - NSPopUpButton item selection
258
259- (IBAction)itemChanged:(id)sender {
Kateryna Kostiuk312f9132017-04-18 12:09:06 -0400260 NSInteger row = [(NSPopUpButton *)sender indexOfSelectedItem] / 2;
Anthony Léonard49cb2912017-11-13 16:15:39 -0500261 auto accList = accMdl_->getAccountList();
262 if (row >= accList.size())
Kateryna Kostiuka16c9862017-05-03 13:30:14 -0400263 return;
Anthony Léonard49cb2912017-11-13 16:15:39 -0500264
265 auto& account = accMdl_->getAccountInfo(accList[row]);
266 [accountSelectionManager_ setSavedAccount:account];
Anthony Léonard9bebf1d2017-12-21 14:33:51 -0500267 [delegate selectAccount:account];
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400268}
269
270#pragma mark - NSMenuDelegate
271- (void)menuWillOpen:(NSMenu *)menu {
272 menuIsOpen = true;
273 // remember selected item to remove highlighting when menu is open
274 selectedMenuItem = [accountSelectionButton selectedItem];
275}
276- (void)menuDidClose:(NSMenu *)menu {
277
278 menuIsOpen = false;
279}
280
281- (void)menu:(NSMenu *)menu willHighlightItem:(nullable NSMenuItem *)item {
282 if (!selectedMenuItem || selectedMenuItem == item) {
283 return;
284 }
285 int index = [menu indexOfItem:selectedMenuItem];
286 [menu removeItemAtIndex:index];
287 [menu insertItem:selectedMenuItem atIndex:index];
288 [accountSelectionButton selectItemAtIndex:index];
289 selectedMenuItem = nil;
290}
291
Kateryna Kostiukabf4e272017-04-18 14:18:00 -0400292-(void) enable {
293 [accountSelectionButton setEnabled:YES];
294}
295-(void) disable {
296 [accountSelectionButton setEnabled:NO];
297}
298
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400299@end