...
 
Commits (59)
......@@ -13,7 +13,7 @@ IF("${RING_VERSION}" STREQUAL "")
ENDIF("${RING_VERSION}" STREQUAL "")
# if build for App Store version and build number should be incremented
IF("${RELEASE_TYPE}" STREQUAL "AppStore")
SET(RING_VERSION_NAME "1.39")
SET(RING_VERSION_NAME "1.51")
ELSE()
SET(RING_VERSION_NAME "1")
ENDIF()
......@@ -176,6 +176,16 @@ SET(ringclient_CONTROLLERS
src/AccountSettingsVC.h
src/LeaveMessageVC.mm
src/LeaveMessageVC.h
src/RecordFileVC.mm
src/RecordFileVC.h
src/ChooseContactVC.mm
src/ChooseContactVC.h
src/CallInConferenceVC.mm
src/CallInConferenceVC.h
src/ConnectToAccManagerVC.mm
src/ConnectToAccManagerVC.h
src/AccountBackupVC.mm
src/AccountBackupVC.h
)
SET(ringclient_VIEWS
......@@ -219,6 +229,10 @@ SET(ringclient_VIEWS
src/views/CenteredClipView.mm
src/views/CallMTKView.h
src/views/CallMTKView.mm
src/views/GradientView.h
src/views/GradientView.mm
src/views/MovableView.h
src/views/MovableView.mm
)
SET(ringclient_OTHERS
......@@ -270,6 +284,11 @@ SET(ringclient_XIBS
AddSIPAccountVC
AccountSettings
LeaveMessageVC
RecordFileVC
ChooseContactVC
CallInConferenceVC
ConnectToAccManagerVC
AccountBackupVC
)
# Icons
......@@ -326,6 +345,9 @@ ${CMAKE_CURRENT_SOURCE_DIR}/data/dark/qrcode.png
${CMAKE_CURRENT_SOURCE_DIR}/data/dark/ic_action_video.png
${CMAKE_CURRENT_SOURCE_DIR}/data/dark/pending_contact_request.png
${CMAKE_CURRENT_SOURCE_DIR}/data/dark/ic_file_upload.png
${CMAKE_CURRENT_SOURCE_DIR}/data/dark/ic_record_stop.png
${CMAKE_CURRENT_SOURCE_DIR}/data/dark/ic_camera.png
${CMAKE_CURRENT_SOURCE_DIR}/data/dark/ic_audio_msg.png
${CMAKE_CURRENT_SOURCE_DIR}/data/light/ic_picture.png)
SET_SOURCE_FILES_PROPERTIES(${ring_ICONS} PROPERTIES
......@@ -497,6 +519,7 @@ ELSE()
XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME TRUE
)
ENDIF()
set(CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "dwarf-with-dsym")
# Make sure we can find the 'ibtool' program. If we can NOT find it we
# skip generation of this project
FIND_PROGRAM(IBTOOL ibtool HINTS "/usr/bin" "${OSX_DEVELOPER_ROOT}/usr/bin")
......
......@@ -9,11 +9,11 @@
\f0\i\fs24 \cf0 \
\fs28 "
\f1\b Live Free or Die"
\f1\b Free as in Freedom"
\f0\b0\fs24 \
\
\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\qc\partightenfactor0
{\field{\*\fldinst{HYPERLINK "https://ring.cx/"}}{\fldrslt \cf0 jami.net}}\
{\field{\*\fldinst{HYPERLINK "https://jami.net/"}}{\fldrslt \cf0 jami.net}}\
\
\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\qc\partightenfactor0
......@@ -62,5 +62,5 @@ Based on SFLphone's project\
\f2\i0\b Translated by
\f0\i\b0 \
\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\qc\partightenfactor0
{\field{\*\fldinst{HYPERLINK "https://www.transifex.com/savoirfairelinux/ring/"}}{\fldrslt \cf0 https://www.transifex.com/savoirfairelinux/ring/}}\
}
\ No newline at end of file
{\field{\*\fldinst{HYPERLINK "https://www.transifex.com/savoirfairelinux/jami/"}}{\fldrslt \cf0 https://www.transifex.com/savoirfairelinux/jami/}}\
}
Ring Mac OSX
Jami for macOS
**********
This is the official Mac port of Ring.
This is the official Mac port of Jami.
For more information about the ring project, see the following:
- Main website: https://ring.cx/
- Bug tracker: https://tuleap.ring.cx/projects/ring/
- Repositories: https://gerrit-ring.savoirfairelinux.com
- Main website: https://jami.net/
- Bug tracker: https://git.jami.net
- Repositories: https://review.jami.net
| App | CI | Packaging
| :-: | :-: | :-:
| [![Download from ring.cx](https://img.shields.io/badge/download-cx.ring-blue.svg)](https://ring.cx/en/download/mac-osx) | [![Build Status](https://test.savoirfairelinux.com/buildStatus/icon?job=ring-client-macosx)](https://test.savoirfairelinux.com/job/ring-client-macosx/) | [![Build Status](https://test.savoirfairelinux.com/buildStatus/icon?job=ring-packaging-client-macosx)](https://test.savoirfairelinux.com/job/ring-packaging-client-macosx/)
| [![Download from jami.net](https://img.shields.io/badge/download-cx.ring-blue.svg)](https://jami.net/download-jami-macos) | [![Build Status](https://test.savoirfairelinux.com/buildStatus/icon?job=ring-client-macosx)](https://test.savoirfairelinux.com/job/ring-client-macosx/) | [![Build Status](https://test.savoirfairelinux.com/buildStatus/icon?job=ring-packaging-client-macosx)](https://test.savoirfairelinux.com/job/ring-packaging-client-macosx/)
Requirements
=============
- Ring daemon
- Jami daemon
- libRingClient (Qt5 version)
- Qt5 Core
- Cocoa framework
......@@ -25,7 +25,7 @@ Build instructions
Build Sparkle framework (optional)
----------------------------------
Ring can ship with the Sparkle framework to allow automatic app updates.
Jami can ship with the Sparkle framework to allow automatic app updates.
This can be disabled for your custom build by specifying -DENABLE_SPARKLE=false
in the cmake phase.
......
......@@ -15,7 +15,7 @@
<key>SUPublicDSAKeyFile</key>
<string>dsa_pub.pem</string>
<key>SUFeedURL</key>
<string>https://dl.ring.cx/mac_osx/sparkle-ring.xml</string>
<string>https://dl.jami.net/mac_osx/sparkle-ring.xml</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>
......
data/dark/ic_action_chat.png

248 Bytes | W: | H:

data/dark/ic_action_chat.png

184 Bytes | W: | H:

data/dark/ic_action_chat.png
data/dark/ic_action_chat.png
data/dark/ic_action_chat.png
data/dark/ic_action_chat.png
  • 2-up
  • Swipe
  • Onion skin
data/dark/ic_action_record.png

2.82 KB | W: | H:

data/dark/ic_action_record.png

234 Bytes | W: | H:

data/dark/ic_action_record.png
data/dark/ic_action_record.png
data/dark/ic_action_record.png
data/dark/ic_action_record.png
  • 2-up
  • Swipe
  • Onion skin
data/dark/ic_audio_file.png

756 Bytes | W: | H:

data/dark/ic_audio_file.png

1.11 KB | W: | H:

data/dark/ic_audio_file.png
data/dark/ic_audio_file.png
data/dark/ic_audio_file.png
data/dark/ic_audio_file.png
  • 2-up
  • Swipe
  • Onion skin
......@@ -14,7 +14,7 @@ security import certificates/certificates/distribution/Certificates.p12 -k $KEYC
DELIVER_PASSWORD=$APPLE_PASSWORD fastlane sigh --app_identifier $BUNDLE_ID --username $APPLE_ACCOUNT --readonly true --platform macos --team_id $TEAM_ID
security set-key-partition-list -S apple-tool:,apple:,productbuild: -s -k $KEYCHAIN_PASSWORD $KEYCHAIN_NAME > /dev/null 2>&1
echo "start signing"
macdeployqt ./Jami.app -codesign="${APP_CERTIFICATE}"
macdeployqt ./Jami.app -no-strip -codesign="${APP_CERTIFICATE}"
codesign --force --sign "${APP_CERTIFICATE}" --entitlements ../data/Jami.entitlements Jami.app
codesign --verify Jami.app
echo "create .pkg"
......
......@@ -52,7 +52,7 @@ const NSInteger BOOTSTRAP_SERVER_TAG = 300;
-(void) viewDidLoad {
[super viewDidLoad];
[[self view] setAutoresizingMask: NSViewMinXMargin | NSViewMaxXMargin];
[[self view] setAutoresizingMask: NSViewMinXMargin | NSViewMaxXMargin | NSViewWidthSizable];
[self updateView];
}
......
......@@ -49,11 +49,14 @@
@property (unsafe_unretained) IBOutlet NSTextField *displayNameField;
@property (unsafe_unretained) IBOutlet NSTextField *ringIDField;
@property (unsafe_unretained) IBOutlet NSTextField *registeredNameField;
@property (unsafe_unretained) IBOutlet NSTextField *passwordField;
@property (unsafe_unretained) IBOutlet RoundedTextField *accountStatus;
@property (unsafe_unretained) IBOutlet NSButton *registerNameButton;
@property (unsafe_unretained) IBOutlet NSButton* photoView;
@property (unsafe_unretained) IBOutlet NSButton* passwordButton;
@property (unsafe_unretained) IBOutlet NSButton* linkDeviceButton;
@property (unsafe_unretained) IBOutlet NSButton* removeAccountButton;
@property (unsafe_unretained) IBOutlet NSButton* exportAccountButton;
@property (unsafe_unretained) IBOutlet NSImageView* addProfilePhotoImage;
@property (unsafe_unretained) IBOutlet NSTableView* devicesTableView;
@property (unsafe_unretained) IBOutlet NSTableView* blockedContactsTableView;
......@@ -90,7 +93,9 @@ QMetaObject::Connection accountStateChangedSignal;
@synthesize delegate;
@synthesize devicesTableView;
@synthesize blockedContactsTableView;
@synthesize linkDeviceButton;
@synthesize passwordField;
@synthesize exportAccountButton;
typedef NS_ENUM(NSInteger, TagViews) {
DISPLAYNAME = 100,
......@@ -120,7 +125,7 @@ typedef NS_ENUM(NSInteger, TagViews) {
devicesTableView.dataSource = self;
blockedContactsTableView.delegate = self;
blockedContactsTableView.dataSource= self;
[[self view] setAutoresizingMask: NSViewMinXMargin | NSViewMaxXMargin];
[[self view] setAutoresizingMask: NSViewMinXMargin | NSViewMaxXMargin | NSViewWidthSizable];
}
- (void)viewDidLoad {
......@@ -152,7 +157,15 @@ typedef NS_ENUM(NSInteger, TagViews) {
NSString* displayName = @(account.profileInfo.alias.c_str());
[displayNameField setStringValue:displayName];
[ringIDField setStringValue:@(account.profileInfo.uri.c_str())];
if(account.registeredName.empty()) {
lrc::api::account::ConfProperties_t accountProperties = self.accountModel->getAccountConfig(self.selectedAccountID);
bool hideLocalAccountConfig = !accountProperties.managerUri.empty();
[passwordButton setHidden:hideLocalAccountConfig];
[linkDeviceButton setHidden:hideLocalAccountConfig];
[passwordField setHidden:hideLocalAccountConfig];
[exportAccountButton setHidden: hideLocalAccountConfig];
if(account.registeredName.empty() && !hideLocalAccountConfig) {
[registerNameButton setHidden:NO];
buttonRegisterWidthConstraint.constant = 260.0;
} else {
......@@ -162,7 +175,6 @@ typedef NS_ENUM(NSInteger, TagViews) {
[registeredNameField setStringValue:@(account.registeredName.c_str())];
lrc::api::account::ConfProperties_t accountProperties = self.accountModel->getAccountConfig(self.selectedAccountID);
[passwordButton setTitle:accountProperties.archiveHasPassword ? @"Change password" : @"Create password"];
self.accountEnabled = account.enabled;
......@@ -368,6 +380,7 @@ typedef NS_ENUM(NSInteger, TagViews) {
- (IBAction)editPhoto:(id)sender
{
auto pictureTaker = [IKPictureTaker pictureTaker];
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101400
if (@available(macOS 10.14, *)) {
AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
if(authStatus == AVAuthorizationStatusRestricted || authStatus == AVAuthorizationStatusDenied)
......@@ -384,6 +397,7 @@ typedef NS_ENUM(NSInteger, TagViews) {
}];
}
}
#endif
[pictureTaker beginPictureTakerSheetForWindow:[self.view window]
withDelegate:self
didEndSelector:@selector(pictureTakerDidEnd:returnCode:contextInfo:)
......@@ -429,14 +443,29 @@ typedef NS_ENUM(NSInteger, TagViews) {
NSSavePanel* filePicker = [NSSavePanel savePanel];
NSString* name = [@(self.selectedAccountID.c_str()) stringByAppendingString: @".gz"];
[filePicker setNameFieldStringValue: name];
if ([filePicker runModal] == NSFileHandlingPanelOKButton) {
const char* fullPath = [[filePicker URL] fileSystemRepresentation];
if (self.accountModel->exportToFile(self.selectedAccountID, fullPath)) {
[self didCompleteExportWithPath:[filePicker URL]];
} else {
[self showAlertWithTitle: @"" andText: NSLocalizedString(@"An error occured during the backup", @"Backup error")];
if ([filePicker runModal] != NSFileHandlingPanelOKButton) {
return;
}
NSString *password = @"";
const char* fullPath = [[filePicker URL] fileSystemRepresentation];
lrc::api::account::ConfProperties_t accountProperties = self.accountModel->getAccountConfig(self.selectedAccountID);
if(accountProperties.archiveHasPassword) {
NSAlert *alert = [[NSAlert alloc] init];
[alert addButtonWithTitle:@"OK"];
[alert addButtonWithTitle:@"Cancel"];
[alert setMessageText: NSLocalizedString(@"Enter account password",
@"Backup enter password")];
NSTextField *input = [[NSSecureTextField alloc] initWithFrame:NSMakeRect(0, 0, 200, 20)];
[alert setAccessoryView:input];
if ([alert runModal] != NSAlertFirstButtonReturn) {
return;
}
password = [input stringValue];
}
if (self.accountModel->exportToFile(self.selectedAccountID, fullPath, [password UTF8String])) {
[self didCompleteExportWithPath:[filePicker URL]];
} else {
[self showAlertWithTitle: @"" andText: NSLocalizedString(@"An error occured during the backup", @"Backup error")];
}
}
......
......@@ -156,6 +156,7 @@ typedef NS_ENUM(NSInteger, TagViews) {
- (IBAction)editPhoto:(id)sender
{
auto pictureTaker = [IKPictureTaker pictureTaker];
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101400
if (@available(macOS 10.14, *)) {
AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
if(authStatus == AVAuthorizationStatusRestricted || authStatus == AVAuthorizationStatusDenied)
......@@ -172,6 +173,7 @@ typedef NS_ENUM(NSInteger, TagViews) {
}];
}
}
#endif
[pictureTaker beginPictureTakerSheetForWindow:[self.view window]
withDelegate:self
......
/*
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#import <Cocoa/Cocoa.h>
#import "LrcModelsProtocol.h"
#import <string>
@protocol AccountBackupDelegate <NSObject>
-(void)completedWithSuccess:(BOOL) success;
-(void)showView:(NSView*)view;
@end
@interface AccountBackupVC : NSViewController <LrcModelsProtocol>
@property (retain, nonatomic) id <AccountBackupDelegate> delegate;
@property std::string accountToBackup;
-(void)show;
@end
/*
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#import "AccountBackupVC.h"
#import "Constants.h"
//LRC
#import <api/lrc.h>
#import <api/newaccountmodel.h>
@interface AccountBackupVC () {
__unsafe_unretained IBOutlet NSView* initialView;
__unsafe_unretained IBOutlet NSView* errorView;
__unsafe_unretained IBOutlet NSButton* skipBackupButton;
}
@end
@implementation AccountBackupVC
@synthesize accountModel, accountToBackup;
-(id) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil accountmodel:(lrc::api::NewAccountModel*) accountModel {
if (self = [self initWithNibName:nibNameOrNil bundle:nibBundleOrNil])
{
self.accountModel = accountModel;
}
return self;
}
-(void)show {
[self.view setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
[initialView setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
[errorView setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
BOOL skipBackup = [[NSUserDefaults standardUserDefaults] boolForKey: SkipBackUpPage];
[skipBackupButton setState: !skipBackup];
[self.delegate showView: initialView];
}
- (IBAction)skip:(id)sender
{
[self.delegate completedWithSuccess:YES];
}
- (IBAction)startAgain:(id)sender
{
[self.delegate showView: initialView];
}
- (IBAction)alwaysSkipBackup:(id)sender
{
[[NSUserDefaults standardUserDefaults] setBool:![sender state] forKey:SkipBackUpPage];
}
- (IBAction)exportAccount:(id)sender
{
NSSavePanel* filePicker = [NSSavePanel savePanel];
NSString* name = [@(self.accountToBackup.c_str()) stringByAppendingString: @".gz"];
[filePicker setNameFieldStringValue: name];
if ([filePicker runModal] != NSFileHandlingPanelOKButton) {
return;
}
NSString *password = @"";
const char* fullPath = [[filePicker URL] fileSystemRepresentation];
lrc::api::account::ConfProperties_t accountProperties = self.accountModel->getAccountConfig(self.accountToBackup);
if(accountProperties.archiveHasPassword) {
NSAlert *alert = [[NSAlert alloc] init];
[alert addButtonWithTitle:@"OK"];
[alert addButtonWithTitle:@"Cancel"];
[alert setMessageText: NSLocalizedString(@"Enter account password",
@"Backup enter password")];
NSTextField *input = [[NSSecureTextField alloc] initWithFrame:NSMakeRect(0, 0, 200, 20)];
[alert setAccessoryView:input];
if ([alert runModal] != NSAlertFirstButtonReturn) {
return;
}
password = [input stringValue];
}
if (self.accountModel->exportToFile(self.accountToBackup, fullPath, [password UTF8String])) {
[self.delegate completedWithSuccess:YES];
} else {
[self.delegate showView: errorView];
}
}
@end
......@@ -114,6 +114,9 @@ CGFloat const VIEW_INSET = 40;
CGRect settingsFrame = accountGeneralVC.view.frame;
settingsFrame.size.height = settingsFrame.size.height + accountAdvancedVC.view.frame.size.height;
NSView* container = [[NSView alloc] initWithFrame:settingsFrame];
CGRect advancedFrame = accountAdvancedVC.view.frame;
advancedFrame.size.width = settingsFrame.size.width;
accountAdvancedVC.view.frame = advancedFrame;
[container addSubview:accountAdvancedVC.view];
CGRect generalSettingsFrame = accountGeneralVC.view.frame;
generalSettingsFrame.origin.y = accountAdvancedVC.view.frame.size.height;
......
......@@ -21,7 +21,7 @@
#import "LrcModelsProtocol.h"
@protocol AddSIPAccountDelegate <NSObject>
- (void)didCreateAccountWithSuccess:(BOOL)success;
- (void)completedWithSuccess:(BOOL)success;
- (void)showView:(NSView*)view;
@end
......
......@@ -50,7 +50,7 @@ NSTimer* timeoutTimer;
- (void)viewDidLoad {
[super viewDidLoad];
[self.view setAutoresizingMask: NSViewHeightSizable];
[self.view setAutoresizingMask: NSViewHeightSizable | NSViewWidthSizable];
}
-(id) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil accountmodel:(lrc::api::NewAccountModel*) accountModel {
......@@ -67,11 +67,12 @@ NSTimer* timeoutTimer;
photoView.layer.masksToBounds = YES;
[photoView setBordered:YES];
[addProfilePhotoImage setWantsLayer: YES];
[self.delegate showView:self.view];
}
- (IBAction)cancel:(id)sender
{
[self.delegate didCreateAccountWithSuccess: NO];
[self.delegate completedWithSuccess: NO];
}
- (IBAction)addAccount:(id)sender
......@@ -97,7 +98,7 @@ NSTimer* timeoutTimer;
}
self.accountModel->setAccountConfig(accountID, accountProperties);
QObject::disconnect(accountCreated);
[self.delegate didCreateAccountWithSuccess: YES];
[self.delegate completedWithSuccess: YES];
});
accountToCreate = self.accountModel->createNewAccount(lrc::api::profile::Type::SIP, [displayName UTF8String], "", "", "", [userNameField.stringValue UTF8String]);
......@@ -109,13 +110,14 @@ NSTimer* timeoutTimer;
-(void) addingAccountTimeout {
QObject::disconnect(accountCreated);
[self.delegate didCreateAccountWithSuccess: YES];
[self.delegate completedWithSuccess: YES];
}
- (IBAction)editPhoto:(id)sender
{
auto pictureTaker = [IKPictureTaker pictureTaker];
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101400
if (@available(macOS 10.14, *)) {
AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
if(authStatus == AVAuthorizationStatusRestricted || authStatus == AVAuthorizationStatusDenied)
......@@ -132,6 +134,7 @@ NSTimer* timeoutTimer;
}];
}
}
#endif
[pictureTaker beginPictureTakerSheetForWindow:[self.delegate window]
withDelegate:self
didEndSelector:@selector(pictureTakerDidEnd:returnCode:contextInfo:)
......
......@@ -98,7 +98,6 @@ std::unique_ptr<lrc::api::Lrc> lrc;
NSActivityOptions options = NSActivitySuddenTerminationDisabled | NSActivityAutomaticTerminationDisabled | NSActivityBackground;
self.activity = [[NSProcessInfo processInfo] beginActivityWithOptions:options reason:@"Receiving calls and messages"];
lrc = std::make_unique<lrc::api::Lrc>();
if([self checkForRingAccount]) {
[self setRingtonePath];
[self showMainWindow];
......
/*
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#import <Cocoa/Cocoa.h>
#include <string>
namespace lrc {
namespace api {
namespace account {
struct Info;
}
}
}
@protocol CallInConferenceVCDelegate
-(void)removePreviewForContactUri:(std::string)uri forCall:(std::string) callId;
@end
@interface CallInConferenceVC: NSViewController
-(id) initWithNibName:(NSString *)nibNameOrNil
bundle:(NSBundle *)nibBundleOrNil
callId:(const std::string)callId
accountInfo:(const lrc::api::account::Info *)accInfo;
@property (retain, nonatomic) id <CallInConferenceVCDelegate> delegate;
@property std::string initiatorCallId;
@end
/*
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#import "CallInConferenceVC.h"
#import "views/IconButton.h"
#import "NSString+Extensions.h"
///LRC
#import <api/newcallmodel.h>
#import <api/account.h>
#import <api/contactmodel.h>
#import <api/contact.h>
@interface CallInConferenceVC () {
std::string callUId;
const lrc::api::account::Info *accountInfo;
}
@property (unsafe_unretained) IBOutlet NSTextField* contactNameLabel;
@property (unsafe_unretained) IBOutlet NSTextField* callStateLabel;
@property (unsafe_unretained) IBOutlet IconButton* cancelCallButton;
@property QMetaObject::Connection callStateChanged;
@end
@implementation CallInConferenceVC
@synthesize cancelCallButton,callStateLabel,contactNameLabel;
-(id) initWithNibName:(NSString *)nibNameOrNil
bundle:(NSBundle *)nibBundleOrNil
callId:(const std::string)callId
accountInfo:(const lrc::api::account::Info *)accInfo {
if (self = [self initWithNibName: nibNameOrNil bundle:nibBundleOrNil])
{
callUId = callId;
accountInfo = accInfo;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
auto* callModel = accountInfo->callModel.get();
auto currentCall = callModel->getCall(callUId);
auto uri = currentCall.peerUri;
auto contact = accountInfo->contactModel->getContact(uri);
NSString *name = @(contact.profileInfo.alias.c_str());
name = [name removeEmptyLinesAtBorders];
if (name.length == 0) {
name = @(contact.registeredName.c_str());
}
name = [name removeEmptyLinesAtBorders];
if (name.length == 0) {
name = @(contact.profileInfo.uri.c_str());
}
self.contactNameLabel.stringValue = [name removeEmptyLinesAtBorders];
QObject::disconnect(self.callStateChanged);
self.callStateChanged = QObject::connect(callModel,
&lrc::api::NewCallModel::callStatusChanged,
[self](const std::string callId) {
if (callId == callUId) {
[self updateCall];
}
});
}
-(void) updateCall
{
if (accountInfo == nil)
return;
auto* callModel = accountInfo->callModel.get();
if (not callModel->hasCall(callUId)) {
return;
}
auto currentCall = callModel->getCall(callUId);
using Status = lrc::api::call::Status;
callStateLabel.stringValue = @(to_string(currentCall.status).c_str());
switch (currentCall.status) {
case Status::IN_PROGRESS:
case Status::ENDED:
case Status::TERMINATING:
case Status::PEER_BUSY:
case Status::TIMEOUT:
case Status::INVALID: {
QObject::disconnect(self.callStateChanged);
[self.delegate removePreviewForContactUri: currentCall.peerUri forCall: self.initiatorCallId];
break;
}
}
}
- (void)awakeFromNib
{
contactNameLabel.textColor = [NSColor textColor];
callStateLabel.textColor = [NSColor textColor];
}
- (IBAction)hangUp:(id)sender {
if (accountInfo == nil)
return;
auto* callModel = accountInfo->callModel.get();
callModel->hangUp(callUId);
}
@end
/*
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#import <Cocoa/Cocoa.h>
#include <string>
@protocol ChooseContactVCDelegate <NSObject>
-(void)callToContact:(std::string)contactUri convUID:(std::string)convID;
-(void)joinCall:(std::string)callId;
@end
namespace lrc {
namespace api {
class ConversationModel;
namespace conversation {
struct Info;
}
}
}
@interface ChooseContactVC: NSViewController
@property (retain, nonatomic) id <ChooseContactVCDelegate> delegate;
- (void)setConversationModel:(lrc::api::ConversationModel *)conversationModel
andCurrentConversation:(std::string)conversation;
@end
This diff is collapsed.
/*
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#import <Cocoa/Cocoa.h>
#import "LrcModelsProtocol.h"
@protocol RingWizardAccManagerDelegate <NSObject>
- (void)didSignInSuccess:(BOOL)success;
- (void)showView:(NSView*)view;
@end
@interface ConnectToAccManagerVC: NSViewController <LrcModelsProtocol>
@property (nonatomic, weak) NSWindowController <RingWizardAccManagerDelegate>* delegate;
/*
* KVO value username
*/
@property (nonatomic, weak) NSString* username;
/*
* KVO value password
*/
@property (nonatomic, weak) NSString* password;
/*
* KVO value account manager
*/
@property (nonatomic, weak) NSString* accountManager;
- (void)show;
@end
/*
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#import "ConnectToAccManagerVC.h"
#import "utils.h"
//LRC
#import <api/lrc.h>
#import <api/newaccountmodel.h>
@interface ConnectToAccManagerVC ()
@end
@implementation ConnectToAccManagerVC {
__unsafe_unretained IBOutlet NSView* initialContainer;
__unsafe_unretained IBOutlet NSView* loadingContainer;
__unsafe_unretained IBOutlet NSProgressIndicator* progressBar;
__unsafe_unretained IBOutlet NSView* errorContainer;
__unsafe_unretained IBOutlet NSTextField* userNameField;
__unsafe_unretained IBOutlet NSTextField* accountManagerField;
__unsafe_unretained IBOutlet NSSecureTextField* passwordTextField;
}
QMetaObject::Connection accountCreatedSuccess;
QMetaObject::Connection accountNotCreated;
std::string accointId;
@synthesize accountModel;
-(id) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil accountmodel:(lrc::api::NewAccountModel*) accountModel {
if (self = [self initWithNibName:nibNameOrNil bundle:nibBundleOrNil])
{
self.accountModel = accountModel;
}
return self;
}
- (void)show
{
self.username = userNameField.stringValue = @"";
self.password = passwordTextField.stringValue = @"";
self.accountManager = accountManagerField.stringValue = @"";
[self.delegate showView:initialContainer];
}
- (void)showError
{
[self.delegate showView:errorContainer];
}
- (void)showLoading
{
[progressBar startAnimation:nil];
[self.delegate showView:loadingContainer];
}
- (void)viewDidLoad {
[super viewDidLoad];
[self.view setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
}
- (IBAction)dismissViewWithError:(id)sender
{
[self.delegate didSignInSuccess:NO];
}
- (IBAction)startAgain:(id)sender
{
[self show];
}
- (IBAction)signIn:(id)sender
{
QObject::disconnect(accountCreatedSuccess);
QObject::disconnect(accountNotCreated);
accountCreatedSuccess = QObject::connect(self.accountModel,
&lrc::api::NewAccountModel::accountAdded,
[self] (const std::string& accountID) {
if(accountID.compare(accointId) != 0) {
return;
}
[self.delegate didSignInSuccess:YES];
lrc::api::account::ConfProperties_t accountProperties = self.accountModel->getAccountConfig(accountID);
accountProperties.Ringtone.ringtonePath = [defaultRingtonePath() UTF8String];
self.accountModel->setAccountConfig(accountID, accountProperties);
QObject::disconnect(accountCreatedSuccess);
QObject::disconnect(accountNotCreated);
});
accountNotCreated = QObject::connect(self.accountModel,
&lrc::api::NewAccountModel::accountRemoved,
[self] (const std::string& accountID) {
if(accountID.compare(accointId) == 0) {
[self showError];
}
});
accountNotCreated = QObject::connect(self.accountModel,
&lrc::api::NewAccountModel::invalidAccountDetected,
[self] (const std::string& accountID) {
if(accountID.compare(accointId) == 0) {
[self showError];
}
});
[self showLoading];
accointId = self.accountModel->connectToAccountManager([userNameField.stringValue UTF8String], [passwordTextField.stringValue UTF8String], [accountManagerField.stringValue UTF8String]);
}
@end
......@@ -39,4 +39,6 @@ namespace Preferences {
NSString * const DownloadFolder = @"download_folder";
}
NSString * const SkipBackUpPage = @"always_skip_backup_page";
const CGFloat MAX_IMAGE_SIZE = 1024;
......@@ -37,7 +37,6 @@
#import "RingWindowController.h"
#import "NSString+Extensions.h"
#import "LeaveMessageVC.h"
#import "LeaveMessageVC.h"
@interface ConversationVC () <QLPreviewPanelDataSource, QLPreviewPanelDelegate>{
......@@ -85,6 +84,7 @@ NSInteger const SEND_PANEL_MAX_HEIGHT = 120;
[leaveMessageVC setAVModel: avModel];
leaveMessageConversations = [[NSMutableArray alloc] init];
leaveMessageVC.delegate = self;
[messagesViewVC setAVModel: avModel];
}
return self;
}
......@@ -212,6 +212,7 @@ NSInteger const SEND_PANEL_MAX_HEIGHT = 120;
- (IBAction)backPressed:(id)sender {
[delegate rightPanelClosed];
[self hideWithAnimation:false];
[messagesViewVC clearData];
}
# pragma mark private IN/OUT animations
......
......@@ -23,6 +23,9 @@
#import "views/CallView.h"
#import <api/account.h>
#import "ChooseContactVC.h"
#import "CallInConferenceVC.h"
namespace lrc {
namespace api {
class AVModel;
......@@ -32,10 +35,11 @@ namespace lrc {
@protocol CallViewControllerDelegate
-(void) conversationInfoUpdatedFor:(const std::string&) conversationID;
-(void) callFinished;
@end
@interface CurrentCallVC : NSViewController <NSSplitViewDelegate, CallDelegate> {
@interface CurrentCallVC : NSViewController <NSSplitViewDelegate, CallDelegate, ChooseContactVCDelegate, CallInConferenceVCDelegate> {
}
@property (retain, nonatomic) id <CallViewControllerDelegate> delegate;
......
This diff is collapsed.
......@@ -23,4 +23,9 @@
@interface GeneralPrefsVC : NSViewController <LrcModelsProtocol, NSOpenSavePanelDelegate>
/**
* KVO to video recording quality
*/
@property (nonatomic) int quality;
@end
......@@ -32,12 +32,19 @@
@interface GeneralPrefsVC () {
__unsafe_unretained IBOutlet NSButton* startUpButton;
__unsafe_unretained IBOutlet NSButton* toggleAutomaticUpdateCheck;
__unsafe_unretained IBOutlet NSButton* alwaysRecording;
__unsafe_unretained IBOutlet NSButton* recordPreview;
__unsafe_unretained IBOutlet NSPopUpButton* checkIntervalPopUp;
__unsafe_unretained IBOutlet NSView* sparkleContainer;
__unsafe_unretained IBOutlet NSStackView* sparkleContainer;
__unsafe_unretained IBOutlet NSButton *downloadFolder;
__unsafe_unretained IBOutlet NSTextField *downloadFolderLabel;
__unsafe_unretained IBOutlet NSButton *recordingFolder;
__unsafe_unretained IBOutlet NSTextField *recordingFolderLabel;
__unsafe_unretained IBOutlet NSStackView *generalStackView;
__unsafe_unretained IBOutlet NSStackView *conversationStackView;
__unsafe_unretained IBOutlet NSStackView *recordingFolderStackView;
__unsafe_unretained IBOutlet NSSlider *qualitySlider;
__unsafe_unretained IBOutlet NSTextField *qualityLabel;
}
@end
......@@ -59,6 +66,7 @@
- (void)loadView
{
[super loadView];
CGFloat heightToReduice = 0;
[startUpButton setState:[self isLaunchAtStartup]];
#if ENABLE_SPARKLE
[sparkleContainer setHidden:NO];
......@@ -69,24 +77,29 @@
[checkIntervalPopUp bind:@"selectedTag" toObject:updater withKeyPath:@"updateCheckInterval" options:nil];
#else
[sparkleContainer setHidden:YES];
heightToReduice += (sparkleContainer.frame.size.height + 25);
#endif
[alwaysRecording setState: avModel->getAlwaysRecord()];
[recordPreview setState: avModel->getRecordPreview()];
[qualitySlider setDoubleValue: avModel->getRecordQuality()];
[qualityLabel setIntValue:avModel->getRecordQuality()];
if (appSandboxed()) {
[downloadFolder setHidden:YES];
[downloadFolder setEnabled:NO];
[downloadFolderLabel setHidden: YES];
[recordingFolder setHidden:YES];
[recordingFolder setEnabled:NO];
[recordingFolderLabel setHidden:YES];
return;
}
if (dataTransferModel) {
downloadFolder.title = [@(dataTransferModel->downloadDirectory.c_str()) lastPathComponent];
}
if (avModel) {
auto name1 = avModel->getRecordPath();
auto name = @(avModel->getRecordPath().c_str());
recordingFolder.title = [@(avModel->getRecordPath().c_str()) lastPathComponent];
[recordingFolderStackView setHidden:YES];
[conversationStackView setHidden:YES];
heightToReduice += (downloadFolder.frame.size.height + recordingFolder.frame.size.height + 25);
} else {
if (dataTransferModel) {
downloadFolder.title = [@(dataTransferModel->downloadDirectory.c_str()) lastPathComponent];
}
if (avModel) {
auto name1 = avModel->getRecordPath();
auto name = @(avModel->getRecordPath().c_str());
recordingFolder.title = [@(avModel->getRecordPath().c_str()) lastPathComponent];
}
}
auto frame = self.view.frame;
frame.size.height -= heightToReduice;
self.view.frame = frame;
}
- (IBAction)changeDownloadFolder:(id)sender {
......@@ -118,6 +131,18 @@
[[NSUserDefaults standardUserDefaults] setObject:path forKey:Preferences::DownloadFolder];
}
- (IBAction)alwaysRecording:(id)sender {
avModel->setAlwaysRecord([sender state]);
}
- (IBAction)recordPreview:(id)sender {
avModel->setRecordPreview([sender state]);
}
- (IBAction)setRecordingQuality:(NSSlider*)sender {
avModel->setRecordQuality([sender intValue]);
}
#pragma mark - Startup API
// MIT license by Brian Dunagan
......
......@@ -20,6 +20,7 @@
#import "LeaveMessageVC.h"
#import "views/NSColor+RingTheme.h"
#import "utils.h"
#import "NSString+Extensions.h"
//lrc
#import <api/avmodel.h>
......@@ -38,9 +39,9 @@
__unsafe_unretained IBOutlet NSTextField* infoLabel;
__unsafe_unretained IBOutlet NSBox* timerBox;
__unsafe_unretained IBOutlet NSTextField* timerLabel;
__unsafe_unretained IBOutlet NSBox* sendBox;
__unsafe_unretained IBOutlet NSTextField* sendFilename;
__unsafe_unretained IBOutlet NSButton* sendButton;
__unsafe_unretained IBOutlet NSButton* recordButton;
__unsafe_unretained IBOutlet NSButton* exitButton;
}
@end
......@@ -51,7 +52,6 @@ bool isRecording = false;
int recordingTime = 0;
NSTimer* refreshDurationTimer;
lrc::api::AVModel* avModel;
std::string fileName;
NSMutableDictionary *filesToSend;
std::string conversationUid;
lrc::api::ConversationModel* conversationModel;
......@@ -62,6 +62,19 @@ lrc::api::ConversationModel* conversationModel;
personPhoto.layer.masksToBounds =true;
personPhoto.layer.cornerRadius = personPhoto.frame.size.width * 0.5;
filesToSend = [[NSMutableDictionary alloc] init];
[self setButtonShadow:sendButton];
[self setButtonShadow:exitButton];
[self setButtonShadow:recordButton];
}
-(void) setButtonShadow:(NSButton*) button {
button.wantsLayer = YES;
button.layer.masksToBounds = NO;
button.shadow = [[NSShadow alloc] init];
button.layer.shadowOpacity = 0.8;
button.layer.shadowColor = [[NSColor grayColor] CGColor];
button.layer.shadowOffset = NSMakeSize(-0.5, 1);
button.layer.shadowRadius = 1;
}
-(void) setAVModel: (lrc::api::AVModel*) avmodel {
......@@ -88,6 +101,7 @@ lrc::api::ConversationModel* conversationModel;
filesToSend[@(conversationUid.c_str())] = @(file_name.c_str());
isRecording = true;
recordButton.image = [NSImage imageNamed:@"ic_stoprecord.png"];
recordButton.title = NSLocalizedString(@"Stop recording", @"Record message title");
[timerBox setHidden:NO];
if (refreshDurationTimer == nil)
refreshDurationTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
......@@ -99,11 +113,11 @@ lrc::api::ConversationModel* conversationModel;
avModel->stopLocalRecorder([filesToSend[@(conversationUid.c_str())] UTF8String]);
isRecording = false;
recordButton.image = [NSImage imageNamed:@"ic_action_audio.png"];
recordButton.title = NSLocalizedString(@"Record a message", @"Record message title");
[refreshDurationTimer invalidate];
refreshDurationTimer = nil;
[timerBox setHidden:YES];
[sendBox setHidden: NO];
[sendFilename setStringValue:[self timeFormatted: recordingTime]];
[sendButton setHidden: NO];
}
}
......@@ -126,28 +140,27 @@ lrc::api::ConversationModel* conversationModel;
- (void)clearData {
recordButton.image = [NSImage imageNamed:@"ic_action_audio.png"];
recordButton.title = NSLocalizedString(@"Record a message", @"Record message title");
recordingTime = 0;
[timerLabel setStringValue: [self timeFormatted: recordingTime]];
[timerLabel setStringValue: [NSString formattedStringTimeFromSeconds: recordingTime]];
isRecording = false;
[timerBox setHidden:YES];
[sendBox setHidden: YES];
[sendButton setHidden: YES];
[refreshDurationTimer invalidate];
refreshDurationTimer = nil;
[sendFilename setStringValue:@""];
[filesToSend removeObjectForKey: @(conversationUid.c_str())];
}
- (void)viewWillHide {
recordButton.image = [NSImage imageNamed:@"ic_action_audio.png"];
recordButton.title = NSLocalizedString(@"Record a message", @"Record message title");
if(filesToSend[@(conversationUid.c_str())]) {
[sendFilename setStringValue:[self timeFormatted: recordingTime]];
[sendBox setHidden: NO];
[sendButton setHidden: NO];
} else {
[sendFilename setStringValue:@""];
[sendBox setHidden: YES];
[sendButton setHidden: YES];
}
recordingTime = 0;
[timerLabel setStringValue: [self timeFormatted: recordingTime]];
[timerLabel setStringValue: [NSString formattedStringTimeFromSeconds: recordingTime]];
isRecording = false;
[timerBox setHidden:YES];
[refreshDurationTimer invalidate];
......@@ -182,7 +195,35 @@ lrc::api::ConversationModel* conversationModel;
QVariant photo = imgManip.conversationPhoto(*it, conversationModel->owner, QSize(120, 120), NO);
[personPhoto setImage:QtMac::toNSImage(qvariant_cast<QPixmap>(photo))];
NSString *name = bestNameForConversation(*it, *conversationModel);
[infoLabel setStringValue:name];
NSFont *fontName = [NSFont systemFontOfSize: 20.0 weight: NSFontWeightSemibold];
NSFont *otherFont = [NSFont systemFontOfSize: 20.0 weight: NSFontWeightThin];
NSColor *color = [NSColor textColor];
NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[style setLineBreakMode:NSLineBreakByWordWrapping];
[style setAlignment:NSCenterTextAlignment];
NSDictionary *nameAttrs = [NSDictionary dictionaryWithObjectsAndKeys:
fontName, NSFontAttributeName,
style, NSParagraphStyleAttributeName,
color, NSForegroundColorAttributeName,
nil];
NSDictionary *otherAttrs = [NSDictionary dictionaryWithObjectsAndKeys:
otherFont, NSFontAttributeName,
style, NSParagraphStyleAttributeName,
color, NSForegroundColorAttributeName,
nil];
NSAttributedString* attributedName = [[NSAttributedString alloc] initWithString:name attributes:nameAttrs];
NSString *str = [NSString stringWithFormat: @"%@%@\n%@",
@" ",
NSLocalizedString(@"appears to be busy.", @"Peer busy message"),
NSLocalizedString(@"Would you like to leave a message?", @"Peer busy message")];
NSAttributedString* attributedOther= [[NSAttributedString alloc] initWithString: str attributes: otherAttrs];
NSMutableAttributedString *result = [[NSMutableAttributedString alloc] init];
[result appendAttributedString:attributedName];
[result appendAttributedString:attributedOther];
NSRange range = NSMakeRange(0, [result length]);
[result addAttribute:NSParagraphStyleAttributeName value:style range: range];
[infoLabel setAttributedStringValue: result];
}
[self show];
}
......@@ -190,14 +231,7 @@ lrc::api::ConversationModel* conversationModel;
-(void) updateDurationLabel
{
recordingTime++;
[timerLabel setStringValue: [self timeFormatted: recordingTime]];
}
- (NSString *)timeFormatted:(int)totalSeconds
{
int seconds = totalSeconds % 60;
int minutes = (totalSeconds / 60) % 60;
return [NSString stringWithFormat:@"%02d:%02d",minutes, seconds];
[timerLabel setStringValue: [NSString formattedStringTimeFromSeconds: recordingTime]];
}
@end
......@@ -20,8 +20,11 @@
#import <Cocoa/Cocoa.h>
#import <api/conversationmodel.h>
#import <api/conversation.h>
#import <api/avmodel.h>
#import "RecordFileVC.h"
@interface MessagesVC : NSViewController
@interface MessagesVC : NSViewController <RecordingViewDelegate>
-(void)setConversationUid:(const std::string)convUid model:(lrc::api::ConversationModel*)model;
-(void)clearData;
......@@ -33,4 +36,6 @@
*/
@property (retain) NSString* message;
-(void) setAVModel: (lrc::api::AVModel*) avmodel;
@end
......@@ -36,6 +36,9 @@
#import "views/IconButton.h"
#import <QuickLook/QuickLook.h>
#import <Quartz/Quartz.h>
#import <AVFoundation/AVFoundation.h>
#import "RecordFileVC.h"
@interface MessagesVC () <NSTableViewDelegate, NSTableViewDataSource, QLPreviewPanelDataSource> {
......@@ -44,12 +47,16 @@
__unsafe_unretained IBOutlet NSView* containerView;
__unsafe_unretained IBOutlet NSTextField* messageField;
__unsafe_unretained IBOutlet IconButton *sendFileButton;
__unsafe_unretained IBOutlet IconButton *recordVideoButton;
__unsafe_unretained IBOutlet IconButton *recordAudioButton;
__unsafe_unretained IBOutlet NSLayoutConstraint* sendPanelHeight;
__unsafe_unretained IBOutlet NSLayoutConstraint* messagesBottomMargin;
IBOutlet NSPopover *recordMessagePopover;
std::string convUid_;
lrc::api::ConversationModel* convModel_;
const lrc::api::conversation::Info* cachedConv_;
lrc::api::AVModel* avModel;
QMetaObject::Connection newInteractionSignal_;
// Both are needed to invalidate cached conversation as pointer
......@@ -59,9 +66,9 @@
QMetaObject::Connection interactionStatusUpdatedSignal_;
NSString* previewImage;
NSMutableDictionary *pendingMessagesToSend;
RecordFileVC * recordingController;
}
@end
// Tags for view
......@@ -113,6 +120,14 @@ typedef NS_ENUM(NSInteger, MessageSequencing) {
return self;
}
-(void) setAVModel: (lrc::api::AVModel*) avmodel {
avModel = avmodel;
if (recordingController == nil) {
recordingController = [[RecordFileVC alloc] initWithNibName:@"RecordFileVC" bundle:nil avModel: self->avModel];
recordingController.delegate = self;
}
}
- (void)setMessage:(NSString *)newValue {
_message = [newValue removeEmptyLinesAtBorders];
}
......@@ -129,6 +144,7 @@ typedef NS_ENUM(NSInteger, MessageSequencing) {
QObject::disconnect(filterChangedSignal_);
QObject::disconnect(interactionStatusUpdatedSignal_);
QObject::disconnect(newInteractionSignal_);
[self closeRecordingView];
}
-(void) scrollToBottom {
......@@ -296,7 +312,7 @@ typedef NS_ENUM(NSInteger, MessageSequencing) {
NSTextField* timeField = [result viewWithTag:GENERIC_INT_TIME_TAG];
// TODO: Fix symbol in LRC
NSString* fixedString = [text stringByReplacingOccurrencesOfString:@"🕽" withString:@"📞"];
NSString* fixedString = [[text stringByReplacingOccurrencesOfString:@"🕽" withString:@""] stringByReplacingOccurrencesOfString:@"📞" withString:@""];
[textField setStringValue:fixedString];
[timeField setStringValue:time];
......@@ -313,7 +329,7 @@ typedef NS_ENUM(NSInteger, MessageSequencing) {
NSString* fileName = @"incoming file";
// First, view is created
if (type == lrc::api::interaction::Type::INCOMING_DATA_TRANSFER) {
if (!interaction.authorUri.empty()) {
switch (status) {
case lrc::api::interaction::Status::TRANSFER_CREATED:
case lrc::api::interaction::Status::TRANSFER_AWAITING_HOST: {
......@@ -341,7 +357,7 @@ typedef NS_ENUM(NSInteger, MessageSequencing) {
result = [tableView makeViewWithIdentifier:@"LeftFinishedFileView" owner:conversationView];
break;
}
} else if (type == lrc::api::interaction::Type::OUTGOING_DATA_TRANSFER) {
} else {
NSString* fileName = @"sent file";
switch (status) {
case lrc::api::interaction::Status::TRANSFER_CREATED:
......@@ -471,8 +487,7 @@ typedef NS_ENUM(NSInteger, MessageSequencing) {
result = [tableView makeViewWithIdentifier:@"LeftMessageView" owner:self];
}
break;
case lrc::api::interaction::Type::INCOMING_DATA_TRANSFER:
case lrc::api::interaction::Type::OUTGOING_DATA_TRANSFER:
case lrc::api::interaction::Type::DATA_TRANSFER:
return [self configureViewforTransfer:interaction interactionID: it->first tableView:tableView];
break;
case lrc::api::interaction::Type::CONTACT:
......@@ -503,7 +518,7 @@ typedef NS_ENUM(NSInteger, MessageSequencing) {
[result.messageStatus setHidden:NO];
[result.sendingMessageIndicator startAnimation:nil];
[result.messageFailed setHidden:YES];
} else if (interaction.status == lrc::api::interaction::Status::FAILED) {
} else if (interaction.status == lrc::api::interaction::Status::FAILURE) {
[result.messageStatus setHidden:NO];
[result.sendingMessageIndicator setHidden:YES];
[result.messageFailed setHidden:NO];
......@@ -582,7 +597,7 @@ typedef NS_ENUM(NSInteger, MessageSequencing) {
bool shouldDisplayTime = (sequence == FIRST_WITH_TIME || sequence == SINGLE_WITH_TIME) ? YES : NO;
if(interaction.type == lrc::api::interaction::Type::INCOMING_DATA_TRANSFER || interaction.type == lrc::api::interaction::Type::OUTGOING_DATA_TRANSFER) {
if(interaction.type == lrc::api::interaction::Type::DATA_TRANSFER) {
if( interaction.status == lrc::api::interaction::Status::TRANSFER_FINISHED) {
NSString* name = @(interaction.body.c_str());
......@@ -717,8 +732,7 @@ typedef NS_ENUM(NSInteger, MessageSequencing) {
bool timeChanged = [self sequenceTimeChangedFrom:interaction to:previousInteraction];
bool authorChanged = [self sequenceAuthorChangedFrom:interaction to:previousInteraction];
bool sequenceWillChange = [self sequenceChangedFrom:interaction to: nextInteraction];
if (previousInteraction.type == lrc::api::interaction::Type::OUTGOING_DATA_TRANSFER ||
previousInteraction.type == lrc::api::interaction::Type::INCOMING_DATA_TRANSFER) {
if (previousInteraction.type == lrc::api::interaction::Type::DATA_TRANSFER) {
if(!sequenceWillChange) {
return FIRST_WITH_TIME;
}
......@@ -772,21 +786,17 @@ typedef NS_ENUM(NSInteger, MessageSequencing) {
if ([[NSCalendar currentCalendar] compareDate:today
toDate:msgTime
toUnitGranularity:NSCalendarUnitYear]!= NSOrderedSame) {
return [NSDateFormatter localizedStringFromDate:msgTime dateStyle:NSDateFormatterMediumStyle timeStyle:NSDateFormatterMediumStyle];
return [NSDateFormatter localizedStringFromDate:msgTime dateStyle:NSDateFormatterLongStyle timeStyle:NSDateFormatterMediumStyle];
}
if ([[NSCalendar currentCalendar] compareDate:today
toDate:msgTime
toUnitGranularity:NSCalendarUnitDay]!= NSOrderedSame ||
[[NSCalendar currentCalendar] compareDate:today
toDate:msgTime
toUnitGranularity:NSCalendarUnitMonth]!= NSOrderedSame) {
[dateFormatter setDateFormat:@"MMM dd, HH:mm"];
return [dateFormatter stringFromDate:msgTime];
}
[dateFormatter setDateFormat:@"HH:mm"];
return [dateFormatter stringFromDate:msgTime];
return [NSDateFormatter localizedStringFromDate:msgTime dateStyle:NSDateFormatterShortStyle timeStyle:NSDateFormatterShortStyle];