diff --git a/TODO b/TODO index db5dea6265ef058a69e24851ae8e63ebaca25e8e..bb3a8920290e3673ff94ac70c9d96aa2cbe7db02 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,5 @@ # Required for release -- Main status - - Show tunnel list with status - NetDB tablet view fixes - Refresh detail fragment when changing tab - Move list to correct item when changing tab diff --git a/res/layout-land/fragment_main.xml b/res/layout-land/fragment_main.xml index 5b495411ca2238c576fa51a8260bf86ea68195bd..f80f76aad356a3b380973b7cf81d8b4b67f40555 100644 --- a/res/layout-land/fragment_main.xml +++ b/res/layout-land/fragment_main.xml @@ -37,7 +37,6 @@ android:scrollbarStyle="outsideInset" > <LinearLayout - android:id="@+id/main_status" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical" > @@ -45,13 +44,31 @@ <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="@string/label_status" + android:text="@string/label_tunnels" android:textAppearance="?android:attr/textAppearanceLarge" /> - <TextView - android:id="@+id/main_status_text" + <TableLayout + android:id="@+id/main_tunnels" android:layout_width="fill_parent" android:layout_height="wrap_content" /> + + <LinearLayout + android:id="@+id/main_status" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="vertical" > + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/label_status" + android:textAppearance="?android:attr/textAppearanceLarge" /> + + <TextView + android:id="@+id/main_status_text" + android:layout_width="fill_parent" + android:layout_height="wrap_content" /> + </LinearLayout> </LinearLayout> </ScrollView> </LinearLayout> \ No newline at end of file diff --git a/res/layout/fragment_main.xml b/res/layout/fragment_main.xml index a7114439d683c703ea9f2b91e355c978dca0cc64..6b796e10748481ce99abe25244fceecc779dd1fa 100644 --- a/res/layout/fragment_main.xml +++ b/res/layout/fragment_main.xml @@ -28,7 +28,6 @@ android:scrollbarStyle="outsideInset" > <LinearLayout - android:id="@+id/main_status" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical" > @@ -36,13 +35,31 @@ <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="@string/label_status" + android:text="@string/label_tunnels" android:textAppearance="?android:attr/textAppearanceLarge" /> - <TextView - android:id="@+id/main_status_text" + <TableLayout + android:id="@+id/main_tunnels" android:layout_width="fill_parent" android:layout_height="wrap_content" /> + + <LinearLayout + android:id="@+id/main_status" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="vertical" > + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/label_status" + android:textAppearance="?android:attr/textAppearanceLarge" /> + + <TextView + android:id="@+id/main_status_text" + android:layout_width="fill_parent" + android:layout_height="wrap_content" /> + </LinearLayout> </LinearLayout> </ScrollView> </LinearLayout> \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index 48ffad8d43f22b4990c4ecfecd1e62240160b944..9371f128a201f75ede2755d30ee081531ab4d8f6 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -7,6 +7,7 @@ <string name="welcome_new_version">New version installed. Please read the release notes. Version:</string> <string name="label_home">Controls and Status</string> + <string name="label_tunnels">Tunnels</string> <string name="label_status">Status</string> <string name="label_addressbook">Addressbook</string> <string name="label_i2ptunnel">I2PTunnel</string> diff --git a/src/net/i2p/android/router/MainFragment.java b/src/net/i2p/android/router/MainFragment.java index fffe631eb74a982c763c17aa125fe26182d73748..6d3863043192738cfbeb98c38f934389203e0ce1 100644 --- a/src/net/i2p/android/router/MainFragment.java +++ b/src/net/i2p/android/router/MainFragment.java @@ -7,17 +7,31 @@ import android.preference.PreferenceManager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.ViewGroup.LayoutParams; import android.widget.LinearLayout; import android.widget.ScrollView; +import android.widget.TableLayout; +import android.widget.TableRow; import android.widget.ToggleButton; import android.widget.ImageView; import android.widget.TextView; + +import java.text.Collator; import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; import net.i2p.android.router.R; import net.i2p.android.router.util.Util; import net.i2p.data.DataHelper; +import net.i2p.data.Destination; +import net.i2p.data.Hash; +import net.i2p.data.LeaseSet; import net.i2p.router.RouterContext; +import net.i2p.router.TunnelPoolSettings; +import net.i2p.util.Translate; public class MainFragment extends I2PFragmentBase { @@ -242,17 +256,22 @@ public class MainFragment extends I2PFragmentBase { RouterContext ctx = getRouterContext(); ScrollView sv = (ScrollView) getActivity().findViewById(R.id.main_scrollview); LinearLayout vStatus = (LinearLayout) getActivity().findViewById(R.id.main_status); - TextView tv = (TextView) getActivity().findViewById(R.id.main_status_text); + TextView vStatusText = (TextView) getActivity().findViewById(R.id.main_status_text); if(!Util.isConnected(getActivity())) { // Manually set state, RouterService won't be running updateState("WAITING"); - tv.setText("No Internet connection is available"); + vStatusText.setText("No Internet connection is available"); + vStatus.setVisibility(View.VISIBLE); sv.setVisibility(View.VISIBLE); } else if(ctx != null) { if(_startPressed) { _startPressed = false; } + + // Load running tunnels + loadDestinations(ctx); + if (PreferenceManager.getDefaultSharedPreferences(getActivity()).getBoolean(PREF_SHOW_STATS, false)) { short reach = ctx.commSystem().getReachabilityStatus(); int active = ctx.commSystem().countActivePeers(); @@ -330,14 +349,14 @@ public class MainFragment extends I2PFragmentBase { + "\nUptime: " + uptime; _savedStatus = status + participate + details; - tv.setText(_savedStatus); + vStatusText.setText(_savedStatus); vStatus.setVisibility(View.VISIBLE); } else vStatus.setVisibility(View.INVISIBLE); sv.setVisibility(View.VISIBLE); } else { // network but no router context - tv.setText("Not running"); + vStatusText.setText("Not running"); sv.setVisibility(View.INVISIBLE); /** * ** @@ -357,6 +376,113 @@ public class MainFragment extends I2PFragmentBase { } } + /** + * Based on net.i2p.router.web.SummaryHelper.getDestinations() + * @param ctx The RouterContext + */ + private void loadDestinations(RouterContext ctx) { + TableLayout dests = (TableLayout) getView().findViewById(R.id.main_tunnels); + dests.removeAllViews(); + + List<Destination> clients = new ArrayList<Destination>(ctx.clientManager().listClients()); + if (!clients.isEmpty()) { + Collections.sort(clients, new AlphaComparator(ctx)); + for (Destination client : clients) { + String name = getName(ctx, client); + Hash h = client.calculateHash(); + TableRow dest = new TableRow(getActivity()); + //dest.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT)); + + // Client or server + ImageView type = new ImageView(getActivity()); + if (ctx.clientManager().shouldPublishLeaseSet(h)) + type.setImageDrawable(getActivity().getResources() + .getDrawable(R.drawable.server)); + else + type.setImageDrawable(getActivity().getResources() + .getDrawable(R.drawable.client)); + dest.addView(type); + + // Name + TextView destName = new TextView(getActivity()); + destName.setText(name); + //destName.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT)); + dest.addView(destName); + + // Status + ImageView status = new ImageView(getActivity()); + LeaseSet ls = ctx.netDb().lookupLeaseSetLocally(h); + if (ls != null && ctx.tunnelManager().getOutboundClientTunnelCount(h) > 0) { + long timeToExpire = ls.getEarliestLeaseDate() - ctx.clock().now(); + if (timeToExpire < 0) { + // red or yellow light + status.setImageDrawable(getActivity().getResources() + .getDrawable(R.drawable.local_inprogress)); + } else { + // green light + status.setImageDrawable(getActivity().getResources() + .getDrawable(R.drawable.local_up)); + } + } else { + // yellow light + status.setImageDrawable(getActivity().getResources() + .getDrawable(R.drawable.local_inprogress)); + } + dest.addView(status); + + dests.addView(dest); + } + } else { + TableRow empty = new TableRow(getActivity()); + TextView emptyText = new TextView(getActivity()); + emptyText.setText("No client tunnels are running yet."); + empty.addView(emptyText); + dests.addView(empty); + } + } + + /** compare translated nicknames - put "shared clients" first in the sort */ + private class AlphaComparator implements Comparator<Destination> { + private String xsc; + private RouterContext _ctx; + + public AlphaComparator(RouterContext ctx) { + _ctx = ctx; + xsc = _(ctx, "shared clients"); + } + + public int compare(Destination lhs, Destination rhs) { + String lname = getName(_ctx, lhs); + String rname = getName(_ctx, rhs); + if (lname.equals(xsc)) + return -1; + if (rname.equals(xsc)) + return 1; + return Collator.getInstance().compare(lname, rname); + } + } + + /** translate here so collation works above */ + private String getName(RouterContext ctx, Destination d) { + TunnelPoolSettings in = ctx.tunnelManager().getInboundSettings(d.calculateHash()); + String name = (in != null ? in.getDestinationNickname() : null); + if (name == null) { + TunnelPoolSettings out = ctx.tunnelManager().getOutboundSettings(d.calculateHash()); + name = (out != null ? out.getDestinationNickname() : null); + if (name == null) + name = d.calculateHash().toBase64().substring(0,6); + else + name = _(ctx, name); + } else { + name = _(ctx, name); + } + return name; + } + + private String _(RouterContext ctx, String s) { + return Translate.getString(s, ctx, "net.i2p.router.web.messages"); + } + private void checkDialog() { VersionDialog dialog = new VersionDialog(); String oldVersion = ((I2PActivityBase) getActivity()).getPref(PREF_INSTALLED_VERSION, "??");