UI improvements for the Java GUI.
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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 );
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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 );
|
||||
|
@ -1 +0,0 @@
|
||||
../../../../../Resources/Media/
|
After Width: | Height: | Size: 8.7 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 8.7 KiB |
After Width: | Height: | Size: 8.9 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 8.5 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 9.1 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 9.3 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 8.7 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 9.1 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 9.0 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 8.6 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 8.8 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 8.7 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 8.7 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 8.7 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 8.4 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 8.8 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 8.6 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 8.7 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 8.6 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 7.6 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 3.7 KiB |
@ -0,0 +1 @@
|
||||
3269
|
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 6.0 KiB |
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 172 KiB |
Before Width: | Height: | Size: 643 KiB |
Before Width: | Height: | Size: 122 KiB |
Before Width: | Height: | Size: 411 KiB |
Before Width: | Height: | Size: 162 KiB |
Before Width: | Height: | Size: 588 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 2.1 KiB |