blob: ffd3f32168955402bbec3fdaba82ca95b85350b9 [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
Alexandre Lision5855b6a2015-02-03 11:31:05 -050029#import <callmodel.h>
30#import <account.h>
Alexandre Lision91d11e52015-03-20 17:42:05 -040031#import <call.h>
Alexandre Lision0f66bd32016-01-18 11:30:45 -050032#import <recentmodel.h>
Kateryna Kostiuk312f9132017-04-18 12:09:06 -040033#import <AvailableAccountModel.h>
Anthony Léonard79597602017-11-13 15:47:09 -050034#import <api/lrc.h>
Anthony Léonard49cb2912017-11-13 16:15:39 -050035#import <api/account.h>
Olivier Soldano994971f2017-12-05 16:30:12 -050036#import <api/newaccountmodel.h>
37#import <api/newcallmodel.h>
38#import <api/behaviorcontroller.h>
39#import <api/conversation.h>
Anthony Léonardd00cd182018-01-17 09:21:27 -050040#import <api/contactmodel.h>
41#import <api/contact.h>
Kateryna Kostiuk67735232018-05-10 15:05:32 -040042#import <api/datatransfermodel.h>
Kateryna Kostiuk74fe20c2018-06-14 12:05:53 -040043#import <media/recordingmodel.h>
Alexandre Lision5855b6a2015-02-03 11:31:05 -050044
Alexandre Lision624b1a82016-09-11 19:29:01 -040045// Ring
Alexandre Lision745e4d62015-03-22 20:03:10 -040046#import "AppDelegate.h"
Alexandre Lisionc65310c2015-04-23 16:44:23 -040047#import "Constants.h"
Alexandre Lision58cab672015-06-09 15:25:40 -040048#import "CurrentCallVC.h"
Alexandre Lision624b1a82016-09-11 19:29:01 -040049#import "MigrateRingAccountsWC.h"
Alexandre Lision0f66bd32016-01-18 11:30:45 -050050#import "ConversationVC.h"
Alexandre Lisionbfa68f62015-09-10 08:38:42 -040051#import "PreferencesWC.h"
Alexandre Lisiona3a43dc2017-03-30 16:21:30 -040052#import "SmartViewVC.h"
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -040053#import "views/IconButton.h"
Alexandre Lisionbfa68f62015-09-10 08:38:42 -040054#import "views/NSColor+RingTheme.h"
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -040055#import "views/HoverButton.h"
Kateryna Kostiuk74fe20c2018-06-14 12:05:53 -040056#import "utils.h"
Kateryna Kostiukd73f9602018-07-24 13:51:28 -040057#import "RingWizardWC.h"
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -040058#import "AccountSettingsVC.h"
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -040059#import "views/CallLayer.h"
60
61typedef NS_ENUM(NSInteger, ViewState) {
62 SHOW_WELCOME_SCREEN = 0,
63 SHOW_CONVERSATION_SCREEN,
64 SHOW_CALL_SCREEN,
65 SHOW_SETTINGS_SCREEN,
66};
Alexandre Lision2db8f472015-07-22 15:05:46 -040067
Kateryna Kostiuk13b76882017-03-30 09:18:44 -040068@interface RingWindowController () <MigrateRingAccountsDelegate, NSToolbarDelegate>
Alexandre Lision624b1a82016-09-11 19:29:01 -040069
70@property (retain) MigrateRingAccountsWC* migrateWC;
Kateryna Kostiukd73f9602018-07-24 13:51:28 -040071@property RingWizardWC* wizard;
Alexandre Lision624b1a82016-09-11 19:29:01 -040072
73@end
74
Alexandre Lisionbfa68f62015-09-10 08:38:42 -040075@implementation RingWindowController {
Alexandre Lision5855b6a2015-02-03 11:31:05 -050076
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -040077 __unsafe_unretained IBOutlet NSLayoutConstraint* centerYQRCodeConstraint;
78 __unsafe_unretained IBOutlet NSLayoutConstraint* centerYWelcomeContainerConstraint;
Kateryna Kostiukab499f42018-04-16 12:27:33 -040079 IBOutlet NSLayoutConstraint* ringLabelTrailingConstraint;
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -040080 __unsafe_unretained IBOutlet NSView* welcomeContainer;
Alexandre Lision1abdf582016-02-09 14:21:19 -050081 __unsafe_unretained IBOutlet NSView* callView;
82 __unsafe_unretained IBOutlet NSTextField* ringIDLabel;
83 __unsafe_unretained IBOutlet NSButton* shareButton;
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -040084 __unsafe_unretained IBOutlet NSImageView* qrcodeView;
Alexandre Lision58cab672015-06-09 15:25:40 -040085
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -040086 PreferencesWC* preferencesWC;
Alexandre Lisiona3a43dc2017-03-30 16:21:30 -040087 IBOutlet SmartViewVC* smartViewVC;
Alexandre Lisione77f6f92016-04-17 23:39:39 -040088
Alexandre Lision0f66bd32016-01-18 11:30:45 -050089 CurrentCallVC* currentCallVC;
Andreas Traczykecdc4fa2018-03-22 16:11:47 -040090 ConversationVC* conversationVC;
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -040091 AccountSettingsVC* settingsVC;
Andreas Traczykecdc4fa2018-03-22 16:11:47 -040092
Kateryna Kostiukdb1f3a12017-04-24 12:08:28 -040093 // toolbar menu items
Kateryna Kostiuk13b76882017-03-30 09:18:44 -040094 ChooseAccountVC* chooseAccountVC;
Alexandre Lisionbfa68f62015-09-10 08:38:42 -040095}
Alexandre Lision58cab672015-06-09 15:25:40 -040096
Kateryna Kostiukdb1f3a12017-04-24 12:08:28 -040097static NSString* const kPreferencesIdentifier = @"PreferencesIdentifier";
98NSString* const kChangeAccountToolBarItemIdentifier = @"ChangeAccountToolBarItemIdentifier";
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -040099NSString* const kOpenAccountToolBarItemIdentifier = @"OpenAccountToolBarItemIdentifier";
Alexandre Lisionc5148052015-03-04 15:10:35 -0500100
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400101@synthesize dataTransferModel, accountModel, behaviorController;
Kateryna Kostiukd73f9602018-07-24 13:51:28 -0400102@synthesize wizard;
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400103
104-(id) initWithWindowNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil accountModel:( lrc::api::NewAccountModel*)accountModel dataTransferModel:( lrc::api::DataTransferModel*)dataTransferModel behaviourController:( lrc::api::BehaviorController*) behaviorController
105{
106 if (self = [self initWithWindowNibName:nibNameOrNil])
107 {
108 self.accountModel = accountModel;
109 self.dataTransferModel = dataTransferModel;
110 self.behaviorController = behaviorController;
111 }
112 return self;
113}
114
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400115-(void)changeViewTo:(ViewState) state {
116 switch (state) {
117 case SHOW_WELCOME_SCREEN:
118 [self accountSettingsShouldOpen: NO];
119 [conversationVC hideWithAnimation:false];
120 [currentCallVC hideWithAnimation:false];
121 [currentCallVC.view removeFromSuperview];
122 [welcomeContainer setHidden: NO];
123 [smartViewVC.view setHidden: NO];
124 [settingsVC hide];
125 break;
126 case SHOW_CONVERSATION_SCREEN:
127 [self accountSettingsShouldOpen: NO];
128 [conversationVC showWithAnimation:false];
129 [currentCallVC hideWithAnimation:false];
130 [currentCallVC.view removeFromSuperview];
131 [welcomeContainer setHidden: YES];
132 [smartViewVC.view setHidden: NO];
133 [settingsVC hide];
134 break;
135 case SHOW_CALL_SCREEN:
136 [self accountSettingsShouldOpen: NO];
137 if (![currentCallVC.view superview]) {
138 [callView addSubview:[currentCallVC view] positioned:NSWindowAbove relativeTo:nil];
139 [currentCallVC initFrame];
140 [currentCallVC showWithAnimation:false];
141 [conversationVC hideWithAnimation:false];
142 [welcomeContainer setHidden: YES];
143 [smartViewVC.view setHidden: NO];
144 [settingsVC hide];
145 }
146 [currentCallVC showWithAnimation:false];
147 break;
148 case SHOW_SETTINGS_SCREEN:
149 @try {
150 [self accountSettingsShouldOpen: YES];
151 }
152 @catch (NSException *ex) {
153 return;
154 }
155 [welcomeContainer setHidden: YES];
156 [currentCallVC hideWithAnimation:false];
157 [currentCallVC.view removeFromSuperview];
158 [conversationVC hideWithAnimation:false];
159 [smartViewVC.view setHidden: YES];
160 [settingsVC show];
161 break;
162 default:
163 break;
164 }
165}
166
Alexandre Lision5855b6a2015-02-03 11:31:05 -0500167- (void)windowDidLoad {
168 [super windowDidLoad];
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400169 [self.window setMovableByWindowBackground:YES];
Alexandre Lision58cab672015-06-09 15:25:40 -0400170
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400171 self.window.titleVisibility = NSWindowTitleHidden;
Alexandre Lisione77f6f92016-04-17 23:39:39 -0400172
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500173 currentCallVC = [[CurrentCallVC alloc] initWithNibName:@"CurrentCall" bundle:nil];
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400174 conversationVC = [[ConversationVC alloc] initWithNibName:@"Conversation" bundle:nil delegate:self];
Kateryna Kostiukdb1f3a12017-04-24 12:08:28 -0400175 // toolbar items
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400176 chooseAccountVC = [[ChooseAccountVC alloc] initWithNibName:@"ChooseAccount" bundle:nil model:self.accountModel delegate:self];
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400177 settingsVC = [[AccountSettingsVC alloc] initWithNibName:@"AccountSettings" bundle:nil accountmodel:self.accountModel];
Alexandre Lision58cab672015-06-09 15:25:40 -0400178 [callView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500179 [[currentCallVC view] setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400180 [[conversationVC view] setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400181 [[settingsVC view] setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
Alexandre Lision58cab672015-06-09 15:25:40 -0400182
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400183 [callView addSubview:[conversationVC view] positioned:NSWindowAbove relativeTo:nil];
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400184 [self.window.contentView addSubview:[settingsVC view] positioned:NSWindowAbove relativeTo:nil];
Alexandre Lision16d9c0a2015-08-10 12:05:15 -0400185
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400186 [conversationVC initFrame];
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400187 [settingsVC initFrame];
Anthony Léonard72128c92017-12-26 16:48:39 -0500188 @try {
189 [smartViewVC setConversationModel: [chooseAccountVC selectedAccount].conversationModel.get()];
190 }
191 @catch (NSException *ex) {
192 NSLog(@"Caught exception %@: %@", [ex name], [ex reason]);
193 }
Alexandre Lisionbb5c2462015-07-30 12:55:37 -0400194
Anthony Léonard49cb2912017-11-13 16:15:39 -0500195 // Fresh run, we need to make sure RingID appears
196 [shareButton sendActionOn:NSLeftMouseDownMask];
197
Olivier Soldano994971f2017-12-05 16:30:12 -0500198 [self connect];
Anthony Léonard49cb2912017-11-13 16:15:39 -0500199 [self updateRingID];
200 // display accounts to select
201 NSToolbar *toolbar = self.window.toolbar;
202 toolbar.delegate = self;
203 [toolbar insertItemWithItemIdentifier:kChangeAccountToolBarItemIdentifier atIndex:1];
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400204 [toolbar insertItemWithItemIdentifier:kOpenAccountToolBarItemIdentifier atIndex:1];
Kateryna Kostiuk74fe20c2018-06-14 12:05:53 -0400205 // set download folder (default - 'Documents')
Kateryna Kostiuk67735232018-05-10 15:05:32 -0400206 NSString* path = [[NSUserDefaults standardUserDefaults] stringForKey:Preferences::DownloadFolder];
207 if (!path || path.length == 0) {
Kateryna Kostiuk74fe20c2018-06-14 12:05:53 -0400208 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
209 path = [[paths objectAtIndex:0] stringByAppendingString:@"/"];
Kateryna Kostiuk67735232018-05-10 15:05:32 -0400210 }
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400211 self.dataTransferModel->downloadDirectory = std::string([path UTF8String]);
Kateryna Kostiuk74fe20c2018-06-14 12:05:53 -0400212 if(appSandboxed()) {
213 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
Kateryna Kostiukf9a72c02018-08-01 14:28:49 -0400214 media::RecordingModel::instance().setRecordPath(QString::fromNSString([paths objectAtIndex:0]));
Kateryna Kostiuk74fe20c2018-06-14 12:05:53 -0400215 }
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500216}
217
218- (void) connect
219{
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400220 QObject::connect(self.behaviorController,
Olivier Soldano994971f2017-12-05 16:30:12 -0500221 &lrc::api::BehaviorController::showCallView,
222 [self](const std::string accountId,
223 const lrc::api::conversation::Info convInfo){
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400224 auto* accInfo = &self.accountModel->getAccountInfo(accountId);
Anthony Léonardd00cd182018-01-17 09:21:27 -0500225 if (accInfo->contactModel->getContact(convInfo.participants[0]).profileInfo.type == lrc::api::profile::Type::PENDING)
226 [smartViewVC selectPendingList];
227 else
228 [smartViewVC selectConversationList];
229
Olivier Soldano994971f2017-12-05 16:30:12 -0500230 [currentCallVC setCurrentCall:convInfo.callId
231 conversation:convInfo.uid
232 account:accInfo];
Anthony Léonard9bebf1d2017-12-21 14:33:51 -0500233 [smartViewVC selectConversation: convInfo model:accInfo->conversationModel.get()];
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400234 [self changeViewTo:SHOW_CALL_SCREEN];
235
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500236 });
Alexandre Lision210fe212016-01-27 11:15:13 -0500237
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400238 QObject::connect(self.behaviorController,
Olivier Soldano994971f2017-12-05 16:30:12 -0500239 &lrc::api::BehaviorController::showIncomingCallView,
240 [self](const std::string accountId,
241 const lrc::api::conversation::Info convInfo){
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400242 auto* accInfo = &self.accountModel->getAccountInfo(accountId);
Anthony Léonardd00cd182018-01-17 09:21:27 -0500243 if (accInfo->contactModel->getContact(convInfo.participants[0]).profileInfo.type == lrc::api::profile::Type::PENDING)
244 [smartViewVC selectPendingList];
245 else
246 [smartViewVC selectConversationList];
247
Olivier Soldano994971f2017-12-05 16:30:12 -0500248 [currentCallVC setCurrentCall:convInfo.callId
249 conversation:convInfo.uid
250 account:accInfo];
Anthony Léonard9bebf1d2017-12-21 14:33:51 -0500251 [smartViewVC selectConversation: convInfo model:accInfo->conversationModel.get()];
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400252 [self changeViewTo:SHOW_CALL_SCREEN];
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400253 });
Anthony Léonard2382b562017-12-13 15:51:28 -0500254
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400255 QObject::connect(self.behaviorController,
Anthony Léonard2382b562017-12-13 15:51:28 -0500256 &lrc::api::BehaviorController::showChatView,
257 [self](const std::string& accountId,
258 const lrc::api::conversation::Info& convInfo){
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400259 auto& accInfo = self.accountModel->getAccountInfo(accountId);
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400260 [conversationVC setConversationUid:convInfo.uid model:accInfo.conversationModel.get()];
Anthony Léonard9bebf1d2017-12-21 14:33:51 -0500261 [smartViewVC selectConversation: convInfo model:accInfo.conversationModel.get()];
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400262 [self changeViewTo:SHOW_CONVERSATION_SCREEN];
Anthony Léonard2382b562017-12-13 15:51:28 -0500263 });
Alexandre Lisionbb5c2462015-07-30 12:55:37 -0400264}
265
266/**
267 * Implement the necessary logic to choose which Ring ID to display.
268 * This tries to choose the "best" ID to show
269 */
270- (void) updateRingID
271{
Anthony Léonard72128c92017-12-26 16:48:39 -0500272 @try {
273 auto& account = [chooseAccountVC selectedAccount];
Alexandre Lisionbb5c2462015-07-30 12:55:37 -0400274
Anthony Léonard72128c92017-12-26 16:48:39 -0500275 [ringIDLabel setStringValue:@""];
Anthony Léonard49cb2912017-11-13 16:15:39 -0500276
Anthony Léonard72128c92017-12-26 16:48:39 -0500277 if(account.profileInfo.type != lrc::api::profile::Type::RING) {
Kateryna Kostiukab499f42018-04-16 12:27:33 -0400278 self.notRingAccount = YES;
279 self.isSIPAccount = YES;
Anthony Léonard72128c92017-12-26 16:48:39 -0500280 return;
281 }
Kateryna Kostiukab499f42018-04-16 12:27:33 -0400282 self.isSIPAccount = NO;
283 self.notRingAccount = NO;
284 [ringLabelTrailingConstraint setActive:YES];
Anthony Léonard72128c92017-12-26 16:48:39 -0500285 auto& registeredName = account.registeredName;
286 auto& ringID = account.profileInfo.uri;
287 NSString* uriToDisplay = nullptr;
288 if (!registeredName.empty()) {
289 uriToDisplay = @(registeredName.c_str());
290 } else {
291 uriToDisplay = @(ringID.c_str());
292 }
293 [ringIDLabel setStringValue:uriToDisplay];
294 [self drawQRCode:@(ringID.c_str())];
Alexandre Lisionbb5c2462015-07-30 12:55:37 -0400295 }
Anthony Léonard72128c92017-12-26 16:48:39 -0500296 @catch (NSException *ex) {
297 NSLog(@"Caught exception %@: %@", [ex name], [ex reason]);
Kateryna Kostiukab499f42018-04-16 12:27:33 -0400298 self.notRingAccount = YES;
299 self.isSIPAccount = NO;
300 [ringLabelTrailingConstraint setActive:NO];
Anthony Léonard70638f02018-02-05 11:10:19 -0500301 [ringIDLabel setStringValue:NSLocalizedString(@"No account available", @"Displayed as RingID when no accounts are available for selection")];
Alexandre Lision313427f2016-11-24 21:04:04 -0500302 }
Alexandre Lision5855b6a2015-02-03 11:31:05 -0500303}
304
Alexandre Lision1abdf582016-02-09 14:21:19 -0500305- (IBAction)shareRingID:(id)sender {
306 NSSharingServicePicker* sharingServicePicker = [[NSSharingServicePicker alloc] initWithItems:[NSArray arrayWithObject:[ringIDLabel stringValue]]];
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -0400307 [sharingServicePicker setDelegate:self];
Alexandre Lision1abdf582016-02-09 14:21:19 -0500308 [sharingServicePicker showRelativeToRect:[sender bounds]
309 ofView:sender
310 preferredEdge:NSMinYEdge];
311}
312
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -0400313- (IBAction)toggleQRCode:(id)sender {
314 // Toggle pressed state of QRCode button
315 [sender setPressed:![sender isPressed]];
Kateryna Kostiuk65ba43e2017-03-30 15:10:04 -0400316 [self showQRCode:[sender isPressed]];
Alexandre Lision313427f2016-11-24 21:04:04 -0500317}
318
319/**
320 * Draw the QRCode in the qrCodeView
321 */
Kateryna Kostiuk65ba43e2017-03-30 15:10:04 -0400322- (void)drawQRCode:(NSString*) uriToDraw
Alexandre Lision313427f2016-11-24 21:04:04 -0500323{
Kateryna Kostiuk65ba43e2017-03-30 15:10:04 -0400324 auto qrCode = QRcode_encodeString(uriToDraw.UTF8String,
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -0400325 0,
326 QR_ECLEVEL_L, // Lowest level of error correction
327 QR_MODE_8, // 8-bit data mode
328 1);
329 if (!qrCode) {
330 return;
331 }
332
Alexandre Lision313427f2016-11-24 21:04:04 -0500333 unsigned char *data = 0;
334 int width;
335 data = qrCode->data;
336 width = qrCode->width;
337 int qr_margin = 3;
338
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -0400339 CGFloat size = qrcodeView.frame.size.width;
340
341 // create context
342 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
343 CGContextRef ctx = CGBitmapContextCreate(0, size, size, 8, size * 4, colorSpace, kCGImageAlphaPremultipliedLast);
344
345 CGAffineTransform translateTransform = CGAffineTransformMakeTranslation(0, -size);
346 CGAffineTransform scaleTransform = CGAffineTransformMakeScale(1, -1);
347 CGContextConcatCTM(ctx, CGAffineTransformConcat(translateTransform, scaleTransform));
348
Alexandre Lision313427f2016-11-24 21:04:04 -0500349 float zoom = ceil((double)size / (qrCode->width + 2.0 * qr_margin));
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -0400350 CGRect rectDraw = CGRectMake(0, 0, zoom, zoom);
351
352 int ran;
353 for(int i = 0; i < width; ++i) {
354 for(int j = 0; j < width; ++j) {
355 if(*data & 1) {
Kateryna Kostiuk394f74c2018-10-05 15:45:26 -0400356 CGContextSetFillColorWithColor(ctx, [NSColor labelColor].CGColor);
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -0400357 rectDraw.origin = CGPointMake((j + qr_margin) * zoom,(i + qr_margin) * zoom);
358 CGContextAddRect(ctx, rectDraw);
359 CGContextFillPath(ctx);
360 } else {
361 CGContextSetFillColorWithColor(ctx, [NSColor windowBackgroundColor].CGColor);
362 rectDraw.origin = CGPointMake((j + qr_margin) * zoom,(i + qr_margin) * zoom);
363 CGContextAddRect(ctx, rectDraw);
364 CGContextFillPath(ctx);
365 }
366 ++data;
367 }
368 }
Alexandre Lision313427f2016-11-24 21:04:04 -0500369
370 // get image
371 auto qrCGImage = CGBitmapContextCreateImage(ctx);
372 auto qrImage = [[NSImage alloc] initWithCGImage:qrCGImage size:qrcodeView.frame.size];
373
374 // some releases
375 CGContextRelease(ctx);
376 CGImageRelease(qrCGImage);
377 CGColorSpaceRelease(colorSpace);
378 QRcode_free(qrCode);
379
380 [qrcodeView setImage:qrImage];
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -0400381}
382
383/**
384 * Start the in/out animation displaying the QRCode
385 * @param show should the QRCode be animated in or out
386 */
387- (void) showQRCode:(BOOL) show
388{
389 static const NSInteger offset = 110;
390 [NSAnimationContext beginGrouping];
391 NSAnimationContext.currentContext.duration = 0.5;
392 [[NSAnimationContext currentContext] setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]];
393 qrcodeView.animator.alphaValue = show ? 1.0 : 0.0;
394 [centerYQRCodeConstraint.animator setConstant: show ? offset : 0];
395 [centerYWelcomeContainerConstraint.animator setConstant:show ? -offset : 0];
396 [NSAnimationContext endGrouping];
397}
398
Alexandre Lision4a7b95e2015-02-20 10:06:43 -0500399- (IBAction)openPreferences:(id)sender
400{
Kateryna Kostiukbb68a1c2018-06-12 15:16:02 -0400401 if (preferencesWC) {
402 [preferencesWC.window orderFront:preferencesWC.window];
403 return;
404 }
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400405
406 preferencesWC = [[PreferencesWC alloc] initWithWindowNibName: @"PreferencesWindow" bundle: nil accountModel:self.accountModel dataTransferModel:self.dataTransferModel behaviourController:self.behaviorController];
Alexandre Lisionbfa68f62015-09-10 08:38:42 -0400407 [preferencesWC.window makeKeyAndOrderFront:preferencesWC.window];
Alexandre Lision5855b6a2015-02-03 11:31:05 -0500408}
Alexandre Lision4a7b95e2015-02-20 10:06:43 -0500409
Kateryna Kostiuk882cbac2017-07-05 17:29:00 -0400410- (IBAction)callClickedAtRow:(id)sender
411{
412 NSTabViewItem *selectedTab = [smartViewVC.tabbar selectedTabViewItem];
413 int index = [smartViewVC.tabbar indexOfTabViewItem:selectedTab];
414 switch (index) {
415 case 0:
416 [smartViewVC startCallForRow:sender];
417 break;
Kateryna Kostiuk882cbac2017-07-05 17:29:00 -0400418 default:
419 break;
420 }
421}
Anthony Léonard0a9904c2018-01-11 16:43:47 -0500422
Alexandre Lision624b1a82016-09-11 19:29:01 -0400423#pragma mark - Ring account migration
424
425- (void) migrateRingAccount:(Account*) acc
426{
427 self.migrateWC = [[MigrateRingAccountsWC alloc] initWithDelegate:self actionCode:1];
428 self.migrateWC.account = acc;
429#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_9
430 [self.window beginSheet:self.migrateWC.window completionHandler:nil];
431#else
432 [NSApp beginSheet: self.migrateWC.window
433 modalForWindow: self.window
434 modalDelegate: self
435 didEndSelector: nil
436 contextInfo: nil];
437#endif
438}
439
Anthony Léonard49cb2912017-11-13 16:15:39 -0500440// TODO: Reimplement as a blocking loop when new LRC models handle migration
Alexandre Lision624b1a82016-09-11 19:29:01 -0400441- (void)checkAccountsToMigrate
442{
443 auto ringList = AccountModel::instance().accountsToMigrate();
444 if (ringList.length() > 0){
445 Account* acc = ringList.value(0);
446 [self migrateRingAccount:acc];
447 } else {
448 // Fresh run, we need to make sure RingID appears
Alexandre Lision624b1a82016-09-11 19:29:01 -0400449 [shareButton sendActionOn:NSLeftMouseDownMask];
450
451 [self connect];
Kateryna Kostiuka7248462017-04-18 16:15:31 -0400452 [self updateRingID];
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400453 // display accounts to select
454 NSToolbar *toolbar = self.window.toolbar;
455 toolbar.delegate = self;
456 [toolbar insertItemWithItemIdentifier:kChangeAccountToolBarItemIdentifier atIndex:1];
Alexandre Lision624b1a82016-09-11 19:29:01 -0400457 }
458}
459
460- (void)migrationDidComplete
461{
462 [self checkAccountsToMigrate];
463}
464
465- (void)migrationDidCompleteWithError
466{
467 [self checkAccountsToMigrate];
468}
469
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400470- (void) selectAccount:(const lrc::api::account::Info&)accInfo currentRemoved:(BOOL) removed
Anthony Léonard9bebf1d2017-12-21 14:33:51 -0500471{
472 // If the selected account has been changed, we close any open panel
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400473 [smartViewVC setConversationModel:accInfo.conversationModel.get()];
Anthony Léonard61e3dcf2017-12-27 12:19:52 -0500474 // Welcome view informations are also updated
475 [self updateRingID];
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400476 [settingsVC setSelectedAccount:accInfo.id];
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400477 [self changeViewTo: ([settingsVC.view isHidden] || removed) ? SHOW_WELCOME_SCREEN : SHOW_SETTINGS_SCREEN];
Anthony Léonard9bebf1d2017-12-21 14:33:51 -0500478}
479
Kateryna Kostiukab499f42018-04-16 12:27:33 -0400480-(void)allAccountsDeleted
481{
482 [smartViewVC clearConversationModel];
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400483 [self changeViewTo:SHOW_WELCOME_SCREEN];
Kateryna Kostiukab499f42018-04-16 12:27:33 -0400484 [self updateRingID];
485}
486
Anthony Léonard8585cc02017-12-28 14:03:45 -0500487-(void)rightPanelClosed
488{
489 [smartViewVC deselect];
Kateryna Kostiuk394f74c2018-10-05 15:45:26 -0400490 [welcomeContainer setHidden:NO];
Anthony Léonard8585cc02017-12-28 14:03:45 -0500491}
492
Anthony Léonard0a9904c2018-01-11 16:43:47 -0500493-(void)currentConversationTrusted
494{
495 [smartViewVC selectConversationList];
496}
497
Anthony Léonardbee94cc2018-01-16 11:42:40 -0500498-(void) listTypeChanged {
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400499 [self changeViewTo:SHOW_WELCOME_SCREEN];
Anthony Léonardbee94cc2018-01-16 11:42:40 -0500500}
501
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400502#pragma mark - NSToolbarDelegate
Kateryna Kostiukdb1f3a12017-04-24 12:08:28 -0400503- (nullable NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag
504{
505 if(itemIdentifier == kChangeAccountToolBarItemIdentifier) {
506 NSToolbarItem *toolbarItem = [[NSToolbarItem alloc] initWithItemIdentifier:kChangeAccountToolBarItemIdentifier];
Kateryna Kostiukd7e2e102018-10-01 13:33:38 -0400507 toolbarItem.maxSize = NSMakeSize(187, 30);
508 toolbarItem.minSize = NSMakeSize(187, 30);
Kateryna Kostiukdb1f3a12017-04-24 12:08:28 -0400509 toolbarItem.view = chooseAccountVC.view;
510 return toolbarItem;
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400511 } else if(itemIdentifier == kOpenAccountToolBarItemIdentifier) {
512 NSToolbarItem *toolbarItem = [[NSToolbarItem alloc] initWithItemIdentifier:kOpenAccountToolBarItemIdentifier];
Kateryna Kostiukd7e2e102018-10-01 13:33:38 -0400513 toolbarItem.maxSize = NSMakeSize(30, 30);
514 toolbarItem.minSize = NSMakeSize(30, 30);
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400515 HoverButton *openSettingsButton = [[HoverButton alloc] initWithFrame:CGRectMake(0, 0, 28, 28)];
516 openSettingsButton.bgColor = [NSColor clearColor];
517 openSettingsButton.imageColor = [NSColor darkGrayColor];
518 openSettingsButton.hoverColor = [NSColor controlHighlightColor];
519 openSettingsButton.highlightColor = [NSColor lightGrayColor];
520 openSettingsButton.imageInsets = 6;
521 openSettingsButton.title = @"";
522 [openSettingsButton setBordered: NO];
523 [openSettingsButton setTransparent:YES];
524 openSettingsButton.image = [NSImage imageNamed: NSImageNameSmartBadgeTemplate];
525 [openSettingsButton setAction:@selector(openAccountSettings:)];
526 [openSettingsButton setTarget:self];
527 toolbarItem.view = openSettingsButton;
528 return toolbarItem;
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400529 }
Kateryna Kostiukdb1f3a12017-04-24 12:08:28 -0400530 return nil;
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400531}
532
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400533- (IBAction)openAccountSettings:(NSButton *)sender
534{
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400535 [self changeViewTo: [settingsVC.view isHidden] ? SHOW_SETTINGS_SCREEN : SHOW_WELCOME_SCREEN];
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400536}
537
Kateryna Kostiukd73f9602018-07-24 13:51:28 -0400538- (void) createNewAccount {
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400539 [self changeViewTo:SHOW_WELCOME_SCREEN];
Kateryna Kostiukd73f9602018-07-24 13:51:28 -0400540 wizard = [[RingWizardWC alloc] initWithNibName:@"RingWizard" bundle: nil accountmodel: self.accountModel];
541 [wizard showChooseWithCancelButton: YES andAdvanced: YES];
542 [self.window beginSheet:wizard.window completionHandler:nil];
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400543}
544
545-(void) accountSettingsShouldOpen: (BOOL) open {
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400546
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400547 if (open) {
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400548 [settingsVC setSelectedAccount: [chooseAccountVC selectedAccount].id];
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400549 }
550 NSToolbar *toolbar = self.window.toolbar;
551 NSArray *settings = [toolbar items];
552
553 for(NSToolbarItem *toolbarItem in settings) {
554 if (toolbarItem.itemIdentifier == kOpenAccountToolBarItemIdentifier) {
555 HoverButton *openSettingsButton = [[HoverButton alloc] initWithFrame:CGRectMake(0, 0, 28, 28)];
556 openSettingsButton.bgColor = [NSColor clearColor];
557 openSettingsButton.imageColor = [NSColor darkGrayColor];
558 openSettingsButton.hoverColor = [NSColor controlHighlightColor];
559 openSettingsButton.highlightColor = [NSColor lightGrayColor];
560 openSettingsButton.imageInsets = 6;
561 openSettingsButton.title = @"";
562 [openSettingsButton setBordered: NO];
563 [openSettingsButton setTransparent:YES];
564 openSettingsButton.image = open ? [NSImage imageNamed: NSImageNameMenuOnStateTemplate] : [NSImage imageNamed: NSImageNameSmartBadgeTemplate];
565 [openSettingsButton setAction:@selector(openAccountSettings:)];
566 [openSettingsButton setTarget:self];
567 toolbarItem.view = openSettingsButton;
568 }
569 }
Kateryna Kostiukd73f9602018-07-24 13:51:28 -0400570}
571
Alexandre Lision5855b6a2015-02-03 11:31:05 -0500572@end