diff options
Diffstat (limited to 'app')
18 files changed, 623 insertions, 0 deletions
| diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 873332f..e863b21 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -85,6 +85,15 @@  		</activity>  		<activity +				android:name=".EditHostActivity" +				android:label="@string/title_host_editor"> + +			<meta-data +					android:name="android.support.PARENT_ACTIVITY" +					android:value="org.connectbot.HostListActivity"/> +		</activity> + +		<activity  			android:name=".HostEditorActivity"  			android:configChanges="keyboardHidden|orientation"  			android:label="@string/title_host_editor"> diff --git a/app/src/main/java/org/connectbot/EditHostActivity.java b/app/src/main/java/org/connectbot/EditHostActivity.java new file mode 100644 index 0000000..6c7da11 --- /dev/null +++ b/app/src/main/java/org/connectbot/EditHostActivity.java @@ -0,0 +1,43 @@ +/* + * ConnectBot: simple, powerful, open-source SSH client for Android + * Copyright 2015 Kenny Root, Jeffrey Sharkey + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.connectbot; + +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; + +import org.connectbot.bean.HostBean; + +public class EditHostActivity extends AppCompatActivity implements HostEditorFragment.Listener { + +	@Override +	protected void onCreate(Bundle savedInstanceState) { +		super.onCreate(savedInstanceState); +		setContentView(R.layout.activity_edit_host); + +		if (savedInstanceState == null) { +			HostEditorFragment editor = HostEditorFragment.newInstance(null); +			getSupportFragmentManager().beginTransaction() +					.add(R.id.fragment_container, editor).commit(); +		} +	} + +	@Override +	public void onHostUpdated(HostBean host) { + +	} +} diff --git a/app/src/main/java/org/connectbot/HostEditorFragment.java b/app/src/main/java/org/connectbot/HostEditorFragment.java new file mode 100644 index 0000000..ea9d65f --- /dev/null +++ b/app/src/main/java/org/connectbot/HostEditorFragment.java @@ -0,0 +1,339 @@ +/* + * ConnectBot: simple, powerful, open-source SSH client for Android + * Copyright 2015 Kenny Root, Jeffrey Sharkey + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.connectbot; + +import android.content.ContentValues; +import android.content.Context; +import android.net.Uri; +import android.os.Bundle; +import android.os.Parcelable; +import android.support.design.widget.TextInputLayout; +import android.support.v4.app.Fragment; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.EditText; +import android.widget.ImageButton; +import android.widget.Spinner; + +import org.connectbot.bean.HostBean; +import org.connectbot.transport.SSH; +import org.connectbot.transport.Telnet; +import org.connectbot.transport.TransportFactory; +import org.connectbot.util.HostDatabase; + +public class HostEditorFragment extends Fragment { + +	private static final String ARG_EXISTING_HOST = "existingHost"; +	private static final String ARG_IS_EXPANDED = "isExpanded"; +	private static final String ARG_QUICKCONNECT_STRING = "quickConnectString"; + +	// The host being edited. +	private HostBean mHost; +	 +	// 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; + +	// Whether the URI parts subsection is expanded. +	private boolean mIsUriEditorExpanded = false; + +	// Whether a URI text edit is in progress. When the quick-connect field is being edited, changes +	// automatically propagate to the URI part fields; likewise, when the URI part fields are +	// edited, changes are propagated to the quick-connect field. This boolean safeguards against +	// infinite loops which can be caused by one field changing the other field, which changes the +	// first field, etc. +	private boolean mUriFieldEditInProgress = false; + +	private Spinner mTransportSpinner; +	private TextInputLayout mQuickConnectContainer; +	private EditText mQuickConnectField; +	private ImageButton mExpandCollapseButton; +	private View mUriPartsContainer; +	private View mUsernameContainer; +	private EditText mUsernameField; +	private View mHostnameContainer; +	private EditText mHostnameField; +	private View mPortContainer; +	private EditText mPortField; + +	public static HostEditorFragment newInstance(HostBean existingHost) { +		HostEditorFragment fragment = new HostEditorFragment(); +		Bundle args = new Bundle(); +		if (existingHost != null) { +			args.putParcelable(ARG_EXISTING_HOST, existingHost.getValues()); +		} +		fragment.setArguments(args); +		return fragment; +	} + +	public HostEditorFragment() { +	} + +	@Override +	public void onCreate(Bundle savedInstanceState) { +		super.onCreate(savedInstanceState); + +		Bundle bundle = savedInstanceState == null ? getArguments() : savedInstanceState; + +		Parcelable existingHostParcelable = bundle.getParcelable(ARG_EXISTING_HOST); +		mIsCreating = existingHostParcelable == null; +		if (existingHostParcelable != null) { +			mHost = HostBean.fromContentValues((ContentValues) existingHostParcelable); +		} else { +			mHost = new HostBean(); +		} + +		mIsUriEditorExpanded = bundle.getBoolean(ARG_IS_EXPANDED); +	} + +	@Override +	public View onCreateView(LayoutInflater inflater, ViewGroup container, +			Bundle savedInstanceState) { +		View view = inflater.inflate(R.layout.fragment_host_editor, container, false); + +		mTransportSpinner = (Spinner) view.findViewById(R.id.transport_selector); +		ArrayAdapter<String> transportSelection = new ArrayAdapter<>( +				getActivity(), +				android.R.layout.simple_spinner_item, +				TransportFactory.getTransportNames()); +		transportSelection.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); +		mTransportSpinner.setAdapter(transportSelection); +		mTransportSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { +			@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()); + +				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); +				} +			} + +			@Override +			public void onNothingSelected(AdapterView<?> parent) { +			} +		}); + +		mQuickConnectContainer = +				(TextInputLayout) view.findViewById(R.id.quickconnect_field_container); + +		mQuickConnectField = (EditText) view.findViewById(R.id.quickconnect_field); +		String oldQuickConnect = savedInstanceState == null ? +				null : savedInstanceState.getString(ARG_QUICKCONNECT_STRING); +		mQuickConnectField.setText(oldQuickConnect == null ? mHost.toString() : oldQuickConnect); +		mQuickConnectField.addTextChangedListener(new TextWatcher() { +			@Override +			public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + +			@Override +			public void onTextChanged(CharSequence s, int start, int before, int count) {} + +			@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()); + +					mUriFieldEditInProgress = true; +					mUsernameField.setText(mHost.getUsername()); +					mHostnameField.setText(mHost.getHostname()); +					mPortField.setText(Integer.toString(mHost.getPort())); +					mUriFieldEditInProgress = false; +				} +			} +		}); + +		mExpandCollapseButton = (ImageButton) view.findViewById(R.id.expand_collapse_button); +		mExpandCollapseButton.setOnClickListener(new View.OnClickListener() { +			@Override +			public void onClick(View v) { +				setUriPartsContainerExpanded(!mIsUriEditorExpanded); +			} +		}); + +		mUriPartsContainer = view.findViewById(R.id.uri_parts_container); + +		mUsernameContainer = view.findViewById(R.id.username_field_container); +		mUsernameField = (EditText) view.findViewById(R.id.username_edit_text); +		mUsernameField.setText(mHost.getUsername()); +		mUsernameField.addTextChangedListener(new UriDataUpdater(HostDatabase.FIELD_HOST_USERNAME)); + +		mHostnameContainer = view.findViewById(R.id.hostname_field_container); +		mHostnameField = (EditText) view.findViewById(R.id.hostname_edit_text); +		mHostnameField.setText(mHost.getHostname()); +		mHostnameField.addTextChangedListener(new UriDataUpdater(HostDatabase.FIELD_HOST_HOSTNAME)); + +		mPortContainer = view.findViewById(R.id.port_field_container); +		mPortField = (EditText) view.findViewById(R.id.port_edit_text); +		mPortField.setText(Integer.toString(mHost.getPort())); +		mPortField.addTextChangedListener(new UriDataUpdater(HostDatabase.FIELD_HOST_PORT)); + +		setUriPartsContainerExpanded(mIsUriEditorExpanded); + +		return view; +	} + +	@Override +	public void onAttach(Context context) { +		super.onAttach(context); +		try { +			mListener = (Listener) context; +		} catch (ClassCastException e) { +			throw new ClassCastException(context.toString() + " must implement Listener"); +		} +	} + +	@Override +	public void onDetach() { +		super.onDetach(); +		mListener = null; +	} + +	@Override +	public void onSaveInstanceState(Bundle savedInstanceState) { +		super.onSaveInstanceState(savedInstanceState); + +		savedInstanceState.putParcelable(ARG_EXISTING_HOST, mHost.getValues()); +		savedInstanceState.putBoolean(ARG_IS_EXPANDED, mIsUriEditorExpanded); +		savedInstanceState.putString( +				ARG_QUICKCONNECT_STRING, mQuickConnectField.getText().toString()); +	} + +	private void setUriPartsContainerExpanded(boolean expanded) { +		mIsUriEditorExpanded = expanded; + +		if (mIsUriEditorExpanded) { +			mExpandCollapseButton.setImageResource(R.drawable.ic_expand_less); +			mUriPartsContainer.setVisibility(View.VISIBLE); +		} else { +			mExpandCollapseButton.setImageResource(R.drawable.ic_expand_more); +			mUriPartsContainer.setVisibility(View.GONE); +		} +	} + +	/** +	 * Applies the quick-connect URI entered in the field by copying its URI parts to mHost's +	 * fields. +	 * @param quickConnectString The URI entered in the quick-connect field. +	 * @param protocol The protocol for this connection. +	 */ +	private void applyQuickConnectString(String quickConnectString, String protocol) { +		if (quickConnectString == null || protocol == null) +			return; + +		Uri uri = TransportFactory.getUri(protocol, quickConnectString); +		if (uri == null) { +			// If the URI was invalid, null out the associated fields. +			mHost.setProtocol(protocol); +			mHost.setUsername(null); +			mHost.setHostname(null); +			mHost.setNickname(null); +			mHost.setPort(TransportFactory.getTransport(protocol).getDefaultPort()); +			return; +		} + +		HostBean host = TransportFactory.getTransport(protocol).createHost(uri); +		mHost.setProtocol(host.getProtocol()); +		mHost.setUsername(host.getUsername()); +		mHost.setHostname(host.getHostname()); +		mHost.setNickname(host.getNickname()); +		mHost.setPort(host.getPort()); +	} + +	public interface Listener { +		public void onHostUpdated(HostBean host); +	} + +	private class UriDataUpdater implements TextWatcher { + +		private final String mFieldType; + +		public UriDataUpdater(String fieldType) { +			mFieldType = fieldType; +		} + +		@Override +		public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + +		@Override +		public void onTextChanged(CharSequence s, int start, int before, int count) {} + +		@Override +		public void afterTextChanged(Editable s) { +			String text = s.toString(); + +			if (HostDatabase.FIELD_HOST_USERNAME.equals(mFieldType)) { +				mHost.setUsername(text); +			} else if (HostDatabase.FIELD_HOST_HOSTNAME.equals(mFieldType)) { +				mHost.setHostname(text); +			} else if (HostDatabase.FIELD_HOST_PORT.equals(mFieldType)) { +				try { +					mHost.setPort(Integer.parseInt(text)); +				} catch (NumberFormatException e) { +					return; +				} +			} else { +				throw new RuntimeException("Invalid field type."); +			} + +			if (!mUriFieldEditInProgress) { +				mUriFieldEditInProgress = true; +				mQuickConnectField.setText(mHost.toString()); +				mUriFieldEditInProgress = false; +			} +		} +	} +} diff --git a/app/src/main/java/org/connectbot/bean/HostBean.java b/app/src/main/java/org/connectbot/bean/HostBean.java index 93d7716..1fbb9be 100644 --- a/app/src/main/java/org/connectbot/bean/HostBean.java +++ b/app/src/main/java/org/connectbot/bean/HostBean.java @@ -17,6 +17,10 @@  package org.connectbot.bean; +import org.connectbot.transport.Local; +import org.connectbot.transport.SSH; +import org.connectbot.transport.Telnet; +import org.connectbot.transport.TransportFactory;  import org.connectbot.util.HostDatabase;  import android.content.ContentValues; @@ -226,6 +230,29 @@ public class HostBean extends AbstractBean {  		return values;  	} +	public static HostBean fromContentValues(ContentValues values) { +		HostBean host = new HostBean(); +		host.setNickname(values.getAsString(HostDatabase.FIELD_HOST_NICKNAME)); +		host.setProtocol(values.getAsString(HostDatabase.FIELD_HOST_PROTOCOL)); +		host.setUsername(values.getAsString(HostDatabase.FIELD_HOST_USERNAME)); +		host.setHostname(values.getAsString(HostDatabase.FIELD_HOST_HOSTNAME)); +		host.setPort(values.getAsInteger(HostDatabase.FIELD_HOST_PORT)); +		host.setLastConnect(values.getAsLong(HostDatabase.FIELD_HOST_LASTCONNECT)); +		host.setColor(values.getAsString(HostDatabase.FIELD_HOST_COLOR)); +		host.setUseKeys(Boolean.valueOf(values.getAsString(HostDatabase.FIELD_HOST_USEKEYS))); +		host.setUseAuthAgent(values.getAsString(HostDatabase.FIELD_HOST_USEAUTHAGENT)); +		host.setPostLogin(values.getAsString(HostDatabase.FIELD_HOST_POSTLOGIN)); +		host.setPubkeyId(values.getAsLong(HostDatabase.FIELD_HOST_PUBKEYID)); +		host.setWantSession(Boolean.valueOf(values.getAsString(HostDatabase.FIELD_HOST_WANTSESSION))); +		host.setDelKey(values.getAsString(HostDatabase.FIELD_HOST_DELKEY)); +		host.setFontSize(values.getAsInteger(HostDatabase.FIELD_HOST_FONTSIZE)); +		host.setCompression(Boolean.valueOf(values.getAsString(HostDatabase.FIELD_HOST_COMPRESSION))); +		host.setEncoding(values.getAsString(HostDatabase.FIELD_HOST_ENCODING)); +		host.setStayConnected(values.getAsBoolean(HostDatabase.FIELD_HOST_STAYCONNECTED)); +		host.setQuickDisconnect(values.getAsBoolean(HostDatabase.FIELD_HOST_QUICKDISCONNECT)); +		return host; +	} +  	@Override  	public boolean equals(Object o) {  		if (o == null || !(o instanceof HostBean)) @@ -302,4 +329,38 @@ public class HostBean extends AbstractBean {  		return Uri.parse(sb.toString());  	} +	/** +	 * Generates a "pretty" string to be used in the quick-connect host edit view. +	 */ +	@Override +	public String toString() { +		if (protocol == null) +			return ""; + +		int defaultPort = TransportFactory.getTransport(protocol).getDefaultPort(); + +		if (SSH.getProtocolName().equals(protocol)) { +			if (username == null || hostname == null || +					username.equals("") || hostname.equals("")) +				return ""; + +			if (port == defaultPort) +				return username + "@" + hostname; +			else +				return username + "@" + hostname + ":" + port; +		} else if (Telnet.getProtocolName().equals(protocol)) { +			if (hostname == null || hostname.equals("")) +				return ""; +			else if (port == defaultPort) +				return hostname; +			else +				return hostname + ":" + port; +		} else if (Local.getProtocolName().equals(protocol)) { +			return nickname; +		} + +		// Fail gracefully. +		return ""; +	} +  } diff --git a/app/src/main/res/drawable-hdpi/ic_expand_less.png b/app/src/main/res/drawable-hdpi/ic_expand_less.pngBinary files differ new file mode 100644 index 0000000..dea8988 --- /dev/null +++ b/app/src/main/res/drawable-hdpi/ic_expand_less.png diff --git a/app/src/main/res/drawable-hdpi/ic_expand_more.png b/app/src/main/res/drawable-hdpi/ic_expand_more.pngBinary files differ new file mode 100644 index 0000000..022e057 --- /dev/null +++ b/app/src/main/res/drawable-hdpi/ic_expand_more.png diff --git a/app/src/main/res/drawable-mdpi/ic_expand_less.png b/app/src/main/res/drawable-mdpi/ic_expand_less.pngBinary files differ new file mode 100644 index 0000000..a2e4baa --- /dev/null +++ b/app/src/main/res/drawable-mdpi/ic_expand_less.png diff --git a/app/src/main/res/drawable-mdpi/ic_expand_more.png b/app/src/main/res/drawable-mdpi/ic_expand_more.pngBinary files differ new file mode 100644 index 0000000..910bb2a --- /dev/null +++ b/app/src/main/res/drawable-mdpi/ic_expand_more.png diff --git a/app/src/main/res/drawable-xhdpi/ic_expand_less.png b/app/src/main/res/drawable-xhdpi/ic_expand_less.pngBinary files differ new file mode 100644 index 0000000..ae36d91 --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/ic_expand_less.png diff --git a/app/src/main/res/drawable-xhdpi/ic_expand_more.png b/app/src/main/res/drawable-xhdpi/ic_expand_more.pngBinary files differ new file mode 100644 index 0000000..c42e2a0 --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/ic_expand_more.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_expand_less.png b/app/src/main/res/drawable-xxhdpi/ic_expand_less.pngBinary files differ new file mode 100644 index 0000000..62fc386 --- /dev/null +++ b/app/src/main/res/drawable-xxhdpi/ic_expand_less.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_expand_more.png b/app/src/main/res/drawable-xxhdpi/ic_expand_more.pngBinary files differ new file mode 100644 index 0000000..dbc0b20 --- /dev/null +++ b/app/src/main/res/drawable-xxhdpi/ic_expand_more.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_expand_less.png b/app/src/main/res/drawable-xxxhdpi/ic_expand_less.pngBinary files differ new file mode 100644 index 0000000..4261551 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_expand_less.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_expand_more.png b/app/src/main/res/drawable-xxxhdpi/ic_expand_more.pngBinary files differ new file mode 100644 index 0000000..2859a6f --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_expand_more.png diff --git a/app/src/main/res/layout/activity_edit_host.xml b/app/src/main/res/layout/activity_edit_host.xml new file mode 100644 index 0000000..f2aa96c --- /dev/null +++ b/app/src/main/res/layout/activity_edit_host.xml @@ -0,0 +1,23 @@ +<!-- +  ~ ConnectBot: simple, powerful, open-source SSH client for Android +  ~ Copyright 2015 Kenny Root, Jeffrey Sharkey +  ~ +  ~ Licensed under the Apache License, Version 2.0 (the "License"); +  ~ you may not use this file except in compliance with the License. +  ~ You may obtain a copy of the License at +  ~ +  ~     http://www.apache.org/licenses/LICENSE-2.0 +  ~ +  ~ Unless required by applicable law or agreed to in writing, software +  ~ distributed under the License is distributed on an "AS IS" BASIS, +  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +  ~ See the License for the specific language governing permissions and +  ~ limitations under the License. +  --> + +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" +	xmlns:tools="http://schemas.android.com/tools" +	android:id="@+id/fragment_container" +	android:layout_width="fill_parent" +	android:layout_height="fill_parent" +	tools:context="org.connectbot.EditHostActivity" /> diff --git a/app/src/main/res/layout/fragment_host_editor.xml b/app/src/main/res/layout/fragment_host_editor.xml new file mode 100644 index 0000000..a88c1d4 --- /dev/null +++ b/app/src/main/res/layout/fragment_host_editor.xml @@ -0,0 +1,137 @@ +<!-- +  ~ ConnectBot: simple, powerful, open-source SSH client for Android +  ~ Copyright 2015 Kenny Root, Jeffrey Sharkey +  ~ +  ~ Licensed under the Apache License, Version 2.0 (the "License"); +  ~ you may not use this file except in compliance with the License. +  ~ You may obtain a copy of the License at +  ~ +  ~     http://www.apache.org/licenses/LICENSE-2.0 +  ~ +  ~ Unless required by applicable law or agreed to in writing, software +  ~ distributed under the License is distributed on an "AS IS" BASIS, +  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +  ~ See the License for the specific language governing permissions and +  ~ limitations under the License. +  --> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" +	xmlns:tools="http://schemas.android.com/tools" +	android:layout_width="match_parent" +	android:layout_height="match_parent" +	android:orientation="vertical" +	tools:context="org.connectbot.HostEditorFragment"> + +  <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:layout_width="wrap_content" +        android:layout_height="wrap_content" +        android:text="@string/protocol_spinner_label" +        android:textSize="12sp" /> + +    <Spinner +        android:id="@+id/transport_selector" +        android:layout_width="wrap_content" +        android:layout_height="wrap_content" /> + +  </LinearLayout> + +  <LinearLayout +      android:layout_width="match_parent" +      android:layout_height="wrap_content" +      android:animateLayoutChanges="true"> + +    <android.support.design.widget.TextInputLayout +        android:id="@+id/quickconnect_field_container" +        android:layout_width="0dp" +        android:layout_weight ="1" +        android:layout_height="wrap_content"> + +      <EditText +          android:id="@+id/quickconnect_field" +          android:layout_width="match_parent" +          android:layout_weight="1" +          android:layout_height="wrap_content" +          android:maxLines="1" +          android:inputType="text" /> + +    </android.support.design.widget.TextInputLayout> + +    <ImageButton +        android:id="@+id/expand_collapse_button" +        android:layout_width="16dp" +        android:layout_height="16dp" +        android:layout_gravity="center" +        android:layout_margin="16dp" +        android:src="@drawable/ic_expand_more" +        android:contentDescription="@string/expand" +        android:background="#00000000" /> + +  </LinearLayout> + +  <LinearLayout +      android:id="@+id/uri_parts_container" +      android:layout_width="match_parent" +      android:layout_height="wrap_content" +      android:orientation="vertical" +      android:layout_marginLeft="56dp" +      android:visibility="gone" +      android:animateLayoutChanges="true"> + +    <android.support.design.widget.TextInputLayout +        android:id="@+id/username_field_container" +        android:layout_width="match_parent" +        android:layout_height="wrap_content"> + +      <EditText +          android:id="@+id/username_edit_text" +          android:layout_width="match_parent" +          android:layout_height="wrap_content" +          android:hint="@string/hostpref_username_title" +          android:maxLines="1" +          android:inputType="text" /> + +    </android.support.design.widget.TextInputLayout> + +    <android.support.design.widget.TextInputLayout +        android:id="@+id/hostname_field_container" +        android:layout_width="match_parent" +        android:layout_height="wrap_content"> + +      <EditText +          android:id="@+id/hostname_edit_text" +          android:layout_width="match_parent" +          android:layout_height="wrap_content" +          android:hint="@string/hostpref_hostname_title" +          android:maxLines="1" +          android:inputType="text" /> + +    </android.support.design.widget.TextInputLayout> + +    <android.support.design.widget.TextInputLayout +        android:id="@+id/port_field_container" +        android:layout_width="match_parent" +        android:layout_height="wrap_content"> + +      <EditText +          android:id="@+id/port_edit_text" +          android:layout_width="match_parent" +          android:layout_height="wrap_content" +          android:inputType="number" +          android:hint="@string/hostpref_port_title" +          android:maxLines="1" /> + +    </android.support.design.widget.TextInputLayout> + +  </LinearLayout> + +  <View style="@style/Divider" /> + +</LinearLayout> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f41d10b..aa40906 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -594,4 +594,8 @@  	<string name="button_key_f11">F11</string>  	<!-- Text for the "F12" button in virtual keyboard. -->  	<string name="button_key_f12">F12</string> +	<string name="connection_type">Connection type:</string> +	<string name="protocol_spinner_label">Protocol</string> +	<string name="expand">Expand</string> +  </resources> diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 322f5e1..af3bd79 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -76,4 +76,11 @@  	<style name="SwitchCompatTheme" parent="Theme.AppCompat">  		<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> | 
