diff --git a/app/src/main/java/net/i2p/android/i2ptunnel/TunnelDetailFragment.java b/app/src/main/java/net/i2p/android/i2ptunnel/TunnelDetailFragment.java index 6d51f3054d47ceefbf95565c19f8594e48f91cb0..f23b3a00e2c6a73b30434cd721348f9f1fb1c9e5 100644 --- a/app/src/main/java/net/i2p/android/i2ptunnel/TunnelDetailFragment.java +++ b/app/src/main/java/net/i2p/android/i2ptunnel/TunnelDetailFragment.java @@ -97,10 +97,10 @@ public class TunnelDetailFragment extends Fragment { description.setText(mTunnel.getDescription()); TextView targetIfacePort = (TextView) v.findViewById(R.id.tunnel_target_interface_port); - targetIfacePort.setText(mTunnel.getIfacePort()); + targetIfacePort.setText(mTunnel.getTunnelLink(false)); TextView accessIfacePort = (TextView) v.findViewById(R.id.tunnel_access_interface_port); - accessIfacePort.setText(mTunnel.getIfacePort()); + accessIfacePort.setText(mTunnel.getTunnelLink(false)); CheckBox autoStart = (CheckBox) v.findViewById(R.id.tunnel_autostart); autoStart.setChecked(mTunnel.startAutomatically()); diff --git a/app/src/main/java/net/i2p/android/i2ptunnel/TunnelEntry.java b/app/src/main/java/net/i2p/android/i2ptunnel/TunnelEntry.java index d2e1d982d826375274f9d5130f66dba7b7bdcc2d..4c8a4550ba06622df6eb95b4c69e3332329e3a33 100644 --- a/app/src/main/java/net/i2p/android/i2ptunnel/TunnelEntry.java +++ b/app/src/main/java/net/i2p/android/i2ptunnel/TunnelEntry.java @@ -90,6 +90,16 @@ public class TunnelEntry { else return NOT_RUNNING; } + public boolean isRunning() { + switch (getStatus()) { + case STANDBY: + case RUNNING: + return true; + default: + return false; + } + } + public boolean isClient() { return TunnelUtil.isClient(mController.getType()); } @@ -100,18 +110,42 @@ public class TunnelEntry { return Boolean.parseBoolean(mController.getSharedClient()); } + /** + * Call this to see if it is okay to linkify getClientLink() + * @return true if getClientLink() can be linkified, false otherwise. + */ + public boolean isClientLinkValid() { + return ("ircclient".equals(mController.getType())) && + mController.getListenOnInterface() != null && + mController.getListenPort() != null; + } + + /** + * @return valid host:port only if isClientLinkValid() is true + */ + public String getClientLink(boolean linkify) { + String host = getClientInterface(); + String port = getClientPort(); + String link = host + ":" + port; + if (linkify) { + if ("ircclient".equals(mController.getType())) + link = "irc://" + link; + } + return link; + } + public String getClientInterface() { + String rv; if ("streamrclient".equals(mController.getType())) - return mController.getTargetHost(); + rv = mController.getTargetHost(); else - return mController.getListenOnInterface(); + rv = mController.getListenOnInterface(); + return rv != null ? rv : ""; } public String getClientPort() { String rv = mController.getListenPort(); - if (rv != null) - return rv; - return ""; + return rv != null ? rv : ""; } public String getClientDestination() { @@ -128,10 +162,10 @@ public class TunnelEntry { /* Server tunnel data */ /** - * Call this to see if it is okay to linkify getServerTarget() - * @return true if getServerTarget() can be linkified, false otherwise. + * Call this to see if it is okay to linkify getServerLink() + * @return true if getServerLink() can be linkified, false otherwise. */ - public boolean isServerTargetLinkValid() { + public boolean isServerLinkValid() { return ("httpserver".equals(mController.getType()) || "httpbidirserver".equals(mController.getType())) && mController.getTargetHost() != null && @@ -139,9 +173,9 @@ public class TunnelEntry { } /** - * @return valid host:port only if isServerTargetLinkValid() is true + * @return valid host:port only if isServerLinkValid() is true */ - public String getServerTarget() { + public String getServerLink(boolean linkify) { String host; if ("streamrserver".equals(getInternalType())) host = mController.getListenOnInterface(); @@ -152,7 +186,13 @@ public class TunnelEntry { if (port == null) port = ""; if (host.indexOf(':') >= 0) host = '[' + host + ']'; - return host + ":" + port; + String link = host + ":" + port; + if (linkify) { + if ("httpserver".equals(mController.getType()) || + "httpbidirserver".equals(mController.getType())) + link = "http://" + link; + } + return link; } public String getDestinationBase64() { @@ -183,18 +223,14 @@ public class TunnelEntry { /* Other output formats */ - public String getIfacePort() { - if (isClient()) { - String host; - if ("streamrclient".equals(getInternalType())) - host = mController.getTargetHost(); - else - host = mController.getListenOnInterface(); - String port = mController.getListenPort(); - if (host == null) host = ""; - if (port == null) port = ""; - return host + ":" + port; - } else return getServerTarget(); + public boolean isTunnelLinkValid() { + if (isClient()) return isClientLinkValid(); + else return isServerLinkValid(); + } + + public String getTunnelLink(boolean linkify) { + if (isClient()) return getClientLink(linkify); + else return getServerLink(linkify); } public String getDetails() { diff --git a/app/src/main/java/net/i2p/android/i2ptunnel/TunnelEntryAdapter.java b/app/src/main/java/net/i2p/android/i2ptunnel/TunnelEntryAdapter.java index b1139969dc5bb1c77a77ed09825f001184c670f7..223d4c44833a1342f549467fd79a0f3985a2d828 100644 --- a/app/src/main/java/net/i2p/android/i2ptunnel/TunnelEntryAdapter.java +++ b/app/src/main/java/net/i2p/android/i2ptunnel/TunnelEntryAdapter.java @@ -1,9 +1,9 @@ package net.i2p.android.i2ptunnel; -import java.util.List; - -import net.i2p.android.router.R; import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Build; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -11,6 +11,10 @@ import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.TextView; +import net.i2p.android.router.R; + +import java.util.List; + public class TunnelEntryAdapter extends ArrayAdapter<TunnelEntry> { private final LayoutInflater mInflater; @@ -31,11 +35,14 @@ public class TunnelEntryAdapter extends ArrayAdapter<TunnelEntry> { @Override public View getView(int position, View convertView, ViewGroup parent) { View v = mInflater.inflate(R.layout.listitem_i2ptunnel, parent, false); - TunnelEntry tunnel = getItem(position); + final TunnelEntry tunnel = getItem(position); ImageView status = (ImageView) v.findViewById(R.id.tunnel_status); status.setImageDrawable(tunnel.getStatusIcon()); - status.setBackground(tunnel.getStatusBackground()); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) + status.setBackgroundDrawable(tunnel.getStatusBackground()); + else + status.setBackground(tunnel.getStatusBackground()); TextView name = (TextView) v.findViewById(R.id.tunnel_name); name.setText(tunnel.getName()); @@ -44,7 +51,20 @@ public class TunnelEntryAdapter extends ArrayAdapter<TunnelEntry> { type.setText(tunnel.getDescription()); TextView ifacePort = (TextView) v.findViewById(R.id.tunnel_interface_port); - ifacePort.setText(tunnel.getIfacePort()); + ifacePort.setText(tunnel.getTunnelLink(false)); + + if (tunnel.isRunning() && tunnel.isTunnelLinkValid()) { + View open = v.findViewById(R.id.tunnel_open); + open.setVisibility(View.VISIBLE); + open.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent i = new Intent(Intent.ACTION_VIEW); + i.setData(Uri.parse(tunnel.getTunnelLink(true))); + getContext().startActivity(i); + } + }); + } return v; } diff --git a/app/src/main/res/drawable-hdpi/ic_open_in_browser_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_open_in_browser_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..b5b0f1b632059eb0f914a8c8007dbd01f8d3f19c Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_open_in_browser_white_24dp.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_open_in_browser_white_24dp.png b/app/src/main/res/drawable-mdpi/ic_open_in_browser_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..1585ff18dff3327d71c82398df20015032cf1e68 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_open_in_browser_white_24dp.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_open_in_browser_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_open_in_browser_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..2da8b3feeb6ed5b38df3d61afeae4ca6b131355a Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_open_in_browser_white_24dp.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_open_in_browser_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_open_in_browser_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..f3fedfa5c3ce8c56fb79d08eb0db8b7b9df2ca15 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_open_in_browser_white_24dp.png differ diff --git a/app/src/main/res/layout/listitem_i2ptunnel.xml b/app/src/main/res/layout/listitem_i2ptunnel.xml index afb8192261c20d425ebfdcf5f99bfc63f790ed7a..8833f51c2bc4cf1955efb5edb3716a9d98633d94 100644 --- a/app/src/main/res/layout/listitem_i2ptunnel.xml +++ b/app/src/main/res/layout/listitem_i2ptunnel.xml @@ -30,18 +30,32 @@ android:text="Tunnel name" android:textAppearance="@style/TextAppearance.AppCompat.Primary" /> + <!-- Open link --> + <ImageView + android:id="@+id/tunnel_open" + android:layout_width="@dimen/listitem_icon_size" + android:layout_height="@dimen/listitem_icon_size" + android:layout_alignParentEnd="true" + android:layout_alignParentRight="true" + android:layout_centerVertical="true" + android:layout_marginLeft="@dimen/listitem_horizontal_margin" + android:layout_marginStart="@dimen/listitem_horizontal_margin" + android:contentDescription="Open" + android:src="@drawable/ic_open_in_browser_white_24dp" + android:visibility="gone" /> + <!-- Interface:port the tunnel listens on or points to --> <TextView android:id="@+id/tunnel_interface_port" - android:layout_width="wrap_content" + android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_alignParentEnd="true" - android:layout_alignParentRight="true" android:layout_alignTop="@id/tunnel_name" android:layout_marginLeft="4dp" android:layout_marginStart="4dp" android:layout_toEndOf="@id/tunnel_name" + android:layout_toLeftOf="@id/tunnel_open" android:layout_toRightOf="@id/tunnel_name" + android:layout_toStartOf="@id/tunnel_open" android:ellipsize="start" android:gravity="right" android:maxLines="1" @@ -57,6 +71,8 @@ android:layout_alignParentBottom="true" android:layout_alignStart="@+id/tunnel_name" android:layout_marginBottom="@dimen/listitem_text_bottom_margin_two_lines" + android:layout_toLeftOf="@id/tunnel_open" + android:layout_toStartOf="@id/tunnel_open" android:ellipsize="end" android:maxLines="1" android:text="Tunnel description"