aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKyle Horimoto <khorimoto@gmail.com>2015-10-20 11:52:14 -0700
committerKyle Horimoto <khorimoto@gmail.com>2015-10-21 12:18:22 -0700
commitd57ab6f788707defad29df2432eafe1bc4dd4e79 (patch)
tree3f122be8a8cb0185e92d3d5cd83a2af7825db5ed
parent5295bbcaae77e9cd797c3ff7ae8fc9dba5549604 (diff)
downloadconnectbot-d57ab6f788707defad29df2432eafe1bc4dd4e79.tar.gz
connectbot-d57ab6f788707defad29df2432eafe1bc4dd4e79.tar.bz2
connectbot-d57ab6f788707defad29df2432eafe1bc4dd4e79.zip
Polish UI for add/edit host.
-rw-r--r--app/src/main/java/org/connectbot/HostEditorFragment.java581
-rw-r--r--app/src/main/java/org/connectbot/bean/HostBean.java2
-rw-r--r--app/src/main/res/layout/fragment_host_editor.xml439
-rw-r--r--app/src/main/res/values-v11/styles.xml13
-rw-r--r--app/src/main/res/values/styles.xml32
5 files changed, 718 insertions, 349 deletions
diff --git a/app/src/main/java/org/connectbot/HostEditorFragment.java b/app/src/main/java/org/connectbot/HostEditorFragment.java
index 56022d7..2a6514e 100644
--- a/app/src/main/java/org/connectbot/HostEditorFragment.java
+++ b/app/src/main/java/org/connectbot/HostEditorFragment.java
@@ -18,6 +18,7 @@
package org.connectbot;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.Map;
import android.content.ContentValues;
@@ -29,10 +30,12 @@ import android.os.Parcelable;
import android.support.design.widget.TextInputLayout;
import android.support.v4.app.Fragment;
import android.support.v7.widget.AppCompatCheckBox;
+import android.support.v7.widget.PopupMenu;
import android.support.v7.widget.SwitchCompat;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
+import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
@@ -59,7 +62,10 @@ public class HostEditorFragment extends Fragment {
private static final String ARG_PUBKEY_VALUES = "pubkeyValues";
private static final String ARG_QUICKCONNECT_STRING = "quickConnectString";
+ // Note: The "max" value for mFontSizeSeekBar is 32. If these font values change, this value
+ // must be changed in the SeekBar's XML.
private static final int MINIMUM_FONT_SIZE = 8;
+ private static final int MAXIMUM_FONT_SIZE = 40;
// The host being edited.
private HostBean mHost;
@@ -68,10 +74,6 @@ public class HostEditorFragment extends Fragment {
// Lists because Bundles can only contain ArrayLists, not general Lists.
private ArrayList<String> mPubkeyNames;
private ArrayList<String> mPubkeyValues;
-
- // Whether the host is being created for the first time (as opposed to an existing one being
- // edited).
- private boolean mIsCreating;
// The listener for changes to this host.
private Listener mListener;
@@ -86,17 +88,24 @@ public class HostEditorFragment extends Fragment {
// first field, etc.
private boolean mUriFieldEditInProgress = false;
- // Values for the colors displayed in the color Spinner. These are not necessarily the same as
- // the text in the Spinner because the text is localized while these values are not.
+ // Names and values for the colors displayed in the color Spinner. Names are localized, while
+ // values are the same across languages, so the values are the ones saved to the database.
+ private TypedArray mColorNames;
private TypedArray mColorValues;
- // Likewise, but for SSH auth agent values.
+ // Likewise, but for SSH auth agent.
+ private TypedArray mSshAuthNames;
private TypedArray mSshAuthValues;
- // Likewise, but for DEL key values.
+ // Likewise, but for DEL key.
+ private TypedArray mDelKeyNames;
private TypedArray mDelKeyValues;
- private Spinner mTransportSpinner;
+ // A map from Charset display name to Charset value (i.e., unique ID for the Charset).
+ private Map<String, String> mCharsetData;
+
+ private View mTransportItem;
+ private TextView mTransportText;
private TextInputLayout mQuickConnectContainer;
private EditText mQuickConnectField;
private ImageButton mExpandCollapseButton;
@@ -108,20 +117,29 @@ public class HostEditorFragment extends Fragment {
private View mPortContainer;
private EditText mPortField;
private EditText mNicknameField;
- private Spinner mColorSelector;
- private TextView mFontSizeText;
+ private View mColorItem;
+ private TextView mColorText;
+ private EditText mFontSizeText;
private SeekBar mFontSizeSeekBar;
- private Spinner mPubkeySpinner;
- private View mUseSshConfirmationContainer;
+ private View mPubkeyItem;
+ private TextView mPubkeyText;
+ private View mDelKeyItem;
+ private TextView mDelKeyText;
+ private View mEncodingItem;
+ private TextView mEncodingText;
+ private View mUseSshAuthItem;
private SwitchCompat mUseSshAuthSwitch;
- private AppCompatCheckBox mSshAuthConfirmationCheckbox;
+ private View mUseSshConfirmationItem;
+ private AppCompatCheckBox mUseSshConfirmationCheckbox;
+ private View mCompressionItem;
private SwitchCompat mCompressionSwitch;
+ private View mStartShellItem;
private SwitchCompat mStartShellSwitch;
+ private View mStayConnectedItem;
private SwitchCompat mStayConnectedSwitch;
+ private View mCloseOnDisconnectItem;
private SwitchCompat mCloseOnDisconnectSwitch;
private EditText mPostLoginAutomationField;
- private Spinner mDelKeySpinner;
- private Spinner mEncodingSpinner;
public static HostEditorFragment newInstance(
HostBean existingHost, ArrayList<String> pubkeyNames, ArrayList<String> pubkeyValues) {
@@ -147,7 +165,6 @@ public class HostEditorFragment extends Fragment {
Bundle bundle = savedInstanceState == null ? getArguments() : savedInstanceState;
Parcelable existingHostParcelable = bundle.getParcelable(ARG_EXISTING_HOST);
- mIsCreating = existingHostParcelable == null;
if (existingHostParcelable != null) {
mHost = HostBean.fromContentValues((ContentValues) existingHostParcelable);
mHost.setId(bundle.getLong(ARG_EXISTING_HOST_ID));
@@ -166,59 +183,28 @@ public class HostEditorFragment extends Fragment {
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_host_editor, container, false);
- mTransportSpinner = (Spinner) view.findViewById(R.id.transport_selector);
- String[] transportNames = TransportFactory.getTransportNames();
- ArrayAdapter<String> transportSelection = new ArrayAdapter<>(
- getActivity(), android.R.layout.simple_spinner_item, transportNames);
- transportSelection.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- mTransportSpinner.setAdapter(transportSelection);
- for (int i = 0; i < transportNames.length; i++) {
- if (transportNames[i].equals(mHost.getProtocol())) {
- mTransportSpinner.setSelection(i);
- break;
- }
- }
- mTransportSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ mTransportItem = view.findViewById(R.id.protocol_item);
+ mTransportItem.setOnClickListener(new View.OnClickListener() {
@Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- String protocol = (String) mTransportSpinner.getSelectedItem();
- if (protocol == null) {
- // During initialization, protocol can be null before the list of dropdown items
- // has been generated. Return early in that case.
- return;
- }
-
- mHost.setProtocol(protocol);
- mHost.setPort(TransportFactory.getTransport(protocol).getDefaultPort());
- handleHostChange();
-
- mQuickConnectContainer.setHint(
- TransportFactory.getFormatHint(protocol, getActivity()));
-
- // Different protocols have different field types, so show only the fields needed.
- if (SSH.getProtocolName().equals(protocol)) {
- mUsernameContainer.setVisibility(View.VISIBLE);
- mHostnameContainer.setVisibility(View.VISIBLE);
- mPortContainer.setVisibility(View.VISIBLE);
- mExpandCollapseButton.setVisibility(View.VISIBLE);
- } else if (Telnet.getProtocolName().equals(protocol)) {
- mUsernameContainer.setVisibility(View.GONE);
- mHostnameContainer.setVisibility(View.VISIBLE);
- mPortContainer.setVisibility(View.VISIBLE);
- mExpandCollapseButton.setVisibility(View.VISIBLE);
- } else {
- // Local protocol has only one field, so no need to show the URI parts
- // container.
- setUriPartsContainerExpanded(false);
- mExpandCollapseButton.setVisibility(View.INVISIBLE);
+ public void onClick(View v) {
+ PopupMenu menu = new PopupMenu(getActivity(), v);
+ for (String name : TransportFactory.getTransportNames()) {
+ menu.getMenu().add(name);
}
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
+ menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ setTransportType(
+ item.getTitle().toString(), /* setDefaultPortInModel */ true);
+ return true;
+ }
+ });
+ menu.show();
}
});
+ mTransportText = (TextView) view.findViewById(R.id.protocol_text);
+
mQuickConnectContainer =
(TextInputLayout) view.findViewById(R.id.quickconnect_field_container);
@@ -237,15 +223,8 @@ public class HostEditorFragment extends Fragment {
@Override
public void afterTextChanged(Editable s) {
- if (mTransportSpinner.getSelectedItem() == null) {
- // During initialization, protocol can be null before the list of dropdown items
- // has been generated. Return early in that case.
- return;
- }
-
if (!mUriFieldEditInProgress) {
- applyQuickConnectString(
- s.toString(), (String) mTransportSpinner.getSelectedItem());
+ applyQuickConnectString(s.toString(), mHost.getProtocol());
mUriFieldEditInProgress = true;
mUsernameField.setText(mHost.getUsername());
@@ -281,39 +260,63 @@ public class HostEditorFragment extends Fragment {
mPortField.setText(Integer.toString(mHost.getPort()));
mPortField.addTextChangedListener(new HostTextFieldWatcher(HostDatabase.FIELD_HOST_PORT));
+ setTransportType(mHost.getProtocol(), /* setDefaultPortInModel */ false);
+
mNicknameField = (EditText) view.findViewById(R.id.nickname_field);
mNicknameField.setText(mHost.getNickname());
mNicknameField.addTextChangedListener(
new HostTextFieldWatcher(HostDatabase.FIELD_HOST_NICKNAME));
- mColorSelector = (Spinner) view.findViewById(R.id.color_selector);
+ mColorItem = view.findViewById(R.id.color_item);
+ mColorItem.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ PopupMenu menu = new PopupMenu(getActivity(), v);
+ for (int i = 0; i < mColorNames.length(); i++) {
+ menu.getMenu().add(mColorNames.getText(i));
+ }
+ menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ for (int i = 0; i < mColorNames.length(); i++) {
+ if (item.getTitle().toString().equals(mColorNames.getText(i).toString())) {
+ mHost.setColor(mColorValues.getText(i).toString());
+ mColorText.setText(mColorNames.getText(i));
+ return true;
+ }
+ }
+ return false;
+ }
+ });
+ menu.show();
+ }
+ });
+
+ mColorText = (TextView) view.findViewById(R.id.color_text);
for (int i = 0; i < mColorValues.length(); i++) {
- if (mColorValues.getString(i).equals(mHost.getColor())) {
- mColorSelector.setSelection(i);
+ if (mColorValues.getText(i).toString().equals(mHost.getColor())) {
+ mColorText.setText(mColorNames.getText(i));
break;
}
}
- mColorSelector.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- mHost.setColor(mColorValues.getString(position));
- handleHostChange();
- }
+ mFontSizeText = (EditText) view.findViewById(R.id.font_size_text);
+ mFontSizeText.setText(Integer.toString(mHost.getFontSize()));
+ mFontSizeText.addTextChangedListener(
+ new HostTextFieldWatcher(HostDatabase.FIELD_HOST_FONTSIZE));
+ mFontSizeText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
- public void onNothingSelected(AdapterView<?> parent) {
+ public void onFocusChange(View v, boolean hasFocus) {
+ if (!hasFocus)
+ mFontSizeText.setText(Integer.toString(mHost.getFontSize()));
}
});
- mFontSizeText = (TextView) view.findViewById(R.id.font_size_text);
mFontSizeSeekBar = (SeekBar) view.findViewById(R.id.font_size_bar);
mFontSizeSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- int fontSize = MINIMUM_FONT_SIZE + progress;
- mHost.setFontSize(fontSize);
- handleHostChange();
- mFontSizeText.setText(Integer.toString(fontSize));
+ setFontSize(MINIMUM_FONT_SIZE + progress);
}
@Override
@@ -326,116 +329,292 @@ public class HostEditorFragment extends Fragment {
});
mFontSizeSeekBar.setProgress(mHost.getFontSize() - MINIMUM_FONT_SIZE);
- mPubkeySpinner = (Spinner) view.findViewById(R.id.pubkey_spinner);
- final String[] pubkeyNames = new String[mPubkeyNames.size()];
- mPubkeyNames.toArray(pubkeyNames);
- ArrayAdapter<String> pubkeySelection = new ArrayAdapter<String>(
- getActivity(), android.R.layout.simple_spinner_item, pubkeyNames);
- pubkeySelection.setDropDownViewResource(
- android.R.layout.simple_spinner_dropdown_item);
- mPubkeySpinner.setAdapter(pubkeySelection);
- for (int i = 0; i < pubkeyNames.length; i++) {
- if (mHost.getPubkeyId() == Integer.parseInt(mPubkeyValues.get(i))) {
- mPubkeySpinner.setSelection(i);
+ mPubkeyItem = view.findViewById(R.id.pubkey_item);
+ mPubkeyItem.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ PopupMenu menu = new PopupMenu(getActivity(), v);
+ for (String name : mPubkeyNames) {
+ menu.getMenu().add(name);
+ }
+ menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ for (int i = 0; i < mPubkeyNames.size(); i++) {
+ if (mPubkeyNames.get(i).equals(item.getTitle())) {
+ mHost.setPubkeyId(Long.parseLong(mPubkeyValues.get(i)));
+ mPubkeyText.setText(mPubkeyNames.get(i));
+ return true;
+ }
+ }
+ return false;
+ }
+ });
+ menu.show();
+ }
+ });
+
+ mPubkeyText = (TextView) view.findViewById(R.id.pubkey_text);
+ for (int i = 0; i < mPubkeyValues.size(); i++) {
+ if (mHost.getPubkeyId() == Long.parseLong(mPubkeyValues.get(i))) {
+ mPubkeyText.setText(mPubkeyNames.get(i));
break;
}
}
- mPubkeySpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+
+ mDelKeyItem = view.findViewById(R.id.delkey_item);
+ mDelKeyItem.setOnClickListener(new View.OnClickListener() {
@Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- mHost.setPubkeyId(Integer.parseInt(mPubkeyValues.get(position)));
- handleHostChange();
+ public void onClick(View v) {
+ PopupMenu menu = new PopupMenu(getActivity(), v);
+ for (int i = 0; i < mDelKeyNames.length(); i++) {
+ menu.getMenu().add(mDelKeyNames.getText(i));
+ }
+ menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ for (int i = 0; i < mDelKeyNames.length(); i++) {
+ if (mDelKeyNames.getText(i).equals(item.getTitle())) {
+ mHost.setDelKey(mDelKeyValues.getText(i).toString());
+ mDelKeyText.setText(mDelKeyNames.getText(i));
+ return true;
+ }
+ }
+ return false;
+ }
+ });
+ menu.show();
+ }
+ });
+
+ mDelKeyText = (TextView) view.findViewById(R.id.delkey_text);
+ for (int i = 0; i < mDelKeyValues.length(); i++) {
+ if (mDelKeyValues.getText(i).toString().equals(mHost.getDelKey())) {
+ mDelKeyText.setText(mDelKeyNames.getText(i));
+ break;
+ }
+ }
+
+ mEncodingItem = view.findViewById(R.id.encoding_item);
+ mEncodingItem.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ PopupMenu menu = new PopupMenu(getActivity(), v);
+ for (String displayName : mCharsetData.keySet()) {
+ menu.getMenu().add(displayName);
+ }
+ menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ for (String displayName : mCharsetData.keySet()) {
+ if (displayName.equals(item.getTitle())) {
+ mHost.setEncoding(mCharsetData.get(displayName));
+ mEncodingText.setText(displayName);
+ return true;
+ }
+ }
+ return false;
+ }
+ });
+ menu.show();
}
+ });
+
+ // The encoding text is initialized in setCharsetData() because Charset data is not always
+ // available when this fragment is created.
+ mEncodingText = (TextView) view.findViewById(R.id.encoding_text);
+ mUseSshAuthItem = view.findViewById(R.id.use_ssh_auth_item);
+ mUseSshAuthItem.setOnClickListener(new View.OnClickListener() {
@Override
- public void onNothingSelected(AdapterView<?> parent) {
+ public void onClick(View v) {
+ mUseSshAuthSwitch.toggle();
}
});
- mUseSshConfirmationContainer = view.findViewById(R.id.ssh_confirmation_container);
mUseSshAuthSwitch = (SwitchCompat) view.findViewById(R.id.use_ssh_auth_switch);
- mSshAuthConfirmationCheckbox =
+ mUseSshAuthSwitch.setChecked(mHost.getUseAuthAgent() != null &&
+ !mHost.getUseAuthAgent().equals(mSshAuthValues.getString(0)));
+ mUseSshAuthSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ processSshAuthChange();
+ }
+ });
+
+ mUseSshConfirmationItem = view.findViewById(R.id.ssh_auth_confirmation_item);
+ mUseSshConfirmationItem.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mUseSshConfirmationCheckbox.toggle();
+ }
+ });
+
+ mUseSshConfirmationCheckbox =
(AppCompatCheckBox) view.findViewById(R.id.ssh_auth_confirmation_checkbox);
- CompoundButton.OnCheckedChangeListener authSwitchListener = new CompoundButton.OnCheckedChangeListener() {
+ mUseSshConfirmationCheckbox.setChecked(mHost.getUseAuthAgent() != null &&
+ mHost.getUseAuthAgent().equals(mSshAuthValues.getString(1)));
+ mUseSshConfirmationCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- mUseSshConfirmationContainer.setVisibility(
- mUseSshAuthSwitch.isChecked() ? View.VISIBLE : View.GONE);
- if (mUseSshAuthSwitch.isChecked()) {
- mHost.setUseAuthAgent(
- mSshAuthConfirmationCheckbox.isChecked() ?
- /* require confirmation */ mSshAuthValues.getString(1) :
- /* don't require confirmation */ mSshAuthValues.getString(2));
- } else {
- mHost.setUseAuthAgent(/* don't use */ mSshAuthValues.getString(0));
- }
- handleHostChange();
+ processSshAuthChange();
}
- };
- if (mHost.getUseAuthAgent() == null ||
- mHost.getUseAuthAgent().equals(mSshAuthValues.getString(0))) {
- mUseSshAuthSwitch.setChecked(false);
- mSshAuthConfirmationCheckbox.setChecked(false);
- } else {
- mUseSshAuthSwitch.setChecked(true);
- mUseSshConfirmationContainer.setVisibility(View.VISIBLE);
- mSshAuthConfirmationCheckbox.setChecked(
- mHost.getUseAuthAgent().equals(mSshAuthValues.getString(1)));
- }
- mUseSshAuthSwitch.setOnCheckedChangeListener(authSwitchListener);
- mSshAuthConfirmationCheckbox.setOnCheckedChangeListener(authSwitchListener);
+ });
+
+ processSshAuthChange();
+
+ mCompressionItem = view.findViewById(R.id.compression_item);
+ mCompressionItem.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mCompressionSwitch.toggle();
+ }
+ });
mCompressionSwitch = (SwitchCompat) view.findViewById(R.id.compression_switch);
mCompressionSwitch.setChecked(mHost.getCompression());
- mCompressionSwitch.setOnCheckedChangeListener(
- new HostSwitchWatcher(HostDatabase.FIELD_HOST_COMPRESSION));
+ mCompressionSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ mHost.setCompression(isChecked);
+ handleHostChange();
+ }
+ });
+
+ mStartShellItem = view.findViewById(R.id.start_shell_item);
+ mStartShellItem.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mStartShellSwitch.toggle();
+ }
+ });
mStartShellSwitch = (SwitchCompat) view.findViewById(R.id.start_shell_switch);
mStartShellSwitch.setChecked(mHost.getWantSession());
- mStartShellSwitch.setOnCheckedChangeListener(
- new HostSwitchWatcher(HostDatabase.FIELD_HOST_WANTSESSION));
+ mStartShellSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ mHost.setWantSession(isChecked);
+ handleHostChange();
+ }
+ });
+
+ mStayConnectedItem = view.findViewById(R.id.stay_connected_item);
+ mStayConnectedItem.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mStayConnectedSwitch.toggle();
+ }
+ });
mStayConnectedSwitch = (SwitchCompat) view.findViewById(R.id.stay_connected_switch);
mStayConnectedSwitch.setChecked(mHost.getStayConnected());
- mStayConnectedSwitch.setOnCheckedChangeListener(
- new HostSwitchWatcher(HostDatabase.FIELD_HOST_STAYCONNECTED));
+ mStayConnectedSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ mHost.setStayConnected(isChecked);
+ handleHostChange();
+ }
+ });
+
+ mCloseOnDisconnectItem = view.findViewById(R.id.close_on_disconnect_item);
+ mCloseOnDisconnectItem.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mCloseOnDisconnectSwitch.toggle();
+ }
+ });
mCloseOnDisconnectSwitch = (SwitchCompat) view.findViewById(R.id.close_on_disconnect_switch);
mCloseOnDisconnectSwitch.setChecked(mHost.getQuickDisconnect());
- mCloseOnDisconnectSwitch.setOnCheckedChangeListener(
- new HostSwitchWatcher(HostDatabase.FIELD_HOST_QUICKDISCONNECT));
+ mCloseOnDisconnectSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ mHost.setQuickDisconnect(isChecked);
+ handleHostChange();
+ }
+ });
mPostLoginAutomationField = (EditText) view.findViewById(R.id.post_login_automation_field);
mPostLoginAutomationField.setText(mHost.getPostLogin());
mPostLoginAutomationField.addTextChangedListener(
new HostTextFieldWatcher(HostDatabase.FIELD_HOST_POSTLOGIN));
- mDelKeySpinner = (Spinner) view.findViewById(R.id.del_key_spinner);
- for (int i = 0; i < mDelKeyValues.length(); i++) {
- if (mHost.getDelKey().equals(mDelKeyValues.getString(i))) {
- mDelKeySpinner.setSelection(i);
- break;
- }
+ setUriPartsContainerExpanded(mIsUriEditorExpanded);
+
+ return view;
+ }
+
+ /**
+ * @param protocol The protocol to set.
+ * @param setDefaultPortInModel True if the model's port should be updated to the default port
+ * for the given protocol.
+ */
+ private void setTransportType(String protocol, boolean setDefaultPortInModel) {
+ mHost.setProtocol(protocol);
+ if (setDefaultPortInModel)
+ mHost.setPort(TransportFactory.getTransport(protocol).getDefaultPort());
+ handleHostChange();
+
+ mTransportText.setText(protocol);
+
+ mQuickConnectContainer.setHint(
+ TransportFactory.getFormatHint(protocol, getActivity()));
+
+ // Different protocols have different field types, so show only the fields needed.
+ if (SSH.getProtocolName().equals(protocol)) {
+ mUsernameContainer.setVisibility(View.VISIBLE);
+ mHostnameContainer.setVisibility(View.VISIBLE);
+ mPortContainer.setVisibility(View.VISIBLE);
+ mExpandCollapseButton.setVisibility(View.VISIBLE);
+ } else if (Telnet.getProtocolName().equals(protocol)) {
+ mUsernameContainer.setVisibility(View.GONE);
+ mHostnameContainer.setVisibility(View.VISIBLE);
+ mPortContainer.setVisibility(View.VISIBLE);
+ mExpandCollapseButton.setVisibility(View.VISIBLE);
+ } else {
+ // Local protocol has only one field, so no need to show the URI parts
+ // container.
+ setUriPartsContainerExpanded(false);
+ mExpandCollapseButton.setVisibility(View.INVISIBLE);
}
- mDelKeySpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- mHost.setDelKey(mDelKeyValues.getString(position));
- handleHostChange();
- }
+ }
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- }
- });
+ private void setFontSize(int fontSize) {
+ if (fontSize < MINIMUM_FONT_SIZE)
+ fontSize = MINIMUM_FONT_SIZE;
- mEncodingSpinner = (Spinner) view.findViewById(R.id.encoding_spinner);
- // The spinner is initialized in setCharsetData() because Charset data is not always
- // available when this fragment is created.
+ if (fontSize > MAXIMUM_FONT_SIZE)
+ fontSize = MAXIMUM_FONT_SIZE;
- setUriPartsContainerExpanded(mIsUriEditorExpanded);
+ mHost.setFontSize(fontSize);
- return view;
+ if (mFontSizeSeekBar.getProgress() + MINIMUM_FONT_SIZE != fontSize) {
+ mFontSizeSeekBar.setProgress(fontSize - MINIMUM_FONT_SIZE);
+ }
+
+ if (!mFontSizeText.isFocused() &&
+ Integer.parseInt(mFontSizeText.getText().toString()) != fontSize) {
+ mFontSizeText.setText(Integer.toString(fontSize));
+ }
+
+ handleHostChange();
+ }
+
+ private void processSshAuthChange() {
+ mUseSshConfirmationItem.setVisibility(
+ mUseSshAuthSwitch.isChecked() ? View.VISIBLE : View.GONE);
+
+ if (mUseSshAuthSwitch.isChecked()) {
+ mHost.setUseAuthAgent(
+ mUseSshConfirmationCheckbox.isChecked() ?
+ /* require confirmation */ mSshAuthValues.getString(1) :
+ /* don't require confirmation */ mSshAuthValues.getString(2));
+ } else {
+ mHost.setUseAuthAgent(/* don't use */ mSshAuthValues.getString(0));
+ }
+
+ handleHostChange();
}
@Override
@@ -449,8 +628,11 @@ public class HostEditorFragment extends Fragment {
// Now that the fragment is attached to an Activity, fetch the arrays from the attached
// Activity's resources.
+ mColorNames = getResources().obtainTypedArray(R.array.list_colors);
mColorValues = getResources().obtainTypedArray(R.array.list_color_values);
+ mSshAuthNames = getResources().obtainTypedArray(R.array.list_authagent);
mSshAuthValues = getResources().obtainTypedArray(R.array.list_authagent_values);
+ mDelKeyNames = getResources().obtainTypedArray(R.array.list_delkey);
mDelKeyValues = getResources().obtainTypedArray(R.array.list_delkey_values);
}
@@ -458,8 +640,11 @@ public class HostEditorFragment extends Fragment {
public void onDetach() {
super.onDetach();
mListener = null;
+ mColorNames.recycle();
mColorValues.recycle();
+ mSshAuthNames.recycle();
mSshAuthValues.recycle();
+ mDelKeyNames.recycle();
mDelKeyValues.recycle();
}
@@ -482,32 +667,17 @@ public class HostEditorFragment extends Fragment {
* Charset).
*/
public void setCharsetData(final Map<String, String> data) {
- if (mEncodingSpinner != null) {
- final String[] encodingNames = new String[data.keySet().size()];
- data.keySet().toArray(encodingNames);
- ArrayAdapter<String> encodingSelection = new ArrayAdapter<String>(
- getActivity(), android.R.layout.simple_spinner_item, encodingNames);
- encodingSelection.setDropDownViewResource(
- android.R.layout.simple_spinner_dropdown_item);
- mEncodingSpinner.setAdapter(encodingSelection);
- for (int i = 0; i < encodingNames.length; i++) {
- if (mHost.getEncoding() != null &&
- mHost.getEncoding().equals(data.get(encodingNames[i]))) {
- mEncodingSpinner.setSelection(i);
- break;
+ mCharsetData = data;
+
+ if (mEncodingText != null) {
+ Iterator it = data.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<String, String> pair = (Map.Entry) it.next();
+ if (pair.getValue().equals(mHost.getEncoding())) {
+ mEncodingText.setText(pair.getKey());
+ return;
}
}
- mEncodingSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- mHost.setEncoding(data.get(encodingNames[position]));
- handleHostChange();
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- }
- });
}
}
@@ -560,16 +730,14 @@ public class HostEditorFragment extends Fragment {
* notified.
*/
private void handleHostChange() {
- String protocol = (String) mTransportSpinner.getSelectedItem();
String quickConnectString = mQuickConnectField.getText().toString();
- if (protocol == null || protocol.equals("") ||
- quickConnectString == null || quickConnectString.equals("")) {
+ if (quickConnectString == null || quickConnectString.equals("")) {
// Invalid protocol and/or string, so don't do anything.
mListener.onHostInvalidated();
return;
}
- Uri uri = TransportFactory.getUri(protocol, quickConnectString);
+ Uri uri = TransportFactory.getUri(mHost.getProtocol(), quickConnectString);
if (uri == null) {
// Valid string, but does not accurately describe a URI.
mListener.onHostInvalidated();
@@ -581,8 +749,8 @@ public class HostEditorFragment extends Fragment {
}
public interface Listener {
- public void onValidHostConfigured(HostBean host);
- public void onHostInvalidated();
+ void onValidHostConfigured(HostBean host);
+ void onHostInvalidated();
}
private class HostTextFieldWatcher implements TextWatcher {
@@ -617,6 +785,14 @@ public class HostEditorFragment extends Fragment {
mHost.setNickname(text);
} else if (HostDatabase.FIELD_HOST_POSTLOGIN.equals(mFieldType)) {
mHost.setPostLogin(text);
+ } else if (HostDatabase.FIELD_HOST_FONTSIZE.equals(mFieldType)) {
+ int fontSize = HostBean.DEFAULT_FONT_SIZE;
+ try {
+ fontSize = Integer.parseInt(text);
+ } catch (NumberFormatException e) {
+ } finally {
+ setFontSize(fontSize);
+ }
} else {
throw new RuntimeException("Invalid field type.");
}
@@ -640,29 +816,4 @@ public class HostEditorFragment extends Fragment {
HostDatabase.FIELD_HOST_PORT.equals(fieldType);
}
}
-
- private class HostSwitchWatcher implements CompoundButton.OnCheckedChangeListener {
-
- private final String mFieldType;
-
- public HostSwitchWatcher(String fieldType) {
- mFieldType = fieldType;
- }
-
- @Override
- public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- if (HostDatabase.FIELD_HOST_COMPRESSION.equals(mFieldType)) {
- mHost.setCompression(isChecked);
- } else if (HostDatabase.FIELD_HOST_WANTSESSION.equals(mFieldType)) {
- mHost.setWantSession(isChecked);
- } else if (HostDatabase.FIELD_HOST_STAYCONNECTED.equals(mFieldType)) {
- mHost.setStayConnected(isChecked);
- } else if (HostDatabase.FIELD_HOST_QUICKDISCONNECT.equals(mFieldType)) {
- mHost.setQuickDisconnect(isChecked);
- } else {
- throw new RuntimeException("Invalid field type.");
- }
- handleHostChange();
- }
- }
}
diff --git a/app/src/main/java/org/connectbot/bean/HostBean.java b/app/src/main/java/org/connectbot/bean/HostBean.java
index 438713e..a31f9ec 100644
--- a/app/src/main/java/org/connectbot/bean/HostBean.java
+++ b/app/src/main/java/org/connectbot/bean/HostBean.java
@@ -33,7 +33,7 @@ import android.net.Uri;
public class HostBean extends AbstractBean {
public static final String BEAN_NAME = "host";
- private static final int DEFAULT_FONT_SIZE = 10;
+ public static final int DEFAULT_FONT_SIZE = 10;
/* Database fields */
private long id = -1;
diff --git a/app/src/main/res/layout/fragment_host_editor.xml b/app/src/main/res/layout/fragment_host_editor.xml
index 5e809d8..20d835d 100644
--- a/app/src/main/res/layout/fragment_host_editor.xml
+++ b/app/src/main/res/layout/fragment_host_editor.xml
@@ -19,7 +19,8 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
+ android:fillViewport="true"
tools:context="org.connectbot.HostEditorFragment"
>
@@ -29,31 +30,41 @@
android:orientation="vertical"
>
- <LinearLayout
- android:layout_width="wrap_content"
+ <RelativeLayout
+ android:id="@+id/protocol_item"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical"
- android:layout_marginStart="4dp"
- android:layout_marginLeft="4dp"
- android:layout_marginBottom="4dp"
>
+ <ImageView
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:src="@drawable/icon"
+ style="@style/ListItemIcon"
+ />
+
<TextView
+ android:id="@+id/protocol_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/protocol_spinner_label"
- android:textSize="12sp"
+ style="@style/ListItemFirstLineText.WithIcon"
/>
- <Spinner
- android:id="@+id/transport_selector"
+ <TextView
+ android:id="@+id/protocol_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_below="@id/protocol_title"
+ tools:text="ssh"
+ style="@style/ListItemSecondLineText.WithIcon"
/>
- </LinearLayout>
+ </RelativeLayout>
<LinearLayout
+ android:layout_marginLeft="68dp"
+ android:layout_marginStart="68dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
@@ -96,8 +107,10 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:layout_marginLeft="56dp"
- android:layout_marginStart="56dp"
+ android:layout_marginLeft="68dp"
+ android:layout_marginStart="68dp"
+ android:layout_marginRight="48dp"
+ android:layout_marginEnd="48dp"
android:visibility="gone"
android:animateLayoutChanges="true"
tools:ignore="UnusedAttribute"
@@ -156,118 +169,214 @@
</LinearLayout>
- <View style="@style/Divider"
- />
-
- <android.support.design.widget.TextInputLayout
+ <RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
- <EditText
- android:id="@+id/nickname_field"
+ <android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:maxLines="1"
- android:inputType="text"
- android:hint="@string/hostpref_nickname_title"
- />
+ android:layout_marginLeft="68dp"
+ android:layout_marginStart="68dp"
+ android:layout_marginRight="16dp"
+ android:layout_marginEnd="16dp"
+ >
- </android.support.design.widget.TextInputLayout>
+ <EditText
+ android:id="@+id/nickname_field"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:maxLines="1"
+ android:inputType="text"
+ android:hint="@string/hostpref_nickname_title"
+ />
- <LinearLayout
+ </android.support.design.widget.TextInputLayout>
+
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/color_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical"
- android:layout_marginStart="4dp"
- android:layout_marginLeft="4dp"
- android:layout_marginBottom="4dp"
>
+ <ImageView
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:src="@drawable/icon"
+ style="@style/ListItemIcon"
+ />
+
<TextView
+ android:id="@+id/color_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hostpref_color_title"
- android:textSize="12sp"
+ style="@style/ListItemFirstLineText.WithIcon"
/>
- <Spinner
- android:id="@+id/color_selector"
+ <TextView
+ android:id="@+id/color_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:entries="@array/list_colors"
- android:entryValues="@array/list_color_values"
+ android:layout_below="@id/color_title"
+ tools:text="gray"
+ style="@style/ListItemSecondLineText.WithIcon"
/>
- </LinearLayout>
+ </RelativeLayout>
- <LinearLayout
+ <RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical"
- android:layout_marginStart="4dp"
- android:layout_marginLeft="4dp"
- android:layout_marginBottom="4dp"
>
+ <ImageView
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:src="@drawable/icon"
+ style="@style/ListItemIcon"
+ />
+
+ <TextView
+ android:id="@+id/font_size_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/hostpref_fontsize_title"
+ style="@style/ListItemFirstLineText.WithIcon"
+ />
+
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginLeft="62dp"
+ android:layout_marginStart="62dp"
+ android:paddingBottom="8dp"
+ android:layout_below="@id/font_size_title"
>
- <TextView
- android:layout_width="wrap_content"
+ <SeekBar
+ android:id="@+id/font_size_bar"
+ android:layout_width="0dp"
+ android:layout_weight="1"
android:layout_height="wrap_content"
- android:text="@string/hostpref_fontsize_title"
- android:textSize="12sp"
+ android:layout_gravity="center"
+ android:max="32"
/>
- <TextView
+ <EditText
android:id="@+id/font_size_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textSize="12sp"
+ android:layout_alignParentRight="true"
+ android:layout_gravity="center_vertical"
+ android:layout_marginRight="16dp"
+ android:inputType="number"
+ android:maxLines="1"
+ tools:text="10"
/>
</LinearLayout>
- <SeekBar
- android:id="@+id/font_size_bar"
- android:layout_width="match_parent"
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/pubkey_item"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ >
+
+ <ImageView
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:src="@drawable/icon"
+ style="@style/ListItemIcon"
+ />
+
+ <TextView
+ android:id="@+id/pubkey_title"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:max="32"
+ android:text="@string/hostpref_pubkeyid_title"
+ style="@style/ListItemFirstLineText.WithIcon"
/>
- </LinearLayout>
+ <TextView
+ android:id="@+id/pubkey_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/pubkey_title"
+ tools:text="Use any key"
+ style="@style/ListItemSecondLineText.WithIcon"
+ />
- <View style="@style/Divider"
- />
+ </RelativeLayout>
- <LinearLayout
- android:layout_width="wrap_content"
+ <RelativeLayout
+ android:id="@+id/delkey_item"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical"
- android:layout_marginStart="4dp"
- android:layout_marginLeft="4dp"
- android:layout_marginBottom="4dp"
>
+ <ImageView
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:src="@drawable/icon"
+ style="@style/ListItemIcon"
+ />
+
<TextView
+ android:id="@+id/delkey_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="@string/hostpref_pubkeyid_title"
- android:textSize="12sp"
+ android:text="@string/hostpref_delkey_title"
+ style="@style/ListItemFirstLineText.WithIcon"
/>
- <Spinner
- android:id="@+id/pubkey_spinner"
+ <TextView
+ android:id="@+id/delkey_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:entries="@array/list_pubkeyids"
- android:entryValues="@array/list_pubkeyids_value"
+ android:layout_below="@id/delkey_title"
+ tools:text="Delete"
+ style="@style/ListItemSecondLineText.WithIcon"
/>
- </LinearLayout>
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/encoding_item"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ >
+
+ <ImageView
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:src="@drawable/icon"
+ style="@style/ListItemIcon"
+ />
+
+ <TextView
+ android:id="@+id/encoding_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/hostpref_encoding_title"
+ style="@style/ListItemFirstLineText.WithIcon"
+ />
+
+ <TextView
+ android:id="@+id/encoding_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/encoding_title"
+ tools:text="UTF-8"
+ style="@style/ListItemSecondLineText.WithIcon"
+ />
+
+ </RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
@@ -276,14 +385,24 @@
>
<RelativeLayout
+ android:id="@+id/use_ssh_auth_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
+ <ImageView
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:src="@drawable/icon"
+ style="@style/ListItemIcon"
+ />
+
<TextView
- android:layout_width="match_parent"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hostpref_authagent_title"
+ android:paddingBottom="24dp"
+ style="@style/ListItemFirstLineText.WithIcon"
/>
<android.support.v7.widget.SwitchCompat
@@ -292,14 +411,17 @@
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
+ android:layout_marginRight="16dp"
+ android:layout_marginEnd="16dp"
+ android:layout_centerVertical="true"
/>
</RelativeLayout>
<RelativeLayout
- android:id="@+id/ssh_confirmation_container"
+ android:id="@+id/ssh_auth_confirmation_item"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="32dp"
android:visibility="gone"
>
@@ -307,6 +429,9 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/hostpref_authagent_with_confirmation"
+ android:textSize="14sp"
+ android:layout_marginTop="8dp"
+ android:layout_marginLeft="72dp"
/>
<android.support.v7.widget.AppCompatCheckBox
@@ -315,6 +440,7 @@
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
+ android:padding="16dp"
/>
</RelativeLayout>
@@ -322,14 +448,24 @@
</LinearLayout>
<RelativeLayout
+ android:id="@+id/compression_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
+ <ImageView
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:src="@drawable/icon"
+ style="@style/ListItemIcon"
+ />
+
<TextView
- android:layout_width="match_parent"
+ android:id="@+id/compression_title"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hostpref_compression_title"
+ style="@style/ListItemFirstLineText.WithIcon"
/>
<android.support.v7.widget.SwitchCompat
@@ -338,19 +474,42 @@
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
+ android:layout_marginRight="16dp"
+ android:layout_marginEnd="16dp"
+ android:layout_centerVertical="true"
+ />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toLeftOf="@id/compression_switch"
+ android:layout_toStartOf="@id/compression_switch"
+ android:layout_below="@id/compression_title"
+ android:text="@string/hostpref_compression_summary"
+ style="@style/ListItemSecondLineText.WithIcon"
/>
</RelativeLayout>
<RelativeLayout
+ android:id="@+id/start_shell_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
+ <ImageView
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:src="@drawable/icon"
+ style="@style/ListItemIcon"
+ />
+
<TextView
- android:layout_width="match_parent"
+ android:id="@+id/shell_session_title"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hostpref_wantsession_title"
+ style="@style/ListItemFirstLineText.WithIcon"
/>
<android.support.v7.widget.SwitchCompat
@@ -359,19 +518,42 @@
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
+ android:layout_marginRight="16dp"
+ android:layout_marginEnd="16dp"
+ android:layout_centerVertical="true"
+ />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/hostpref_wantsession_summary"
+ android:layout_toLeftOf="@id/start_shell_switch"
+ android:layout_toStartOf="@id/start_shell_switch"
+ android:layout_below="@id/shell_session_title"
+ style="@style/ListItemSecondLineText.WithIcon"
/>
</RelativeLayout>
<RelativeLayout
+ android:id="@+id/stay_connected_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
+ <ImageView
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:src="@drawable/icon"
+ style="@style/ListItemIcon"
+ />
+
<TextView
- android:layout_width="match_parent"
+ android:id="@+id/stay_connected_title"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hostpref_stayconnected_title"
+ style="@style/ListItemFirstLineText.WithIcon"
/>
<android.support.v7.widget.SwitchCompat
@@ -380,19 +562,42 @@
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
+ android:layout_marginRight="16dp"
+ android:layout_marginEnd="16dp"
+ android:layout_centerVertical="true"
+ />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/hostpref_stayconnected_summary"
+ android:layout_toLeftOf="@id/stay_connected_switch"
+ android:layout_toStartOf="@id/stay_connected_switch"
+ android:layout_below="@id/stay_connected_title"
+ style="@style/ListItemSecondLineText.WithIcon"
/>
</RelativeLayout>
<RelativeLayout
+ android:id="@+id/close_on_disconnect_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
+ <ImageView
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:src="@drawable/icon"
+ style="@style/ListItemIcon"
+ />
+
<TextView
- android:layout_width="match_parent"
+ android:id="@+id/close_on_disconnect_title"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hostpref_quickdisconnect_title"
+ style="@style/ListItemFirstLineText.WithIcon"
/>
<android.support.v7.widget.SwitchCompat
@@ -401,81 +606,69 @@
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
+ android:layout_marginRight="16dp"
+ android:layout_marginEnd="16dp"
+ android:layout_centerVertical="true"
/>
- </RelativeLayout>
-
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- >
-
<TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/hostpref_postlogin_title"
- />
-
- <EditText
- android:id="@+id/post_login_automation_field"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_width="fill_parent"
- android:inputType="textMultiLine"
- android:lines="8"
- android:minLines="2"
+ android:text="@string/hostpref_quickdisconnect_summary"
+ android:layout_toLeftOf="@id/close_on_disconnect_switch"
+ android:layout_toStartOf="@id/close_on_disconnect_switch"
+ android:layout_below="@id/close_on_disconnect_title"
+ style="@style/ListItemSecondLineText.WithIcon"
/>
</RelativeLayout>
- <LinearLayout
- android:layout_width="wrap_content"
+ <RelativeLayout
+ android:id="@+id/postlogin_item"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical"
- android:layout_marginStart="4dp"
- android:layout_marginLeft="4dp"
- android:layout_marginBottom="4dp"
>
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/hostpref_delkey_title"
- android:textSize="12sp"
+ <ImageView
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:src="@drawable/icon"
+ style="@style/ListItemIcon"
/>
- <Spinner
- android:id="@+id/del_key_spinner"
+ <TextView
+ android:id="@+id/postlogin_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:entries="@array/list_delkey"
- android:entryValues="@array/list_delkey_values"
+ android:text="@string/hostpref_postlogin_title"
+ style="@style/ListItemFirstLineText.WithIcon"
/>
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:layout_marginStart="4dp"
- android:layout_marginLeft="4dp"
- android:layout_marginBottom="4dp"
- >
-
<TextView
+ android:id="@+id/postlogin_summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="@string/hostpref_encoding_title"
- android:textSize="12sp"
+ android:text="@string/hostpref_postlogin_summary"
+ android:layout_below="@id/postlogin_title"
+ android:layout_alignParentBottom="false"
+ android:paddingBottom="2dp"
+ style="@style/ListItemSecondLineText.WithIcon"
/>
- <Spinner
- android:id="@+id/encoding_spinner"
- android:layout_width="wrap_content"
+ <EditText
+ android:id="@+id/post_login_automation_field"
android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_marginLeft="72dp"
+ android:layout_marginStart="72dp"
+ android:layout_below="@id/postlogin_summary"
+ android:inputType="textMultiLine"
+ android:lines="8"
+ android:minLines="2"
/>
- </LinearLayout>
+
+ </RelativeLayout>
</LinearLayout>
diff --git a/app/src/main/res/values-v11/styles.xml b/app/src/main/res/values-v11/styles.xml
index 79f9633..37c3f6e 100644
--- a/app/src/main/res/values-v11/styles.xml
+++ b/app/src/main/res/values-v11/styles.xml
@@ -25,16 +25,23 @@
</style>
<style name="ListItemFirstLineText" parent="TextAppearance.AppCompat">
+ <item name="android:layout_alignParentTop">true</item>
<item name="android:textColor">?android:textColorPrimary</item>
<item name="android:textSize">16sp</item>
+ <item name="android:paddingTop">20dp</item>
+ <item name="android:layout_alignParentLeft">true</item>
</style>
<style name="ListItemSecondLineText" parent="TextAppearance.AppCompat">
+ <item name="android:layout_alignParentBottom">true</item>
<item name="android:textColor">?android:textColorSecondary</item>
<item name="android:textSize">14sp</item>
+ <item name="android:paddingBottom">20dp</item>
+ <item name="android:layout_alignParentLeft">true</item>
</style>
- <style name="SelectableItem">
- <item name="android:background">?android:attr/selectableItemBackground</item>
- </style>
+ <style name="SelectableItem">
+ <item name="android:background">?android:attr/selectableItemBackground</item>
+ </style>
+
</resources>
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index af3bd79..12aea8e 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -16,7 +16,7 @@
~ limitations under the License.
*/
-->
-<resources>
+<resources xmlns:tools="http://schemas.android.com/tools">
<style name="AppTheme" parent="Theme.AppCompat">
<item name="colorPrimary">@color/primary</item>
@@ -36,14 +36,38 @@
<item name="android:background">@drawable/keyboard_button_selector</item>
</style>
+ <style name="ListItemIcon">
+ <item name="android:layout_marginLeft">16dp</item>
+ <item name="android:layout_marginStart" tools:ignore="NewApi">16dp</item>
+ <item name="android:layout_centerVertical">true</item>
+ <item name="android:layout_alignParentLeft">true</item>
+ <item name="android:layout_alignParentStart" tools:ignore="NewApi">true</item>
+ </style>
+
<style name="ListItemFirstLineText">
+ <item name="android:layout_alignParentTop">true</item>
<item name="android:textColor">?android:textColorPrimary</item>
<item name="android:textSize">16sp</item>
+ <item name="android:paddingTop">20dp</item>
+ <item name="android:layout_alignParentLeft">true</item>
+ </style>
+
+ <style name="ListItemFirstLineText.WithIcon" parent="ListItemFirstLineText">
+ <item name="android:layout_marginLeft">72dp</item>
+ <item name="android:layout_marginStart" tools:ignore="NewApi">72dp</item>
</style>
<style name="ListItemSecondLineText">
+ <item name="android:layout_alignParentBottom">true</item>
<item name="android:textColor">?android:textColorSecondary</item>
<item name="android:textSize">14sp</item>
+ <item name="android:paddingBottom">20dp</item>
+ <item name="android:layout_alignParentLeft">true</item>
+ </style>
+
+ <style name="ListItemSecondLineText.WithIcon" parent="ListItemSecondLineText">
+ <item name="android:layout_marginLeft">72dp</item>
+ <item name="android:layout_marginStart" tools:ignore="NewApi">72dp</item>
</style>
<style name="ListItemFirstLineText.Red" parent="ListItemFirstLineText">
@@ -77,10 +101,4 @@
<item name="colorAccent">@color/accent</item>
</style>
- <style name="Divider">
- <item name="android:layout_width">match_parent</item>
- <item name="android:layout_height">1dp</item>
- <item name="android:background">?android:attr/listDivider</item>
- </style>
-
</resources>