Fixes #138- delays identicon update to avoid leaking interactive keyboard input.
This commit is contained in:
		@@ -10,7 +10,7 @@ To skip the intro and go straight to the information on how to use the code, [cl
 | 
			
		||||
 | 
			
		||||
Master Password is available for [📲 iOS](https://itunes.apple.com/app/id510296984), [🖥 macOS](https://ssl.masterpasswordapp.com/masterpassword-mac.zip), [📲 Android](https://ssl.masterpasswordapp.com/masterpassword-android.apk), [🖥 Desktop](https://ssl.masterpasswordapp.com/masterpassword-gui.jar), and [⌨ Console](https://ssl.masterpasswordapp.com/masterpassword-cli.tar.gz).
 | 
			
		||||
 | 
			
		||||
Master Password is also available from the following package managers: [mac OS: Homebrew](https://brew.sh/).  Get in touch if you are interested in adding Master Password to any other package managers.
 | 
			
		||||
Master Password is also available from the following package managers: [macOS: Homebrew](https://brew.sh/).  Get in touch if you are interested in adding Master Password to any other package managers.
 | 
			
		||||
 | 
			
		||||
## What is a password?
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,15 @@
 | 
			
		||||
apply plugin: 'java'
 | 
			
		||||
plugins {
 | 
			
		||||
    id 'java'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
description = 'Master Password Algorithm Implementation'
 | 
			
		||||
 | 
			
		||||
dependencies {
 | 
			
		||||
    compile( 'com.lyndir.lhunath.opal:opal-system:1.6-p10' ) {
 | 
			
		||||
    compile (group: 'com.lyndir.lhunath.opal', name: 'opal-system', version: '1.6-p10') {
 | 
			
		||||
        exclude( module: 'joda-time' )
 | 
			
		||||
    }
 | 
			
		||||
    compile 'com.lambdaworks:scrypt:1.4.0'
 | 
			
		||||
    compile 'org.jetbrains:annotations:13.0'
 | 
			
		||||
    compile 'com.google.code.findbugs:jsr305:3.0.1'
 | 
			
		||||
 | 
			
		||||
    compile group: 'com.lambdaworks', name: 'scrypt', version: '1.4.0'
 | 
			
		||||
    compile group: 'org.jetbrains', name: 'annotations', version: '13.0'
 | 
			
		||||
    compile group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.1'
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,6 @@ dependencies {
 | 
			
		||||
    compile     project(':masterpassword:algorithm')
 | 
			
		||||
 | 
			
		||||
    compile     group: 'joda-time', name: 'joda-time', version:'2.4'
 | 
			
		||||
 | 
			
		||||
    compileOnly group: 'com.google.auto.value', name: 'auto-value', version: '1.2'
 | 
			
		||||
    apt         group: 'com.google.auto.value', name: 'auto-value', version: '1.2'
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,6 @@
 | 
			
		||||
apply plugin: 'java'
 | 
			
		||||
plugins {
 | 
			
		||||
    id 'java'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
description = 'Master Password Test Suite'
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,14 +2,10 @@ package com.lyndir.masterpassword;
 | 
			
		||||
 | 
			
		||||
import static org.testng.Assert.*;
 | 
			
		||||
 | 
			
		||||
import com.google.common.io.Resources;
 | 
			
		||||
import com.lyndir.lhunath.opal.system.CodeUtils;
 | 
			
		||||
import com.lyndir.lhunath.opal.system.logging.Logger;
 | 
			
		||||
import com.lyndir.lhunath.opal.system.util.NNFunctionNN;
 | 
			
		||||
import com.lyndir.lhunath.opal.system.util.StringUtils;
 | 
			
		||||
import java.net.URL;
 | 
			
		||||
import javax.annotation.Nonnull;
 | 
			
		||||
import javax.xml.bind.JAXBContext;
 | 
			
		||||
import org.testng.annotations.BeforeMethod;
 | 
			
		||||
import org.testng.annotations.Test;
 | 
			
		||||
 | 
			
		||||
@@ -88,7 +84,7 @@ public class MasterKeyTest {
 | 
			
		||||
            masterKey.encode( defaultCase.getSiteName(), defaultCase.getSiteType(), defaultCase.getSiteCounter(),
 | 
			
		||||
                              defaultCase.getSiteVariant(), defaultCase.getSiteContext() );
 | 
			
		||||
 | 
			
		||||
            assertTrue( false, "[testInvalidate] Master key should have been invalidated, but was still usable." );
 | 
			
		||||
            fail( "[testInvalidate] Master key should have been invalidated, but was still usable." );
 | 
			
		||||
        }
 | 
			
		||||
        catch (IllegalStateException ignored) {
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										30
									
								
								gradle/.idea/runConfigurations/Android.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								gradle/.idea/runConfigurations/Android.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
			
		||||
<component name="ProjectRunConfigurationManager">
 | 
			
		||||
  <configuration default="false" name="Android" type="AndroidRunConfigurationType" factoryName="Android App">
 | 
			
		||||
    <module name="android" />
 | 
			
		||||
    <option name="DEPLOY" value="true" />
 | 
			
		||||
    <option name="ARTIFACT_NAME" value="" />
 | 
			
		||||
    <option name="PM_INSTALL_OPTIONS" value="" />
 | 
			
		||||
    <option name="ACTIVITY_EXTRA_FLAGS" value="" />
 | 
			
		||||
    <option name="MODE" value="default_activity" />
 | 
			
		||||
    <option name="TARGET_SELECTION_MODE" value="SHOW_DIALOG" />
 | 
			
		||||
    <option name="PREFERRED_AVD" value="" />
 | 
			
		||||
    <option name="CLEAR_LOGCAT" value="false" />
 | 
			
		||||
    <option name="SHOW_LOGCAT_AUTOMATICALLY" value="false" />
 | 
			
		||||
    <option name="SKIP_NOOP_APK_INSTALLATIONS" value="true" />
 | 
			
		||||
    <option name="FORCE_STOP_RUNNING_APP" value="true" />
 | 
			
		||||
    <option name="DEBUGGER_TYPE" value="Java" />
 | 
			
		||||
    <option name="USE_LAST_SELECTED_DEVICE" value="false" />
 | 
			
		||||
    <option name="PREFERRED_AVD" value="" />
 | 
			
		||||
    <Java />
 | 
			
		||||
    <Profilers>
 | 
			
		||||
      <option name="ENABLE_ADVANCED_PROFILING" value="false" />
 | 
			
		||||
      <option name="GAPID_ENABLED" value="false" />
 | 
			
		||||
      <option name="GAPID_DISABLE_PCS" value="false" />
 | 
			
		||||
      <option name="SUPPORT_LIB_ENABLED" value="true" />
 | 
			
		||||
      <option name="INSTRUMENTATION_ENABLED" value="true" />
 | 
			
		||||
    </Profilers>
 | 
			
		||||
    <option name="DEEP_LINK" value="" />
 | 
			
		||||
    <option name="ACTIVITY_CLASS" value="" />
 | 
			
		||||
    <method />
 | 
			
		||||
  </configuration>
 | 
			
		||||
</component>
 | 
			
		||||
							
								
								
									
										16
									
								
								gradle/.idea/runConfigurations/GUI.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								gradle/.idea/runConfigurations/GUI.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
<component name="ProjectRunConfigurationManager">
 | 
			
		||||
  <configuration default="false" name="GUI" type="Application" factoryName="Application">
 | 
			
		||||
    <option name="MAIN_CLASS_NAME" value="com.lyndir.masterpassword.gui.GUI" />
 | 
			
		||||
    <option name="VM_PARAMETERS" value="" />
 | 
			
		||||
    <option name="PROGRAM_PARAMETERS" value="" />
 | 
			
		||||
    <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
 | 
			
		||||
    <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
 | 
			
		||||
    <option name="ALTERNATIVE_JRE_PATH" />
 | 
			
		||||
    <option name="ENABLE_SWING_INSPECTOR" value="false" />
 | 
			
		||||
    <option name="ENV_VARIABLES" />
 | 
			
		||||
    <option name="PASS_PARENT_ENVS" value="true" />
 | 
			
		||||
    <module name="gui" />
 | 
			
		||||
    <envs />
 | 
			
		||||
    <method />
 | 
			
		||||
  </configuration>
 | 
			
		||||
</component>
 | 
			
		||||
							
								
								
									
										29
									
								
								gradle/.idea/runConfigurations/Tests.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								gradle/.idea/runConfigurations/Tests.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
<component name="ProjectRunConfigurationManager">
 | 
			
		||||
  <configuration default="false" name="Tests" type="TestNG" factoryName="TestNG">
 | 
			
		||||
    <module name="tests" />
 | 
			
		||||
    <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
 | 
			
		||||
    <option name="ALTERNATIVE_JRE_PATH" />
 | 
			
		||||
    <option name="SUITE_NAME" value="" />
 | 
			
		||||
    <option name="PACKAGE_NAME" value="com.lyndir.masterpassword" />
 | 
			
		||||
    <option name="MAIN_CLASS_NAME" value="" />
 | 
			
		||||
    <option name="METHOD_NAME" value="" />
 | 
			
		||||
    <option name="GROUP_NAME" value="" />
 | 
			
		||||
    <option name="TEST_OBJECT" value="PACKAGE" />
 | 
			
		||||
    <option name="VM_PARAMETERS" value="-ea" />
 | 
			
		||||
    <option name="PARAMETERS" value="" />
 | 
			
		||||
    <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/../core/java/tests" />
 | 
			
		||||
    <option name="OUTPUT_DIRECTORY" value="" />
 | 
			
		||||
    <option name="ANNOTATION_TYPE" />
 | 
			
		||||
    <option name="ENV_VARIABLES" />
 | 
			
		||||
    <option name="PASS_PARENT_ENVS" value="true" />
 | 
			
		||||
    <option name="TEST_SEARCH_SCOPE">
 | 
			
		||||
      <value defaultName="singleModule" />
 | 
			
		||||
    </option>
 | 
			
		||||
    <option name="USE_DEFAULT_REPORTERS" value="false" />
 | 
			
		||||
    <option name="PROPERTIES_FILE" value="" />
 | 
			
		||||
    <envs />
 | 
			
		||||
    <properties />
 | 
			
		||||
    <listeners />
 | 
			
		||||
    <method />
 | 
			
		||||
  </configuration>
 | 
			
		||||
</component>
 | 
			
		||||
@@ -5,8 +5,8 @@ allprojects    {
 | 
			
		||||
    version = 'GIT-SNAPSHOT'
 | 
			
		||||
 | 
			
		||||
    tasks.withType(JavaCompile) {
 | 
			
		||||
        sourceCompatibility = "1.7"
 | 
			
		||||
        targetCompatibility = "1.7"
 | 
			
		||||
        sourceCompatibility = '1.7'
 | 
			
		||||
        targetCompatibility = '1.7'
 | 
			
		||||
    }
 | 
			
		||||
    tasks.withType(FindBugs) {
 | 
			
		||||
        reports {
 | 
			
		||||
@@ -29,6 +29,6 @@ buildscript {
 | 
			
		||||
subprojects {
 | 
			
		||||
    repositories {
 | 
			
		||||
        mavenCentral()
 | 
			
		||||
        maven { url "http://maven.lyndir.com" }
 | 
			
		||||
        maven { url 'http://maven.lyndir.com' }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,32 +2,34 @@ apply plugin: 'com.android.application'
 | 
			
		||||
 | 
			
		||||
android {
 | 
			
		||||
    compileSdkVersion 25
 | 
			
		||||
    buildToolsVersion "25.0.0"
 | 
			
		||||
    buildToolsVersion '25.0.0'
 | 
			
		||||
 | 
			
		||||
    compileOptions {
 | 
			
		||||
        sourceCompatibility JavaVersion.VERSION_1_7
 | 
			
		||||
        targetCompatibility JavaVersion.VERSION_1_7
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    defaultConfig {
 | 
			
		||||
        applicationId "com.lyndir.masterpassword"
 | 
			
		||||
        applicationId 'com.lyndir.masterpassword'
 | 
			
		||||
        minSdkVersion 19
 | 
			
		||||
        targetSdkVersion 25
 | 
			
		||||
        versionCode 20401
 | 
			
		||||
        versionName "2.4.1"
 | 
			
		||||
        versionName '2.4.1'
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // release with: STORE_PW=$(mpw masterpassword.keystore) KEY_PW=$(mpw masterpassword-android) gradle assembleRelease
 | 
			
		||||
    signingConfigs {
 | 
			
		||||
        release {
 | 
			
		||||
            storeFile file('masterpassword.keystore')
 | 
			
		||||
            storePassword System.getenv('STORE_PW')
 | 
			
		||||
            storeFile file( 'masterpassword.keystore' )
 | 
			
		||||
            storePassword System.getenv( 'STORE_PW' )
 | 
			
		||||
 | 
			
		||||
            keyAlias 'masterpassword-android'
 | 
			
		||||
            keyPassword System.getenv('KEY_PW')
 | 
			
		||||
            keyPassword System.getenv( 'KEY_PW' )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    buildTypes {
 | 
			
		||||
        release {
 | 
			
		||||
            if (System.getenv('STORE_PW') != null)
 | 
			
		||||
            if (System.getenv( 'STORE_PW' ) != null)
 | 
			
		||||
                signingConfig signingConfigs.release
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -37,9 +39,8 @@ dependencies {
 | 
			
		||||
    compile             project( ':masterpassword:algorithm' )
 | 
			
		||||
    compile             project( ':masterpassword:tests' )
 | 
			
		||||
 | 
			
		||||
    // Android dependencies
 | 
			
		||||
    compile 'org.slf4j:slf4j-android:1.7.13-underscore'
 | 
			
		||||
    compile 'com.jakewharton:butterknife:8.5.1'
 | 
			
		||||
    annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1'
 | 
			
		||||
    compile files('libs/scrypt-1.4.0-native.jar')
 | 
			
		||||
    compile             group: 'org.slf4j', name: 'slf4j-android', version:'1.7.13-underscore'
 | 
			
		||||
    compile             group: 'com.jakewharton', name: 'butterknife', version:'8.5.1'
 | 
			
		||||
    annotationProcessor group: 'com.jakewharton', name: 'butterknife-compiler', version:'8.5.1'
 | 
			
		||||
    compile             files( 'libs/scrypt-1.4.0-native.jar' )
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -22,6 +22,9 @@ import com.google.common.io.*;
 | 
			
		||||
import com.lyndir.lhunath.opal.system.logging.Logger;
 | 
			
		||||
import com.lyndir.lhunath.opal.system.util.TypeUtils;
 | 
			
		||||
 | 
			
		||||
import com.lyndir.masterpassword.gui.model.User;
 | 
			
		||||
import com.lyndir.masterpassword.gui.view.PasswordFrame;
 | 
			
		||||
import com.lyndir.masterpassword.gui.view.UnlockFrame;
 | 
			
		||||
import java.io.*;
 | 
			
		||||
import java.net.URI;
 | 
			
		||||
import java.net.URL;
 | 
			
		||||
 
 | 
			
		||||
@@ -30,12 +30,16 @@ import javax.swing.*;
 | 
			
		||||
 */
 | 
			
		||||
public abstract class Res {
 | 
			
		||||
 | 
			
		||||
    private static final WeakHashMap<Window, ExecutorService> executorByWindow = new WeakHashMap<>();
 | 
			
		||||
    private static final WeakHashMap<Window, ScheduledExecutorService> executorByWindow = new WeakHashMap<>();
 | 
			
		||||
    private static final Logger                                        logger           = Logger.get( Res.class );
 | 
			
		||||
    private static final Colors                                        colors           = new Colors();
 | 
			
		||||
 | 
			
		||||
    public static Future<?> execute(final Window host, final Runnable job) {
 | 
			
		||||
        return getExecutor( host ).submit( new Runnable() {
 | 
			
		||||
        return schedule( host, job, 0, TimeUnit.MILLISECONDS );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static Future<?> schedule(final Window host, final Runnable job, final long delay, final TimeUnit timeUnit) {
 | 
			
		||||
        return getExecutor( host ).schedule( new Runnable() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void run() {
 | 
			
		||||
                try {
 | 
			
		||||
@@ -45,12 +49,16 @@ public abstract class Res {
 | 
			
		||||
                    logger.err( t, "Unexpected: %s", t.getLocalizedMessage() );
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } );
 | 
			
		||||
        }, delay, timeUnit );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static <V> ListenableFuture<V> execute(final Window host, final Callable<V> job) {
 | 
			
		||||
        ExecutorService executor = getExecutor( host );
 | 
			
		||||
        return JdkFutureAdapters.listenInPoolThread( executor.submit( new Callable<V>() {
 | 
			
		||||
        return schedule( host, job, 0, TimeUnit.MILLISECONDS );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static <V> ListenableFuture<V> schedule(final Window host, final Callable<V> job, final long delay, final TimeUnit timeUnit) {
 | 
			
		||||
        ScheduledExecutorService executor = getExecutor( host );
 | 
			
		||||
        return JdkFutureAdapters.listenInPoolThread( executor.schedule( new Callable<V>() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public V call()
 | 
			
		||||
                    throws Exception {
 | 
			
		||||
@@ -62,14 +70,14 @@ public abstract class Res {
 | 
			
		||||
                    throw t;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } ), executor );
 | 
			
		||||
        }, delay, timeUnit ), executor );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static ExecutorService getExecutor(final Window host) {
 | 
			
		||||
        ExecutorService executor = executorByWindow.get( host );
 | 
			
		||||
    private static ScheduledExecutorService getExecutor(final Window host) {
 | 
			
		||||
        ScheduledExecutorService executor = executorByWindow.get( host );
 | 
			
		||||
 | 
			
		||||
        if (executor == null) {
 | 
			
		||||
            executorByWindow.put( host, executor = Executors.newSingleThreadExecutor() );
 | 
			
		||||
            executorByWindow.put( host, executor = Executors.newSingleThreadScheduledExecutor() );
 | 
			
		||||
 | 
			
		||||
            host.addWindowListener( new WindowAdapter() {
 | 
			
		||||
                @Override
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package com.lyndir.masterpassword.gui;
 | 
			
		||||
package com.lyndir.masterpassword.gui.model;
 | 
			
		||||
 | 
			
		||||
import com.google.common.primitives.UnsignedInteger;
 | 
			
		||||
import com.lyndir.masterpassword.MPSiteType;
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package com.lyndir.masterpassword.gui;
 | 
			
		||||
package com.lyndir.masterpassword.gui.model;
 | 
			
		||||
 | 
			
		||||
import com.google.common.collect.ImmutableList;
 | 
			
		||||
import com.lyndir.masterpassword.model.IncorrectMasterPasswordException;
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package com.lyndir.masterpassword.gui;
 | 
			
		||||
package com.lyndir.masterpassword.gui.model;
 | 
			
		||||
 | 
			
		||||
import com.google.common.primitives.UnsignedInteger;
 | 
			
		||||
import com.lyndir.masterpassword.MPSiteType;
 | 
			
		||||
@@ -1,8 +1,9 @@
 | 
			
		||||
package com.lyndir.masterpassword.gui;
 | 
			
		||||
package com.lyndir.masterpassword.gui.model;
 | 
			
		||||
 | 
			
		||||
import com.google.common.base.Function;
 | 
			
		||||
import com.google.common.base.Preconditions;
 | 
			
		||||
import com.google.common.collect.FluentIterable;
 | 
			
		||||
import com.lyndir.masterpassword.gui.*;
 | 
			
		||||
import com.lyndir.masterpassword.model.*;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
@@ -43,7 +44,7 @@ public class ModelUser extends User {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setAvatar(final int avatar) {
 | 
			
		||||
        model.setAvatar(avatar % Res.avatars());
 | 
			
		||||
        model.setAvatar( avatar % Res.avatars());
 | 
			
		||||
        MPUserFileManager.get().save();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package com.lyndir.masterpassword.gui;
 | 
			
		||||
package com.lyndir.masterpassword.gui.model;
 | 
			
		||||
 | 
			
		||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
 | 
			
		||||
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package com.lyndir.masterpassword.gui;
 | 
			
		||||
package com.lyndir.masterpassword.gui.model;
 | 
			
		||||
 | 
			
		||||
import com.google.common.base.Preconditions;
 | 
			
		||||
import com.google.common.collect.Maps;
 | 
			
		||||
@@ -2,8 +2,8 @@ package com.lyndir.masterpassword.gui.platform.mac;
 | 
			
		||||
 | 
			
		||||
import com.apple.eawt.*;
 | 
			
		||||
import com.lyndir.masterpassword.gui.GUI;
 | 
			
		||||
import com.lyndir.masterpassword.gui.PasswordFrame;
 | 
			
		||||
import com.lyndir.masterpassword.gui.User;
 | 
			
		||||
import com.lyndir.masterpassword.gui.view.PasswordFrame;
 | 
			
		||||
import com.lyndir.masterpassword.gui.model.User;
 | 
			
		||||
 | 
			
		||||
import javax.swing.*;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,10 @@
 | 
			
		||||
package com.lyndir.masterpassword.gui;
 | 
			
		||||
package com.lyndir.masterpassword.gui.view;
 | 
			
		||||
 | 
			
		||||
import com.google.common.collect.ImmutableList;
 | 
			
		||||
import com.lyndir.masterpassword.MPIdenticon;
 | 
			
		||||
import com.lyndir.masterpassword.gui.Res;
 | 
			
		||||
import com.lyndir.masterpassword.gui.model.User;
 | 
			
		||||
import com.lyndir.masterpassword.gui.util.Components;
 | 
			
		||||
import com.lyndir.masterpassword.gui.view.UnlockFrame;
 | 
			
		||||
import java.awt.*;
 | 
			
		||||
import javax.annotation.Nonnull;
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
@@ -1,5 +1,8 @@
 | 
			
		||||
package com.lyndir.masterpassword.gui;
 | 
			
		||||
package com.lyndir.masterpassword.gui.view;
 | 
			
		||||
 | 
			
		||||
import com.lyndir.masterpassword.gui.Res;
 | 
			
		||||
import com.lyndir.masterpassword.gui.model.IncognitoUser;
 | 
			
		||||
import com.lyndir.masterpassword.gui.model.User;
 | 
			
		||||
import com.lyndir.masterpassword.gui.util.Components;
 | 
			
		||||
import java.awt.*;
 | 
			
		||||
import java.awt.event.ActionEvent;
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package com.lyndir.masterpassword.gui;
 | 
			
		||||
package com.lyndir.masterpassword.gui.view;
 | 
			
		||||
 | 
			
		||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
 | 
			
		||||
 | 
			
		||||
@@ -6,6 +6,8 @@ import com.google.common.base.Function;
 | 
			
		||||
import com.google.common.base.Preconditions;
 | 
			
		||||
import com.google.common.collect.*;
 | 
			
		||||
import com.lyndir.lhunath.opal.system.logging.Logger;
 | 
			
		||||
import com.lyndir.masterpassword.gui.Res;
 | 
			
		||||
import com.lyndir.masterpassword.gui.model.ModelUser;
 | 
			
		||||
import com.lyndir.masterpassword.model.MPUser;
 | 
			
		||||
import com.lyndir.masterpassword.model.MPUserFileManager;
 | 
			
		||||
import com.lyndir.masterpassword.gui.util.Components;
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package com.lyndir.masterpassword.gui;
 | 
			
		||||
package com.lyndir.masterpassword.gui.view;
 | 
			
		||||
 | 
			
		||||
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.ifNotNullElse;
 | 
			
		||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
 | 
			
		||||
@@ -9,6 +9,8 @@ import com.google.common.collect.Iterables;
 | 
			
		||||
import com.google.common.primitives.UnsignedInteger;
 | 
			
		||||
import com.google.common.util.concurrent.*;
 | 
			
		||||
import com.lyndir.masterpassword.*;
 | 
			
		||||
import com.lyndir.masterpassword.gui.Res;
 | 
			
		||||
import com.lyndir.masterpassword.gui.model.*;
 | 
			
		||||
import com.lyndir.masterpassword.gui.util.Components;
 | 
			
		||||
import com.lyndir.masterpassword.gui.util.UnsignedIntegerModel;
 | 
			
		||||
import java.awt.*;
 | 
			
		||||
@@ -1,12 +1,16 @@
 | 
			
		||||
package com.lyndir.masterpassword.gui;
 | 
			
		||||
package com.lyndir.masterpassword.gui.view;
 | 
			
		||||
 | 
			
		||||
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
 | 
			
		||||
 | 
			
		||||
import com.lyndir.masterpassword.MPIdenticon;
 | 
			
		||||
import com.lyndir.masterpassword.gui.*;
 | 
			
		||||
import com.lyndir.masterpassword.gui.model.User;
 | 
			
		||||
import com.lyndir.masterpassword.gui.util.Components;
 | 
			
		||||
import com.lyndir.masterpassword.model.IncorrectMasterPasswordException;
 | 
			
		||||
import java.awt.*;
 | 
			
		||||
import java.awt.event.*;
 | 
			
		||||
import java.util.concurrent.Future;
 | 
			
		||||
import java.util.concurrent.TimeUnit;
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import javax.swing.*;
 | 
			
		||||
 | 
			
		||||
@@ -22,6 +26,7 @@ public class UnlockFrame extends JFrame {
 | 
			
		||||
    private final JButton                  signInButton;
 | 
			
		||||
    private final JPanel                   authenticationContainer;
 | 
			
		||||
    private       AuthenticationPanel      authenticationPanel;
 | 
			
		||||
    private       Future<?>                identiconFuture;
 | 
			
		||||
    private       boolean                  incognito;
 | 
			
		||||
    public        User                     user;
 | 
			
		||||
 | 
			
		||||
@@ -139,18 +144,34 @@ public class UnlockFrame extends JFrame {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    boolean checkSignIn() {
 | 
			
		||||
        if (identiconFuture != null)
 | 
			
		||||
            identiconFuture.cancel( false );
 | 
			
		||||
        identiconFuture = Res.schedule( this, new Runnable() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void run() {
 | 
			
		||||
                SwingUtilities.invokeLater( new Runnable() {
 | 
			
		||||
                    @Override
 | 
			
		||||
                    public void run() {
 | 
			
		||||
                        String fullName = user == null? "": user.getFullName();
 | 
			
		||||
                        char[] masterPassword = authenticationPanel.getMasterPassword();
 | 
			
		||||
 | 
			
		||||
                        if (fullName.isEmpty() || masterPassword.length == 0) {
 | 
			
		||||
                            identiconLabel.setText( " " );
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        MPIdenticon identicon = new MPIdenticon( fullName, masterPassword );
 | 
			
		||||
                        identiconLabel.setText( identicon.getText() );
 | 
			
		||||
                        identiconLabel.setForeground(
 | 
			
		||||
                                Res.colors().fromIdenticonColor( identicon.getColor(), Res.Colors.BackgroundMode.DARK ) );
 | 
			
		||||
                    }
 | 
			
		||||
                } );
 | 
			
		||||
            }
 | 
			
		||||
        }, 300, TimeUnit.MILLISECONDS );
 | 
			
		||||
 | 
			
		||||
        String fullName = user == null? "": user.getFullName();
 | 
			
		||||
        char[] masterPassword = authenticationPanel.getMasterPassword();
 | 
			
		||||
        boolean enabled = !fullName.isEmpty() && masterPassword.length > 0;
 | 
			
		||||
 | 
			
		||||
        if (fullName.isEmpty() || masterPassword.length == 0)
 | 
			
		||||
            identiconLabel.setText( " " );
 | 
			
		||||
        else {
 | 
			
		||||
            MPIdenticon identicon = new MPIdenticon( fullName, masterPassword );
 | 
			
		||||
            identiconLabel.setText( identicon.getText() );
 | 
			
		||||
            identiconLabel.setForeground( Res.colors().fromIdenticonColor( identicon.getColor(), Res.Colors.BackgroundMode.DARK ) );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        signInButton.setEnabled( enabled );
 | 
			
		||||
 | 
			
		||||
        return enabled;
 | 
			
		||||
@@ -197,7 +218,7 @@ public class UnlockFrame extends JFrame {
 | 
			
		||||
        } );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    interface SignInCallback {
 | 
			
		||||
    public interface SignInCallback {
 | 
			
		||||
 | 
			
		||||
        void signedIn(User user);
 | 
			
		||||
    }
 | 
			
		||||
		Reference in New Issue
	
	Block a user