blob: f4009da445e128d2422bfc22cc7523c55dc727dc [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,
80 [self]{
Kateryna Kostiuk312f9132017-04-18 12:09:06 -040081 [self update];
82 });
Anthony Léonard49cb2912017-11-13 16:15:39 -050083 QObject::connect(accMdl_,
84 &lrc::api::NewAccountModel::accountRemoved,
85 [self]{
Kateryna Kostiuk312f9132017-04-18 12:09:06 -040086 [self update];
87 });
Anthony Léonard49cb2912017-11-13 16:15:39 -050088 QObject::connect(accMdl_,
89 &lrc::api::NewAccountModel::profileUpdated,
Kateryna Kostiuk312f9132017-04-18 12:09:06 -040090 [self]{
91 [self update];
92 });
Kateryna Kostiuk13b76882017-03-30 09:18:44 -040093}
94
Anthony Léonard49cb2912017-11-13 16:15:39 -050095-(const lrc::api::account::Info&) selectedAccount
96{
Anthony Léonard72128c92017-12-26 16:48:39 -050097 try {
98 return [accountSelectionManager_ savedAccount];
99 } catch (std::out_of_range& e) { // Is thrown when no account are saved yet
100 auto accountList = accMdl_->getAccountList();
101 if (!accountList.empty()) {
102 const auto& fallbackAccount = accMdl_->getAccountInfo(accountList.at(0));
Anthony Léonard49cb2912017-11-13 16:15:39 -0500103 return fallbackAccount;
Anthony Léonard72128c92017-12-26 16:48:39 -0500104 } else {
105 NSException* noAccEx = [NSException
106 exceptionWithName:@"NoAccountException"
107 reason:@"No account in AccountModel"
108 userInfo:nil];
109 @throw noAccEx;
Anthony Léonard49cb2912017-11-13 16:15:39 -0500110 }
111 }
Anthony Léonard49cb2912017-11-13 16:15:39 -0500112}
113
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400114-(void) updateMenu {
115 [accountsMenu removeAllItems];
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400116
Anthony Léonard49cb2912017-11-13 16:15:39 -0500117 auto accList = accMdl_->getAccountList();
118
119 for (std::string accId : accList) {
120 auto& account = accMdl_->getAccountInfo(accId);
121
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400122 NSMenuItem* menuBarItem = [[NSMenuItem alloc]
Kateryna Kostiuk312f9132017-04-18 12:09:06 -0400123 initWithTitle:[self itemTitleForAccount:account]
124 action:NULL
125 keyEquivalent:@""];
126
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400127 menuBarItem.attributedTitle = [self attributedItemTitleForAccount:account];
128 AccountMenuItemView *itemView = [[AccountMenuItemView alloc] initWithFrame:CGRectZero];
Anthony Léonard49cb2912017-11-13 16:15:39 -0500129 [itemView.accountLabel setStringValue:@(account.profileInfo.alias.c_str())];
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400130 NSString* userNameString = [self nameForAccount: account];
131 [itemView.userNameLabel setStringValue:userNameString];
Anthony Léonard49cb2912017-11-13 16:15:39 -0500132 switch (account.profileInfo.type) {
133 case lrc::api::profile::Type::SIP:
Kateryna Kostiuka7248462017-04-18 16:15:31 -0400134 [itemView.accountTypeLabel setStringValue:@"SIP"];
135 break;
Anthony Léonard49cb2912017-11-13 16:15:39 -0500136 case lrc::api::profile::Type::RING:
Kateryna Kostiuka7248462017-04-18 16:15:31 -0400137 [itemView.accountTypeLabel setStringValue:@"RING"];
138 break;
139 default:
140 break;
141 }
Anthony Léonard49cb2912017-11-13 16:15:39 -0500142
Anthony Léonard48079de2018-02-15 17:00:50 -0500143 bool isAccountAlone = accList.size() == 1;
144
145 [[accountSelectionButton cell] setArrowPosition: (isAccountAlone)?NSPopUpNoArrow:NSPopUpArrowAtBottom];
146 [accountSelectionButton setEnabled:!isAccountAlone];
147
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400148 [menuBarItem setView:itemView];
149 [accountsMenu addItem:menuBarItem];
150 [accountsMenu addItem:[NSMenuItem separatorItem]];
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400151 }
152}
153
Anthony Léonard49cb2912017-11-13 16:15:39 -0500154-(void) updatePhoto
155{
Anthony Léonard72128c92017-12-26 16:48:39 -0500156 @try {
157 auto& account = [self selectedAccount];
158 if(account.profileInfo.type == lrc::api::profile::Type::INVALID)
159 return;
Anthony Léonard49cb2912017-11-13 16:15:39 -0500160
Anthony Léonard72128c92017-12-26 16:48:39 -0500161 QByteArray ba = QByteArray::fromStdString(account.profileInfo.avatar);
Anthony Léonard49cb2912017-11-13 16:15:39 -0500162
Anthony Léonard72128c92017-12-26 16:48:39 -0500163 QVariant photo = GlobalInstances::pixmapManipulator().personPhoto(ba);
164 [profileImage setImage:QtMac::toNSImage(qvariant_cast<QPixmap>(photo))];
165 }
166 @catch (NSException *ex) {
167 NSLog(@"Caught exception %@: %@", [ex name], [ex reason]);
168 }
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400169}
170
Anthony Léonard49cb2912017-11-13 16:15:39 -0500171-(NSString*) nameForAccount:(const lrc::api::account::Info&) account {
172 auto name = account.registeredName;
173 return @(name.c_str());
174}
175
176-(NSString*) itemTitleForAccount:(const lrc::api::account::Info&) account {
177 NSString* alias = @(account.profileInfo.alias.c_str());
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400178 NSString* userNameString = [self nameForAccount: account];
Kateryna Kostiuka7248462017-04-18 16:15:31 -0400179 if([userNameString length] > 0) {
180 alias = [NSString stringWithFormat: @"%@\n", alias];
181 }
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400182 return [alias stringByAppendingString:userNameString];
183}
184
Anthony Léonard49cb2912017-11-13 16:15:39 -0500185- (NSAttributedString*) attributedItemTitleForAccount:(const lrc::api::account::Info&) account {
186 NSString* alias = @(account.profileInfo.alias.c_str());
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400187 NSString* userNameString = [self nameForAccount: account];
Kateryna Kostiuka7248462017-04-18 16:15:31 -0400188 if([userNameString length] > 0){
189 alias = [NSString stringWithFormat: @"%@\n", alias];
190 }
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400191 NSFont *fontAlias = [NSFont userFontOfSize:14.0];
192 NSFont *fontUserName = [NSFont userFontOfSize:11.0];
193 NSColor *colorAlias = [NSColor labelColor];
194 NSColor *colorAUserName = [NSColor secondaryLabelColor];
195 NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
196 paragraphStyle.lineBreakMode = NSLineBreakByTruncatingTail;
197 NSDictionary *aliasAttrs = [NSDictionary dictionaryWithObjectsAndKeys:fontAlias,NSFontAttributeName,
198 colorAlias,NSForegroundColorAttributeName,
199 paragraphStyle,NSParagraphStyleAttributeName, nil];
200 NSDictionary *userNameAttrs = [NSDictionary dictionaryWithObjectsAndKeys:fontUserName,NSFontAttributeName,
201 colorAUserName,NSForegroundColorAttributeName,
202 paragraphStyle,NSParagraphStyleAttributeName, nil];
203 NSAttributedString* attributedString = [[NSAttributedString alloc] initWithString:alias attributes:aliasAttrs];
204 NSAttributedString* attributedStringSecond= [[NSAttributedString alloc] initWithString:userNameString attributes:userNameAttrs];
205 NSMutableAttributedString *result = [[NSMutableAttributedString alloc] init];
206 [result appendAttributedString:attributedString];
207 [result appendAttributedString:attributedStringSecond];
208 return result;
209}
210
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400211-(void) update {
212 if(menuIsOpen) {
213 return;
214 }
215 [self updateMenu];
Anthony Léonard49cb2912017-11-13 16:15:39 -0500216 [self updatePhoto];
Kateryna Kostiuk312f9132017-04-18 12:09:06 -0400217 [self setPopUpButtonSelection];
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400218}
219
Kateryna Kostiuk312f9132017-04-18 12:09:06 -0400220-(void) setPopUpButtonSelection {
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400221 if(accountsMenu.itemArray.count == 0) {
222 [self.view setHidden:YES];
223 return;
224 }
Kateryna Kostiuk312f9132017-04-18 12:09:06 -0400225 [self.view setHidden:NO];
Anthony Léonard72128c92017-12-26 16:48:39 -0500226 @try {
227 auto& account = [self selectedAccount];
228 if(account.profileInfo.type == lrc::api::profile::Type::INVALID){
229 return;
230 }
231 [accountSelectionButton selectItemWithTitle:[self itemTitleForAccount:account]];
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400232 }
Anthony Léonard72128c92017-12-26 16:48:39 -0500233 @catch (NSException *ex) {
234 NSLog(@"Caught exception %@: %@", [ex name], [ex reason]);
235 }
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400236}
237
238#pragma mark - NSPopUpButton item selection
239
240- (IBAction)itemChanged:(id)sender {
Kateryna Kostiuk312f9132017-04-18 12:09:06 -0400241 NSInteger row = [(NSPopUpButton *)sender indexOfSelectedItem] / 2;
Anthony Léonard49cb2912017-11-13 16:15:39 -0500242 auto accList = accMdl_->getAccountList();
243 if (row >= accList.size())
Kateryna Kostiuka16c9862017-05-03 13:30:14 -0400244 return;
Anthony Léonard49cb2912017-11-13 16:15:39 -0500245
246 auto& account = accMdl_->getAccountInfo(accList[row]);
247 [accountSelectionManager_ setSavedAccount:account];
Anthony Léonard9bebf1d2017-12-21 14:33:51 -0500248 [delegate selectAccount:account];
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400249}
250
251#pragma mark - NSMenuDelegate
252- (void)menuWillOpen:(NSMenu *)menu {
253 menuIsOpen = true;
254 // remember selected item to remove highlighting when menu is open
255 selectedMenuItem = [accountSelectionButton selectedItem];
256}
257- (void)menuDidClose:(NSMenu *)menu {
258
259 menuIsOpen = false;
260}
261
262- (void)menu:(NSMenu *)menu willHighlightItem:(nullable NSMenuItem *)item {
263 if (!selectedMenuItem || selectedMenuItem == item) {
264 return;
265 }
266 int index = [menu indexOfItem:selectedMenuItem];
267 [menu removeItemAtIndex:index];
268 [menu insertItem:selectedMenuItem atIndex:index];
269 [accountSelectionButton selectItemAtIndex:index];
270 selectedMenuItem = nil;
271}
272
Kateryna Kostiukabf4e272017-04-18 14:18:00 -0400273-(void) enable {
274 [accountSelectionButton setEnabled:YES];
275}
276-(void) disable {
277 [accountSelectionButton setEnabled:NO];
278}
279
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400280@end