Identicon support and UI improvements.
This commit is contained in:
		@@ -27,6 +27,7 @@ import com.lyndir.lhunath.opal.system.logging.Logger;
 | 
			
		||||
import java.nio.*;
 | 
			
		||||
import java.nio.charset.Charset;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.Locale;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -83,6 +84,10 @@ public class MPIdenticon {
 | 
			
		||||
        return text;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getHTML() {
 | 
			
		||||
        return strf( "<span style='color: %s'>%s</span>", color.getCSS(), text );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Color getColor() {
 | 
			
		||||
        return color;
 | 
			
		||||
    }
 | 
			
		||||
@@ -94,6 +99,15 @@ public class MPIdenticon {
 | 
			
		||||
        BLUE,
 | 
			
		||||
        MAGENTA,
 | 
			
		||||
        CYAN,
 | 
			
		||||
        MONO
 | 
			
		||||
        MONO {
 | 
			
		||||
            @Override
 | 
			
		||||
            public String getCSS() {
 | 
			
		||||
                return "inherit";
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        public String getCSS() {
 | 
			
		||||
            return name().toLowerCase( Locale.ROOT );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -180,20 +180,20 @@ public abstract class Res {
 | 
			
		||||
 | 
			
		||||
    public static class Fonts {
 | 
			
		||||
 | 
			
		||||
        public Font emoticonsFont() {
 | 
			
		||||
            return emoticonsRegular();
 | 
			
		||||
        public Font emoticonsFont(final float size) {
 | 
			
		||||
            return emoticonsRegular().deriveFont( size );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Font controlFont() {
 | 
			
		||||
            return exoRegular();
 | 
			
		||||
        public Font controlFont(final float size) {
 | 
			
		||||
            return exoRegular().deriveFont( size );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Font valueFont() {
 | 
			
		||||
            return sourceSansProRegular();
 | 
			
		||||
        public Font valueFont(final float size) {
 | 
			
		||||
            return sourceSansProRegular().deriveFont( size );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Font bigValueFont() {
 | 
			
		||||
            return sourceSansProBlack();
 | 
			
		||||
        public Font bigValueFont(final float size) {
 | 
			
		||||
            return sourceSansProBlack().deriveFont( size );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Font emoticonsRegular() {
 | 
			
		||||
@@ -268,12 +268,17 @@ public abstract class Res {
 | 
			
		||||
 | 
			
		||||
    public static class Colors {
 | 
			
		||||
 | 
			
		||||
        private final Color transparent   = new Color( 0, 0, 0, 0 );
 | 
			
		||||
        private final Color frameBg       = Color.decode( "#5A5D6B" );
 | 
			
		||||
        private final Color controlBg     = SystemColor.window;
 | 
			
		||||
        private final Color controlBorder = Color.decode( "#BFBFBF" );
 | 
			
		||||
        private final Color highlightFg   = SystemColor.controlHighlight;
 | 
			
		||||
        private final Color errorFg       = Color.decode( "#FF3333" );
 | 
			
		||||
 | 
			
		||||
        public Color transparent() {
 | 
			
		||||
            return transparent;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Color frameBg() {
 | 
			
		||||
            return frameBg;
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -4,17 +4,20 @@ import com.google.common.collect.ImmutableList;
 | 
			
		||||
import java.util.*;
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import javax.swing.*;
 | 
			
		||||
import javax.swing.event.ListSelectionEvent;
 | 
			
		||||
import javax.swing.event.ListSelectionListener;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author lhunath, 2018-07-19
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("serial")
 | 
			
		||||
public class CollectionListModel<E> extends AbstractListModel<E> implements ComboBoxModel<E> {
 | 
			
		||||
public class CollectionListModel<E> extends AbstractListModel<E> implements ComboBoxModel<E>, ListSelectionListener {
 | 
			
		||||
 | 
			
		||||
    private final List<E> model = new LinkedList<>();
 | 
			
		||||
    private final List<E>  model = new LinkedList<>();
 | 
			
		||||
    @Nullable
 | 
			
		||||
    private       E       selectedItem;
 | 
			
		||||
    private       E        selectedItem;
 | 
			
		||||
    private       JList<E> list;
 | 
			
		||||
 | 
			
		||||
    public CollectionListModel() {
 | 
			
		||||
    }
 | 
			
		||||
@@ -77,6 +80,10 @@ public class CollectionListModel<E> extends AbstractListModel<E> implements Comb
 | 
			
		||||
        if (!Objects.equals( selectedItem, newSelectedItem ) && model.contains( newSelectedItem )) {
 | 
			
		||||
            selectedItem = (E) newSelectedItem;
 | 
			
		||||
            fireContentsChanged( this, -1, -1 );
 | 
			
		||||
 | 
			
		||||
            //noinspection ObjectEquality
 | 
			
		||||
            if ((list != null) && (list.getModel() == this))
 | 
			
		||||
                list.setSelectedValue( selectedItem, true );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -85,4 +92,21 @@ public class CollectionListModel<E> extends AbstractListModel<E> implements Comb
 | 
			
		||||
    public synchronized E getSelectedItem() {
 | 
			
		||||
        return selectedItem;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public synchronized void registerList(final JList<E> list) {
 | 
			
		||||
        // TODO: This class should probably implement ListSelectionModel instead.
 | 
			
		||||
        if (this.list != null)
 | 
			
		||||
            this.list.removeListSelectionListener( this );
 | 
			
		||||
 | 
			
		||||
        this.list = list;
 | 
			
		||||
        this.list.addListSelectionListener( this );
 | 
			
		||||
        this.list.setModel( this );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public synchronized void valueChanged(final ListSelectionEvent event) {
 | 
			
		||||
        //noinspection ObjectEquality
 | 
			
		||||
        if ((event.getSource() == list) && (list.getModel() == this))
 | 
			
		||||
            selectedItem = list.getSelectedValue();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -32,8 +32,10 @@ import javax.swing.border.CompoundBorder;
 | 
			
		||||
 */
 | 
			
		||||
public abstract class Components {
 | 
			
		||||
 | 
			
		||||
    private static final float HEADING_TEXT_SIZE = 19f;
 | 
			
		||||
    private static final float CONTROL_TEXT_SIZE = 13f;
 | 
			
		||||
    public static final float TEXT_SIZE_HEADING = 19f;
 | 
			
		||||
    public static final float TEXT_SIZE_CONTROL = 13f;
 | 
			
		||||
    public static final int   SIZE_MARGIN       = 20;
 | 
			
		||||
    public static final int   SIZE_PADDING      = 8;
 | 
			
		||||
 | 
			
		||||
    public static GradientPanel boxPanel(final int axis, final Component... components) {
 | 
			
		||||
        GradientPanel container = gradientPanel( null, null );
 | 
			
		||||
@@ -77,7 +79,7 @@ public abstract class Components {
 | 
			
		||||
            {
 | 
			
		||||
                setBorder( BorderFactory.createCompoundBorder( BorderFactory.createLineBorder( Res.colors().controlBorder(), 1, true ),
 | 
			
		||||
                                                               BorderFactory.createEmptyBorder( 4, 4, 4, 4 ) ) );
 | 
			
		||||
                setFont( Res.fonts().valueFont().deriveFont( CONTROL_TEXT_SIZE ) );
 | 
			
		||||
                setFont( Res.fonts().valueFont( TEXT_SIZE_CONTROL ) );
 | 
			
		||||
                setAlignmentX( LEFT_ALIGNMENT );
 | 
			
		||||
                setAlignmentY( BOTTOM_ALIGNMENT );
 | 
			
		||||
            }
 | 
			
		||||
@@ -108,7 +110,7 @@ public abstract class Components {
 | 
			
		||||
    public static <E> JList<E> list(final ListModel<E> model, final Function<E, String> valueTransformer) {
 | 
			
		||||
        return new JList<E>( model ) {
 | 
			
		||||
            {
 | 
			
		||||
                setFont( Res.fonts().valueFont().deriveFont( CONTROL_TEXT_SIZE ) );
 | 
			
		||||
                setFont( Res.fonts().valueFont( TEXT_SIZE_CONTROL ) );
 | 
			
		||||
                setBorder( BorderFactory.createEmptyBorder( 4, 0, 4, 0 ) );
 | 
			
		||||
                setCellRenderer( new DefaultListCellRenderer() {
 | 
			
		||||
                    {
 | 
			
		||||
@@ -147,7 +149,7 @@ public abstract class Components {
 | 
			
		||||
    public static JButton button(final String label) {
 | 
			
		||||
        return new JButton( label ) {
 | 
			
		||||
            {
 | 
			
		||||
                setFont( Res.fonts().controlFont().deriveFont( CONTROL_TEXT_SIZE ) );
 | 
			
		||||
                setFont( Res.fonts().controlFont( TEXT_SIZE_CONTROL ) );
 | 
			
		||||
                setAlignmentX( LEFT_ALIGNMENT );
 | 
			
		||||
                setAlignmentY( BOTTOM_ALIGNMENT );
 | 
			
		||||
            }
 | 
			
		||||
@@ -160,7 +162,7 @@ public abstract class Components {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static Component strut() {
 | 
			
		||||
        return strut( 8 );
 | 
			
		||||
        return strut( SIZE_PADDING );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static Component strut(final int size) {
 | 
			
		||||
@@ -172,6 +174,18 @@ public abstract class Components {
 | 
			
		||||
        return rigidArea;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static int margin() {
 | 
			
		||||
        return SIZE_MARGIN;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static Border marginBorder() {
 | 
			
		||||
        return marginBorder( margin() );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static Border marginBorder(final int size) {
 | 
			
		||||
        return BorderFactory.createEmptyBorder( size, size, size, size );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static JSpinner spinner(final SpinnerModel model) {
 | 
			
		||||
        return new JSpinner( model ) {
 | 
			
		||||
            {
 | 
			
		||||
@@ -191,6 +205,14 @@ public abstract class Components {
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static JLabel heading() {
 | 
			
		||||
        return heading( " " );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static JLabel heading(final int horizontalAlignment) {
 | 
			
		||||
        return heading( " ", horizontalAlignment );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static JLabel heading(@Nullable final String heading) {
 | 
			
		||||
        return heading( heading, SwingConstants.CENTER );
 | 
			
		||||
    }
 | 
			
		||||
@@ -207,7 +229,7 @@ public abstract class Components {
 | 
			
		||||
    public static JLabel heading(@Nullable final String heading, final int horizontalAlignment) {
 | 
			
		||||
        return new JLabel( heading, horizontalAlignment ) {
 | 
			
		||||
            {
 | 
			
		||||
                setFont( Res.fonts().controlFont().deriveFont( Font.BOLD, HEADING_TEXT_SIZE ) );
 | 
			
		||||
                setFont( Res.fonts().controlFont( TEXT_SIZE_HEADING ).deriveFont( Font.BOLD ) );
 | 
			
		||||
                setAlignmentX( LEFT_ALIGNMENT );
 | 
			
		||||
                setAlignmentY( BOTTOM_ALIGNMENT );
 | 
			
		||||
            }
 | 
			
		||||
@@ -219,6 +241,14 @@ public abstract class Components {
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static JLabel label() {
 | 
			
		||||
        return label( " " );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static JLabel label(final int horizontalAlignment) {
 | 
			
		||||
        return label( " ", horizontalAlignment );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static JLabel label(@Nullable final String label) {
 | 
			
		||||
        return label( label, SwingConstants.LEADING );
 | 
			
		||||
    }
 | 
			
		||||
@@ -235,7 +265,7 @@ public abstract class Components {
 | 
			
		||||
    public static JLabel label(@Nullable final String label, final int horizontalAlignment) {
 | 
			
		||||
        return new JLabel( label, horizontalAlignment ) {
 | 
			
		||||
            {
 | 
			
		||||
                setFont( Res.fonts().controlFont().deriveFont( CONTROL_TEXT_SIZE ) );
 | 
			
		||||
                setFont( Res.fonts().controlFont( TEXT_SIZE_CONTROL ) );
 | 
			
		||||
                setAlignmentX( LEFT_ALIGNMENT );
 | 
			
		||||
                setAlignmentY( BOTTOM_ALIGNMENT );
 | 
			
		||||
            }
 | 
			
		||||
@@ -250,7 +280,7 @@ public abstract class Components {
 | 
			
		||||
    public static JCheckBox checkBox(final String label) {
 | 
			
		||||
        return new JCheckBox( label ) {
 | 
			
		||||
            {
 | 
			
		||||
                setFont( Res.fonts().controlFont().deriveFont( CONTROL_TEXT_SIZE ) );
 | 
			
		||||
                setFont( Res.fonts().controlFont( TEXT_SIZE_CONTROL ) );
 | 
			
		||||
                setBackground( null );
 | 
			
		||||
                setAlignmentX( LEFT_ALIGNMENT );
 | 
			
		||||
                setAlignmentY( BOTTOM_ALIGNMENT );
 | 
			
		||||
@@ -266,7 +296,7 @@ public abstract class Components {
 | 
			
		||||
    public static <E> JComboBox<E> comboBox(final ComboBoxModel<E> model, final Function<E, String> valueTransformer) {
 | 
			
		||||
        return new JComboBox<E>( model ) {
 | 
			
		||||
            {
 | 
			
		||||
                setFont( Res.fonts().valueFont().deriveFont( CONTROL_TEXT_SIZE ) );
 | 
			
		||||
                setFont( Res.fonts().valueFont( TEXT_SIZE_CONTROL ) );
 | 
			
		||||
                setBorder( BorderFactory.createEmptyBorder( 4, 0, 4, 0 ) );
 | 
			
		||||
                setRenderer( new DefaultListCellRenderer() {
 | 
			
		||||
                    {
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@ public class FilesPanel extends JPanel implements ItemListener {
 | 
			
		||||
 | 
			
		||||
    protected FilesPanel() {
 | 
			
		||||
        setOpaque( false );
 | 
			
		||||
        setBackground( new Color( 0, 0, 0, 0 ) );
 | 
			
		||||
        setBackground( Res.colors().transparent() );
 | 
			
		||||
        setLayout( new BoxLayout( this, BoxLayout.PAGE_AXIS ) );
 | 
			
		||||
 | 
			
		||||
        // -
 | 
			
		||||
@@ -46,9 +46,6 @@ public class FilesPanel extends JPanel implements ItemListener {
 | 
			
		||||
        // User Selection
 | 
			
		||||
        add( userField );
 | 
			
		||||
        userField.addItemListener( this );
 | 
			
		||||
 | 
			
		||||
        // -
 | 
			
		||||
        add( Box.createVerticalGlue() );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void reload() {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,12 @@
 | 
			
		||||
package com.lyndir.masterpassword.gui.view;
 | 
			
		||||
 | 
			
		||||
import com.lyndir.lhunath.opal.system.logging.Logger;
 | 
			
		||||
import com.lyndir.masterpassword.gui.Res;
 | 
			
		||||
import com.lyndir.masterpassword.gui.util.Components;
 | 
			
		||||
import com.lyndir.masterpassword.model.MPUser;
 | 
			
		||||
import java.awt.*;
 | 
			
		||||
import java.awt.event.ComponentEvent;
 | 
			
		||||
import java.awt.event.ComponentListener;
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import javax.swing.*;
 | 
			
		||||
 | 
			
		||||
@@ -11,21 +14,24 @@ import javax.swing.*;
 | 
			
		||||
/**
 | 
			
		||||
 * @author lhunath, 2018-07-14
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("MagicNumber")
 | 
			
		||||
public class MasterPasswordFrame extends JFrame implements FilesPanel.Listener {
 | 
			
		||||
@SuppressWarnings("serial")
 | 
			
		||||
public class MasterPasswordFrame extends JFrame implements FilesPanel.Listener, ComponentListener {
 | 
			
		||||
 | 
			
		||||
    private static final Logger logger = Logger.get( MasterPasswordFrame.class );
 | 
			
		||||
 | 
			
		||||
    @SuppressWarnings("FieldCanBeLocal")
 | 
			
		||||
    private final Components.GradientPanel root;
 | 
			
		||||
    private final FilesPanel               filesPanel = new FilesPanel();
 | 
			
		||||
    private final UserPanel                userPanel  = new UserPanel();
 | 
			
		||||
 | 
			
		||||
    @SuppressWarnings("MagicNumber")
 | 
			
		||||
    public MasterPasswordFrame() {
 | 
			
		||||
        super( "Master Password" );
 | 
			
		||||
 | 
			
		||||
        setDefaultCloseOperation( DISPOSE_ON_CLOSE );
 | 
			
		||||
        setContentPane( root = Components.gradientPanel( Res.colors().frameBg(), new FlowLayout() ) );
 | 
			
		||||
        root.setLayout( new BoxLayout( root, BoxLayout.PAGE_AXIS ) );
 | 
			
		||||
        root.setBorder( BorderFactory.createEmptyBorder( 20, 20, 20, 20 ) );
 | 
			
		||||
        root.setBorder( Components.marginBorder() );
 | 
			
		||||
 | 
			
		||||
        root.add( filesPanel );
 | 
			
		||||
        root.add( new JSeparator( SwingConstants.HORIZONTAL ) );
 | 
			
		||||
@@ -35,7 +41,8 @@ public class MasterPasswordFrame extends JFrame implements FilesPanel.Listener {
 | 
			
		||||
        filesPanel.addListener( this );
 | 
			
		||||
        filesPanel.reload();
 | 
			
		||||
 | 
			
		||||
        setMinimumSize( new Dimension( 640, 480 ) );
 | 
			
		||||
        addComponentListener(this  );
 | 
			
		||||
        setPreferredSize( new Dimension( 640, 480 ) );
 | 
			
		||||
        pack();
 | 
			
		||||
 | 
			
		||||
        setLocationByPlatform( true );
 | 
			
		||||
@@ -46,4 +53,21 @@ public class MasterPasswordFrame extends JFrame implements FilesPanel.Listener {
 | 
			
		||||
    public void onUserSelected(@Nullable final MPUser<?> selectedUser) {
 | 
			
		||||
        userPanel.setUser( selectedUser );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void componentResized(final ComponentEvent e) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void componentMoved(final ComponentEvent e) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void componentShown(final ComponentEvent e) {
 | 
			
		||||
        userPanel.transferFocus();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void componentHidden(final ComponentEvent e) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,9 @@ import java.awt.datatransfer.StringSelection;
 | 
			
		||||
import java.awt.datatransfer.Transferable;
 | 
			
		||||
import java.awt.event.*;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
import java.util.Random;
 | 
			
		||||
import java.util.concurrent.Future;
 | 
			
		||||
import java.util.concurrent.TimeUnit;
 | 
			
		||||
import java.util.function.Consumer;
 | 
			
		||||
import javax.annotation.Nonnull;
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
@@ -34,8 +36,9 @@ public class UserPanel extends Components.GradientPanel implements MPUser.Listen
 | 
			
		||||
    private MPUser<?> user;
 | 
			
		||||
 | 
			
		||||
    public UserPanel() {
 | 
			
		||||
        super( new BorderLayout( 20, 20 ), null );
 | 
			
		||||
        setBorder( BorderFactory.createEmptyBorder( 20, 20, 20, 20 ) );
 | 
			
		||||
        super( new BorderLayout( Components.margin(), Components.margin() ), null );
 | 
			
		||||
        setBorder( Components.marginBorder() );
 | 
			
		||||
        setUser( null );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setUser(@Nullable final MPUser<?> user) {
 | 
			
		||||
@@ -61,6 +64,7 @@ public class UserPanel extends Components.GradientPanel implements MPUser.Listen
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            revalidate();
 | 
			
		||||
            transferFocus();
 | 
			
		||||
        } );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -88,11 +92,16 @@ public class UserPanel extends Components.GradientPanel implements MPUser.Listen
 | 
			
		||||
 | 
			
		||||
    private static final class AuthenticateUserPanel extends JPanel implements ActionListener, DocumentListener {
 | 
			
		||||
 | 
			
		||||
        private static final Random random = new Random();
 | 
			
		||||
 | 
			
		||||
        @Nonnull
 | 
			
		||||
        private final MPUser<?> user;
 | 
			
		||||
 | 
			
		||||
        private final JPasswordField masterPasswordField = Components.passwordField();
 | 
			
		||||
        private final JLabel         errorLabel          = Components.label( null );
 | 
			
		||||
        private final JLabel         errorLabel          = Components.label();
 | 
			
		||||
        private final JLabel         identiconLabel      = Components.label( SwingConstants.CENTER );
 | 
			
		||||
 | 
			
		||||
        private Future<?> identiconJob;
 | 
			
		||||
 | 
			
		||||
        private AuthenticateUserPanel(@Nonnull final MPUser<?> user) {
 | 
			
		||||
            setLayout( new BoxLayout( this, BoxLayout.PAGE_AXIS ) );
 | 
			
		||||
@@ -110,39 +119,72 @@ public class UserPanel extends Components.GradientPanel implements MPUser.Listen
 | 
			
		||||
            add( errorLabel );
 | 
			
		||||
            errorLabel.setForeground( Res.colors().errorFg() );
 | 
			
		||||
 | 
			
		||||
            add( Box.createGlue() );
 | 
			
		||||
            add( Components.strut() );
 | 
			
		||||
            add( identiconLabel );
 | 
			
		||||
            identiconLabel.setFont( Res.fonts().emoticonsFont( Components.TEXT_SIZE_CONTROL ) );
 | 
			
		||||
 | 
			
		||||
            Res.ui( false, masterPasswordField::requestFocusInWindow );
 | 
			
		||||
            add( Box.createGlue() );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void actionPerformed(final ActionEvent event) {
 | 
			
		||||
            try {
 | 
			
		||||
                user.authenticate( masterPasswordField.getPassword() );
 | 
			
		||||
            }
 | 
			
		||||
            catch (final MPIncorrectMasterPasswordException e) {
 | 
			
		||||
                logger.wrn( e, "During user authentication for: %s", user );
 | 
			
		||||
                errorLabel.setText( e.getLocalizedMessage() );
 | 
			
		||||
            }
 | 
			
		||||
            catch (final MPAlgorithmException e) {
 | 
			
		||||
                logger.err( e, "During user authentication for: %s", user );
 | 
			
		||||
                errorLabel.setText( e.getLocalizedMessage() );
 | 
			
		||||
            }
 | 
			
		||||
            updateIdenticon();
 | 
			
		||||
            
 | 
			
		||||
            char[] masterPassword = masterPasswordField.getPassword();
 | 
			
		||||
            Res.job( () -> {
 | 
			
		||||
                try {
 | 
			
		||||
                    user.authenticate( masterPassword );
 | 
			
		||||
                }
 | 
			
		||||
                catch (final MPIncorrectMasterPasswordException e) {
 | 
			
		||||
                    logger.wrn( e, "During user authentication for: %s", user );
 | 
			
		||||
                    errorLabel.setText( e.getLocalizedMessage() );
 | 
			
		||||
                }
 | 
			
		||||
                catch (final MPAlgorithmException e) {
 | 
			
		||||
                    logger.err( e, "During user authentication for: %s", user );
 | 
			
		||||
                    errorLabel.setText( e.getLocalizedMessage() );
 | 
			
		||||
                }
 | 
			
		||||
            } );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void insertUpdate(final DocumentEvent event) {
 | 
			
		||||
            errorLabel.setText( null );
 | 
			
		||||
            update();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void removeUpdate(final DocumentEvent event) {
 | 
			
		||||
            errorLabel.setText( null );
 | 
			
		||||
            update();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void changedUpdate(final DocumentEvent event) {
 | 
			
		||||
            update();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private synchronized void update() {
 | 
			
		||||
            errorLabel.setText( null );
 | 
			
		||||
 | 
			
		||||
            if (identiconJob != null)
 | 
			
		||||
                identiconJob.cancel( true );
 | 
			
		||||
 | 
			
		||||
            identiconJob = Res.job( this::updateIdenticon, 100 + random.nextInt( 100 ), TimeUnit.MILLISECONDS );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void updateIdenticon() {
 | 
			
		||||
            char[] masterPassword = masterPasswordField.getPassword();
 | 
			
		||||
            MPIdenticon identicon = ((masterPassword != null) && (masterPassword.length > 0))?
 | 
			
		||||
                    new MPIdenticon( user.getFullName(), masterPassword ): null;
 | 
			
		||||
 | 
			
		||||
            Res.ui( () -> {
 | 
			
		||||
                if (identicon != null) {
 | 
			
		||||
                    identiconLabel.setForeground(
 | 
			
		||||
                            Res.colors().fromIdenticonColor( identicon.getColor(), Res.Colors.BackgroundMode.LIGHT ) );
 | 
			
		||||
                    identiconLabel.setText( identicon.getText() );
 | 
			
		||||
                } else {
 | 
			
		||||
                    identiconLabel.setForeground( null );
 | 
			
		||||
                    identiconLabel.setText( " " );
 | 
			
		||||
                }
 | 
			
		||||
            } );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -150,11 +192,13 @@ public class UserPanel extends Components.GradientPanel implements MPUser.Listen
 | 
			
		||||
    private static final class AuthenticatedUserPanel extends JPanel implements ActionListener, DocumentListener, ListSelectionListener,
 | 
			
		||||
            KeyListener {
 | 
			
		||||
 | 
			
		||||
        public static final int SIZE_RESULT = 48;
 | 
			
		||||
 | 
			
		||||
        @Nonnull
 | 
			
		||||
        private final MPUser<?>                      user;
 | 
			
		||||
        private final JLabel                         passwordLabel = Components.label( " ", SwingConstants.CENTER );
 | 
			
		||||
        private final JLabel                         passwordField = Components.heading( " ", SwingConstants.CENTER );
 | 
			
		||||
        private final JLabel                         queryLabel    = Components.label( " " );
 | 
			
		||||
        private final JLabel                         passwordLabel = Components.label( SwingConstants.CENTER );
 | 
			
		||||
        private final JLabel                         passwordField = Components.heading( SwingConstants.CENTER );
 | 
			
		||||
        private final JLabel                         queryLabel    = Components.label();
 | 
			
		||||
        private final JTextField                     queryField    = Components.textField();
 | 
			
		||||
        private final CollectionListModel<MPSite<?>> sitesModel    = new CollectionListModel<>();
 | 
			
		||||
        private final JList<MPSite<?>>               sitesList     = Components.list( sitesModel,
 | 
			
		||||
@@ -172,7 +216,7 @@ public class UserPanel extends Components.GradientPanel implements MPUser.Listen
 | 
			
		||||
            add( passwordLabel );
 | 
			
		||||
            add( passwordField );
 | 
			
		||||
            passwordField.setForeground( Res.colors().highlightFg() );
 | 
			
		||||
            passwordField.setFont( Res.fonts().bigValueFont().deriveFont( Font.BOLD, 48 ) );
 | 
			
		||||
            passwordField.setFont( Res.fonts().bigValueFont( SIZE_RESULT ) );
 | 
			
		||||
            add( Box.createGlue() );
 | 
			
		||||
            add( Components.strut() );
 | 
			
		||||
 | 
			
		||||
@@ -182,12 +226,12 @@ public class UserPanel extends Components.GradientPanel implements MPUser.Listen
 | 
			
		||||
            queryField.addActionListener( this );
 | 
			
		||||
            queryField.addKeyListener( this );
 | 
			
		||||
            queryField.getDocument().addDocumentListener( this );
 | 
			
		||||
            queryField.requestFocusInWindow();
 | 
			
		||||
            add( Components.strut() );
 | 
			
		||||
            add( Components.scrollPane( sitesList ) );
 | 
			
		||||
            sitesModel.registerList( sitesList );
 | 
			
		||||
            sitesList.addListSelectionListener( this );
 | 
			
		||||
            add( Box.createGlue() );
 | 
			
		||||
 | 
			
		||||
            Res.ui( false, queryField::requestFocusInWindow );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user