2
0

UI improvements for the Java GUI.

This commit is contained in:
Maarten Billemont 2014-06-11 09:16:24 -04:00
parent 6808016ab7
commit be0ae7ff45
71 changed files with 201 additions and 31 deletions

View File

@ -19,7 +19,7 @@ public abstract class AuthenticationPanel extends JPanel {
// Avatar
add( Box.createVerticalGlue() );
add( new JLabel( new ImageIcon( Resources.getResource( "media/Avatars/avatar-0.png" ) ) ) {
add( new JLabel( Res.avatar(0) ) {
@Override
public Dimension getMaximumSize() {
return new Dimension( Integer.MAX_VALUE, Integer.MAX_VALUE );
@ -37,4 +37,8 @@ public abstract class AuthenticationPanel extends JPanel {
public Component getFocusComponent() {
return null;
}
public String getHelpText() {
return null;
}
}

View File

@ -45,6 +45,15 @@ public class ConfigAuthenticationPanel extends AuthenticationPanel implements It
return (User) userField.getSelectedItem();
}
@Override
public String getHelpText() {
return "<html>"
+ "Reads users from ~/.mpw<br><br>"
+ "Use the following syntax:<br>"
+ "My Name:mymasterpassword<br><br>"
+ "Make sure the read permissions<br>to the file are safe!";
}
public static boolean hasConfigUsers() {
return new File( System.getProperty( "user.home" ), ".mpw" ).canRead();
}

View File

@ -2,6 +2,7 @@ package com.lyndir.lhunath.masterpassword;
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
import com.google.common.io.Resources;
import com.lyndir.lhunath.masterpassword.util.Components;
import java.awt.*;
import java.awt.datatransfer.StringSelection;
@ -19,10 +20,7 @@ import javax.swing.event.*;
*/
public class PasswordFrame extends JFrame implements DocumentListener {
private static final ExecutorService executor = Executors.newSingleThreadExecutor();
private final User user;
private final JPanel root;
private final JTextField siteNameField;
private final JComboBox<MPElementType> siteTypeField;
private final JSpinner siteCounterField;
@ -36,8 +34,11 @@ public class PasswordFrame extends JFrame implements DocumentListener {
JLabel label;
setDefaultCloseOperation( DISPOSE_ON_CLOSE );
setContentPane( root = new JPanel( new BorderLayout( 20, 20 ) ) );
root.setBorder( new EmptyBorder( 20, 20, 20, 20 ) );
setContentPane( new JPanel( new BorderLayout( 20, 20 ) ) {
{
setBorder( new EmptyBorder( 20, 20, 20, 20 ) );
}
});
// User
add( label = new JLabel( strf( "Generating passwords for: %s", user.getName() ) ), BorderLayout.NORTH );
@ -82,17 +83,21 @@ public class PasswordFrame extends JFrame implements DocumentListener {
} );
// Site Type & Counter
sitePanel.add( Components.boxLayout( BoxLayout.LINE_AXIS, //
siteTypeField = new JComboBox<>( MPElementType.values() ),
siteCounterField = new JSpinner( new SpinnerNumberModel( 1, 1, Integer.MAX_VALUE, 1 ) ) {
@Override
public Dimension getMaximumSize() {
return new Dimension( 50, getPreferredSize().height );
}
} ) );
JComponent siteSettings = Components.boxLayout( BoxLayout.LINE_AXIS, //
siteTypeField = new JComboBox<>( MPElementType.values() ),
siteCounterField = new JSpinner( new SpinnerNumberModel( 1, 1, Integer.MAX_VALUE, 1 ) ) {
@Override
public Dimension getMaximumSize() {
return new Dimension( 20, getPreferredSize().height );
}
} );
siteSettings.setAlignmentX( LEFT_ALIGNMENT );
sitePanel.add( siteSettings );
siteTypeField.setAlignmentX( LEFT_ALIGNMENT );
siteTypeField.setAlignmentY( CENTER_ALIGNMENT );
siteTypeField.setSelectedItem( MPElementType.GeneratedLong );
siteCounterField.setAlignmentX( LEFT_ALIGNMENT );
siteCounterField.setAlignmentX( RIGHT_ALIGNMENT );
siteCounterField.setAlignmentY( CENTER_ALIGNMENT );
siteCounterField.addChangeListener( new ChangeListener() {
@Override
public void stateChanged(final ChangeEvent e) {
@ -103,7 +108,7 @@ public class PasswordFrame extends JFrame implements DocumentListener {
// Password
add( passwordLabel = new JLabel( " ", JLabel.CENTER ), BorderLayout.SOUTH );
passwordLabel.setAlignmentX( LEFT_ALIGNMENT );
passwordLabel.setFont( passwordLabel.getFont().deriveFont( 40f ) );
passwordLabel.setFont( Res.sourceCodeProBlack().deriveFont( 40f ) );
pack();
setMinimumSize( getSize() );
@ -119,7 +124,7 @@ public class PasswordFrame extends JFrame implements DocumentListener {
final String siteName = siteNameField.getText();
final int siteCounter = (Integer) siteCounterField.getValue();
executor.submit( new Runnable() {
Res.execute( new Runnable() {
@Override
public void run() {
final String sitePassword = MasterPassword.generateContent( siteType, siteName, user.getKey(), siteCounter );

View File

@ -0,0 +1,120 @@
package com.lyndir.lhunath.masterpassword;
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.ifNotNullElse;
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
import com.google.common.base.Throwables;
import com.google.common.io.Resources;
import com.lyndir.lhunath.opal.system.logging.Logger;
import java.awt.*;
import java.awt.image.ImageObserver;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.*;
/**
* @author lhunath, 2014-06-11
*/
public abstract class Res {
private static final ExecutorService executor = Executors.newSingleThreadExecutor();
private static final Logger logger = Logger.get( Res.class );
private static Font sourceCodeProBlack;
public static void execute(final Runnable job) {
executor.submit( new Runnable() {
@Override
public void run() {
try {
job.run();
}
catch (Throwable t) {
logger.err( t, "Unexpected: %s", t.getLocalizedMessage() );
}
}
} );
}
public static Icon iconQuestion() {
return new RetinaIcon( Resources.getResource( "media/icon_question@2x.png" ) );
}
public static Icon avatar(final int index) {
return new RetinaIcon( Resources.getResource( strf( "media/avatar-%d@2x.png", index ) ) );
}
public static Font sourceCodeProBlack() {
try {
URL resource = Resources.getResource( "fonts/SourceCodePro-Bold.otf" );
Font font = Font.createFont( Font.TRUETYPE_FONT, resource.openStream() );
return sourceCodeProBlack != null? sourceCodeProBlack: //
(sourceCodeProBlack = font);
}
catch (FontFormatException | IOException e) {
throw Throwables.propagate( e );
}
}
private static final class RetinaIcon extends ImageIcon {
private static final Pattern scalePattern = Pattern.compile(".*@(\\d+)x.[^.]+$");
private final float scale;
public RetinaIcon(final URL url) {
super( url );
Matcher scaleMatcher = scalePattern.matcher( url.getPath() );
if (scaleMatcher.matches())
scale = Float.parseFloat( scaleMatcher.group( 1 ) );
else
scale = 1;
}
//private static URL retinaURL(final URL url) {
// try {
// final boolean[] isRetina = new boolean[1];
// new apple.awt.CImage.HiDPIScaledImage(1,1, BufferedImage.TYPE_INT_ARGB) {
// @Override
// public void drawIntoImage(BufferedImage image, float v) {
// isRetina[0] = v > 1;
// }
// };
// return isRetina[0];
// } catch (Throwable e) {
// e.printStackTrace();
// return url;
// }
//}
@Override
public int getIconWidth() {
return (int) (super.getIconWidth() / scale);
}
@Override
public int getIconHeight() {
return (int) (super.getIconHeight() / scale);
}
public synchronized void paintIcon(Component c, Graphics g, int x, int y) {
ImageObserver observer = ifNotNullElse( getImageObserver(), c );
Image image = getImage();
int width = image.getWidth( observer );
int height = image.getHeight( observer );
final Graphics2D g2d = (Graphics2D) g.create( x, y, width, height );
g2d.scale( 1 / scale, 1 / scale );
g2d.drawImage( image, 0, 0, observer );
g2d.scale( 1, 1 );
g2d.dispose();
}
}
}

View File

@ -1,12 +1,10 @@
package com.lyndir.lhunath.masterpassword;
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.ifNotNullElse;
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
import com.lyndir.lhunath.masterpassword.util.Components;
import java.awt.*;
import java.awt.event.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.swing.*;
import javax.swing.border.*;
@ -16,8 +14,6 @@ import javax.swing.border.*;
*/
public class UnlockFrame extends JFrame {
private static final ExecutorService executor = Executors.newSingleThreadExecutor();
private final SignInCallback signInCallback;
private final JPanel root;
private final JButton signInButton;
@ -77,13 +73,13 @@ public class UnlockFrame extends JFrame {
authenticationPanel.updateUser();
authenticationContainer.add( authenticationPanel, BorderLayout.CENTER );
final JCheckBox configCheckBox = new JCheckBox( "Use Config File" );
configCheckBox.setAlignmentX( LEFT_ALIGNMENT );
configCheckBox.setSelected( useConfig );
configCheckBox.addItemListener( new ItemListener() {
final JCheckBox typeCheckBox = new JCheckBox( "Use Config File" );
typeCheckBox.setAlignmentX( LEFT_ALIGNMENT );
typeCheckBox.setSelected( useConfig );
typeCheckBox.addItemListener( new ItemListener() {
@Override
public void itemStateChanged(final ItemEvent e) {
useConfig = configCheckBox.isSelected();
useConfig = typeCheckBox.isSelected();
SwingUtilities.invokeLater( new Runnable() {
@Override
public void run() {
@ -92,12 +88,48 @@ public class UnlockFrame extends JFrame {
} );
}
} );
authenticationContainer.add( configCheckBox );
JButton typeHelp = new JButton( Res.iconQuestion() );
typeHelp.setMargin( new Insets( 0, 0, 0, 0 ) );
typeHelp.setBackground( Color.red );
typeHelp.setAlignmentX( RIGHT_ALIGNMENT );
typeHelp.setBorder( null );
typeHelp.addActionListener( new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
final JDialog dialog = new JDialog( UnlockFrame.this, "Help", true );
dialog.setContentPane( new JPanel( new BorderLayout( 8, 8 ) ) {
{
setBorder( new EmptyBorder( 8, 8, 8, 8 ) );
}
} );
dialog.add( new JLabel( authenticationPanel.getHelpText() ), BorderLayout.CENTER );
dialog.add( new JButton( "OK" ) {
{
addActionListener( new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
dialog.dispose();
}
} );
}
}, BorderLayout.SOUTH );
dialog.pack();
dialog.setLocationRelativeTo( UnlockFrame.this );
dialog.setVisible( true );
}
} );
if (authenticationPanel.getHelpText() == null) {
typeHelp.setVisible( false );
}
JComponent typePanel = Components.boxLayout( BoxLayout.LINE_AXIS, typeCheckBox, Box.createGlue(), typeHelp );
typePanel.setAlignmentX( Component.LEFT_ALIGNMENT );
authenticationContainer.add( typePanel );
checkSignIn();
validate();
repack();
SwingUtilities.invokeLater( new Runnable() {
@Override
public void run() {
@ -130,7 +162,7 @@ public class UnlockFrame extends JFrame {
signInButton.setEnabled( false );
signInButton.setText( "Signing In..." );
executor.submit( new Runnable() {
Res.execute( new Runnable() {
@Override
public void run() {
final boolean success = signInCallback.signedIn( user );

View File

@ -1 +0,0 @@
../../../../../Resources/Media/

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 643 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 411 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 588 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB