Commit 886cde17 authored by Alexandre Lision's avatar Alexandre Lision

accounts: refactor account panel

This commit simplifies the UI to manage (create, remove, backup,
restore) accounts. It includes the rewording of the previous
Import/Export feature to prevent confusion with the new multidevice
export.
Import is now 'Restore account'
Export is now 'Backup account'
Additionnal label have been added as well

Tuleap: #1152
Change-Id: I64506ce8a2d740f33eeb4719efb4bf8e9f2df746
parent 849514f5
......@@ -114,8 +114,10 @@ SET(ringclient_CONTROLLERS
src/AccSecurityVC.h
src/CertificateWC.mm
src/CertificateWC.h
src/PathPasswordWC.mm
src/PathPasswordWC.h
src/BackupAccountWC.mm
src/BackupAccountWC.h
src/RestoreAccountWC.mm
src/RestoreAccountWC.h
src/AudioPrefsVC.mm
src/AudioPrefsVC.h
src/AccountsVC.mm
......@@ -209,7 +211,8 @@ SET(ringclient_XIBS
PreferencesWindow
RingWizard
CertificateWindow
PathPasswordWindow
BackupAccountWindow
RestoreAccountWindow
ExportPasswordWindow
MigrateRingAccountsWindow
PersonLinker
......
......@@ -86,11 +86,6 @@ typedef NS_ENUM(NSInteger, TagViews) {
AccountModel::instance().selectedAccount()->setHasCustomUserAgent([sender state] == NSOnState);
}
- (IBAction)removeAccount:(id)sender {
AccountModel::instance().remove(AccountModel::instance().selectedAccount());
AccountModel::instance().save();
}
- (void)loadAccount
{
auto account = AccountModel::instance().selectedAccount();
......
......@@ -24,7 +24,6 @@
@interface AccRingVC ()
@property (assign) IBOutlet NSTextField *aliasTextField;
@property (assign) IBOutlet NSTextField *typeLabel;
@property (assign) IBOutlet NSTextField *bootstrapField;
@property (assign) IBOutlet NSTextField *hashField;
......@@ -39,7 +38,6 @@
@end
@implementation AccRingVC
@synthesize typeLabel;
@synthesize bootstrapField;
@synthesize hashField;
@synthesize aliasTextField;
......@@ -71,19 +69,12 @@ typedef NS_ENUM(NSInteger, TagViews) {
});
}
- (IBAction)removeAccount:(id)sender {
AccountModel::instance().remove(AccountModel::instance().selectedAccount());
AccountModel::instance().save();
}
- (void)loadAccount
{
auto account = AccountModel::instance().selectedAccount();
[self.aliasTextField setStringValue:account->alias().toNSString()];
[typeLabel setStringValue:@"RING"];
[allowUnknown setState:account->allowIncomingFromUnknown()];
[allowHistory setState:account->allowIncomingFromHistory()];
[allowContacts setState:account->allowIncomingFromContact()];
......
This diff is collapsed.
/*
* Copyright (C) 2016 Savoir-faire Linux Inc.
* Author: Alexandre Lision <alexandre.lision@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 <QtCore/qdir.h>
#import "LoadingWCDelegate.h"
#import "AbstractLoadingWC.h"
@protocol BackupAccountDelegate <LoadingWCDelegate>
@optional
-(void) didCompleteExportWithPath:(NSURL*) path;
@end
@interface BackupAccountWC : AbstractLoadingWC
- (id)initWithDelegate:(id <LoadingWCDelegate>) del;
/**
* Allow the NSPathControl of this window to select files or not
*/
@property (nonatomic) BOOL allowFileSelection;
/**
* password string contained in passwordField.
* This is a KVO method to bind the text with the OK Button
* if password.length is > 0, button is enabled, otherwise disabled
*/
@property (retain) NSString* password;
/**
* Object uses to store account to exports
*/
@property (assign) QStringList accounts;
/**
* passwordConfirmation string contained in passwordConfirmationField.
*/
@property (retain) NSString* passwordConfirmation;
/**
* computed properties calculated by password string contained in
* passwordField and passwordCOnfirmation string contained
* inpasswordConfirmationField
* This is a KVO method to bind the text with the OK Button
* if password.length is > 0 AND passwordConfirmation.length > 0
* AND password isEqualsToString passwordCOnfirmationbutton is enabled,
* otherwise disabled
*/
@property (readonly) BOOL validatePasswords;
@end
/*
* Copyright (C) 2016 Savoir-faire Linux Inc.
* Author: Alexandre Lision <alexandre.lision@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 "BackupAccountWC.h"
//LRC
#import <accountmodel.h>
//Ring
#import "views/ITProgressIndicator.h"
@interface BackupAccountWC() <NSTextFieldDelegate> {
__unsafe_unretained IBOutlet NSPathControl* path;
__unsafe_unretained IBOutlet NSSecureTextField* passwordField;
__unsafe_unretained IBOutlet NSSecureTextField* passwordConfirmationField;
__unsafe_unretained IBOutlet ITProgressIndicator* progressIndicator;
}
@end
@implementation BackupAccountWC {
struct {
unsigned int didCompleteExport:1;
} delegateRespondsTo;
}
@synthesize accounts;
- (id)initWithDelegate:(id <LoadingWCDelegate>) del
{
return [self initWithDelegate:del actionCode:0];
}
- (id)initWithDelegate:(id <BackupAccountDelegate>) del actionCode:(NSInteger) code
{
return [super initWithWindowNibName:@"BackupAccountWindow" delegate:del actionCode:code];
}
- (void)windowDidLoad
{
[super windowDidLoad];
[path setURL: [NSURL fileURLWithPath:NSHomeDirectory()]];
}
- (void)setDelegate:(id <BackupAccountDelegate>)aDelegate
{
if (self.delegate != aDelegate) {
[super setDelegate: aDelegate];
delegateRespondsTo.didCompleteExport = [self.delegate respondsToSelector:@selector(didCompleteExportWithPath:)];
}
}
- (BOOL)validatePasswords
{
BOOL result = (self.password.length != 0 && [self.password isEqualToString:self.passwordConfirmation]);
NSLog(@"ValidatesPasswords : %s", result ? "true" : "false");
return result;
}
+ (NSSet *)keyPathsForValuesAffectingValidatePasswords
{
return [NSSet setWithObjects:@"password", @"passwordConfirmation", nil];
}
- (void) setAllowFileSelection:(BOOL) b
{
_allowFileSelection = b;
[path setAllowedTypes:_allowFileSelection ? nil : [NSArray arrayWithObject:@"public.folder"]];
}
- (IBAction)completeAction:(id)sender
{
auto finalURL = [path.URL URLByAppendingPathComponent:@"accounts.ring"];
[self showLoading];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
int result = AccountModel::instance().exportAccounts(accounts, finalURL.path.UTF8String, passwordField.stringValue.UTF8String);
switch (result) {
case 0:
if (delegateRespondsTo.didCompleteExport){
[((id<BackupAccountDelegate>)self.delegate) didCompleteExportWithPath:finalURL];
}
[self close];
break;
default:{
[self showError] ;
}break;
}
});
}
- (void)showLoading
{
[progressIndicator setNumberOfLines:30];
[progressIndicator setWidthOfLine:2];
[progressIndicator setLengthOfLine:5];
[progressIndicator setInnerMargin:20];
[super showLoading];
}
@end
......@@ -30,17 +30,17 @@ typedef NS_ENUM(NSUInteger, Action) {
ACTION_IMPORT = 1,
};
@protocol PathPasswordDelegate <LoadingWCDelegate>
@protocol RestoreAccountDelegate <LoadingWCDelegate>
@optional
-(void) didCompleteExportWithPath:(NSURL*) path;
-(void) didCompleteImport;
@end
@interface PathPasswordWC : AbstractLoadingWC
@interface RestoreAccountWC : AbstractLoadingWC
- (id)initWithDelegate:(id <LoadingWCDelegate>) del;
/**
* Allow the NSPathControl of this window to select files or not
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#import "PathPasswordWC.h"
#import "RestoreAccountWC.h"
//LRC
#import <accountmodel.h>
......@@ -24,26 +24,29 @@
//Ring
#import "views/ITProgressIndicator.h"
@interface PathPasswordWC() <NSTextFieldDelegate>{
@interface RestoreAccountWC() <NSTextFieldDelegate> {
__unsafe_unretained IBOutlet NSPathControl* path;
__unsafe_unretained IBOutlet NSSecureTextField* passwordField;
__unsafe_unretained IBOutlet NSTextField* errorField;
__unsafe_unretained IBOutlet ITProgressIndicator* progressIndicator;
}
@end
@implementation PathPasswordWC {
@implementation RestoreAccountWC {
struct {
unsigned int didCompleteExport:1;
unsigned int didCompleteImport:1;
} delegateRespondsTo;
}
@synthesize accounts;
- (id)initWithDelegate:(id <PathPasswordDelegate>) del actionCode:(NSInteger) code
- (id)initWithDelegate:(id <LoadingWCDelegate>) del
{
return [super initWithWindowNibName:@"PathPasswordWindow" delegate:del actionCode:code];
return [self initWithDelegate:del actionCode:0];
}
- (id)initWithDelegate:(id <RestoreAccountDelegate>) del actionCode:(NSInteger) code
{
return [super initWithWindowNibName:@"RestoreAccountWindow" delegate:del actionCode:code];
}
- (void)windowDidLoad
......@@ -52,11 +55,10 @@
[path setURL: [NSURL fileURLWithPath:NSHomeDirectory()]];
}
- (void)setDelegate:(id <PathPasswordDelegate>)aDelegate
- (void)setDelegate:(id <RestoreAccountDelegate>)aDelegate
{
if (self.delegate != aDelegate) {
[super setDelegate: aDelegate];
delegateRespondsTo.didCompleteExport = [self.delegate respondsToSelector:@selector(didCompleteExportWithPath:)];
delegateRespondsTo.didCompleteImport = [self.delegate respondsToSelector:@selector(didCompleteWithImport)];
}
}
......@@ -67,13 +69,23 @@
[path setAllowedTypes:_allowFileSelection ? nil : [NSArray arrayWithObject:@"public.folder"]];
}
- (IBAction)completeAction:(id)sender
{
[self didCompleteWithPath:path.URL Password:passwordField.stringValue ActionCode:self.actionCode];
auto passwordString = passwordField.stringValue;
auto pathURL = path.URL;
[self showLoading];
SEL sel = @selector(importAccountsWithPath:andPassword:);
NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:sel]];
[inv setSelector:sel];
[inv setTarget:self];
//arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation
[inv setArgument:&pathURL atIndex:2];
[inv setArgument:&passwordString atIndex:3];
// Schedule import for next iteration of event loop in order to let us start the loading anim
[inv performSelector:@selector(invoke) withObject:nil afterDelay:0];
}
- (void)showLoading
{
[progressIndicator setNumberOfLines:30];
......@@ -83,63 +95,17 @@
[super showLoading];
}
-(void) didCompleteWithPath:(NSURL*) path Password:(NSString*) password ActionCode:(NSInteger)requestCode
{
switch (requestCode) {
case Action::ACTION_EXPORT:
{
auto finalURL = [path URLByAppendingPathComponent:@"accounts.ring"];
[self showLoading];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
int result = AccountModel::instance().exportAccounts(accounts, finalURL.path.UTF8String, password.UTF8String);
switch (result) {
case 0:
if (delegateRespondsTo.didCompleteExport){
[((id<PathPasswordDelegate>)self.delegate) didCompleteExportWithPath:finalURL];
}
[self close];
break;
default:{
[errorField setStringValue:NSLocalizedString(@"An error occured during the export", @"Error shown to the user" )];
[self showError] ;
}break;
}
});
}
break;
case Action::ACTION_IMPORT: {
[self showLoading];
SEL sel = @selector(importAccountsWithPath:andPassword:);
NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:sel]];
[inv setSelector:sel];
[inv setTarget:self];
//arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation
[inv setArgument:&path atIndex:2];
[inv setArgument:&password atIndex:3];
// Schedule import for next iteration of event loop in order to let us start the loading anim
[inv performSelector:@selector(invoke) withObject:nil afterDelay:0];
}
break;
default:
NSLog(@"Unrecognized action %d", requestCode);
break;
}
}
- (void) importAccountsWithPath:(NSURL*) path andPassword:(NSString*) password
- (void) importAccountsWithPath:(NSURL*) urlPath andPassword:(NSString*) password
{
int result = AccountModel::instance().importAccounts(path.path.UTF8String, password.UTF8String);
int result = AccountModel::instance().importAccounts(urlPath.path.UTF8String, password.UTF8String);
switch (result) {
case 0:
if (delegateRespondsTo.didCompleteImport)
[((id<PathPasswordDelegate>)self.delegate) didCompleteImport];
[((id<RestoreAccountDelegate>)self.delegate) didCompleteImport];
[self close];
break;
default:
{
[errorField setStringValue:NSLocalizedString(@"An error occured during the import", @"Error shown to the user" )];
[self showError];
}
break;
......
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11201" systemVersion="15G1004" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11201" systemVersion="16B2553a" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11201"/>
</dependencies>
......@@ -22,7 +22,7 @@
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customView id="c22-O7-iKe">
<rect key="frame" x="0.0" y="0.0" width="582" height="380"/>
<rect key="frame" x="0.0" y="0.0" width="474" height="380"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="0Ej-Lr-p20">
......@@ -214,20 +214,6 @@
<action selector="toggleUpnp:" target="-2" id="pl8-QR-BBc"/>
</connections>
</button>
<button translatesAutoresizingMaskIntoConstraints="NO" id="p00-of-ToC">
<rect key="frame" x="532" y="330" width="30" height="30"/>
<constraints>
<constraint firstAttribute="width" constant="30" id="2ib-pL-Iah"/>
<constraint firstAttribute="height" constant="30" id="cbq-Gc-goJ"/>
</constraints>
<buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="ic_delete" imagePosition="only" alignment="center" imageScaling="proportionallyUpOrDown" inset="2" id="u1c-BX-hXL">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="removeAccount:" target="-2" id="uzp-ub-gsq"/>
</connections>
</button>
<button translatesAutoresizingMaskIntoConstraints="NO" id="TiO-iR-TOU">
<rect key="frame" x="154" y="19" width="42" height="18"/>
<buttonCell key="cell" type="radio" title="SIP" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="jch-Qt-hTO">
......@@ -271,7 +257,6 @@
<constraint firstItem="Rsc-fc-lz8" firstAttribute="top" secondItem="POs-9R-DUW" secondAttribute="bottom" constant="18" id="GSg-HW-W8s"/>
<constraint firstItem="T5L-Hx-tAq" firstAttribute="top" secondItem="Rsc-fc-lz8" secondAttribute="bottom" constant="16" id="H5c-Bw-EuR"/>
<constraint firstItem="POs-9R-DUW" firstAttribute="leading" secondItem="3ZB-JI-U6Y" secondAttribute="trailing" constant="8" id="I7j-dS-1py"/>
<constraint firstAttribute="trailing" secondItem="p00-of-ToC" secondAttribute="trailing" constant="20" symbolic="YES" id="IzJ-IM-9AB"/>
<constraint firstItem="Rsc-fc-lz8" firstAttribute="trailing" secondItem="T5L-Hx-tAq" secondAttribute="trailing" id="JlA-2p-9dJ"/>
<constraint firstItem="x2R-Ot-MbT" firstAttribute="leading" secondItem="Otd-nX-zTh" secondAttribute="leading" id="LeR-6H-gXC"/>
<constraint firstItem="a4o-bf-KQu" firstAttribute="baseline" secondItem="y8K-Hi-TMC" secondAttribute="baseline" id="NFa-EB-UB7"/>
......@@ -291,7 +276,6 @@
<constraint firstItem="a4o-bf-KQu" firstAttribute="top" secondItem="T5L-Hx-tAq" secondAttribute="bottom" constant="17" id="g8X-uT-844"/>
<constraint firstItem="h5v-jy-4zX" firstAttribute="top" secondItem="c22-O7-iKe" secondAttribute="top" constant="20" symbolic="YES" id="gQs-pR-Wa3"/>
<constraint firstItem="Ilk-QS-8PT" firstAttribute="leading" secondItem="7wz-eU-lJh" secondAttribute="trailing" constant="8" symbolic="YES" id="gXl-g0-zFa"/>
<constraint firstItem="h5v-jy-4zX" firstAttribute="top" secondItem="p00-of-ToC" secondAttribute="top" id="iP9-fP-Vgi"/>
<constraint firstItem="TiO-iR-TOU" firstAttribute="top" secondItem="ATi-aw-lOp" secondAttribute="bottom" constant="6" id="jWm-jt-2fo"/>
<constraint firstItem="y8K-Hi-TMC" firstAttribute="leading" secondItem="a4o-bf-KQu" secondAttribute="trailing" constant="8" id="joX-fO-ZF6"/>
<constraint firstItem="h5v-jy-4zX" firstAttribute="leading" secondItem="c22-O7-iKe" secondAttribute="leading" constant="20" symbolic="YES" id="jvd-5E-ELU"/>
......@@ -308,10 +292,7 @@
<constraint firstItem="ATi-aw-lOp" firstAttribute="top" secondItem="a4o-bf-KQu" secondAttribute="bottom" constant="23" id="zeU-0O-mqX"/>
<constraint firstItem="0Ej-Lr-p20" firstAttribute="leading" secondItem="7fA-3M-fa5" secondAttribute="trailing" constant="8" id="zhV-Nm-bmz"/>
</constraints>
<point key="canvasLocation" x="13" y="37"/>
<point key="canvasLocation" x="-41" y="37"/>
</customView>
</objects>
<resources>
<image name="ic_delete" width="72" height="72"/>
</resources>
</document>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment