account: Add selected account in Toolbar
This commit add dropdown list to toolbar to change currently selected account.
After selection it update ring id used to share account info.
Tuleap: #1532
Change-Id: I9fe3e65513ec45dce8bd53d8611f4daca6081663
Reviewed-by: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
diff --git a/src/ChooseAccountVC.h b/src/ChooseAccountVC.h
new file mode 100644
index 0000000..9c2e268
--- /dev/null
+++ b/src/ChooseAccountVC.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015-2017 Savoir-faire Linux Inc.
+ * Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
+ *
+ * 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
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+@interface ChooseAccountVC : NSViewController
+
+@end
diff --git a/src/ChooseAccountVC.mm b/src/ChooseAccountVC.mm
new file mode 100644
index 0000000..b6316fa
--- /dev/null
+++ b/src/ChooseAccountVC.mm
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2015-2017 Savoir-faire Linux Inc.
+ * Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
+ *
+ * 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
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#import "ChooseAccountVC.h"
+
+//Qt
+#import <QSize>
+#import <QtMacExtras/qmacfunctions.h>
+#import <QPixmap>
+
+//LRC
+#import <profilemodel.h>
+#import <profile.h>
+#import <person.h>
+#import <globalinstances.h>
+#import <accountmodel.h>
+#import <account.h>
+#import <QItemSelectionModel.h>
+#import <interfaces/pixmapmanipulatori.h>
+//RING
+#import "views/AccountMenuItemView.h"
+
+@interface ChooseAccountVC () <NSMenuDelegate>
+
+@end
+
+@implementation ChooseAccountVC {
+ __unsafe_unretained IBOutlet NSImageView* profileImage;
+ __unsafe_unretained IBOutlet NSPopUpButton* accountSelectionButton;
+}
+Boolean menuIsOpen;
+Boolean menuNeedsUpdate;
+NSMenu* accountsMenu;
+NSMenuItem* selectedMenuItem;
+QMetaObject::Connection accountUpdate;
+
+- (void)awakeFromNib
+{
+ [profileImage setWantsLayer: YES];
+ profileImage.layer.cornerRadius = profileImage.frame.size.width / 2;
+ profileImage.layer.masksToBounds = YES;
+
+ if (auto pro = ProfileModel::instance().selectedProfile()) {
+ auto photo = GlobalInstances::pixmapManipulator().contactPhoto(pro->person(), {140,140});
+ [profileImage setImage:QtMac::toNSImage(qvariant_cast<QPixmap>(photo))];
+ }
+
+ accountsMenu = [[NSMenu alloc] initWithTitle:@""];
+ [accountsMenu setDelegate:self];
+ accountSelectionButton.menu = accountsMenu;
+ [self update];
+
+ QObject::disconnect(accountUpdate);
+ accountUpdate = QObject::connect(&AccountModel::instance(),
+ &AccountModel::dataChanged,
+ [=] {
+ [self update];
+ });
+}
+
+-(void) updateMenu {
+ [accountsMenu removeAllItems];
+ QList<Account*> allAccounts = AccountModel::instance().getAccountsByProtocol(Account::Protocol::RING);
+ NSLog(@"numberOfaccounts: %d", allAccounts.count());
+
+ for (auto account : allAccounts) {
+ NSMenuItem* menuBarItem = [[NSMenuItem alloc]
+ initWithTitle:[self itemTitleForAccount:account] action:NULL keyEquivalent:@""];
+ menuBarItem.attributedTitle = [self attributedItemTitleForAccount:account];
+ AccountMenuItemView *itemView = [[AccountMenuItemView alloc] initWithFrame:CGRectZero];
+ [itemView.accountLabel setStringValue:account->alias().toNSString()];
+ NSString* userNameString = [self nameForAccount: account];
+ [itemView.userNameLabel setStringValue:userNameString];
+ [itemView.accountTypeLabel setStringValue:@"Ring"];
+ auto humanState = account->toHumanStateName();
+ [itemView.accountStatus setStringValue:humanState.toNSString()];
+ [menuBarItem setView:itemView];
+ [accountsMenu addItem:menuBarItem];
+ [accountsMenu addItem:[NSMenuItem separatorItem]];
+
+ }
+}
+
+-(NSString*) nameForAccount:(Account*) account {
+ auto name = account->registeredName();
+ NSString* userNameString = nullptr;
+ if (!name.isNull() && !name.isEmpty()) {
+ userNameString = name.toNSString();
+ } else {
+ userNameString = account->username().toNSString();
+ }
+ return userNameString;
+}
+
+-(NSString*) itemTitleForAccount:(Account*) account {
+ NSString* alias = account->alias().toNSString();
+ alias = [NSString stringWithFormat: @"%@\n", alias];
+ NSString* userNameString = [self nameForAccount: account];
+ return [alias stringByAppendingString:userNameString];
+}
+
+- (NSAttributedString*) attributedItemTitleForAccount:(Account*) account {
+ NSString* alias = account->alias().toNSString();
+ alias = [NSString stringWithFormat: @"%@\n", alias];
+ NSString* userNameString = [self nameForAccount: account];
+ NSFont *fontAlias = [NSFont userFontOfSize:14.0];
+ NSFont *fontUserName = [NSFont userFontOfSize:11.0];
+ NSColor *colorAlias = [NSColor labelColor];
+ NSColor *colorAUserName = [NSColor secondaryLabelColor];
+ NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
+ paragraphStyle.lineBreakMode = NSLineBreakByTruncatingTail;
+ NSDictionary *aliasAttrs = [NSDictionary dictionaryWithObjectsAndKeys:fontAlias,NSFontAttributeName,
+ colorAlias,NSForegroundColorAttributeName,
+ paragraphStyle,NSParagraphStyleAttributeName, nil];
+ NSDictionary *userNameAttrs = [NSDictionary dictionaryWithObjectsAndKeys:fontUserName,NSFontAttributeName,
+ colorAUserName,NSForegroundColorAttributeName,
+ paragraphStyle,NSParagraphStyleAttributeName, nil];
+ NSAttributedString* attributedString = [[NSAttributedString alloc] initWithString:alias attributes:aliasAttrs];
+ NSAttributedString* attributedStringSecond= [[NSAttributedString alloc] initWithString:userNameString attributes:userNameAttrs];
+ NSMutableAttributedString *result = [[NSMutableAttributedString alloc] init];
+ [result appendAttributedString:attributedString];
+ [result appendAttributedString:attributedStringSecond];
+ return result;
+}
+
+-(Account *)selectedAccount {
+ Account* finalChoice = nullptr;
+ finalChoice = AccountModel::instance().userChosenAccount();
+
+ if(finalChoice == nil) {
+ Account* registered = nullptr;
+ Account* enabled = nullptr;
+ auto ringList = AccountModel::instance().getAccountsByProtocol(Account::Protocol::RING);
+ for (int i = 0 ; i < ringList.size() && !registered ; ++i) {
+ auto account = ringList.value(i);
+ if (account->isEnabled()) {
+ if(!enabled) {
+ enabled = finalChoice = account;
+ }
+ if (account->registrationState() == Account::RegistrationState::READY) {
+ registered = enabled = finalChoice = account;
+ }
+ } else {
+ if (!finalChoice) {
+ finalChoice = account;
+ }
+ }
+ }
+ }
+ return finalChoice;
+}
+
+
+-(void) update {
+ if(menuIsOpen) {
+ return;
+ }
+ [self updateMenu];
+ [self chooseAccount];
+}
+
+-(void) chooseAccount {
+ if(accountsMenu.itemArray.count == 0) {
+ [self.view setHidden:YES];
+ return;
+ }
+ Account* selectedAccount = [self selectedAccount];
+ NSString *itemTitle = [self itemTitleForAccount:selectedAccount];
+ if([accountSelectionButton itemWithTitle:itemTitle]){
+ [accountSelectionButton selectItemWithTitle:itemTitle];
+ // check if chosen account is the same as selected in popup button. If yes we don.t need setUserChosenAccount
+ Account* choosenaccount = AccountModel::instance().userChosenAccount();
+ if (choosenaccount && [itemTitle isEqualToString:[self itemTitleForAccount:choosenaccount]]){
+ return;
+ }
+ AccountModel::instance().setUserChosenAccount(selectedAccount);
+ }
+}
+
+#pragma mark - NSPopUpButton item selection
+
+- (IBAction)itemChanged:(id)sender {
+ NSInteger index = [(NSPopUpButton *)sender indexOfSelectedItem];
+ QList<Account*> allAccounts = AccountModel::instance().getAccountsByProtocol(Account::Protocol::RING);
+ // menu contains accounts and separation lines, so divide it by 2 to get account index
+ Account *selectedAccount = allAccounts.at(index/2);
+ AccountModel::instance().setUserChosenAccount(selectedAccount);
+}
+
+#pragma mark - NSMenuDelegate
+- (void)menuWillOpen:(NSMenu *)menu {
+ menuIsOpen = true;
+ // remember selected item to remove highlighting when menu is open
+ selectedMenuItem = [accountSelectionButton selectedItem];
+}
+- (void)menuDidClose:(NSMenu *)menu {
+
+ menuIsOpen = false;
+}
+
+- (void)menu:(NSMenu *)menu willHighlightItem:(nullable NSMenuItem *)item {
+ if (!selectedMenuItem || selectedMenuItem == item) {
+ return;
+ }
+ int index = [menu indexOfItem:selectedMenuItem];
+ [menu removeItemAtIndex:index];
+ [menu insertItem:selectedMenuItem atIndex:index];
+ [accountSelectionButton selectItemAtIndex:index];
+ selectedMenuItem = nil;
+}
+
+@end
diff --git a/src/RingWindowController.mm b/src/RingWindowController.mm
index 62e43d5..c545f09 100644
--- a/src/RingWindowController.mm
+++ b/src/RingWindowController.mm
@@ -42,8 +42,9 @@
#import "views/IconButton.h"
#import "views/NSColor+RingTheme.h"
#import "views/BackgroundView.h"
+#import "ChooseAccountVC.h"
-@interface RingWindowController () <MigrateRingAccountsDelegate>
+@interface RingWindowController () <MigrateRingAccountsDelegate, NSToolbarDelegate>
@property (retain) MigrateRingAccountsWC* migrateWC;
@@ -64,20 +65,23 @@
CurrentCallVC* currentCallVC;
ConversationVC* offlineVC;
+
+ ChooseAccountVC* chooseAccountVC;
}
-QMetaObject::Connection accountUpdate;
static NSString* const kPreferencesIdentifier = @"PreferencesIdentifier";
+NSString* const kChangeAccountToolBarItemIdentifier = @"ChangeAccountToolBarItemIdentifier";
- (void)windowDidLoad {
[super windowDidLoad];
[self.window setMovableByWindowBackground:YES];
[self.window setBackgroundColor:[NSColor colorWithRed:242.0/255 green:242.0/255 blue:242.0/255 alpha:1.0]];
+ self.window.titleVisibility = NSWindowTitleHidden;
currentCallVC = [[CurrentCallVC alloc] initWithNibName:@"CurrentCall" bundle:nil];
offlineVC = [[ConversationVC alloc] initWithNibName:@"Conversation" bundle:nil];
-
+ chooseAccountVC = [[ChooseAccountVC alloc] initWithNibName:@"ChooseAccount" bundle:nil];
[callView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[[currentCallVC view] setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[[offlineVC view] setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
@@ -94,13 +98,6 @@
- (void) connect
{
// Update Ring ID label based on account model changes
- QObject::disconnect(accountUpdate);
- accountUpdate = QObject::connect(&AccountModel::instance(),
- &AccountModel::dataChanged,
- [=] {
- [self updateRingID];
- });
-
QObject::connect(RecentModel::instance().selectionModel(),
&QItemSelectionModel::currentChanged,
[=](const QModelIndex ¤t, const QModelIndex &previous) {
@@ -137,6 +134,14 @@
[offlineVC animateOut];
}
});
+ QObject::connect(AccountModel::instance().userSelectionModel(),
+ &QItemSelectionModel::currentChanged,
+ [=](const QModelIndex ¤t, const QModelIndex &previous) {
+ if(!current.isValid())
+ return;
+ [self updateRingID];
+ });
+
}
/**
@@ -150,23 +155,26 @@
Account* finalChoice = nullptr;
[ringIDLabel setStringValue:@""];
- auto ringList = AccountModel::instance().getAccountsByProtocol(Account::Protocol::RING);
- for (int i = 0 ; i < ringList.size() && !registered ; ++i) {
- auto account = ringList.value(i);
- if (account->isEnabled()) {
- if(!enabled) {
- enabled = finalChoice = account;
- }
- if (account->registrationState() == Account::RegistrationState::READY) {
- registered = enabled = finalChoice = account;
- }
- } else {
- if (!finalChoice) {
- finalChoice = account;
+ finalChoice = AccountModel::instance().userChosenAccount();
+
+ if(finalChoice == nil) {
+ auto ringList = AccountModel::instance().getAccountsByProtocol(Account::Protocol::RING);
+ for (int i = 0 ; i < ringList.size() && !registered ; ++i) {
+ auto account = ringList.value(i);
+ if (account->isEnabled()) {
+ if(!enabled) {
+ enabled = finalChoice = account;
+ }
+ if (account->registrationState() == Account::RegistrationState::READY) {
+ registered = enabled = finalChoice = account;
+ }
+ } else {
+ if (!finalChoice) {
+ finalChoice = account;
+ }
}
}
}
-
auto name = finalChoice->registeredName();
NSString* uriToDisplay = nullptr;
if (!name.isNull() && !name.isEmpty()) {
@@ -319,10 +327,13 @@
[self migrateRingAccount:acc];
} else {
// Fresh run, we need to make sure RingID appears
- [self updateRingID];
[shareButton sendActionOn:NSLeftMouseDownMask];
[self connect];
+ // display accounts to select
+ NSToolbar *toolbar = self.window.toolbar;
+ toolbar.delegate = self;
+ [toolbar insertItemWithItemIdentifier:kChangeAccountToolBarItemIdentifier atIndex:1];
}
}
@@ -336,4 +347,15 @@
[self checkAccountsToMigrate];
}
+#pragma mark - NSToolbarDelegate
+- (nullable NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag{
+ if(!(itemIdentifier == kChangeAccountToolBarItemIdentifier)) {
+ return nil;
+ }
+ NSToolbarItem *toolbarItem = [[NSToolbarItem alloc] initWithItemIdentifier:kChangeAccountToolBarItemIdentifier];
+ CGRect frame = chooseAccountVC.view.frame;
+ toolbarItem.view = chooseAccountVC.view;
+ return toolbarItem;
+}
+
@end
diff --git a/src/views/AccountMenuItemView.h b/src/views/AccountMenuItemView.h
new file mode 100644
index 0000000..038a122
--- /dev/null
+++ b/src/views/AccountMenuItemView.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015-2017 Savoir-faire Linux Inc.
+ * Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
+ *
+ * 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
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+@interface AccountMenuItemView : NSView
+
+@property (nonatomic, strong) IBOutlet NSView* containerView;
+@property (nonatomic, strong) IBOutlet NSTextField* accountLabel;
+@property (nonatomic, strong) IBOutlet NSTextField* userNameLabel;
+@property (nonatomic, strong) IBOutlet NSTextField* accountTypeLabel;
+@property (nonatomic, strong) IBOutlet NSTextField* accountStatus;
+
+@end
diff --git a/src/views/AccountMenuItemView.mm b/src/views/AccountMenuItemView.mm
new file mode 100644
index 0000000..8b8a3aa
--- /dev/null
+++ b/src/views/AccountMenuItemView.mm
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2015-2017 Savoir-faire Linux Inc.
+ * Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
+ *
+ * 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
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#import "AccountMenuItemView.h"
+#import "NSColor+RingTheme.h"
+
+@implementation AccountMenuItemView
+
+- (instancetype)initWithFrame:(CGRect)frame
+{
+ self = [super initWithFrame:frame];
+ if (self) {
+ [self loadFromNib];
+ }
+ return self;
+}
+
+- (void)loadFromNib
+{
+ NSView *viewFromXib = nil;
+ NSArray *objectsFromXib = nil;
+ [[NSBundle mainBundle] loadNibNamed:@"AccountMenuItemView" owner:self topLevelObjects:&objectsFromXib];
+ for (id item in objectsFromXib) {
+ if ([item isKindOfClass:[NSView class]]) {
+ viewFromXib = item;
+ break;
+ }
+ }
+ if (viewFromXib != nil) {
+ self.frame = viewFromXib.frame;
+ self.containerView = viewFromXib;
+ [self addSubview:self.containerView];
+ }
+}
+
+- (BOOL)acceptsFirstMouse:(NSEvent *)event {
+ return YES;
+}
+
+-(void) mouseUp:(NSEvent *)theEvent {
+ NSMenu *menu = self.enclosingMenuItem.menu;
+ [menu cancelTracking];
+ [menu performActionForItemAtIndex:[menu indexOfItem:self.enclosingMenuItem]];
+ [super mouseUp:theEvent];
+}
+
+- (void) drawRect: (NSRect) rect {
+ NSMenuItem *menuItem = ([self enclosingMenuItem]);
+ BOOL isHighlighted = [menuItem isHighlighted];
+ if (isHighlighted) {
+ [[NSColor ringGreyHighlight] set];
+ [NSBezierPath fillRect:rect];
+ } else {
+ [super drawRect: rect];
+ }
+}
+
+@end