diff --git a/platform-independent/java/gui/src/main/java/com/lyndir/masterpassword/gui/MPGuiConfig.java b/platform-independent/java/gui/src/main/java/com/lyndir/masterpassword/gui/MPGuiConfig.java index b58c5a86..926d7e0b 100644 --- a/platform-independent/java/gui/src/main/java/com/lyndir/masterpassword/gui/MPGuiConfig.java +++ b/platform-independent/java/gui/src/main/java/com/lyndir/masterpassword/gui/MPGuiConfig.java @@ -35,6 +35,7 @@ public class MPGuiConfig extends MPConfig { Boolean checkForUpdates; Boolean stayResident; + Boolean logoutOnClose; public boolean checkForUpdates() { return (checkForUpdates != null)? checkForUpdates: @@ -55,4 +56,13 @@ public class MPGuiConfig extends MPConfig { this.stayResident = stayResident; setChanged(); } + + public boolean logoutOnClose() { + return (logoutOnClose != null)? logoutOnClose: true; + } + + public void setLogoutOnClose(final boolean logoutOnClose) { + this.logoutOnClose = logoutOnClose; + setChanged(); + } } diff --git a/platform-independent/java/gui/src/main/java/com/lyndir/masterpassword/gui/MPGuiConstants.java b/platform-independent/java/gui/src/main/java/com/lyndir/masterpassword/gui/MPGuiConstants.java index 09ba0678..25fc1c53 100644 --- a/platform-independent/java/gui/src/main/java/com/lyndir/masterpassword/gui/MPGuiConstants.java +++ b/platform-independent/java/gui/src/main/java/com/lyndir/masterpassword/gui/MPGuiConstants.java @@ -11,4 +11,6 @@ import javax.swing.*; public final class MPGuiConstants { public static final KeyStroke ui_hotkey = KeyStroke.getKeyStroke( KeyEvent.VK_P, InputEvent.ALT_DOWN_MASK | InputEvent.META_DOWN_MASK ); + + public static final int FORCE_CLOSE_KEY = KeyEvent.VK_ALT; } diff --git a/platform-independent/java/gui/src/main/java/com/lyndir/masterpassword/gui/util/Res.java b/platform-independent/java/gui/src/main/java/com/lyndir/masterpassword/gui/util/Res.java index 2f9e7671..f75a519b 100644 --- a/platform-independent/java/gui/src/main/java/com/lyndir/masterpassword/gui/util/Res.java +++ b/platform-independent/java/gui/src/main/java/com/lyndir/masterpassword/gui/util/Res.java @@ -165,6 +165,10 @@ public abstract class Res { return icon( "media/icon_key.png" ); } + public Icon prefs() { + return icon( "media/prefs.png" ); + } + public Icon avatar(final int index) { return icon( strf( "media/avatar-%d.png", index % avatars() ) ); } diff --git a/platform-independent/java/gui/src/main/java/com/lyndir/masterpassword/gui/view/MasterPasswordFrame.java b/platform-independent/java/gui/src/main/java/com/lyndir/masterpassword/gui/view/MasterPasswordFrame.java index 50cc607d..643ad381 100644 --- a/platform-independent/java/gui/src/main/java/com/lyndir/masterpassword/gui/view/MasterPasswordFrame.java +++ b/platform-independent/java/gui/src/main/java/com/lyndir/masterpassword/gui/view/MasterPasswordFrame.java @@ -2,6 +2,7 @@ package com.lyndir.masterpassword.gui.view; import com.lyndir.lhunath.opal.system.logging.Logger; import com.lyndir.masterpassword.gui.MPGuiConfig; +import com.lyndir.masterpassword.gui.MPGuiConstants; import com.lyndir.masterpassword.gui.util.Components; import com.lyndir.masterpassword.gui.util.Res; import com.lyndir.masterpassword.model.impl.MPFileUserManager; @@ -19,8 +20,6 @@ public class MasterPasswordFrame extends JFrame { private static final Logger logger = Logger.get( MasterPasswordFrame.class ); - private final UserContentPanel userContent; - @SuppressWarnings("MagicNumber") public MasterPasswordFrame() { super( "Master Password" ); @@ -32,14 +31,16 @@ public class MasterPasswordFrame extends JFrame { root.add( Components.strut() ); root.add( userPanel = Components.panel( new BorderLayout( 0, 0 ) ) ); + final UserContentPanel userContent = new UserContentPanel(); userPanel.add( Components.borderPanel( BorderFactory.createBevelBorder( BevelBorder.RAISED, Res.colors().controlBorder(), Res.colors().frameBg() ), - Res.colors().controlBg(), BoxLayout.PAGE_AXIS, userContent = new UserContentPanel() ), BorderLayout.CENTER ); + Res.colors().controlBg(), BoxLayout.PAGE_AXIS, userContent), BorderLayout.CENTER ); userPanel.add( userContent.getUserToolbar(), BorderLayout.LINE_START ); userPanel.add( userContent.getSiteToolbar(), BorderLayout.LINE_END ); - addComponentListener( new ComponentHandler() ); - addWindowListener( new WindowHandler() ); + final WindowHandler windowHandler = new WindowHandler(); + addWindowListener(windowHandler); + KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(windowHandler); setPreferredSize( new Dimension( 800, 560 ) ); setDefaultCloseOperation( DISPOSE_ON_CLOSE ); pack(); @@ -48,22 +49,30 @@ public class MasterPasswordFrame extends JFrame { setLocationByPlatform( true ); } - private class ComponentHandler extends ComponentAdapter { - @Override - public void componentShown(final ComponentEvent e) { - MPFileUserManager.get().reload(); - userContent.transferFocus(); - } - } + private static class WindowHandler extends WindowAdapter implements KeyEventDispatcher { - - private static class WindowHandler extends WindowAdapter { + private boolean forceClose = false; @Override public void windowClosed(final WindowEvent e) { - if (!MPGuiConfig.get().stayResident()) + if (!MPGuiConfig.get().stayResident() || forceClose) { + System.exit( 0 ); + } + else if (MPGuiConfig.get().logoutOnClose()) { + + MPFileUserManager.get().reload(); + } + } + + @Override + public boolean dispatchKeyEvent(KeyEvent e) { + + if (e.getKeyCode() == MPGuiConstants.FORCE_CLOSE_KEY) + forceClose = (e.getID() == KeyEvent.KEY_PRESSED); + + return false; } } } diff --git a/platform-independent/java/gui/src/main/java/com/lyndir/masterpassword/gui/view/UserContentPanel.java b/platform-independent/java/gui/src/main/java/com/lyndir/masterpassword/gui/view/UserContentPanel.java index 1a5cc7af..c84fb84c 100644 --- a/platform-independent/java/gui/src/main/java/com/lyndir/masterpassword/gui/view/UserContentPanel.java +++ b/platform-independent/java/gui/src/main/java/com/lyndir/masterpassword/gui/view/UserContentPanel.java @@ -57,6 +57,8 @@ public class UserContentPanel extends JPanel implements MasterPassword.Listener, "Import a user from a backup file into Master Password." ); private final JButton helpButton = Components.button( Res.icons().help(), event -> showHelp(), "Show information on how to use Master Password." ); + private final JButton prefsButton = Components.button( Res.icons().prefs(), event -> showAppPreferences(), + "Show application preferences." ); private final JPanel userToolbar = Components.panel( BoxLayout.PAGE_AXIS ); private final JPanel siteToolbar = Components.panel( BoxLayout.PAGE_AXIS ); @@ -250,6 +252,24 @@ public class UserContentPanel extends JPanel implements MasterPassword.Listener, "About Master Password", JOptionPane.INFORMATION_MESSAGE ); } + private void showAppPreferences() { + Component checkForUpdates = Components.checkBox("Check For Updates", MPGuiConfig.get().checkForUpdates(), MPGuiConfig.get()::setCheckForUpdates); + + JCheckBox stayResident = Components.checkBox(strf("Stay running in background when closed (reactivate with %s+%s)", + InputEvent.getModifiersExText(MPGuiConstants.ui_hotkey.getModifiers()), + KeyEvent.getKeyText(MPGuiConstants.ui_hotkey.getKeyCode())), + MPGuiConfig.get().stayResident(), MPGuiConfig.get()::setStayResident); + stayResident.setToolTipText(strf("Hold %s while closing to force exit", KeyEvent.getKeyText(MPGuiConstants.FORCE_CLOSE_KEY))); + + Component logoutOnClose = Components.checkBox("Logout current user on close", MPGuiConfig.get().logoutOnClose(), MPGuiConfig.get()::setLogoutOnClose); + + stayResident.addItemListener(e -> logoutOnClose.setEnabled(e.getStateChange() == ItemEvent.SELECTED)); + logoutOnClose.setEnabled(stayResident.isSelected()); + + Components.showDialog(this, "Application Preferences", + new JOptionPane(Components.panel(BoxLayout.PAGE_AXIS, checkForUpdates, stayResident, logoutOnClose))); + } + private enum ContentMode { NO_USER, AUTHENTICATE, @@ -291,6 +311,9 @@ public class UserContentPanel extends JPanel implements MasterPassword.Listener, userToolbar.add( Box.createGlue() ); userToolbar.add( helpButton ); + siteToolbar.add(Box.createGlue()); + siteToolbar.add(prefsButton); + add( Box.createGlue() ); add( Components.heading( "Select a user to proceed." ) ); add( Box.createGlue() ); @@ -329,6 +352,9 @@ public class UserContentPanel extends JPanel implements MasterPassword.Listener, userToolbar.add( Box.createGlue() ); userToolbar.add( helpButton ); + siteToolbar.add(Box.createGlue()); + siteToolbar.add(prefsButton); + add( Components.heading( user.getFullName(), SwingConstants.CENTER ) ); add( Components.strut() ); @@ -532,6 +558,8 @@ public class UserContentPanel extends JPanel implements MasterPassword.Listener, siteToolbar.add( editButton ); siteToolbar.add( keyButton ); siteToolbar.add( deleteButton ); + siteToolbar.add(Box.createGlue()); + siteToolbar.add(prefsButton); settingsButton.setEnabled( false ); questionsButton.setEnabled( false ); editButton.setEnabled( false ); @@ -605,19 +633,14 @@ public class UserContentPanel extends JPanel implements MasterPassword.Listener, user.getPreferences().getDefaultType(), user.getPreferences()::setDefaultType ), Components.strut() ); + components.add( Components.label( "Default Login Type:" ), + Components.comboBox( MPResultType.values(), MPResultType::getLongName, + user.getPreferences().getDefaultLoginType(), user.getPreferences()::setDefaultLoginType), + Components.strut() ); + components.add( Components.checkBox( "Hide Passwords", user.getPreferences().isHidePasswords(), user.getPreferences()::setHidePasswords ) ); - components.add( new JSeparator() ); - - components.add( Components.checkBox( "Check For Updates", - MPGuiConfig.get().checkForUpdates(), MPGuiConfig.get()::setCheckForUpdates ) ); - - components.add( Components.checkBox( strf( "Stay Resident (reactivate with %s+%s)", - InputEvent.getModifiersExText( MPGuiConstants.ui_hotkey.getModifiers() ), - KeyEvent.getKeyText( MPGuiConstants.ui_hotkey.getKeyCode() ) ), - MPGuiConfig.get().stayResident(), MPGuiConfig.get()::setStayResident ) ); - Components.showDialog( this, user.getFullName(), new JOptionPane( Components.panel( BoxLayout.PAGE_AXIS, components.build().toArray( new Component[0] ) ) ) ); } @@ -650,7 +673,7 @@ public class UserContentPanel extends JPanel implements MasterPassword.Listener, components.add( Components.label( "Login Type:" ), Components.comboBox( MPResultType.values(), type -> - getTypeDescription( type, user.getAlgorithm().mpw_default_login_type() ), + getTypeDescription( type, user.getPreferences().getDefaultLoginType() ), site.getLoginType(), site::setLoginType ), Components.strut() ); diff --git a/platform-independent/java/gui/src/main/resources/media/prefs.png b/platform-independent/java/gui/src/main/resources/media/prefs.png new file mode 100644 index 00000000..9717aea7 Binary files /dev/null and b/platform-independent/java/gui/src/main/resources/media/prefs.png differ diff --git a/platform-independent/java/gui/src/main/resources/media/prefs@2x.png b/platform-independent/java/gui/src/main/resources/media/prefs@2x.png new file mode 100644 index 00000000..8855bc33 Binary files /dev/null and b/platform-independent/java/gui/src/main/resources/media/prefs@2x.png differ diff --git a/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/MPUserPreferences.java b/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/MPUserPreferences.java index d7bab23f..5749335c 100644 --- a/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/MPUserPreferences.java +++ b/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/MPUserPreferences.java @@ -13,6 +13,10 @@ public interface MPUserPreferences { void setDefaultType(@Nullable MPResultType defaultType); + MPResultType getDefaultLoginType(); + + void setDefaultLoginType(@Nullable MPResultType defaultLoginType); + boolean isHidePasswords(); void setHidePasswords(boolean hidePasswords); diff --git a/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPBasicSite.java b/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPBasicSite.java index 9b646d15..e4e177c4 100644 --- a/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPBasicSite.java +++ b/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPBasicSite.java @@ -56,7 +56,7 @@ public abstract class MPBasicSite, Q extends MPQuestion> ext this.algorithm = (algorithm != null)? algorithm: this.user.getAlgorithm(); this.counter = (counter != null)? counter: this.algorithm.mpw_default_counter(); this.resultType = (resultType != null)? resultType: this.user.getPreferences().getDefaultType(); - this.loginType = (loginType != null)? loginType: this.algorithm.mpw_default_login_type(); + this.loginType = (loginType != null)? loginType: this.user.getPreferences().getDefaultLoginType(); } // - Meta @@ -125,7 +125,7 @@ public abstract class MPBasicSite, Q extends MPQuestion> ext if (this.loginType == loginType) return; - this.loginType = ifNotNullElse( loginType, getAlgorithm().mpw_default_login_type() ); + this.loginType = ifNotNullElse( loginType, this.user.getPreferences().getDefaultLoginType() ); setChanged(); } diff --git a/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPBasicUserPreferences.java b/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPBasicUserPreferences.java index a32363f7..b69d3410 100644 --- a/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPBasicUserPreferences.java +++ b/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPBasicUserPreferences.java @@ -14,6 +14,8 @@ public class MPBasicUserPreferences> implements MPUserP @Nullable private MPResultType defaultType; + @Nullable + private MPResultType defaultLoginType; private boolean hidePasswords; public MPBasicUserPreferences(final U user) { @@ -34,6 +36,16 @@ public class MPBasicUserPreferences> implements MPUserP this.defaultType = defaultType; } + @Override + public MPResultType getDefaultLoginType() { + return (defaultLoginType != null) ? defaultLoginType : user.getAlgorithm().mpw_default_login_type(); + } + + @Override + public void setDefaultLoginType(@Nullable final MPResultType defaultLoginType) { + this.defaultLoginType = defaultLoginType; + } + @Override public boolean isHidePasswords() { return hidePasswords; diff --git a/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPFileUser.java b/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPFileUser.java index d05ece6d..57081991 100755 --- a/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPFileUser.java +++ b/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPFileUser.java @@ -62,18 +62,19 @@ public class MPFileUser extends MPBasicUser { } public MPFileUser(final String fullName, @Nullable final byte[] keyID, final MPAlgorithm algorithm, final File location) { - this( fullName, keyID, algorithm, 0, null, new Instant(), false, + this( fullName, keyID, algorithm, 0, null, null, new Instant(), false, MPMarshaller.ContentMode.PROTECTED, MPMarshalFormat.DEFAULT, location ); } public MPFileUser(final String fullName, @Nullable final byte[] keyID, final MPAlgorithm algorithm, final int avatar, - @Nullable final MPResultType defaultType, final ReadableInstant lastUsed, final boolean hidePasswords, - final MPMarshaller.ContentMode contentMode, final MPMarshalFormat format, final File location) { + @Nullable final MPResultType defaultType, @Nullable final MPResultType defaultLoginType, + final ReadableInstant lastUsed, final boolean hidePasswords, final MPMarshaller.ContentMode contentMode, + final MPMarshalFormat format, final File location) { super( avatar, fullName, algorithm ); this.keyID = (keyID != null)? keyID.clone(): null; this.lastUsed = lastUsed; - this.preferences = new MPFileUserPreferences( this, defaultType, hidePasswords ); + this.preferences = new MPFileUserPreferences( this, defaultType, defaultLoginType, hidePasswords); this.format = format; this.contentMode = contentMode; diff --git a/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPFileUserPreferences.java b/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPFileUserPreferences.java index b800f0c6..acf1a666 100644 --- a/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPFileUserPreferences.java +++ b/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPFileUserPreferences.java @@ -10,10 +10,11 @@ import javax.annotation.Nullable; */ public class MPFileUserPreferences extends MPBasicUserPreferences { - public MPFileUserPreferences(final MPFileUser user, @Nullable final MPResultType defaultType, final boolean hidePasswords) { + public MPFileUserPreferences(final MPFileUser user, @Nullable final MPResultType defaultType, @Nullable final MPResultType defaultLoginType, final boolean hidePasswords) { super( user ); setDefaultType( defaultType ); + setDefaultLoginType(defaultLoginType); setHidePasswords( hidePasswords ); } @@ -26,6 +27,15 @@ public class MPFileUserPreferences extends MPBasicUserPreferences { getUser().setChanged(); } + @Override + public void setDefaultLoginType(@Nullable final MPResultType defaultLoginType) { + if (getDefaultLoginType() == defaultLoginType) + return; + + super.setDefaultLoginType(defaultLoginType); + getUser().setChanged(); + } + @Override public void setHidePasswords(final boolean hidePasswords) { if (Objects.equals( isHidePasswords(), hidePasswords )) diff --git a/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPFlatMarshaller.java b/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPFlatMarshaller.java index b3cca47c..aac53f3b 100644 --- a/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPFlatMarshaller.java +++ b/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPFlatMarshaller.java @@ -57,6 +57,7 @@ public class MPFlatMarshaller implements MPMarshaller { content.append( "# Key ID: " ).append( user.exportKeyID() ).append( '\n' ); content.append( "# Algorithm: " ).append( user.getAlgorithm().version().toInt() ).append( '\n' ); content.append( "# Default Type: " ).append( user.getPreferences().getDefaultType().getType() ).append( '\n' ); + content.append( "# Default Login Type: " ).append( user.getPreferences().getDefaultLoginType().getType() ).append( '\n' ); content.append( "# Passwords: " ).append( user.getContentMode().name() ).append( '\n' ); content.append( "##\n" ); content.append( "#\n" ); diff --git a/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPFlatUnmarshaller.java b/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPFlatUnmarshaller.java index 9d6e290f..8a6e0bc9 100644 --- a/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPFlatUnmarshaller.java +++ b/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPFlatUnmarshaller.java @@ -56,11 +56,12 @@ public class MPFlatUnmarshaller implements MPUnmarshaller { int mpVersion = 0, avatar = 0; boolean clearContent = false, headerStarted = false; MPResultType defaultType = null; + MPResultType defaultLoginType = null; Instant date = null; //noinspection HardcodedLineSeparator for (final String line : CharStreams.readLines( reader )) - // Header delimitor. + // Header delimiter. if (line.startsWith( "##" )) { if (!headerStarted) // Starts the header. @@ -68,7 +69,7 @@ public class MPFlatUnmarshaller implements MPUnmarshaller { else if ((fullName != null) && (keyID != null)) // Ends the header. return new MPFileUser( - fullName, keyID, MPAlgorithm.Version.fromInt( mpVersion ).getAlgorithm(), avatar, defaultType, + fullName, keyID, MPAlgorithm.Version.fromInt( mpVersion ).getAlgorithm(), avatar, defaultType, defaultLoginType, date, false, clearContent? MPMarshaller.ContentMode.VISIBLE: MPMarshaller.ContentMode.PROTECTED, MPMarshalFormat.Flat, file ); @@ -93,6 +94,8 @@ public class MPFlatUnmarshaller implements MPUnmarshaller { clearContent = "visible".equalsIgnoreCase( value ); else if ("Default Type".equalsIgnoreCase( name )) defaultType = MPResultType.forType( ConversionUtils.toIntegerNN( value ) ); + else if ("Default Login Type".equalsIgnoreCase( name )) + defaultLoginType = MPResultType.forType( ConversionUtils.toIntegerNN( value ) ); else if ("Date".equalsIgnoreCase( name )) date = MPModelConstants.dateTimeFormatter.parseDateTime( value ).toInstant(); } diff --git a/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPJSONFile.java b/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPJSONFile.java index 5cb3b85a..0a1eee23 100644 --- a/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPJSONFile.java +++ b/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPJSONFile.java @@ -20,11 +20,6 @@ package com.lyndir.masterpassword.model.impl; import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*; -import com.fasterxml.jackson.annotation.JsonAutoDetect; -import com.fasterxml.jackson.annotation.PropertyAccessor; -import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; -import com.fasterxml.jackson.core.util.Separators; -import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.primitives.UnsignedInteger; import com.lyndir.lhunath.opal.system.CodeUtils; import com.lyndir.masterpassword.*; @@ -66,6 +61,7 @@ public class MPJSONFile extends MPJSONAnyObject { user._ext_mpw = new User.Ext() { { default_type = modelUser.getPreferences().getDefaultType(); + default_login_type = modelUser.getPreferences().getDefaultLoginType(); hide_passwords = modelUser.getPreferences().isHidePasswords(); } }; @@ -133,6 +129,7 @@ public class MPJSONFile extends MPJSONAnyObject { return new MPFileUser( user.full_name, CodeUtils.decodeHex( user.key_id ), algorithm, user.avatar, (user._ext_mpw != null)? user._ext_mpw.default_type: null, + (user._ext_mpw != null)? user._ext_mpw.default_login_type : null, (user.last_used != null)? MPModelConstants.dateTimeFormatter.parseDateTime( user.last_used ): new Instant(), (user._ext_mpw != null) && user._ext_mpw.hide_passwords, export.redacted? MPMarshaller.ContentMode.PROTECTED: MPMarshaller.ContentMode.VISIBLE, @@ -211,6 +208,8 @@ public class MPJSONFile extends MPJSONAnyObject { @Nullable MPResultType default_type; + @Nullable + MPResultType default_login_type; boolean hide_passwords; } }