You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			197 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			JavaScript
		
	
			
		
		
	
	
			197 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			JavaScript
		
	
/*
 | 
						|
 * vim: ts=4:sw=4:expandtab
 | 
						|
 */
 | 
						|
(function () {
 | 
						|
    'use strict';
 | 
						|
    window.Whisper = window.Whisper || {};
 | 
						|
 | 
						|
    var Steps = {
 | 
						|
        INSTALL_SIGNAL: 2,
 | 
						|
        SCAN_QR_CODE: 3,
 | 
						|
        ENTER_NAME: 4,
 | 
						|
        PROGRESS_BAR: 5,
 | 
						|
        TOO_MANY_DEVICES: 'TooManyDevices',
 | 
						|
        NETWORK_ERROR: 'NetworkError',
 | 
						|
    };
 | 
						|
 | 
						|
    var DEVICE_NAME_SELECTOR = 'input.device-name';
 | 
						|
    var CONNECTION_ERROR = -1;
 | 
						|
    var TOO_MANY_DEVICES = 411;
 | 
						|
 | 
						|
    Whisper.InstallView = Whisper.View.extend({
 | 
						|
        templateName: 'link-flow-template',
 | 
						|
        className: 'main full-screen-flow',
 | 
						|
        events: {
 | 
						|
            'click .try-again': 'connect',
 | 
						|
            'click .finish': 'finishLinking',
 | 
						|
            // the actual next step happens in confirmNumber() on submit form #link-phone
 | 
						|
        },
 | 
						|
        initialize: function(options) {
 | 
						|
            options = options || {};
 | 
						|
 | 
						|
            this.selectStep(Steps.SCAN_QR_CODE);
 | 
						|
            this.connect();
 | 
						|
            this.on('disconnected', this.reconnect);
 | 
						|
 | 
						|
            // Keep data around if it's a re-link, or the middle of a light import
 | 
						|
            this.shouldRetainData = Whisper.Registration.everDone() || options.hasExistingData;
 | 
						|
        },
 | 
						|
        render_attributes: function() {
 | 
						|
            var errorMessage;
 | 
						|
 | 
						|
            if (this.error) {
 | 
						|
                if (this.error.name === 'HTTPError'
 | 
						|
                    && this.error.code == TOO_MANY_DEVICES) {
 | 
						|
 | 
						|
                    errorMessage = i18n('installTooManyDevices');
 | 
						|
                }
 | 
						|
                else if (this.error.name === 'HTTPError'
 | 
						|
                    && this.error.code == CONNECTION_ERROR) {
 | 
						|
 | 
						|
                    errorMessage = i18n('installConnectionFailed');
 | 
						|
                }
 | 
						|
                else if (this.error.message === 'websocket closed') {
 | 
						|
                    // AccountManager.registerSecondDevice uses this specific
 | 
						|
                    //   'websocket closed' error message
 | 
						|
                    errorMessage = i18n('installConnectionFailed');
 | 
						|
                }
 | 
						|
 | 
						|
                return {
 | 
						|
                    isError: true,
 | 
						|
                    errorHeader: 'Something went wrong!',
 | 
						|
                    errorMessage,
 | 
						|
                    errorButton: 'Try again',
 | 
						|
                };
 | 
						|
            }
 | 
						|
 | 
						|
            return {
 | 
						|
                isStep3: this.step === Steps.SCAN_QR_CODE,
 | 
						|
                linkYourPhone: i18n('linkYourPhone'),
 | 
						|
                signalSettings: i18n('signalSettings'),
 | 
						|
                linkedDevices: i18n('linkedDevices'),
 | 
						|
                androidFinalStep: i18n('plusButton'),
 | 
						|
                appleFinalStep: i18n('linkNewDevice'),
 | 
						|
 | 
						|
                isStep4: this.step === Steps.ENTER_NAME,
 | 
						|
                chooseName: i18n('chooseDeviceName'),
 | 
						|
                finishLinkingPhoneButton: i18n('finishLinkingPhone'),
 | 
						|
 | 
						|
                isStep5: this.step === Steps.PROGRESS_BAR,
 | 
						|
                syncing: i18n('initialSync'),
 | 
						|
            };
 | 
						|
        },
 | 
						|
        selectStep: function(step) {
 | 
						|
            this.step = step;
 | 
						|
            this.render();
 | 
						|
        },
 | 
						|
        connect: function() {
 | 
						|
            this.error = null;
 | 
						|
            this.selectStep(Steps.SCAN_QR_CODE);
 | 
						|
            this.clearQR();
 | 
						|
            if (this.timeout) {
 | 
						|
                clearTimeout(this.timeout);
 | 
						|
                this.timeout = null;
 | 
						|
            }
 | 
						|
 | 
						|
            var accountManager = getAccountManager();
 | 
						|
 | 
						|
            accountManager.registerSecondDevice(
 | 
						|
                this.setProvisioningUrl.bind(this),
 | 
						|
                this.confirmNumber.bind(this)
 | 
						|
            ).catch(this.handleDisconnect.bind(this));
 | 
						|
        },
 | 
						|
        handleDisconnect: function(e) {
 | 
						|
            console.log('provisioning failed', e.stack);
 | 
						|
 | 
						|
            this.error = e;
 | 
						|
            this.render();
 | 
						|
 | 
						|
            if (e.message === 'websocket closed') {
 | 
						|
                this.trigger('disconnected');
 | 
						|
            } else if (e.name !== 'HTTPError'
 | 
						|
                || (e.code !== CONNECTION_ERROR && e.code !== TOO_MANY_DEVICES)) {
 | 
						|
 | 
						|
                throw e;
 | 
						|
            }
 | 
						|
        },
 | 
						|
        reconnect: function() {
 | 
						|
            if (this.timeout) {
 | 
						|
                clearTimeout(this.timeout);
 | 
						|
                this.timeout = null;
 | 
						|
            }
 | 
						|
            this.timeout = setTimeout(this.connect.bind(this), 10000);
 | 
						|
        },
 | 
						|
        clearQR: function() {
 | 
						|
            this.$('#qr img').remove();
 | 
						|
            this.$('#qr canvas').remove();
 | 
						|
            this.$('#qr .container').show();
 | 
						|
            this.$('#qr').removeClass('ready');
 | 
						|
        },
 | 
						|
        setProvisioningUrl: function(url) {
 | 
						|
            if ($('#qr').length === 0) {
 | 
						|
                console.log('Did not find #qr element in the DOM!');
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            this.$('#qr .container').hide();
 | 
						|
            this.qr = new QRCode(this.$('#qr')[0]).makeCode(url);
 | 
						|
            this.$('#qr').removeAttr('title');
 | 
						|
            this.$('#qr').addClass('ready');
 | 
						|
        },
 | 
						|
        setDeviceNameDefault: function() {
 | 
						|
            var deviceName = textsecure.storage.user.getDeviceName();
 | 
						|
 | 
						|
            this.$(DEVICE_NAME_SELECTOR).val(deviceName || window.config.hostname);
 | 
						|
            this.$(DEVICE_NAME_SELECTOR).focus();
 | 
						|
        },
 | 
						|
        finishLinking: function() {
 | 
						|
            // We use a form so we get submit-on-enter behavior
 | 
						|
            this.$('#link-phone').submit();
 | 
						|
        },
 | 
						|
        confirmNumber: function(number) {
 | 
						|
            var tsp = textsecure.storage.protocol;
 | 
						|
 | 
						|
            window.removeSetupMenuItems();
 | 
						|
            this.selectStep(Steps.ENTER_NAME);
 | 
						|
            this.setDeviceNameDefault();
 | 
						|
 | 
						|
            return new Promise(function(resolve, reject) {
 | 
						|
                this.$('#link-phone').submit(function(e) {
 | 
						|
                    e.stopPropagation();
 | 
						|
                    e.preventDefault();
 | 
						|
 | 
						|
                    var name = this.$(DEVICE_NAME_SELECTOR).val();
 | 
						|
                    name = name.replace(/\0/g,''); // strip unicode null
 | 
						|
                    if (name.trim().length === 0) {
 | 
						|
                        this.$(DEVICE_NAME_SELECTOR).focus();
 | 
						|
                        return;
 | 
						|
                    }
 | 
						|
 | 
						|
                    this.selectStep(Steps.PROGRESS_BAR);
 | 
						|
 | 
						|
                    var finish = function() {
 | 
						|
                        resolve(name);
 | 
						|
                    };
 | 
						|
 | 
						|
                    // Delete all data from database unless we're in the middle
 | 
						|
                    //   of a re-link, or we are finishing a light import. Without this,
 | 
						|
                    //   app restarts at certain times can cause weird things to happen,
 | 
						|
                    //   like data from a previous incomplete light import showing up
 | 
						|
                    //   after a new install.
 | 
						|
                    if (this.shouldRetainData) {
 | 
						|
                        return finish();
 | 
						|
                    }
 | 
						|
 | 
						|
                    tsp.removeAllData().then(finish, function(error) {
 | 
						|
                        console.log(
 | 
						|
                          'confirmNumber: error clearing database',
 | 
						|
                          error && error.stack ? error.stack : error
 | 
						|
                        );
 | 
						|
                        finish();
 | 
						|
                    });
 | 
						|
                }.bind(this));
 | 
						|
            }.bind(this));
 | 
						|
        },
 | 
						|
    });
 | 
						|
})();
 |