diff options
| author | Kyle Horimoto <khorimoto@gmail.com> | 2015-10-20 11:52:14 -0700 | 
|---|---|---|
| committer | Kyle Horimoto <khorimoto@gmail.com> | 2015-10-21 12:18:22 -0700 | 
| commit | d57ab6f788707defad29df2432eafe1bc4dd4e79 (patch) | |
| tree | 3f122be8a8cb0185e92d3d5cd83a2af7825db5ed | |
| parent | 5295bbcaae77e9cd797c3ff7ae8fc9dba5549604 (diff) | |
| download | connectbot-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.java | 581 | ||||
| -rw-r--r-- | app/src/main/java/org/connectbot/bean/HostBean.java | 2 | ||||
| -rw-r--r-- | app/src/main/res/layout/fragment_host_editor.xml | 439 | ||||
| -rw-r--r-- | app/src/main/res/values-v11/styles.xml | 13 | ||||
| -rw-r--r-- | app/src/main/res/values/styles.xml | 32 | 
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>  | 
