Commit 49cb2918 authored by Anthony Léonard's avatar Anthony Léonard Committed by Guillaume Roguez

reimplement ChooseAccountVC with new account model

This controller is in charge of the account selector shown at the top
right of the client.

It now uses the new account model in LRC to display account available
on the machine. As the account selection is now to be managed on
client instead of LRC, a lot has changed in the AccountSelectionManager
too.

Finally, RingWindowController gives a reference of the account model
to the ChooseAccountVC has we don't use singleton that are accessible
from anywhere anymore.

Change-Id: I5c320923cd561dc44f600d388793a338af89adfd
Reviewed-by: Guillaume Roguez's avatarGuillaume Roguez <guillaume.roguez@savoirfairelinux.com>
parent 79597607
/* /*
* Copyright (C) 2015-2017 Savoir-faire Linux Inc. * Copyright (C) 2015-2017 Savoir-faire Linux Inc.
* Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com> * Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
* Author: Olivier Soldano <olivier.soldano@savoirfairelinux.com>
* Author: Anthony Léonard <anthony.leonard@savoirfairelinux.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -19,9 +21,20 @@ ...@@ -19,9 +21,20 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
namespace lrc {
namespace api {
class NewAccountModel;
namespace account {
struct Info;
}
}
}
@interface AccountSelectionManager : NSObject @interface AccountSelectionManager : NSObject
- (void) saveAccountWithIndex:(QModelIndex )index; @property const lrc::api::account::Info& savedAccount;
- (void) selectChosenAccount;
- (id) initWithAccountModel:(const lrc::api::NewAccountModel*) accMdl;
@end @end
/* /*
* Copyright (C) 2015-2017 Savoir-faire Linux Inc. * Copyright (C) 2015-2017 Savoir-faire Linux Inc.
* Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com> * Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
* Author: Olivier Soldano <olivier.soldano@savoirfairelinux.com>
* Author: Anthony Léonard <anthony.leonard@savoirfairelinux.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -18,67 +20,45 @@ ...@@ -18,67 +20,45 @@
*/ */
// LRC // LRC
#import <accountmodel.h> #import <api/newaccountmodel.h>
#import <account.h> #import <api/account.h>
#import <AvailableAccountModel.h>
#import <QItemSelectionModel.h>
#import "AccountSelectionManager.h" #import "AccountSelectionManager.h"
@implementation AccountSelectionManager @implementation AccountSelectionManager {
const lrc::api::NewAccountModel* accMdl_;
}
NSString* const savedUserAccountKey = @"savedUserSelectedAccountKey"; NSString* const savedUserAccountKey = @"savedUserSelectedAccountKey";
- (void) saveAccountWithIndex:(QModelIndex )index { - (id) initWithAccountModel:(const lrc::api::NewAccountModel*) accMdl {
if(!index.isValid()) { accMdl_ = accMdl;
return; return [self init];
}
QByteArray accountID = index.data(static_cast<int>(Account::Role::Id)).toByteArray();
if (accountID.isEmpty()) {
return;
}
NSString* accountToNSString = QString::QString(accountID).toNSString();
[[NSUserDefaults standardUserDefaults] setObject:accountToNSString forKey:savedUserAccountKey];
} }
- (void) saveAccountWithId:(NSString*)accId
{
[[NSUserDefaults standardUserDefaults] setObject:accId forKey:savedUserAccountKey];
}
- (void) selectChosenAccount { - (NSString*) getSavedAccountId
NSString* savedAccount = [[NSUserDefaults standardUserDefaults] stringForKey:savedUserAccountKey]; {
if(!savedAccount || savedAccount.length <= 0) { return [[NSUserDefaults standardUserDefaults] stringForKey:savedUserAccountKey];
return; }
}
const char* secondName = [savedAccount UTF8String];
QByteArray assountToarray = QByteArray::QByteArray(secondName);
if (strlen(assountToarray) <= 0) {
return;
}
if (!(AccountModel::instance().getById(assountToarray))) {
return;
}
auto account = AccountModel::instance().getById(assountToarray);
QModelIndex savedIndex = QModelIndex::QModelIndex();
// first try to get saved account
savedIndex = AvailableAccountModel::instance().mapFromSource(account->index());
if (savedIndex.isValid()) {
AvailableAccountModel::instance().selectionModel()->setCurrentIndex(savedIndex, QItemSelectionModel::ClearAndSelect);
return;
}
// if account is not saved, try to select RING account
if (auto account = AvailableAccountModel::instance().currentDefaultAccount(URI::SchemeType::RING)) {
savedIndex = AvailableAccountModel::instance().mapFromSource(account->index());
}
if (savedIndex.isValid()) {
AvailableAccountModel::instance().selectionModel()->setCurrentIndex(savedIndex, QItemSelectionModel::ClearAndSelect);
return;
}
// if no RING account try to select SIP
if (auto account = AvailableAccountModel::instance().currentDefaultAccount(URI::SchemeType::SIP)) {
savedIndex = AvailableAccountModel::instance().mapFromSource(account->index());
} - (const lrc::api::account::Info&) savedAccount
if (savedIndex.isValid()) { {
AvailableAccountModel::instance().selectionModel()->setCurrentIndex(savedIndex, QItemSelectionModel::ClearAndSelect); return accMdl_->getAccountInfo(std::string([[self getSavedAccountId] UTF8String]));
} }
- (void) setSavedAccount:(const lrc::api::account::Info&) acc
{
if (acc.profileInfo.type == lrc::api::profile::Type::INVALID)
return;
else
saveAccountWithId:@(acc.id.c_str());
} }
@end @end
/* /*
* Copyright (C) 2015-2017 Savoir-faire Linux Inc. * Copyright (C) 2015-2017 Savoir-faire Linux Inc.
* Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com> * Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
* Author: Olivier Soldano <olivier.soldano@savoirfairelinux.com>
* Author: Anthony Léonard <anthony.leonard@savoirfairelinux.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -19,9 +21,22 @@ ...@@ -19,9 +21,22 @@
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
namespace lrc {
namespace api {
class NewAccountModel;
namespace account {
struct Info;
}
}
}
@interface ChooseAccountVC : NSViewController @interface ChooseAccountVC : NSViewController
@property (readonly) const lrc::api::account::Info& selectedAccount;
-(void) enable; -(void) enable;
-(void) disable; -(void) disable;
-(id) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil model:(const lrc::api::NewAccountModel*) accMdl;
@end @end
/* /*
* Copyright (C) 2015-2017 Savoir-faire Linux Inc. * Copyright (C) 2015-2017 Savoir-faire Linux Inc.
* Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com> * Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
* Author: Olivier Soldano <olivier.soldano@savoirfairelinux.com>
* Author: Anthony Léonard <anthony.leonard@savoirfairelinux.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -25,15 +27,11 @@ ...@@ -25,15 +27,11 @@
#import <QPixmap> #import <QPixmap>
//LRC //LRC
#import <profilemodel.h>
#import <profile.h>
#import <person.h>
#import <globalinstances.h> #import <globalinstances.h>
#import <accountmodel.h>
#import <account.h>
#import <QItemSelectionModel.h> #import <QItemSelectionModel.h>
#import <interfaces/pixmapmanipulatori.h> #import <interfaces/pixmapmanipulatori.h>
#import <AvailableAccountModel.h> #import <api/newaccountmodel.h>
#import <api/account.h>
//RING //RING
#import "views/AccountMenuItemView.h" #import "views/AccountMenuItemView.h"
...@@ -47,73 +45,73 @@ ...@@ -47,73 +45,73 @@
__unsafe_unretained IBOutlet NSImageView* profileImage; __unsafe_unretained IBOutlet NSImageView* profileImage;
__unsafe_unretained IBOutlet NSPopUpButton* accountSelectionButton; __unsafe_unretained IBOutlet NSPopUpButton* accountSelectionButton;
const lrc::api::NewAccountModel* accMdl_;
AccountSelectionManager* accountSelectionManager_;
} }
Boolean menuIsOpen; Boolean menuIsOpen;
Boolean menuNeedsUpdate; Boolean menuNeedsUpdate;
NSMenu* accountsMenu; NSMenu* accountsMenu;
NSMenuItem* selectedMenuItem; NSMenuItem* selectedMenuItem;
QMetaObject::Connection accountUpdate;
QMetaObject::Connection personUpdate; -(id) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil model:(const lrc::api::NewAccountModel*) accMdl
AccountSelectionManager* accountManager; {
accMdl_ = accMdl;
accountSelectionManager_ = [[AccountSelectionManager alloc] initWithAccountModel:accMdl_];
return [self initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
}
- (void)awakeFromNib - (void)awakeFromNib
{ {
[profileImage setWantsLayer: YES]; [profileImage setWantsLayer: YES];
profileImage.layer.cornerRadius = profileImage.frame.size.width / 2; profileImage.layer.cornerRadius = profileImage.frame.size.width / 2;
profileImage.layer.masksToBounds = YES; profileImage.layer.masksToBounds = YES;
accountManager = [[AccountSelectionManager alloc] init];
if (ProfileModel::instance().selectedProfile() && ProfileModel::instance().selectedProfile()->person()) {
Person* person = ProfileModel::instance().selectedProfile()->person();
auto photo = GlobalInstances::pixmapManipulator().contactPhoto(person, {140,140});
[profileImage setImage:QtMac::toNSImage(qvariant_cast<QPixmap>(photo))];
QObject::disconnect(personUpdate);
personUpdate = QObject::connect(person,
&Person::changed,
[=] {
//give time to cach to be updated and then change image
dispatch_time_t updateTime = dispatch_time(DISPATCH_TIME_NOW, 1);
dispatch_after(updateTime, dispatch_get_main_queue(), ^(void){
auto photo = GlobalInstances::pixmapManipulator().contactPhoto(person, {140,140});
[profileImage setImage:QtMac::toNSImage(qvariant_cast<QPixmap>(photo))];
});
});
}
accountsMenu = [[NSMenu alloc] initWithTitle:@""]; accountsMenu = [[NSMenu alloc] initWithTitle:@""];
[accountsMenu setDelegate:self]; [accountsMenu setDelegate:self];
accountSelectionButton.menu = accountsMenu; accountSelectionButton.menu = accountsMenu;
[self update]; [self update];
QObject::disconnect(accountUpdate); QObject::connect(accMdl_,
accountUpdate = QObject::connect(&AccountModel::instance(), &lrc::api::NewAccountModel::accountAdded,
&AccountModel::dataChanged, [self]{
[=] {
[self update]; [self update];
}); });
QObject::connect(AvailableAccountModel::instance().selectionModel(), QObject::connect(accMdl_,
&QItemSelectionModel::currentChanged, &lrc::api::NewAccountModel::accountRemoved,
[self](const QModelIndex& idx){ [self]{
if(!idx.isValid()) {
return;
}
[accountManager saveAccountWithIndex:idx];
[self update]; [self update];
}); });
QObject::connect(&AvailableAccountModel::instance(), QObject::connect(accMdl_,
&QAbstractItemModel::rowsRemoved, &lrc::api::NewAccountModel::profileUpdated,
[self]{ [self]{
[self update]; [self update];
}); });
} }
-(const lrc::api::account::Info&) selectedAccount
{
const auto& account = [accountSelectionManager_ savedAccount];
if(account.profileInfo.type == lrc::api::profile::Type::INVALID){
try {
auto accountId = accMdl_->getAccountList().at(0);
const auto& fallbackAccount = accMdl_->getAccountInfo(accMdl_->getAccountList().at(0));
return fallbackAccount;
} catch (std::out_of_range& e) { // Is thrown if account model has no account. We then return an invalid account
return account;
}
}
return account;
}
-(void) updateMenu { -(void) updateMenu {
[accountsMenu removeAllItems]; [accountsMenu removeAllItems];
for (int i = 0; i < AvailableAccountModel::instance().rowCount(); i++) {
QModelIndex index = AvailableAccountModel::instance().selectionModel()->model()->index(i, 0); auto accList = accMdl_->getAccountList();
Account* account = index.data(static_cast<int>(Account::Role::Object)).value<Account*>();
for (std::string accId : accList) {
auto& account = accMdl_->getAccountInfo(accId);
NSMenuItem* menuBarItem = [[NSMenuItem alloc] NSMenuItem* menuBarItem = [[NSMenuItem alloc]
initWithTitle:[self itemTitleForAccount:account] initWithTitle:[self itemTitleForAccount:account]
action:NULL action:NULL
...@@ -121,40 +119,45 @@ AccountSelectionManager* accountManager; ...@@ -121,40 +119,45 @@ AccountSelectionManager* accountManager;
menuBarItem.attributedTitle = [self attributedItemTitleForAccount:account]; menuBarItem.attributedTitle = [self attributedItemTitleForAccount:account];
AccountMenuItemView *itemView = [[AccountMenuItemView alloc] initWithFrame:CGRectZero]; AccountMenuItemView *itemView = [[AccountMenuItemView alloc] initWithFrame:CGRectZero];
[itemView.accountLabel setStringValue:account->alias().toNSString()]; [itemView.accountLabel setStringValue:@(account.profileInfo.alias.c_str())];
NSString* userNameString = [self nameForAccount: account]; NSString* userNameString = [self nameForAccount: account];
[itemView.userNameLabel setStringValue:userNameString]; [itemView.userNameLabel setStringValue:userNameString];
switch (account->protocol()) { switch (account.profileInfo.type) {
case Account::Protocol::SIP: case lrc::api::profile::Type::SIP:
[itemView.accountTypeLabel setStringValue:@"SIP"]; [itemView.accountTypeLabel setStringValue:@"SIP"];
break; break;
case Account::Protocol::RING: case lrc::api::profile::Type::RING:
[itemView.accountTypeLabel setStringValue:@"RING"]; [itemView.accountTypeLabel setStringValue:@"RING"];
break; break;
default: default:
break; break;
} }
auto humanState = account->toHumanStateName();
[itemView.accountStatus setStringValue:humanState.toNSString()];
[menuBarItem setView:itemView]; [menuBarItem setView:itemView];
[accountsMenu addItem:menuBarItem]; [accountsMenu addItem:menuBarItem];
[accountsMenu addItem:[NSMenuItem separatorItem]]; [accountsMenu addItem:[NSMenuItem separatorItem]];
} }
} }
-(NSString*) nameForAccount:(Account*) account { -(void) updatePhoto
auto name = account->registeredName(); {
NSString* userNameString = nullptr; auto& account = [self selectedAccount];
if (!name.isNull() && !name.isEmpty()) { if(account.profileInfo.type == lrc::api::profile::Type::INVALID)
userNameString = name.toNSString(); return;
} else {
userNameString = account->username().toNSString(); QByteArray ba = QByteArray::fromStdString(account.profileInfo.avatar);
}
return userNameString; QVariant photo = GlobalInstances::pixmapManipulator().personPhoto(ba);
[profileImage setImage:QtMac::toNSImage(qvariant_cast<QPixmap>(photo))];
}
-(NSString*) nameForAccount:(const lrc::api::account::Info&) account {
auto name = account.registeredName;
return @(name.c_str());
} }
-(NSString*) itemTitleForAccount:(Account*) account { -(NSString*) itemTitleForAccount:(const lrc::api::account::Info&) account {
NSString* alias = account->alias().toNSString(); NSString* alias = @(account.profileInfo.alias.c_str());
NSString* userNameString = [self nameForAccount: account]; NSString* userNameString = [self nameForAccount: account];
if([userNameString length] > 0) { if([userNameString length] > 0) {
alias = [NSString stringWithFormat: @"%@\n", alias]; alias = [NSString stringWithFormat: @"%@\n", alias];
...@@ -162,8 +165,8 @@ AccountSelectionManager* accountManager; ...@@ -162,8 +165,8 @@ AccountSelectionManager* accountManager;
return [alias stringByAppendingString:userNameString]; return [alias stringByAppendingString:userNameString];
} }
- (NSAttributedString*) attributedItemTitleForAccount:(Account*) account { - (NSAttributedString*) attributedItemTitleForAccount:(const lrc::api::account::Info&) account {
NSString* alias = account->alias().toNSString(); NSString* alias = @(account.profileInfo.alias.c_str());
NSString* userNameString = [self nameForAccount: account]; NSString* userNameString = [self nameForAccount: account];
if([userNameString length] > 0){ if([userNameString length] > 0){
alias = [NSString stringWithFormat: @"%@\n", alias]; alias = [NSString stringWithFormat: @"%@\n", alias];
...@@ -193,6 +196,7 @@ AccountSelectionManager* accountManager; ...@@ -193,6 +196,7 @@ AccountSelectionManager* accountManager;
return; return;
} }
[self updateMenu]; [self updateMenu];
[self updatePhoto];
[self setPopUpButtonSelection]; [self setPopUpButtonSelection];
} }
...@@ -202,9 +206,8 @@ AccountSelectionManager* accountManager; ...@@ -202,9 +206,8 @@ AccountSelectionManager* accountManager;
return; return;
} }
[self.view setHidden:NO]; [self.view setHidden:NO];
QModelIndex index = AvailableAccountModel::instance().selectionModel()->currentIndex(); auto& account = [self selectedAccount];
Account* account = index.data(static_cast<int>(Account::Role::Object)).value<Account*>(); if(account.profileInfo.type == lrc::api::profile::Type::INVALID){
if(account == nil){
return; return;
} }
[accountSelectionButton selectItemWithTitle:[self itemTitleForAccount:account]]; [accountSelectionButton selectItemWithTitle:[self itemTitleForAccount:account]];
...@@ -214,12 +217,12 @@ AccountSelectionManager* accountManager; ...@@ -214,12 +217,12 @@ AccountSelectionManager* accountManager;
- (IBAction)itemChanged:(id)sender { - (IBAction)itemChanged:(id)sender {
NSInteger row = [(NSPopUpButton *)sender indexOfSelectedItem] / 2; NSInteger row = [(NSPopUpButton *)sender indexOfSelectedItem] / 2;
QModelIndex index = AvailableAccountModel::instance().selectionModel()->model()->index(row, 0); auto accList = accMdl_->getAccountList();
if(!index.isValid()) { if (row >= accList.size())
return; return;
}
AvailableAccountModel::instance().selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect); auto& account = accMdl_->getAccountInfo(accList[row]);
[accountManager saveAccountWithIndex:index]; [accountSelectionManager_ setSavedAccount:account];
} }
#pragma mark - NSMenuDelegate #pragma mark - NSMenuDelegate
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#import <recentmodel.h> #import <recentmodel.h>
#import <AvailableAccountModel.h> #import <AvailableAccountModel.h>
#import <api/lrc.h> #import <api/lrc.h>
#import <api/account.h>
// Ring // Ring
#import "AppDelegate.h" #import "AppDelegate.h"
...@@ -94,7 +95,7 @@ NSString* const kTrustRequestMenuItemIdentifier = @"TrustRequestMenuItemIde ...@@ -94,7 +95,7 @@ NSString* const kTrustRequestMenuItemIdentifier = @"TrustRequestMenuItemIde
currentCallVC = [[CurrentCallVC alloc] initWithNibName:@"CurrentCall" bundle:nil]; currentCallVC = [[CurrentCallVC alloc] initWithNibName:@"CurrentCall" bundle:nil];
offlineVC = [[ConversationVC alloc] initWithNibName:@"Conversation" bundle:nil]; offlineVC = [[ConversationVC alloc] initWithNibName:@"Conversation" bundle:nil];
// toolbar items // toolbar items
chooseAccountVC = [[ChooseAccountVC alloc] initWithNibName:@"ChooseAccount" bundle:nil]; chooseAccountVC = [[ChooseAccountVC alloc] initWithNibName:@"ChooseAccount" bundle:nil model:&(lrc_->getAccountModel())];
contactRequestVC = [[ContactRequestVC alloc] initWithNibName:@"ContactRequest" bundle:nil]; contactRequestVC = [[ContactRequestVC alloc] initWithNibName:@"ContactRequest" bundle:nil];
[callView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; [callView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[[currentCallVC view] setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; [[currentCallVC view] setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
...@@ -106,9 +107,18 @@ NSString* const kTrustRequestMenuItemIdentifier = @"TrustRequestMenuItemIde ...@@ -106,9 +107,18 @@ NSString* const kTrustRequestMenuItemIdentifier = @"TrustRequestMenuItemIde
[currentCallVC initFrame]; [currentCallVC initFrame];
[offlineVC initFrame]; [offlineVC initFrame];
[self checkAccountsToMigrate]; // Fresh run, we need to make sure RingID appears
[shareButton sendActionOn:NSLeftMouseDownMask];
[self updateRingID];
// display accounts to select
NSToolbar *toolbar = self.window.toolbar;
toolbar.delegate = self;
[toolbar insertItemWithItemIdentifier:kChangeAccountToolBarItemIdentifier atIndex:1];
[toolbar insertItemWithItemIdentifier:kTrustRequestMenuItemIdentifier atIndex:2];
} }
// TODO: Reimplement with new LRC signals
- (void) connect - (void) connect
{ {
// Update Ring ID label based on account model changes // Update Ring ID label based on account model changes
...@@ -167,25 +177,25 @@ NSString* const kTrustRequestMenuItemIdentifier = @"TrustRequestMenuItemIde ...@@ -167,25 +177,25 @@ NSString* const kTrustRequestMenuItemIdentifier = @"TrustRequestMenuItemIde
*/ */
- (void) updateRingID - (void) updateRingID
{ {
Account* finalChoice = nullptr; auto& account = [chooseAccountVC selectedAccount];
[ringIDLabel setStringValue:@""]; [ringIDLabel setStringValue:@""];
QModelIndex index = AvailableAccountModel::instance().selectionModel()->currentIndex();
finalChoice = index.data(static_cast<int>(Account::Role::Object)).value<Account*>(); if(account.profileInfo.type != lrc::api::profile::Type::RING) {
if(finalChoice == nil || (finalChoice->protocol() != Account::Protocol::RING)) {
self.hideRingID = YES; self.hideRingID = YES;
return; return;
} }
self.hideRingID = NO; self.hideRingID = NO;
auto name = finalChoice->registeredName(); auto& registeredName = account.registeredName;
auto& ringID = account.profileInfo.uri;
NSString* uriToDisplay = nullptr; NSString* uriToDisplay = nullptr;
if (!name.isNull() && !name.isEmpty()) {