blob: 971622e4f0c8c714410e17b273caa32793a8ebbf [file] [log] [blame]
Alexandre Lision8521baa2015-03-13 11:08:00 -04001/*
Alexandre Lision9fe374b2016-01-06 10:17:31 -05002 * Copyright (C) 2015-2016 Savoir-faire Linux Inc.
Alexandre Lision8521baa2015-03-13 11:08:00 -04003 * Author: Alexandre Lision <alexandre.lision@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.
Alexandre Lision8521baa2015-03-13 11:08:00 -040018 */
Alexandre Lision5855b6a2015-02-03 11:31:05 -050019#import "RingWindowController.h"
Alexandre Lision0f66bd32016-01-18 11:30:45 -050020#import <QuartzCore/QuartzCore.h>
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -040021#include <qrencode.h>
Anthony Léonard79597602017-11-13 15:47:09 -050022#include <memory>
Alexandre Lision0f66bd32016-01-18 11:30:45 -050023
24//Qt
25#import <QItemSelectionModel>
26#import <QItemSelection>
Alexandre Lision5855b6a2015-02-03 11:31:05 -050027
Alexandre Lisionbb5c2462015-07-30 12:55:37 -040028//LRC
Kateryna Kostiuk312f9132017-04-18 12:09:06 -040029#import <AvailableAccountModel.h>
Anthony Léonard79597602017-11-13 15:47:09 -050030#import <api/lrc.h>
Anthony Léonard49cb2912017-11-13 16:15:39 -050031#import <api/account.h>
Olivier Soldano994971f2017-12-05 16:30:12 -050032#import <api/newaccountmodel.h>
33#import <api/newcallmodel.h>
34#import <api/behaviorcontroller.h>
35#import <api/conversation.h>
Anthony Léonardd00cd182018-01-17 09:21:27 -050036#import <api/contactmodel.h>
37#import <api/contact.h>
Kateryna Kostiuk67735232018-05-10 15:05:32 -040038#import <api/datatransfermodel.h>
Kateryna Kostiuk74fe20c2018-06-14 12:05:53 -040039#import <media/recordingmodel.h>
Alexandre Lision5855b6a2015-02-03 11:31:05 -050040
Alexandre Lision624b1a82016-09-11 19:29:01 -040041// Ring
Alexandre Lision745e4d62015-03-22 20:03:10 -040042#import "AppDelegate.h"
Alexandre Lisionc65310c2015-04-23 16:44:23 -040043#import "Constants.h"
Alexandre Lision58cab672015-06-09 15:25:40 -040044#import "CurrentCallVC.h"
Alexandre Lision624b1a82016-09-11 19:29:01 -040045#import "MigrateRingAccountsWC.h"
Alexandre Lision0f66bd32016-01-18 11:30:45 -050046#import "ConversationVC.h"
Alexandre Lisionbfa68f62015-09-10 08:38:42 -040047#import "PreferencesWC.h"
Alexandre Lisiona3a43dc2017-03-30 16:21:30 -040048#import "SmartViewVC.h"
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -040049#import "views/IconButton.h"
Alexandre Lisionbfa68f62015-09-10 08:38:42 -040050#import "views/NSColor+RingTheme.h"
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -040051#import "views/HoverButton.h"
Kateryna Kostiuk74fe20c2018-06-14 12:05:53 -040052#import "utils.h"
Kateryna Kostiukd73f9602018-07-24 13:51:28 -040053#import "RingWizardWC.h"
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -040054#import "AccountSettingsVC.h"
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -040055#import "views/CallLayer.h"
56
57typedef NS_ENUM(NSInteger, ViewState) {
58 SHOW_WELCOME_SCREEN = 0,
59 SHOW_CONVERSATION_SCREEN,
60 SHOW_CALL_SCREEN,
61 SHOW_SETTINGS_SCREEN,
62};
Alexandre Lision2db8f472015-07-22 15:05:46 -040063
Kateryna Kostiukef66f972018-11-02 17:10:37 -040064@interface RingWindowController () <MigrateRingAccountsDelegate>
Alexandre Lision624b1a82016-09-11 19:29:01 -040065
66@property (retain) MigrateRingAccountsWC* migrateWC;
Kateryna Kostiukd73f9602018-07-24 13:51:28 -040067@property RingWizardWC* wizard;
Alexandre Lision624b1a82016-09-11 19:29:01 -040068
69@end
70
Alexandre Lisionbfa68f62015-09-10 08:38:42 -040071@implementation RingWindowController {
Alexandre Lision5855b6a2015-02-03 11:31:05 -050072
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -040073 __unsafe_unretained IBOutlet NSLayoutConstraint* centerYQRCodeConstraint;
74 __unsafe_unretained IBOutlet NSLayoutConstraint* centerYWelcomeContainerConstraint;
Kateryna Kostiukab499f42018-04-16 12:27:33 -040075 IBOutlet NSLayoutConstraint* ringLabelTrailingConstraint;
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -040076 __unsafe_unretained IBOutlet NSView* welcomeContainer;
Alexandre Lision1abdf582016-02-09 14:21:19 -050077 __unsafe_unretained IBOutlet NSView* callView;
78 __unsafe_unretained IBOutlet NSTextField* ringIDLabel;
Kateryna Kostiuk85a334e2018-12-03 15:54:19 -050079 __unsafe_unretained IBOutlet NSTextField* explanationLabel;
Alexandre Lision1abdf582016-02-09 14:21:19 -050080 __unsafe_unretained IBOutlet NSButton* shareButton;
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -040081 __unsafe_unretained IBOutlet NSImageView* qrcodeView;
Alexandre Lision58cab672015-06-09 15:25:40 -040082
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -040083 PreferencesWC* preferencesWC;
Alexandre Lisiona3a43dc2017-03-30 16:21:30 -040084 IBOutlet SmartViewVC* smartViewVC;
Alexandre Lisione77f6f92016-04-17 23:39:39 -040085
Alexandre Lision0f66bd32016-01-18 11:30:45 -050086 CurrentCallVC* currentCallVC;
Andreas Traczykecdc4fa2018-03-22 16:11:47 -040087 ConversationVC* conversationVC;
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -040088 AccountSettingsVC* settingsVC;
Andreas Traczykecdc4fa2018-03-22 16:11:47 -040089
Kateryna Kostiukdb1f3a12017-04-24 12:08:28 -040090 // toolbar menu items
Kateryna Kostiukef66f972018-11-02 17:10:37 -040091 IBOutlet ChooseAccountVC* chooseAccountVC;
Alexandre Lisionbfa68f62015-09-10 08:38:42 -040092}
Alexandre Lision58cab672015-06-09 15:25:40 -040093
Kateryna Kostiukdb1f3a12017-04-24 12:08:28 -040094static NSString* const kPreferencesIdentifier = @"PreferencesIdentifier";
95NSString* const kChangeAccountToolBarItemIdentifier = @"ChangeAccountToolBarItemIdentifier";
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -040096NSString* const kOpenAccountToolBarItemIdentifier = @"OpenAccountToolBarItemIdentifier";
Alexandre Lisionc5148052015-03-04 15:10:35 -050097
Kateryna Kostiukecaa3952018-07-13 16:00:34 -040098@synthesize dataTransferModel, accountModel, behaviorController;
Kateryna Kostiukd73f9602018-07-24 13:51:28 -040099@synthesize wizard;
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400100
101-(id) initWithWindowNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil accountModel:( lrc::api::NewAccountModel*)accountModel dataTransferModel:( lrc::api::DataTransferModel*)dataTransferModel behaviourController:( lrc::api::BehaviorController*) behaviorController
102{
103 if (self = [self initWithWindowNibName:nibNameOrNil])
104 {
105 self.accountModel = accountModel;
106 self.dataTransferModel = dataTransferModel;
107 self.behaviorController = behaviorController;
108 }
109 return self;
110}
111
Kateryna Kostiukef66f972018-11-02 17:10:37 -0400112- (NSApplicationPresentationOptions)window:(NSWindow *)window willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions
113{
114 return (NSApplicationPresentationFullScreen |
115 NSApplicationPresentationAutoHideMenuBar |
116 NSApplicationPresentationAutoHideToolbar);
117}
118
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400119-(void)changeViewTo:(ViewState) state {
120 switch (state) {
121 case SHOW_WELCOME_SCREEN:
122 [self accountSettingsShouldOpen: NO];
123 [conversationVC hideWithAnimation:false];
124 [currentCallVC hideWithAnimation:false];
Kateryna Kostiuk4f37d952018-12-04 13:19:17 -0500125 [currentCallVC cleanUp];
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400126 [currentCallVC.view removeFromSuperview];
127 [welcomeContainer setHidden: NO];
128 [smartViewVC.view setHidden: NO];
129 [settingsVC hide];
130 break;
131 case SHOW_CONVERSATION_SCREEN:
132 [self accountSettingsShouldOpen: NO];
133 [conversationVC showWithAnimation:false];
134 [currentCallVC hideWithAnimation:false];
Kateryna Kostiuk4f37d952018-12-04 13:19:17 -0500135 [currentCallVC cleanUp];
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400136 [currentCallVC.view removeFromSuperview];
137 [welcomeContainer setHidden: YES];
138 [smartViewVC.view setHidden: NO];
139 [settingsVC hide];
140 break;
141 case SHOW_CALL_SCREEN:
142 [self accountSettingsShouldOpen: NO];
143 if (![currentCallVC.view superview]) {
144 [callView addSubview:[currentCallVC view] positioned:NSWindowAbove relativeTo:nil];
145 [currentCallVC initFrame];
146 [currentCallVC showWithAnimation:false];
147 [conversationVC hideWithAnimation:false];
148 [welcomeContainer setHidden: YES];
149 [smartViewVC.view setHidden: NO];
150 [settingsVC hide];
151 }
152 [currentCallVC showWithAnimation:false];
153 break;
154 case SHOW_SETTINGS_SCREEN:
155 @try {
156 [self accountSettingsShouldOpen: YES];
157 }
158 @catch (NSException *ex) {
159 return;
160 }
161 [welcomeContainer setHidden: YES];
162 [currentCallVC hideWithAnimation:false];
163 [currentCallVC.view removeFromSuperview];
164 [conversationVC hideWithAnimation:false];
165 [smartViewVC.view setHidden: YES];
166 [settingsVC show];
167 break;
168 default:
169 break;
170 }
171}
172
Alexandre Lision5855b6a2015-02-03 11:31:05 -0500173- (void)windowDidLoad {
174 [super windowDidLoad];
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400175 [self.window setMovableByWindowBackground:YES];
Alexandre Lision58cab672015-06-09 15:25:40 -0400176
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400177 self.window.titleVisibility = NSWindowTitleHidden;
Alexandre Lisione77f6f92016-04-17 23:39:39 -0400178
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500179 currentCallVC = [[CurrentCallVC alloc] initWithNibName:@"CurrentCall" bundle:nil];
Kateryna Kostiuk133364b2018-10-31 11:36:08 -0400180 currentCallVC.delegate = self;
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400181 conversationVC = [[ConversationVC alloc] initWithNibName:@"Conversation" bundle:nil delegate:self];
Kateryna Kostiukdb1f3a12017-04-24 12:08:28 -0400182 // toolbar items
Kateryna Kostiukef66f972018-11-02 17:10:37 -0400183 //chooseAccountVC = [[ChooseAccountVC alloc] initWithNibName:@"ChooseAccount" bundle:nil model:self.accountModel delegate:self];
184 [chooseAccountVC updateWithDelegate: self andModel:self.accountModel];
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400185 settingsVC = [[AccountSettingsVC alloc] initWithNibName:@"AccountSettings" bundle:nil accountmodel:self.accountModel];
Kateryna Kostiukef66f972018-11-02 17:10:37 -0400186 //[self.window.contentView addSubview:[chooseAccountVC view]];
Alexandre Lision58cab672015-06-09 15:25:40 -0400187 [callView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500188 [[currentCallVC view] setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400189 [[conversationVC view] setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400190 [[settingsVC view] setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
Alexandre Lision58cab672015-06-09 15:25:40 -0400191
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400192 [callView addSubview:[conversationVC view] positioned:NSWindowAbove relativeTo:nil];
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400193 [self.window.contentView addSubview:[settingsVC view] positioned:NSWindowAbove relativeTo:nil];
Alexandre Lision16d9c0a2015-08-10 12:05:15 -0400194
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400195 [conversationVC initFrame];
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400196 [settingsVC initFrame];
Anthony Léonard72128c92017-12-26 16:48:39 -0500197 @try {
198 [smartViewVC setConversationModel: [chooseAccountVC selectedAccount].conversationModel.get()];
199 }
200 @catch (NSException *ex) {
201 NSLog(@"Caught exception %@: %@", [ex name], [ex reason]);
202 }
Alexandre Lisionbb5c2462015-07-30 12:55:37 -0400203
Anthony Léonard49cb2912017-11-13 16:15:39 -0500204 // Fresh run, we need to make sure RingID appears
205 [shareButton sendActionOn:NSLeftMouseDownMask];
206
Olivier Soldano994971f2017-12-05 16:30:12 -0500207 [self connect];
Anthony Léonard49cb2912017-11-13 16:15:39 -0500208 [self updateRingID];
Kateryna Kostiuk74fe20c2018-06-14 12:05:53 -0400209 // set download folder (default - 'Documents')
Kateryna Kostiuk67735232018-05-10 15:05:32 -0400210 NSString* path = [[NSUserDefaults standardUserDefaults] stringForKey:Preferences::DownloadFolder];
211 if (!path || path.length == 0) {
Kateryna Kostiuk74fe20c2018-06-14 12:05:53 -0400212 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
213 path = [[paths objectAtIndex:0] stringByAppendingString:@"/"];
Kateryna Kostiuk67735232018-05-10 15:05:32 -0400214 }
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400215 self.dataTransferModel->downloadDirectory = std::string([path UTF8String]);
Kateryna Kostiuk74fe20c2018-06-14 12:05:53 -0400216 if(appSandboxed()) {
217 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
Kateryna Kostiukf9a72c02018-08-01 14:28:49 -0400218 media::RecordingModel::instance().setRecordPath(QString::fromNSString([paths objectAtIndex:0]));
Kateryna Kostiuk74fe20c2018-06-14 12:05:53 -0400219 }
Kateryna Kostiukef66f972018-11-02 17:10:37 -0400220 NSToolbar *tb = [[self window] toolbar];
221 [tb setAllowsUserCustomization:NO];
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500222}
223
224- (void) connect
225{
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400226 QObject::connect(self.behaviorController,
Olivier Soldano994971f2017-12-05 16:30:12 -0500227 &lrc::api::BehaviorController::showCallView,
228 [self](const std::string accountId,
229 const lrc::api::conversation::Info convInfo){
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400230 auto* accInfo = &self.accountModel->getAccountInfo(accountId);
Anthony Léonardd00cd182018-01-17 09:21:27 -0500231 if (accInfo->contactModel->getContact(convInfo.participants[0]).profileInfo.type == lrc::api::profile::Type::PENDING)
232 [smartViewVC selectPendingList];
233 else
234 [smartViewVC selectConversationList];
235
Olivier Soldano994971f2017-12-05 16:30:12 -0500236 [currentCallVC setCurrentCall:convInfo.callId
237 conversation:convInfo.uid
238 account:accInfo];
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400239 [self changeViewTo:SHOW_CALL_SCREEN];
240
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500241 });
Alexandre Lision210fe212016-01-27 11:15:13 -0500242
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400243 QObject::connect(self.behaviorController,
Olivier Soldano994971f2017-12-05 16:30:12 -0500244 &lrc::api::BehaviorController::showIncomingCallView,
245 [self](const std::string accountId,
246 const lrc::api::conversation::Info convInfo){
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400247 auto* accInfo = &self.accountModel->getAccountInfo(accountId);
Anthony Léonardd00cd182018-01-17 09:21:27 -0500248 if (accInfo->contactModel->getContact(convInfo.participants[0]).profileInfo.type == lrc::api::profile::Type::PENDING)
249 [smartViewVC selectPendingList];
250 else
251 [smartViewVC selectConversationList];
252
Olivier Soldano994971f2017-12-05 16:30:12 -0500253 [currentCallVC setCurrentCall:convInfo.callId
254 conversation:convInfo.uid
255 account:accInfo];
Anthony Léonard9bebf1d2017-12-21 14:33:51 -0500256 [smartViewVC selectConversation: convInfo model:accInfo->conversationModel.get()];
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400257 [self changeViewTo:SHOW_CALL_SCREEN];
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400258 });
Anthony Léonard2382b562017-12-13 15:51:28 -0500259
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400260 QObject::connect(self.behaviorController,
Anthony Léonard2382b562017-12-13 15:51:28 -0500261 &lrc::api::BehaviorController::showChatView,
262 [self](const std::string& accountId,
263 const lrc::api::conversation::Info& convInfo){
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400264 auto& accInfo = self.accountModel->getAccountInfo(accountId);
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400265 [conversationVC setConversationUid:convInfo.uid model:accInfo.conversationModel.get()];
Anthony Léonard9bebf1d2017-12-21 14:33:51 -0500266 [smartViewVC selectConversation: convInfo model:accInfo.conversationModel.get()];
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400267 [self changeViewTo:SHOW_CONVERSATION_SCREEN];
Anthony Léonard2382b562017-12-13 15:51:28 -0500268 });
Alexandre Lisionbb5c2462015-07-30 12:55:37 -0400269}
270
271/**
272 * Implement the necessary logic to choose which Ring ID to display.
273 * This tries to choose the "best" ID to show
274 */
275- (void) updateRingID
276{
Anthony Léonard72128c92017-12-26 16:48:39 -0500277 @try {
278 auto& account = [chooseAccountVC selectedAccount];
Alexandre Lisionbb5c2462015-07-30 12:55:37 -0400279
Anthony Léonard72128c92017-12-26 16:48:39 -0500280 [ringIDLabel setStringValue:@""];
Anthony Léonard49cb2912017-11-13 16:15:39 -0500281
Anthony Léonard72128c92017-12-26 16:48:39 -0500282 if(account.profileInfo.type != lrc::api::profile::Type::RING) {
Kateryna Kostiukab499f42018-04-16 12:27:33 -0400283 self.notRingAccount = YES;
284 self.isSIPAccount = YES;
Anthony Léonard72128c92017-12-26 16:48:39 -0500285 return;
286 }
Kateryna Kostiukab499f42018-04-16 12:27:33 -0400287 self.isSIPAccount = NO;
288 self.notRingAccount = NO;
289 [ringLabelTrailingConstraint setActive:YES];
Anthony Léonard72128c92017-12-26 16:48:39 -0500290 auto& registeredName = account.registeredName;
291 auto& ringID = account.profileInfo.uri;
292 NSString* uriToDisplay = nullptr;
293 if (!registeredName.empty()) {
294 uriToDisplay = @(registeredName.c_str());
Kateryna Kostiuk85a334e2018-12-03 15:54:19 -0500295 [explanationLabel setStringValue: NSLocalizedString(@"This is your Jami username. \nCopy and share it with your friends!", @"Explanation label when user have Jami username")];
Anthony Léonard72128c92017-12-26 16:48:39 -0500296 } else {
297 uriToDisplay = @(ringID.c_str());
Kateryna Kostiuk85a334e2018-12-03 15:54:19 -0500298 [explanationLabel setStringValue: NSLocalizedString(@"This is your ID. \nCopy and share it with your friends!", @"Explanation label when user have just ID")];
Anthony Léonard72128c92017-12-26 16:48:39 -0500299 }
300 [ringIDLabel setStringValue:uriToDisplay];
301 [self drawQRCode:@(ringID.c_str())];
Alexandre Lisionbb5c2462015-07-30 12:55:37 -0400302 }
Anthony Léonard72128c92017-12-26 16:48:39 -0500303 @catch (NSException *ex) {
304 NSLog(@"Caught exception %@: %@", [ex name], [ex reason]);
Kateryna Kostiukab499f42018-04-16 12:27:33 -0400305 self.notRingAccount = YES;
306 self.isSIPAccount = NO;
307 [ringLabelTrailingConstraint setActive:NO];
Anthony Léonard70638f02018-02-05 11:10:19 -0500308 [ringIDLabel setStringValue:NSLocalizedString(@"No account available", @"Displayed as RingID when no accounts are available for selection")];
Alexandre Lision313427f2016-11-24 21:04:04 -0500309 }
Alexandre Lision5855b6a2015-02-03 11:31:05 -0500310}
311
Alexandre Lision1abdf582016-02-09 14:21:19 -0500312- (IBAction)shareRingID:(id)sender {
313 NSSharingServicePicker* sharingServicePicker = [[NSSharingServicePicker alloc] initWithItems:[NSArray arrayWithObject:[ringIDLabel stringValue]]];
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -0400314 [sharingServicePicker setDelegate:self];
Alexandre Lision1abdf582016-02-09 14:21:19 -0500315 [sharingServicePicker showRelativeToRect:[sender bounds]
316 ofView:sender
317 preferredEdge:NSMinYEdge];
318}
319
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -0400320- (IBAction)toggleQRCode:(id)sender {
321 // Toggle pressed state of QRCode button
Kateryna Kostiuk85a334e2018-12-03 15:54:19 -0500322 // [sender setPressed:![sender isPressed]];
323 bool show = qrcodeView.animator.alphaValue == 0.0f ? YES: NO;
324 [self showQRCode: show];
Alexandre Lision313427f2016-11-24 21:04:04 -0500325}
326
327/**
328 * Draw the QRCode in the qrCodeView
329 */
Kateryna Kostiuk65ba43e2017-03-30 15:10:04 -0400330- (void)drawQRCode:(NSString*) uriToDraw
Alexandre Lision313427f2016-11-24 21:04:04 -0500331{
Kateryna Kostiuk65ba43e2017-03-30 15:10:04 -0400332 auto qrCode = QRcode_encodeString(uriToDraw.UTF8String,
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -0400333 0,
334 QR_ECLEVEL_L, // Lowest level of error correction
335 QR_MODE_8, // 8-bit data mode
336 1);
337 if (!qrCode) {
338 return;
339 }
340
Alexandre Lision313427f2016-11-24 21:04:04 -0500341 unsigned char *data = 0;
342 int width;
343 data = qrCode->data;
344 width = qrCode->width;
345 int qr_margin = 3;
346
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -0400347 CGFloat size = qrcodeView.frame.size.width;
348
349 // create context
350 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
351 CGContextRef ctx = CGBitmapContextCreate(0, size, size, 8, size * 4, colorSpace, kCGImageAlphaPremultipliedLast);
352
353 CGAffineTransform translateTransform = CGAffineTransformMakeTranslation(0, -size);
354 CGAffineTransform scaleTransform = CGAffineTransformMakeScale(1, -1);
355 CGContextConcatCTM(ctx, CGAffineTransformConcat(translateTransform, scaleTransform));
356
Alexandre Lision313427f2016-11-24 21:04:04 -0500357 float zoom = ceil((double)size / (qrCode->width + 2.0 * qr_margin));
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -0400358 CGRect rectDraw = CGRectMake(0, 0, zoom, zoom);
359
360 int ran;
361 for(int i = 0; i < width; ++i) {
362 for(int j = 0; j < width; ++j) {
363 if(*data & 1) {
Kateryna Kostiuk394f74c2018-10-05 15:45:26 -0400364 CGContextSetFillColorWithColor(ctx, [NSColor labelColor].CGColor);
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -0400365 rectDraw.origin = CGPointMake((j + qr_margin) * zoom,(i + qr_margin) * zoom);
366 CGContextAddRect(ctx, rectDraw);
367 CGContextFillPath(ctx);
368 } else {
369 CGContextSetFillColorWithColor(ctx, [NSColor windowBackgroundColor].CGColor);
370 rectDraw.origin = CGPointMake((j + qr_margin) * zoom,(i + qr_margin) * zoom);
371 CGContextAddRect(ctx, rectDraw);
372 CGContextFillPath(ctx);
373 }
374 ++data;
375 }
376 }
Alexandre Lision313427f2016-11-24 21:04:04 -0500377
378 // get image
379 auto qrCGImage = CGBitmapContextCreateImage(ctx);
380 auto qrImage = [[NSImage alloc] initWithCGImage:qrCGImage size:qrcodeView.frame.size];
381
382 // some releases
383 CGContextRelease(ctx);
384 CGImageRelease(qrCGImage);
385 CGColorSpaceRelease(colorSpace);
386 QRcode_free(qrCode);
387
388 [qrcodeView setImage:qrImage];
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -0400389}
390
391/**
392 * Start the in/out animation displaying the QRCode
393 * @param show should the QRCode be animated in or out
394 */
395- (void) showQRCode:(BOOL) show
396{
397 static const NSInteger offset = 110;
398 [NSAnimationContext beginGrouping];
399 NSAnimationContext.currentContext.duration = 0.5;
400 [[NSAnimationContext currentContext] setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]];
401 qrcodeView.animator.alphaValue = show ? 1.0 : 0.0;
402 [centerYQRCodeConstraint.animator setConstant: show ? offset : 0];
403 [centerYWelcomeContainerConstraint.animator setConstant:show ? -offset : 0];
404 [NSAnimationContext endGrouping];
405}
406
Alexandre Lision4a7b95e2015-02-20 10:06:43 -0500407- (IBAction)openPreferences:(id)sender
408{
Kateryna Kostiukbb68a1c2018-06-12 15:16:02 -0400409 if (preferencesWC) {
410 [preferencesWC.window orderFront:preferencesWC.window];
411 return;
412 }
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400413
414 preferencesWC = [[PreferencesWC alloc] initWithWindowNibName: @"PreferencesWindow" bundle: nil accountModel:self.accountModel dataTransferModel:self.dataTransferModel behaviourController:self.behaviorController];
Alexandre Lisionbfa68f62015-09-10 08:38:42 -0400415 [preferencesWC.window makeKeyAndOrderFront:preferencesWC.window];
Alexandre Lision5855b6a2015-02-03 11:31:05 -0500416}
Alexandre Lision4a7b95e2015-02-20 10:06:43 -0500417
Kateryna Kostiuk882cbac2017-07-05 17:29:00 -0400418- (IBAction)callClickedAtRow:(id)sender
419{
420 NSTabViewItem *selectedTab = [smartViewVC.tabbar selectedTabViewItem];
421 int index = [smartViewVC.tabbar indexOfTabViewItem:selectedTab];
422 switch (index) {
423 case 0:
424 [smartViewVC startCallForRow:sender];
425 break;
Kateryna Kostiuk882cbac2017-07-05 17:29:00 -0400426 default:
427 break;
428 }
429}
Anthony Léonard0a9904c2018-01-11 16:43:47 -0500430
Alexandre Lision624b1a82016-09-11 19:29:01 -0400431#pragma mark - Ring account migration
432
433- (void) migrateRingAccount:(Account*) acc
434{
435 self.migrateWC = [[MigrateRingAccountsWC alloc] initWithDelegate:self actionCode:1];
436 self.migrateWC.account = acc;
437#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_9
438 [self.window beginSheet:self.migrateWC.window completionHandler:nil];
439#else
440 [NSApp beginSheet: self.migrateWC.window
441 modalForWindow: self.window
442 modalDelegate: self
443 didEndSelector: nil
444 contextInfo: nil];
445#endif
446}
447
Anthony Léonard49cb2912017-11-13 16:15:39 -0500448// TODO: Reimplement as a blocking loop when new LRC models handle migration
Alexandre Lision624b1a82016-09-11 19:29:01 -0400449- (void)checkAccountsToMigrate
450{
451 auto ringList = AccountModel::instance().accountsToMigrate();
452 if (ringList.length() > 0){
453 Account* acc = ringList.value(0);
454 [self migrateRingAccount:acc];
455 } else {
456 // Fresh run, we need to make sure RingID appears
Alexandre Lision624b1a82016-09-11 19:29:01 -0400457 [shareButton sendActionOn:NSLeftMouseDownMask];
458
459 [self connect];
Kateryna Kostiuka7248462017-04-18 16:15:31 -0400460 [self updateRingID];
Alexandre Lision624b1a82016-09-11 19:29:01 -0400461 }
462}
463
464- (void)migrationDidComplete
465{
466 [self checkAccountsToMigrate];
467}
468
469- (void)migrationDidCompleteWithError
470{
471 [self checkAccountsToMigrate];
472}
473
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400474- (void) selectAccount:(const lrc::api::account::Info&)accInfo currentRemoved:(BOOL) removed
Anthony Léonard9bebf1d2017-12-21 14:33:51 -0500475{
476 // If the selected account has been changed, we close any open panel
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400477 [smartViewVC setConversationModel:accInfo.conversationModel.get()];
Anthony Léonard61e3dcf2017-12-27 12:19:52 -0500478 // Welcome view informations are also updated
479 [self updateRingID];
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400480 [settingsVC setSelectedAccount:accInfo.id];
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400481 [self changeViewTo: ([settingsVC.view isHidden] || removed) ? SHOW_WELCOME_SCREEN : SHOW_SETTINGS_SCREEN];
Anthony Léonard9bebf1d2017-12-21 14:33:51 -0500482}
483
Kateryna Kostiukab499f42018-04-16 12:27:33 -0400484-(void)allAccountsDeleted
485{
486 [smartViewVC clearConversationModel];
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400487 [self changeViewTo:SHOW_WELCOME_SCREEN];
Kateryna Kostiukab499f42018-04-16 12:27:33 -0400488 [self updateRingID];
489}
490
Anthony Léonard8585cc02017-12-28 14:03:45 -0500491-(void)rightPanelClosed
492{
493 [smartViewVC deselect];
Kateryna Kostiuk394f74c2018-10-05 15:45:26 -0400494 [welcomeContainer setHidden:NO];
Anthony Léonard8585cc02017-12-28 14:03:45 -0500495}
496
Anthony Léonard0a9904c2018-01-11 16:43:47 -0500497-(void)currentConversationTrusted
498{
499 [smartViewVC selectConversationList];
500}
501
Anthony Léonardbee94cc2018-01-16 11:42:40 -0500502-(void) listTypeChanged {
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400503 [self changeViewTo:SHOW_WELCOME_SCREEN];
Anthony Léonardbee94cc2018-01-16 11:42:40 -0500504}
505
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400506- (IBAction)openAccountSettings:(NSButton *)sender
507{
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400508 [self changeViewTo: [settingsVC.view isHidden] ? SHOW_SETTINGS_SCREEN : SHOW_WELCOME_SCREEN];
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400509}
510
Kateryna Kostiukd73f9602018-07-24 13:51:28 -0400511- (void) createNewAccount {
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400512 [self changeViewTo:SHOW_WELCOME_SCREEN];
Kateryna Kostiukd73f9602018-07-24 13:51:28 -0400513 wizard = [[RingWizardWC alloc] initWithNibName:@"RingWizard" bundle: nil accountmodel: self.accountModel];
514 [wizard showChooseWithCancelButton: YES andAdvanced: YES];
515 [self.window beginSheet:wizard.window completionHandler:nil];
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400516}
517
Kateryna Kostiuk23222fe2018-11-16 14:28:02 -0500518- (NSRect)window:(NSWindow *)window willPositionSheet:(NSWindow *)sheet
519 usingRect:(NSRect)rect
520{
521 float titleBarHeight = self.window.frame.size.height - [NSWindow contentRectForFrameRect:self.window.frame styleMask:self.window.styleMask].size.height;
522 rect.origin.y = self.window.frame.size.height;
523 return rect;
524}
525
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400526-(void) accountSettingsShouldOpen: (BOOL) open {
527 if (open) {
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400528 [settingsVC setSelectedAccount: [chooseAccountVC selectedAccount].id];
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400529 }
Kateryna Kostiukd73f9602018-07-24 13:51:28 -0400530}
531
Kateryna Kostiuk133364b2018-10-31 11:36:08 -0400532#pragma mark - CallViewControllerDelegate
533
534-(void) conversationInfoUpdatedFor:(const std::string&) conversationID {
535 [smartViewVC reloadConversationWithUid:@(conversationID.c_str())];
536}
537
Kateryna Kostiuke3503842018-12-12 16:39:45 -0500538-(void) showConversation:(NSString* )conversationId forAccount:(NSString*)accountId {
539 auto& accInfo = self.accountModel->getAccountInfo([accountId UTF8String]);
540 [chooseAccountVC selectAccount: accountId];
541 [settingsVC setSelectedAccount: [accountId UTF8String]];
542 [smartViewVC setConversationModel:accInfo.conversationModel.get()];
543 [smartViewVC selectConversationList];
544 [self updateRingID];
545 auto convInfo = getConversationFromUid([conversationId UTF8String], *accInfo.conversationModel.get());
546 auto convQueue = accInfo.conversationModel.get()->allFilteredConversations();
547 if (convInfo != convQueue.end()) {
548 [conversationVC setConversationUid:convInfo->uid model:accInfo.conversationModel.get()];
549 [smartViewVC selectConversation: *convInfo model:accInfo.conversationModel.get()];
550 accInfo.conversationModel.get()->clearUnreadInteractions([conversationId UTF8String]);
551 }
552 [self changeViewTo:SHOW_CONVERSATION_SCREEN];
553}
554
555-(void) showCall:(NSString* )callId forAccount:(NSString*)accountId forConversation:(NSString*)conversationId {
556 auto& accInfo = self.accountModel->getAccountInfo([accountId UTF8String]);
557 [chooseAccountVC selectAccount: accountId];
558 [settingsVC setSelectedAccount:accInfo.id];
559 [smartViewVC setConversationModel:accInfo.conversationModel.get()];
560 [self updateRingID];
561 auto convInfo = getConversationFromUid([conversationId UTF8String], *accInfo.conversationModel.get());
562 auto convQueue = accInfo.conversationModel.get()->allFilteredConversations();
563 if (convInfo != convQueue.end()) {
564 if (accInfo.contactModel->getContact(convInfo->participants[0]).profileInfo.type == lrc::api::profile::Type::PENDING)
565 [smartViewVC selectPendingList];
566 else
567 [smartViewVC selectConversationList];
568 [smartViewVC selectConversation: *convInfo model:accInfo.conversationModel.get()];
569 }
570 [currentCallVC setCurrentCall:[callId UTF8String]
571 conversation:[conversationId UTF8String]
572 account:&accInfo];
573 [self changeViewTo:SHOW_CALL_SCREEN];
574}
575
576-(void) showContactRequestFor:(NSString* )accountId contactUri:(NSString*)uri {
577 auto& accInfo = self.accountModel->getAccountInfo([accountId UTF8String]);
578 [chooseAccountVC selectAccount: accountId];
579 [settingsVC setSelectedAccount:accInfo.id];
580 [smartViewVC setConversationModel:accInfo.conversationModel.get()];
581 [self updateRingID];
582 [smartViewVC selectPendingList];
583 auto convInfo = getConversationFromURI([uri UTF8String], *accInfo.conversationModel.get());
584 auto convQueue = accInfo.conversationModel.get()->allFilteredConversations();
585 if (convInfo != convQueue.end()) {
586 [conversationVC setConversationUid:convInfo->uid model:accInfo.conversationModel.get()];
587 [smartViewVC selectConversation: *convInfo model:accInfo.conversationModel.get()];
588 }
589 [self changeViewTo:SHOW_CONVERSATION_SCREEN];
590}
Alexandre Lision5855b6a2015-02-03 11:31:05 -0500591@end