blob: 4d26b6859ef10482dcb3b8e79228f0d2d0709b55 [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>
Alexandre Lision0f66bd32016-01-18 11:30:45 -050022
Alexandre Lisionbb5c2462015-07-30 12:55:37 -040023//LRC
Anthony Léonard79597602017-11-13 15:47:09 -050024#import <api/lrc.h>
Anthony Léonard49cb2912017-11-13 16:15:39 -050025#import <api/account.h>
Olivier Soldano994971f2017-12-05 16:30:12 -050026#import <api/newaccountmodel.h>
27#import <api/newcallmodel.h>
28#import <api/behaviorcontroller.h>
29#import <api/conversation.h>
Anthony Léonardd00cd182018-01-17 09:21:27 -050030#import <api/contactmodel.h>
31#import <api/contact.h>
Kateryna Kostiuk67735232018-05-10 15:05:32 -040032#import <api/datatransfermodel.h>
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -040033#import <api/avmodel.h>
Alexandre Lision5855b6a2015-02-03 11:31:05 -050034
Alexandre Lision624b1a82016-09-11 19:29:01 -040035// Ring
Alexandre Lision745e4d62015-03-22 20:03:10 -040036#import "AppDelegate.h"
Alexandre Lisionc65310c2015-04-23 16:44:23 -040037#import "Constants.h"
Alexandre Lision58cab672015-06-09 15:25:40 -040038#import "CurrentCallVC.h"
Alexandre Lision624b1a82016-09-11 19:29:01 -040039#import "MigrateRingAccountsWC.h"
Alexandre Lision0f66bd32016-01-18 11:30:45 -050040#import "ConversationVC.h"
Alexandre Lisionbfa68f62015-09-10 08:38:42 -040041#import "PreferencesWC.h"
Alexandre Lisiona3a43dc2017-03-30 16:21:30 -040042#import "SmartViewVC.h"
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -040043#import "views/IconButton.h"
Alexandre Lisionbfa68f62015-09-10 08:38:42 -040044#import "views/NSColor+RingTheme.h"
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -040045#import "views/HoverButton.h"
Kateryna Kostiuk74fe20c2018-06-14 12:05:53 -040046#import "utils.h"
Kateryna Kostiukd73f9602018-07-24 13:51:28 -040047#import "RingWizardWC.h"
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -040048#import "AccountSettingsVC.h"
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -040049
50typedef NS_ENUM(NSInteger, ViewState) {
51 SHOW_WELCOME_SCREEN = 0,
52 SHOW_CONVERSATION_SCREEN,
53 SHOW_CALL_SCREEN,
54 SHOW_SETTINGS_SCREEN,
Kateryna Kostiukf6317422018-09-27 17:08:20 -040055 LEAVE_MESSAGE,
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -040056};
Alexandre Lision2db8f472015-07-22 15:05:46 -040057
Kateryna Kostiukef66f972018-11-02 17:10:37 -040058@interface RingWindowController () <MigrateRingAccountsDelegate>
Alexandre Lision624b1a82016-09-11 19:29:01 -040059
60@property (retain) MigrateRingAccountsWC* migrateWC;
Kateryna Kostiukd73f9602018-07-24 13:51:28 -040061@property RingWizardWC* wizard;
Kateryna Kostiuk4db61092019-10-17 16:57:40 -040062@property QMetaObject::Connection callState;
Alexandre Lision624b1a82016-09-11 19:29:01 -040063
64@end
65
Alexandre Lisionbfa68f62015-09-10 08:38:42 -040066@implementation RingWindowController {
Alexandre Lision5855b6a2015-02-03 11:31:05 -050067
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -040068 __unsafe_unretained IBOutlet NSLayoutConstraint* centerYQRCodeConstraint;
69 __unsafe_unretained IBOutlet NSLayoutConstraint* centerYWelcomeContainerConstraint;
Kateryna Kostiukab499f42018-04-16 12:27:33 -040070 IBOutlet NSLayoutConstraint* ringLabelTrailingConstraint;
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -040071 __unsafe_unretained IBOutlet NSView* welcomeContainer;
Alexandre Lision1abdf582016-02-09 14:21:19 -050072 __unsafe_unretained IBOutlet NSView* callView;
73 __unsafe_unretained IBOutlet NSTextField* ringIDLabel;
Kateryna Kostiuk85a334e2018-12-03 15:54:19 -050074 __unsafe_unretained IBOutlet NSTextField* explanationLabel;
Alexandre Lision1abdf582016-02-09 14:21:19 -050075 __unsafe_unretained IBOutlet NSButton* shareButton;
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -040076 __unsafe_unretained IBOutlet NSImageView* qrcodeView;
Alexandre Lision58cab672015-06-09 15:25:40 -040077
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -040078 PreferencesWC* preferencesWC;
Alexandre Lisiona3a43dc2017-03-30 16:21:30 -040079 IBOutlet SmartViewVC* smartViewVC;
Alexandre Lisione77f6f92016-04-17 23:39:39 -040080
Alexandre Lision0f66bd32016-01-18 11:30:45 -050081 CurrentCallVC* currentCallVC;
Andreas Traczykecdc4fa2018-03-22 16:11:47 -040082 ConversationVC* conversationVC;
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -040083 AccountSettingsVC* settingsVC;
Andreas Traczykecdc4fa2018-03-22 16:11:47 -040084
Kateryna Kostiukef66f972018-11-02 17:10:37 -040085 IBOutlet ChooseAccountVC* chooseAccountVC;
Alexandre Lisionbfa68f62015-09-10 08:38:42 -040086}
Alexandre Lision58cab672015-06-09 15:25:40 -040087
Kateryna Kostiukf6317422018-09-27 17:08:20 -040088@synthesize dataTransferModel, accountModel, behaviorController, avModel;
Kateryna Kostiukd73f9602018-07-24 13:51:28 -040089@synthesize wizard;
Kateryna Kostiukecaa3952018-07-13 16:00:34 -040090
Kateryna Kostiukf6317422018-09-27 17:08:20 -040091-(id) initWithWindowNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil accountModel:( lrc::api::NewAccountModel*)accountModel dataTransferModel:( lrc::api::DataTransferModel*)dataTransferModel behaviourController:( lrc::api::BehaviorController*) behaviorController avModel: (lrc::api::AVModel*)avModel
Kateryna Kostiukecaa3952018-07-13 16:00:34 -040092{
93 if (self = [self initWithWindowNibName:nibNameOrNil])
94 {
95 self.accountModel = accountModel;
96 self.dataTransferModel = dataTransferModel;
97 self.behaviorController = behaviorController;
Kateryna Kostiukf6317422018-09-27 17:08:20 -040098 self.avModel = avModel;
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -040099 self.avModel->useAVFrame(YES);
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400100 }
101 return self;
102}
103
Kateryna Kostiukef66f972018-11-02 17:10:37 -0400104- (NSApplicationPresentationOptions)window:(NSWindow *)window willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions
105{
106 return (NSApplicationPresentationFullScreen |
107 NSApplicationPresentationAutoHideMenuBar |
108 NSApplicationPresentationAutoHideToolbar);
109}
110
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400111-(void)changeViewTo:(ViewState) state {
112 switch (state) {
113 case SHOW_WELCOME_SCREEN:
114 [self accountSettingsShouldOpen: NO];
115 [conversationVC hideWithAnimation:false];
116 [currentCallVC hideWithAnimation:false];
Kateryna Kostiuk4f37d952018-12-04 13:19:17 -0500117 [currentCallVC cleanUp];
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400118 [currentCallVC.view removeFromSuperview];
119 [welcomeContainer setHidden: NO];
120 [smartViewVC.view setHidden: NO];
121 [settingsVC hide];
122 break;
123 case SHOW_CONVERSATION_SCREEN:
124 [self accountSettingsShouldOpen: NO];
125 [conversationVC showWithAnimation:false];
126 [currentCallVC hideWithAnimation:false];
Kateryna Kostiuk4f37d952018-12-04 13:19:17 -0500127 [currentCallVC cleanUp];
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400128 [currentCallVC.view removeFromSuperview];
129 [welcomeContainer setHidden: YES];
130 [smartViewVC.view setHidden: NO];
131 [settingsVC hide];
132 break;
133 case SHOW_CALL_SCREEN:
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400134 self.avModel->useAVFrame(YES);
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400135 [self accountSettingsShouldOpen: NO];
136 if (![currentCallVC.view superview]) {
137 [callView addSubview:[currentCallVC view] positioned:NSWindowAbove relativeTo:nil];
138 [currentCallVC initFrame];
139 [currentCallVC showWithAnimation:false];
140 [conversationVC hideWithAnimation:false];
141 [welcomeContainer setHidden: YES];
142 [smartViewVC.view setHidden: NO];
143 [settingsVC hide];
144 }
145 [currentCallVC showWithAnimation:false];
146 break;
147 case SHOW_SETTINGS_SCREEN:
148 @try {
149 [self accountSettingsShouldOpen: YES];
150 }
151 @catch (NSException *ex) {
152 return;
153 }
154 [welcomeContainer setHidden: YES];
155 [currentCallVC hideWithAnimation:false];
156 [currentCallVC.view removeFromSuperview];
157 [conversationVC hideWithAnimation:false];
158 [smartViewVC.view setHidden: YES];
159 [settingsVC show];
160 break;
Kateryna Kostiukf6317422018-09-27 17:08:20 -0400161 case LEAVE_MESSAGE:
162 [conversationVC showWithAnimation: false];
163 [currentCallVC hideWithAnimation: false];
164 [conversationVC presentLeaveMessageView];
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400165 default:
166 break;
167 }
168}
169
Alexandre Lision5855b6a2015-02-03 11:31:05 -0500170- (void)windowDidLoad {
171 [super windowDidLoad];
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400172 [self.window setMovableByWindowBackground:YES];
Alexandre Lision58cab672015-06-09 15:25:40 -0400173
Kateryna Kostiuk13b76882017-03-30 09:18:44 -0400174 self.window.titleVisibility = NSWindowTitleHidden;
“Kateryna”a4d72772020-04-08 11:30:27 -0400175 self.window.titlebarAppearsTransparent = true;
Alexandre Lisione77f6f92016-04-17 23:39:39 -0400176
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500177 currentCallVC = [[CurrentCallVC alloc] initWithNibName:@"CurrentCall" bundle:nil];
Kateryna Kostiuk133364b2018-10-31 11:36:08 -0400178 currentCallVC.delegate = self;
Kateryna Kostiukf6317422018-09-27 17:08:20 -0400179 conversationVC = [[ConversationVC alloc] initWithNibName:@"Conversation" bundle:nil delegate:self aVModel:self.avModel];
Kateryna Kostiukef66f972018-11-02 17:10:37 -0400180 [chooseAccountVC updateWithDelegate: self andModel:self.accountModel];
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400181 settingsVC = [[AccountSettingsVC alloc] initWithNibName:@"AccountSettings" bundle:nil accountmodel:self.accountModel];
Alexandre Lision58cab672015-06-09 15:25:40 -0400182 [callView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
Kateryna Kostiukc24e0f92019-10-02 13:37:16 -0400183 [[currentCallVC view] setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400184 [[conversationVC view] setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400185 [[settingsVC view] setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
Alexandre Lision58cab672015-06-09 15:25:40 -0400186
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400187 [callView addSubview:[conversationVC view] positioned:NSWindowAbove relativeTo:nil];
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400188 [self.window.contentView addSubview:[settingsVC view] positioned:NSWindowAbove relativeTo:nil];
Alexandre Lision16d9c0a2015-08-10 12:05:15 -0400189
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400190 [conversationVC initFrame];
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400191 [settingsVC initFrame];
Alexandre Lisionbb5c2462015-07-30 12:55:37 -0400192
Kateryna Kostiukbe7e2e42019-07-26 17:44:12 -0400193 [self checkAccountsToMigrate];
Anthony Léonard49cb2912017-11-13 16:15:39 -0500194
Kateryna Kostiuk74fe20c2018-06-14 12:05:53 -0400195 // set download folder (default - 'Documents')
Kateryna Kostiuk67735232018-05-10 15:05:32 -0400196 NSString* path = [[NSUserDefaults standardUserDefaults] stringForKey:Preferences::DownloadFolder];
197 if (!path || path.length == 0) {
Kateryna Kostiuk74fe20c2018-06-14 12:05:53 -0400198 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
199 path = [[paths objectAtIndex:0] stringByAppendingString:@"/"];
Kateryna Kostiuk67735232018-05-10 15:05:32 -0400200 }
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400201 self.dataTransferModel->downloadDirectory = QString::fromNSString(path);
Kateryna Kostiuk74fe20c2018-06-14 12:05:53 -0400202 if(appSandboxed()) {
203 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400204 avModel->setRecordPath(QString::fromNSString([paths objectAtIndex:0]));
205 } else if (avModel->getRecordPath().isEmpty()) {
206 avModel->setRecordPath(QString::fromNSString(NSHomeDirectory()));
Kateryna Kostiuk74fe20c2018-06-14 12:05:53 -0400207 }
Kateryna Kostiukef66f972018-11-02 17:10:37 -0400208 NSToolbar *tb = [[self window] toolbar];
209 [tb setAllowsUserCustomization:NO];
Kateryna Kostiukf6317422018-09-27 17:08:20 -0400210
211 //add messages view controller to responders chain
212 NSResponder * viewNextResponder = [self nextResponder];
213 [self setNextResponder: [conversationVC getMessagesView]];
214 [[conversationVC getMessagesView] setNextResponder: viewNextResponder];
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500215}
216
217- (void) connect
218{
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400219 QObject::connect(self.behaviorController,
Olivier Soldano994971f2017-12-05 16:30:12 -0500220 &lrc::api::BehaviorController::showCallView,
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400221 [self](const QString& accountId,
Olivier Soldano994971f2017-12-05 16:30:12 -0500222 const lrc::api::conversation::Info convInfo){
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400223 auto* accInfo = &self.accountModel->getAccountInfo(accountId);
224 try {
225 if (accInfo->contactModel->getContact(convInfo.participants[0]).profileInfo.type == lrc::api::profile::Type::PENDING)
226 [smartViewVC selectPendingList];
227 else
228 [smartViewVC selectConversationList];
Anthony Léonardd00cd182018-01-17 09:21:27 -0500229
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400230 [currentCallVC setCurrentCall:convInfo.callId
231 conversation:convInfo.uid
232 account:accInfo
233 avModel: avModel];
234 [self changeViewTo:SHOW_CALL_SCREEN];
235 [conversationVC setConversationUid:convInfo.uid model:accInfo->conversationModel.get()];
236 } catch (std::out_of_range& e) {
237 NSLog(@"contact out of range");
238 }
239 });
Alexandre Lision210fe212016-01-27 11:15:13 -0500240
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400241 QObject::connect(self.behaviorController,
Olivier Soldano994971f2017-12-05 16:30:12 -0500242 &lrc::api::BehaviorController::showIncomingCallView,
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400243 [self](const QString& accountId,
Olivier Soldano994971f2017-12-05 16:30:12 -0500244 const lrc::api::conversation::Info convInfo){
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400245 auto* accInfo = &self.accountModel->getAccountInfo(accountId);
246 try {
247 if (accInfo->contactModel->getContact(convInfo.participants[0]).profileInfo.type == lrc::api::profile::Type::PENDING)
248 [smartViewVC selectPendingList];
249 else
250 [smartViewVC selectConversationList];
251 [currentCallVC setCurrentCall:convInfo.callId
252 conversation:convInfo.uid
253 account:accInfo
254 avModel: avModel];
255 [smartViewVC selectConversation: convInfo model:accInfo->conversationModel.get()];
256 [self changeViewTo:SHOW_CALL_SCREEN];
257 [conversationVC setConversationUid:convInfo.uid model:accInfo->conversationModel.get()];
258 } catch (std::out_of_range& e) {
259 NSLog(@"contact out of range");
260 }
261 });
Anthony Léonard2382b562017-12-13 15:51:28 -0500262
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400263 QObject::connect(self.behaviorController,
Anthony Léonard2382b562017-12-13 15:51:28 -0500264 &lrc::api::BehaviorController::showChatView,
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400265 [self](const QString& accountId,
Anthony Léonard2382b562017-12-13 15:51:28 -0500266 const lrc::api::conversation::Info& convInfo){
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400267 auto& accInfo = self.accountModel->getAccountInfo(accountId);
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400268 [conversationVC setConversationUid:convInfo.uid model:accInfo.conversationModel.get()];
Anthony Léonard9bebf1d2017-12-21 14:33:51 -0500269 [smartViewVC selectConversation: convInfo model:accInfo.conversationModel.get()];
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400270 [self changeViewTo:SHOW_CONVERSATION_SCREEN];
Anthony Léonard2382b562017-12-13 15:51:28 -0500271 });
Kateryna Kostiukf6317422018-09-27 17:08:20 -0400272 QObject::connect(self.behaviorController,
273 &lrc::api::BehaviorController::showLeaveMessageView,
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400274 [self](const QString& accountId,
Kateryna Kostiukf6317422018-09-27 17:08:20 -0400275 const lrc::api::conversation::Info& convInfo){
276 auto& accInfo = self.accountModel->getAccountInfo(accountId);
277 [conversationVC setConversationUid:convInfo.uid model:accInfo.conversationModel.get()];
278 [smartViewVC selectConversation: convInfo model:accInfo.conversationModel.get()];
279 [self changeViewTo:LEAVE_MESSAGE];
280 });
Alexandre Lisionbb5c2462015-07-30 12:55:37 -0400281}
282
Kateryna Kostiukbe7e2e42019-07-26 17:44:12 -0400283#pragma mark - Ring account migration
284
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400285- (void) migrateRingAccount:(const QString&) acc
Kateryna Kostiukbe7e2e42019-07-26 17:44:12 -0400286{
287 self.migrateWC = [[MigrateRingAccountsWC alloc] initWithDelegate:self actionCode:1];
288 self.migrateWC.accountModel = self.accountModel;
289 self.migrateWC.accountToMigrate = acc;
290 [self.window beginSheet:self.migrateWC.window completionHandler:nil];
291}
292
293- (void)checkAccountsToMigrate
294{
295 auto accounts = self.accountModel->getAccountList();
296 for (auto accountId: accounts) {
297 const lrc::api::account::Info& accountInfo = self.accountModel->getAccountInfo(accountId);
298 if (accountInfo.status == lrc::api::account::Status::ERROR_NEED_MIGRATION) {
299 [self migrateRingAccount:accountInfo.id];
300 return;
301 }
302 }
303 @try {
304 [smartViewVC setConversationModel: [chooseAccountVC selectedAccount].conversationModel.get()];
305 }
306 @catch (NSException *ex) {
307 NSLog(@"Caught exception %@: %@", [ex name], [ex reason]);
308 }
309 [shareButton sendActionOn:NSLeftMouseDownMask];
310 [self connect];
311 [self updateRingID];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400312 [self connectCallSignalsForAccount];
313}
314
315- (void)connectCallSignalsForAccount
316{
317 @try {
318 auto& account = [chooseAccountVC selectedAccount];
319 QObject::disconnect(self.callState);
320 auto *callModel = account.callModel.get();
321 self.callState = QObject::connect(callModel,
322 &lrc::api::NewCallModel::callStatusChanged,
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400323 [self, callModel](const QString& callId) {
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400324 if (callModel->hasCall(callId)) {
325 auto call = callModel->getCall(callId);
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400326 [smartViewVC reloadConversationWithURI: call.peerUri.toNSString()];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400327 }
328 });
329 } @catch (NSException *ex) {
330 }
Kateryna Kostiukbe7e2e42019-07-26 17:44:12 -0400331}
332
333- (void)migrationDidComplete
334{
335 [self checkAccountsToMigrate];
336}
337
338- (void)migrationDidCompleteWithError
339{
340 [self checkAccountsToMigrate];
341}
342
Alexandre Lisionbb5c2462015-07-30 12:55:37 -0400343/**
344 * Implement the necessary logic to choose which Ring ID to display.
345 * This tries to choose the "best" ID to show
346 */
347- (void) updateRingID
348{
Anthony Léonard72128c92017-12-26 16:48:39 -0500349 @try {
350 auto& account = [chooseAccountVC selectedAccount];
Alexandre Lisionbb5c2462015-07-30 12:55:37 -0400351
Anthony Léonard72128c92017-12-26 16:48:39 -0500352 [ringIDLabel setStringValue:@""];
Anthony Léonard49cb2912017-11-13 16:15:39 -0500353
Anthony Léonard72128c92017-12-26 16:48:39 -0500354 if(account.profileInfo.type != lrc::api::profile::Type::RING) {
Kateryna Kostiukab499f42018-04-16 12:27:33 -0400355 self.notRingAccount = YES;
356 self.isSIPAccount = YES;
Anthony Léonard72128c92017-12-26 16:48:39 -0500357 return;
358 }
Kateryna Kostiukab499f42018-04-16 12:27:33 -0400359 self.isSIPAccount = NO;
360 self.notRingAccount = NO;
361 [ringLabelTrailingConstraint setActive:YES];
Anthony Léonard72128c92017-12-26 16:48:39 -0500362 auto& registeredName = account.registeredName;
363 auto& ringID = account.profileInfo.uri;
364 NSString* uriToDisplay = nullptr;
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400365 if (!registeredName.isEmpty()) {
366 uriToDisplay = registeredName.toNSString();
Kateryna Kostiuk85a334e2018-12-03 15:54:19 -0500367 [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 -0500368 } else {
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400369 uriToDisplay = ringID.toNSString();
Kateryna Kostiuk85a334e2018-12-03 15:54:19 -0500370 [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 -0500371 }
372 [ringIDLabel setStringValue:uriToDisplay];
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400373 [self drawQRCode: ringID.toNSString()];
Alexandre Lisionbb5c2462015-07-30 12:55:37 -0400374 }
Anthony Léonard72128c92017-12-26 16:48:39 -0500375 @catch (NSException *ex) {
376 NSLog(@"Caught exception %@: %@", [ex name], [ex reason]);
Kateryna Kostiukab499f42018-04-16 12:27:33 -0400377 self.notRingAccount = YES;
378 self.isSIPAccount = NO;
379 [ringLabelTrailingConstraint setActive:NO];
Anthony Léonard70638f02018-02-05 11:10:19 -0500380 [ringIDLabel setStringValue:NSLocalizedString(@"No account available", @"Displayed as RingID when no accounts are available for selection")];
Alexandre Lision313427f2016-11-24 21:04:04 -0500381 }
Alexandre Lision5855b6a2015-02-03 11:31:05 -0500382}
383
Alexandre Lision1abdf582016-02-09 14:21:19 -0500384- (IBAction)shareRingID:(id)sender {
385 NSSharingServicePicker* sharingServicePicker = [[NSSharingServicePicker alloc] initWithItems:[NSArray arrayWithObject:[ringIDLabel stringValue]]];
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -0400386 [sharingServicePicker setDelegate:self];
Alexandre Lision1abdf582016-02-09 14:21:19 -0500387 [sharingServicePicker showRelativeToRect:[sender bounds]
388 ofView:sender
389 preferredEdge:NSMinYEdge];
390}
391
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -0400392- (IBAction)toggleQRCode:(id)sender {
393 // Toggle pressed state of QRCode button
Kateryna Kostiuk85a334e2018-12-03 15:54:19 -0500394 // [sender setPressed:![sender isPressed]];
395 bool show = qrcodeView.animator.alphaValue == 0.0f ? YES: NO;
396 [self showQRCode: show];
Alexandre Lision313427f2016-11-24 21:04:04 -0500397}
398
399/**
400 * Draw the QRCode in the qrCodeView
401 */
Kateryna Kostiuk65ba43e2017-03-30 15:10:04 -0400402- (void)drawQRCode:(NSString*) uriToDraw
Alexandre Lision313427f2016-11-24 21:04:04 -0500403{
Kateryna Kostiuk65ba43e2017-03-30 15:10:04 -0400404 auto qrCode = QRcode_encodeString(uriToDraw.UTF8String,
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -0400405 0,
406 QR_ECLEVEL_L, // Lowest level of error correction
407 QR_MODE_8, // 8-bit data mode
408 1);
409 if (!qrCode) {
410 return;
411 }
412
Alexandre Lision313427f2016-11-24 21:04:04 -0500413 unsigned char *data = 0;
414 int width;
415 data = qrCode->data;
416 width = qrCode->width;
417 int qr_margin = 3;
418
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -0400419 CGFloat size = qrcodeView.frame.size.width;
420
421 // create context
422 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
423 CGContextRef ctx = CGBitmapContextCreate(0, size, size, 8, size * 4, colorSpace, kCGImageAlphaPremultipliedLast);
424
425 CGAffineTransform translateTransform = CGAffineTransformMakeTranslation(0, -size);
426 CGAffineTransform scaleTransform = CGAffineTransformMakeScale(1, -1);
427 CGContextConcatCTM(ctx, CGAffineTransformConcat(translateTransform, scaleTransform));
428
Alexandre Lision313427f2016-11-24 21:04:04 -0500429 float zoom = ceil((double)size / (qrCode->width + 2.0 * qr_margin));
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -0400430 CGRect rectDraw = CGRectMake(0, 0, zoom, zoom);
431
432 int ran;
433 for(int i = 0; i < width; ++i) {
434 for(int j = 0; j < width; ++j) {
435 if(*data & 1) {
Kateryna Kostiukbf899502019-09-25 11:25:45 -0400436 CGContextSetFillColorWithColor(ctx, [NSColor blackColor].CGColor);
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -0400437 rectDraw.origin = CGPointMake((j + qr_margin) * zoom,(i + qr_margin) * zoom);
438 CGContextAddRect(ctx, rectDraw);
439 CGContextFillPath(ctx);
440 } else {
Kateryna Kostiuke28a0382019-10-25 16:29:08 -0400441 CGContextSetFillColorWithColor(ctx, [NSColor clearColor].CGColor);
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -0400442 rectDraw.origin = CGPointMake((j + qr_margin) * zoom,(i + qr_margin) * zoom);
443 CGContextAddRect(ctx, rectDraw);
444 CGContextFillPath(ctx);
445 }
446 ++data;
447 }
448 }
Alexandre Lision313427f2016-11-24 21:04:04 -0500449
450 // get image
451 auto qrCGImage = CGBitmapContextCreateImage(ctx);
452 auto qrImage = [[NSImage alloc] initWithCGImage:qrCGImage size:qrcodeView.frame.size];
453
454 // some releases
455 CGContextRelease(ctx);
456 CGImageRelease(qrCGImage);
457 CGColorSpaceRelease(colorSpace);
458 QRcode_free(qrCode);
459
460 [qrcodeView setImage:qrImage];
Alexandre Lisionfd0d6c82016-03-29 17:06:54 -0400461}
462
463/**
464 * Start the in/out animation displaying the QRCode
465 * @param show should the QRCode be animated in or out
466 */
467- (void) showQRCode:(BOOL) show
468{
469 static const NSInteger offset = 110;
470 [NSAnimationContext beginGrouping];
471 NSAnimationContext.currentContext.duration = 0.5;
472 [[NSAnimationContext currentContext] setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]];
473 qrcodeView.animator.alphaValue = show ? 1.0 : 0.0;
474 [centerYQRCodeConstraint.animator setConstant: show ? offset : 0];
475 [centerYWelcomeContainerConstraint.animator setConstant:show ? -offset : 0];
476 [NSAnimationContext endGrouping];
477}
478
Alexandre Lision4a7b95e2015-02-20 10:06:43 -0500479- (IBAction)openPreferences:(id)sender
480{
Kateryna Kostiukbb68a1c2018-06-12 15:16:02 -0400481 if (preferencesWC) {
482 [preferencesWC.window orderFront:preferencesWC.window];
483 return;
484 }
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400485
Kateryna Kostiukc3fc76c2019-01-06 22:12:34 -0500486 preferencesWC = [[PreferencesWC alloc] initWithWindowNibName: @"PreferencesWindow" bundle: nil accountModel:self.accountModel dataTransferModel:self.dataTransferModel behaviourController:self.behaviorController avModel: self.avModel];
Alexandre Lisionbfa68f62015-09-10 08:38:42 -0400487 [preferencesWC.window makeKeyAndOrderFront:preferencesWC.window];
Alexandre Lision5855b6a2015-02-03 11:31:05 -0500488}
Alexandre Lision4a7b95e2015-02-20 10:06:43 -0500489
Kateryna Kostiuk882cbac2017-07-05 17:29:00 -0400490- (IBAction)callClickedAtRow:(id)sender
491{
492 NSTabViewItem *selectedTab = [smartViewVC.tabbar selectedTabViewItem];
493 int index = [smartViewVC.tabbar indexOfTabViewItem:selectedTab];
494 switch (index) {
495 case 0:
496 [smartViewVC startCallForRow:sender];
497 break;
Kateryna Kostiuk882cbac2017-07-05 17:29:00 -0400498 default:
499 break;
500 }
501}
Anthony Léonard0a9904c2018-01-11 16:43:47 -0500502
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400503- (void) selectAccount:(const lrc::api::account::Info&)accInfo currentRemoved:(BOOL) removed
Anthony Léonard9bebf1d2017-12-21 14:33:51 -0500504{
505 // If the selected account has been changed, we close any open panel
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400506 [smartViewVC setConversationModel:accInfo.conversationModel.get()];
Anthony Léonard61e3dcf2017-12-27 12:19:52 -0500507 // Welcome view informations are also updated
508 [self updateRingID];
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400509 [settingsVC setSelectedAccount:accInfo.id];
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400510 [self changeViewTo: ([settingsVC.view isHidden] || removed) ? SHOW_WELCOME_SCREEN : SHOW_SETTINGS_SCREEN];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400511 [self connectCallSignalsForAccount];
Anthony Léonard9bebf1d2017-12-21 14:33:51 -0500512}
513
Kateryna Kostiukab499f42018-04-16 12:27:33 -0400514-(void)allAccountsDeleted
515{
516 [smartViewVC clearConversationModel];
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400517 [self changeViewTo:SHOW_WELCOME_SCREEN];
Kateryna Kostiukab499f42018-04-16 12:27:33 -0400518 [self updateRingID];
Kateryna Kostiukb0db48e2019-01-10 16:03:55 -0500519 qrcodeView.animator.alphaValue = 0.0;
520 [centerYQRCodeConstraint.animator setConstant: 0];
521 [centerYWelcomeContainerConstraint.animator setConstant: 0];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400522 QObject::disconnect(self.callState);
Kateryna Kostiukb0db48e2019-01-10 16:03:55 -0500523 [self close];
524 AppDelegate* delegate = (AppDelegate*)[[NSApplication sharedApplication] delegate];
525 [delegate showWizard];
Kateryna Kostiukab499f42018-04-16 12:27:33 -0400526}
527
Anthony Léonard8585cc02017-12-28 14:03:45 -0500528-(void)rightPanelClosed
529{
530 [smartViewVC deselect];
Kateryna Kostiuk394f74c2018-10-05 15:45:26 -0400531 [welcomeContainer setHidden:NO];
Anthony Léonard8585cc02017-12-28 14:03:45 -0500532}
533
Anthony Léonard0a9904c2018-01-11 16:43:47 -0500534-(void)currentConversationTrusted
535{
536 [smartViewVC selectConversationList];
537}
538
Anthony Léonardbee94cc2018-01-16 11:42:40 -0500539-(void) listTypeChanged {
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400540 [self changeViewTo:SHOW_WELCOME_SCREEN];
Anthony Léonardbee94cc2018-01-16 11:42:40 -0500541}
542
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400543- (IBAction)openAccountSettings:(NSButton *)sender
544{
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400545 [self changeViewTo: [settingsVC.view isHidden] ? SHOW_SETTINGS_SCREEN : SHOW_WELCOME_SCREEN];
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400546}
547
Kateryna Kostiukd73f9602018-07-24 13:51:28 -0400548- (void) createNewAccount {
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400549 [self changeViewTo:SHOW_WELCOME_SCREEN];
Kateryna Kostiukd73f9602018-07-24 13:51:28 -0400550 wizard = [[RingWizardWC alloc] initWithNibName:@"RingWizard" bundle: nil accountmodel: self.accountModel];
Kateryna Kostiukc7e68f32019-10-09 16:15:45 -0400551 [wizard showChooseWithCancelButton: YES];
Kateryna Kostiukd73f9602018-07-24 13:51:28 -0400552 [self.window beginSheet:wizard.window completionHandler:nil];
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400553}
554
Kateryna Kostiuk23222fe2018-11-16 14:28:02 -0500555- (NSRect)window:(NSWindow *)window willPositionSheet:(NSWindow *)sheet
556 usingRect:(NSRect)rect
557{
558 float titleBarHeight = self.window.frame.size.height - [NSWindow contentRectForFrameRect:self.window.frame styleMask:self.window.styleMask].size.height;
559 rect.origin.y = self.window.frame.size.height;
560 return rect;
561}
562
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400563-(void) accountSettingsShouldOpen: (BOOL) open {
564 if (open) {
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400565 [settingsVC setSelectedAccount: [chooseAccountVC selectedAccount].id];
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400566 }
Kateryna Kostiukd73f9602018-07-24 13:51:28 -0400567}
568
Kateryna Kostiuk133364b2018-10-31 11:36:08 -0400569#pragma mark - CallViewControllerDelegate
570
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400571-(void) conversationInfoUpdatedFor:(const QString&) conversationID {
572 [smartViewVC reloadConversationWithUid:conversationID.toNSString()];
Kateryna Kostiuk133364b2018-10-31 11:36:08 -0400573}
574
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400575-(void) callFinished {
576 [self changeViewTo:SHOW_CONVERSATION_SCREEN];
577}
578
Kateryna Kostiuke3503842018-12-12 16:39:45 -0500579-(void) showConversation:(NSString* )conversationId forAccount:(NSString*)accountId {
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400580 auto& accInfo = self.accountModel->getAccountInfo(QString::fromNSString(accountId));
Kateryna Kostiuke3503842018-12-12 16:39:45 -0500581 [chooseAccountVC selectAccount: accountId];
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400582 [settingsVC setSelectedAccount: QString::fromNSString(accountId)];
Kateryna Kostiuke3503842018-12-12 16:39:45 -0500583 [smartViewVC setConversationModel:accInfo.conversationModel.get()];
584 [smartViewVC selectConversationList];
585 [self updateRingID];
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400586 auto convInfo = getConversationFromUid(QString::fromNSString(conversationId), *accInfo.conversationModel.get());
Kateryna Kostiuke3503842018-12-12 16:39:45 -0500587 auto convQueue = accInfo.conversationModel.get()->allFilteredConversations();
588 if (convInfo != convQueue.end()) {
589 [conversationVC setConversationUid:convInfo->uid model:accInfo.conversationModel.get()];
590 [smartViewVC selectConversation: *convInfo model:accInfo.conversationModel.get()];
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400591 accInfo.conversationModel.get()->clearUnreadInteractions(QString::fromNSString(conversationId));
Kateryna Kostiuke3503842018-12-12 16:39:45 -0500592 }
593 [self changeViewTo:SHOW_CONVERSATION_SCREEN];
594}
595
596-(void) showCall:(NSString* )callId forAccount:(NSString*)accountId forConversation:(NSString*)conversationId {
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400597 auto& accInfo = self.accountModel->getAccountInfo(QString::fromNSString(accountId));
Kateryna Kostiuke3503842018-12-12 16:39:45 -0500598 [chooseAccountVC selectAccount: accountId];
599 [settingsVC setSelectedAccount:accInfo.id];
600 [smartViewVC setConversationModel:accInfo.conversationModel.get()];
601 [self updateRingID];
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400602 auto convInfo = getConversationFromUid(QString::fromNSString(conversationId), *accInfo.conversationModel.get());
Kateryna Kostiuke3503842018-12-12 16:39:45 -0500603 auto convQueue = accInfo.conversationModel.get()->allFilteredConversations();
604 if (convInfo != convQueue.end()) {
605 if (accInfo.contactModel->getContact(convInfo->participants[0]).profileInfo.type == lrc::api::profile::Type::PENDING)
606 [smartViewVC selectPendingList];
607 else
608 [smartViewVC selectConversationList];
609 [smartViewVC selectConversation: *convInfo model:accInfo.conversationModel.get()];
610 }
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400611 [currentCallVC setCurrentCall:QString::fromNSString(callId)
612 conversation:QString::fromNSString(conversationId)
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400613 account:&accInfo
614 avModel:avModel];
Kateryna Kostiuke3503842018-12-12 16:39:45 -0500615 [self changeViewTo:SHOW_CALL_SCREEN];
616}
617
618-(void) showContactRequestFor:(NSString* )accountId contactUri:(NSString*)uri {
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400619 auto& accInfo = self.accountModel->getAccountInfo(QString::fromNSString(accountId));
Kateryna Kostiuke3503842018-12-12 16:39:45 -0500620 [chooseAccountVC selectAccount: accountId];
621 [settingsVC setSelectedAccount:accInfo.id];
622 [smartViewVC setConversationModel:accInfo.conversationModel.get()];
623 [self updateRingID];
624 [smartViewVC selectPendingList];
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400625 auto convInfo = getConversationFromURI(QString::fromNSString(uri), *accInfo.conversationModel.get());
Kateryna Kostiuke3503842018-12-12 16:39:45 -0500626 auto convQueue = accInfo.conversationModel.get()->allFilteredConversations();
627 if (convInfo != convQueue.end()) {
628 [conversationVC setConversationUid:convInfo->uid model:accInfo.conversationModel.get()];
629 [smartViewVC selectConversation: *convInfo model:accInfo.conversationModel.get()];
630 }
631 [self changeViewTo:SHOW_CONVERSATION_SCREEN];
632}
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400633
Alexandre Lision5855b6a2015-02-03 11:31:05 -0500634@end