]> hydra-www.ietfng.org Git - acmetensortoys-ctfws-android/commitdiff
UI improvements
authorNathaniel Wesley Filardo <nwf@cs.jhu.edu>
Fri, 10 Feb 2017 03:46:59 +0000 (22:46 -0500)
committerNathaniel Wesley Filardo <nwf@cs.jhu.edu>
Fri, 10 Feb 2017 03:46:59 +0000 (22:46 -0500)
Dialog for setting server URI preference
Feedback TextViews at the bottom

mobile/src/main/java/com/acmetensortoys/ctfwstimer/CtFwSDisplay.java
mobile/src/main/java/com/acmetensortoys/ctfwstimer/MainActivity.java
mobile/src/main/java/com/acmetensortoys/ctfwstimer/StringSettingDialogFragment.java [new file with mode: 0644]
mobile/src/main/res/layout/activity_main.xml
mobile/src/main/res/layout/server_dialog.xml [new file with mode: 0644]
mobile/src/main/res/menu/mainmenu.xml [new file with mode: 0644]
mobile/src/main/res/values/strings.xml

index 4d3b3cad04469505b03fe23afb58f0fb6882bfd8..cc66d914da0582a712d8a7c03a2b3782d970c879 100644 (file)
@@ -59,13 +59,7 @@ class CtFwSDisplay {
 
         // Clear the mesage log if it looks like it's a new game in play
         if (lastMsgTimeMS < mCgs.startT * 1000) {
-            final TextView msgs = (TextView) (mAct.findViewById(R.id.msgs));
-            msgs.post(new Runnable() {
-                @Override
-                public void run() {
-                    msgs.setText("");
-                }
-            });
+            clearMsgs();
         }
 
         mHandler.removeCallbacks(mProber);
@@ -246,6 +240,16 @@ class CtFwSDisplay {
         });
     }
 
+    void clearMsgs() {
+        final TextView msgs = (TextView) (mAct.findViewById(R.id.msgs));
+        msgs.post(new Runnable() {
+            @Override
+            public void run() {
+                msgs.setText("");
+            }
+        });
+    }
+
     void notifyMessage(String m) {
         lastMsgTimeMS = System.currentTimeMillis();
 
index a9d3ea2d84f1501948a9107b01ee32c6ff5245b1..2c5c0dedc72a626449add1aaf2923d79d8cfe97f 100644 (file)
@@ -3,9 +3,15 @@ package com.acmetensortoys.ctfwstimer;
 import android.content.SharedPreferences;
 import android.os.Handler;
 import android.support.annotation.Nullable;
+import android.support.annotation.StringRes;
+import android.support.v4.app.DialogFragment;
 import android.support.v7.app.AppCompatActivity;
 import android.os.Bundle;
 import android.util.Log;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.widget.TextView;
 
 import org.eclipse.paho.android.service.MqttAndroidClient;
 import org.eclipse.paho.client.mqttv3.IMqttActionListener;
@@ -26,11 +32,33 @@ public class MainActivity extends AppCompatActivity {
     private CtFwSDisplay mCdl; // set in onCreate
     private CtFwSCallbacksMQTT mCtfwscbs ; // set in onCreate
 
+    private TextView mTvSU; // set in onCreate
+    private TextView mTvSS; // set in onCreate
+    private void setServerStateText(@StringRes final int resid) {
+        mTvSS.post(new Runnable() {
+            @Override
+            public void run() { mTvSS.setText(resid); }
+        });
+    }
+
+    // We'll use this common callback object for our subscriptions below
+    final IMqttActionListener subal = new IMqttActionListener() {
+        @Override
+        public void onSuccess(IMqttToken asyncActionToken) {
+            Log.d("CtFwS", "Sub OK: " + asyncActionToken);
+        }
+
+        @Override
+        public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
+            Log.e("CtFws", "Sub Fail: " + asyncActionToken, exception);
+        }
+    };
+
     private synchronized void doMqtt(@Nullable String server) {
         // Hang up on an existing connection, if we have one
         synchronized (this) {
             if (mMqc != null) {
-                mMqc.close();
+                try { mMqc.disconnect(); } catch (MqttException me) { ; }
             }
             mMqc = null;
             mCgs.configured = false;
@@ -38,23 +66,17 @@ public class MainActivity extends AppCompatActivity {
         }
 
         // If that's all we were told to do, we're done
-        if (server == null) { return ; }
+        if (server == null) {
+            Log.d("CtFwS", "doMqtt null");
+            mTvSU.setText(R.string.string_null);
+            return;
+        }
+        Log.d("CtFwS", "doMqtt not null:" + server);
 
-        // We'll use this common callback object for our subscriptions below
-        final IMqttActionListener subal = new IMqttActionListener() {
-            @Override
-            public void onSuccess(IMqttToken asyncActionToken) {
-                Log.d("CtFwS", "Sub OK: " + asyncActionToken);
-            }
-
-            @Override
-            public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
-                Log.e("CtFws", "Sub Fail: " + asyncActionToken, exception);
-            }
-        };
+        mTvSU.setText(server);
 
         // Make our MQTT client and grab callbacks on *everything in sight*
-        final MqttAndroidClient mqc = new MqttAndroidClient(this,server, mqttClientId);
+        final MqttAndroidClient mqc = new MqttAndroidClient(this,server,mqttClientId);
         mqc.setCallback(new MqttCallbackExtended() {
             @Override
             public void connectComplete(boolean reconnect, String serverURI) {
@@ -66,6 +88,7 @@ public class MainActivity extends AppCompatActivity {
                     mqc.subscribe(p+"flags"         , 2, null, subal, mCtfwscbs.onFlags);
                     mqc.subscribe(p+"message"       , 2, null, subal, mCtfwscbs.onMessage);
                     mqc.subscribe(p+"message/player", 2, null, subal, mCtfwscbs.onPlayerMessage);
+                    setServerStateText(R.string.mqtt_subbed);
                 } catch (MqttException e) {
                     Log.e("CtFwS", "Exn Sub", e);
                 }
@@ -74,6 +97,7 @@ public class MainActivity extends AppCompatActivity {
             @Override
             public void connectionLost(Throwable cause) {
                 Log.d("CtFwS", "Conn Lost", cause);
+                setServerStateText(R.string.mqtt_disconn);
             }
 
             @Override
@@ -94,6 +118,7 @@ public class MainActivity extends AppCompatActivity {
         // react to messages sent to us.  Have we lost the thread yet?
         try {
             MqttConnectOptions mco = new MqttConnectOptions();
+            mco.setCleanSession(true);
             mco.setAutomaticReconnect(true);
             mco.setKeepAliveInterval(180); // seconds
 
@@ -101,11 +126,15 @@ public class MainActivity extends AppCompatActivity {
                 @Override
                 public void onSuccess(IMqttToken asyncActionToken) {
                     Log.d("CtFwS", "Conn OK 1");
+                    setServerStateText(R.string.mqtt_conn);
+                    mCdl.clearMsgs();
                 }
 
                 @Override
                 public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                     Log.e("CtFws", "Conn Fail", exception);
+                    setServerStateText(R.string.mqtt_disconn);
+                    mCdl.clearMsgs();
                 }
             });
 
@@ -126,7 +155,8 @@ public class MainActivity extends AppCompatActivity {
         public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
             switch(key) {
                 case "server":
-                    doMqtt(sharedPreferences.getString("server",null));
+                    String s = sharedPreferences.getString(key,null);
+                    if (s != null) { doMqtt(s); }
                     break;
             }
         }
@@ -134,16 +164,49 @@ public class MainActivity extends AppCompatActivity {
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
+        String defserver = "tcp://nwf1.xen.prgmr.com:1883";
+
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
 
+        mTvSU = (TextView) findViewById(R.id.tv_mqtt_server_uri);
+        mTvSS = (TextView) findViewById(R.id.tv_mqtt_state);
+
         mCdl = new CtFwSDisplay(this, new Handler(), mCgs);
         mCtfwscbs = new CtFwSCallbacksMQTT(mCdl, mCgs);
 
-        // TODO There really should be a UI thing for changing the server; we're all
-        // set for when-/if-ever that happens.
+        SharedPreferences sp = getPreferences(MODE_PRIVATE);
+        if (sp.getString("server", null) == null) {
+            sp.edit().putString("server", defserver).apply();
+        }
+        if (BuildConfig.DEBUG && sp.getString("server", null) == null) {
+            throw new AssertionError("Shared Preferences not sticking!");
+        }
+
+        synchronized(this) {
+            sp.registerOnSharedPreferenceChangeListener(mOSPCL);
+            doMqtt(sp.getString("server", defserver));
+        }
+    }
 
-        getPreferences(MODE_PRIVATE).registerOnSharedPreferenceChangeListener(mOSPCL);
-        doMqtt(getPreferences(MODE_PRIVATE).getString("server","tcp://nwf1.xen.prgmr.com:1883"));
+    @Override
+    public boolean onOptionsItemSelected(MenuItem mi) {
+        switch(mi.getItemId()) {
+            case R.id.menu_mqtt :
+                DialogFragment d =
+                        StringSettingDialogFragment.newInstance(
+                                R.layout.server_dialog, R.id.server_text, "server");
+                d.show(getSupportFragmentManager(),"serverdialog");
+                return true;
+            default:
+                return super.onOptionsItemSelected(mi);
+        }
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        MenuInflater mi = getMenuInflater();
+        mi.inflate(R.menu.mainmenu, menu);
+        return true;
     }
 }
diff --git a/mobile/src/main/java/com/acmetensortoys/ctfwstimer/StringSettingDialogFragment.java b/mobile/src/main/java/com/acmetensortoys/ctfwstimer/StringSettingDialogFragment.java
new file mode 100644 (file)
index 0000000..08b049d
--- /dev/null
@@ -0,0 +1,68 @@
+package com.acmetensortoys.ctfwstimer;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v4.app.DialogFragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.TextView;
+
+public class StringSettingDialogFragment extends DialogFragment
+    implements SharedPreferences.OnSharedPreferenceChangeListener
+{
+    private final static String ARG_LRES_IX = "lres"; // layout id
+    private final static String ARG_VRES_IX = "vres"; // text view id
+    private final static String ARG_PREF_IX = "pref"; // preference name
+
+    private TextView mTv;
+
+    public static StringSettingDialogFragment newInstance(int lres, int vres, String pref) {
+        StringSettingDialogFragment ssdf = new StringSettingDialogFragment();
+        Bundle args = new Bundle();
+        args.putInt   (ARG_LRES_IX, lres);
+        args.putInt   (ARG_VRES_IX, vres);
+        args.putString(ARG_PREF_IX, pref);
+        ssdf.setArguments(args);
+        return ssdf;
+    }
+
+    @NonNull @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        Bundle a = getArguments();
+        AlertDialog.Builder adb = new AlertDialog.Builder(getActivity());
+        LayoutInflater li = getActivity().getLayoutInflater();
+        View v = li.inflate(a.getInt(ARG_LRES_IX), null);
+
+        mTv = (TextView)v.findViewById(a.getInt(ARG_VRES_IX));
+        final SharedPreferences sp = getActivity().getPreferences(Context.MODE_PRIVATE);
+        sp.registerOnSharedPreferenceChangeListener(this);
+        onSharedPreferenceChanged(sp,a.getString(ARG_PREF_IX));
+
+        adb.setView(v)
+                .setPositiveButton(R.string.dialog_ok, new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        sp.edit().putString("server", mTv.getText().toString()).apply();
+                    }
+                })
+                .setNegativeButton(R.string.dialog_cancel, new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        // NOP
+                    }
+                });
+        return adb.create();
+    }
+
+    @Override
+    public void onSharedPreferenceChanged(SharedPreferences sp, String p) {
+        if (p != null && getArguments().getString(ARG_PREF_IX).equals(p)) {
+            mTv.setText(sp.getString(p, ""));
+        }
+    }
+}
index 381648e5e4bed727a6edab0238389b321520c8b9..349ad30d59d5a47ca67f06b5e2fd7936eb167241 100644 (file)
                 android:inputType="none"
                 android:ems="10"
                 android:id="@+id/msgs"
-                android:maxLines="10"
-                android:minLines="1"
+                android:lines="10"
                 android:scrollbars="vertical"
                 android:gravity="bottom" />
+
+        </LinearLayout>
+
+        <LinearLayout
+            android:orientation="vertical"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center"
+                android:text="@string/mqtt_header" />
+
+            <TableLayout
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:stretchColumns="1">
+
+                <TableRow
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent">
+
+                    <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="@string/menutext_mqtt_label"
+                        android:gravity="center" />
+
+                    <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:id="@+id/tv_mqtt_server_uri"
+                        android:gravity="center" />
+                </TableRow>
+
+                <TableRow
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent">
+
+                    <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="@string/mqtt_state_label"
+                        android:gravity="center" />
+
+                    <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:id="@+id/tv_mqtt_state"
+                        android:gravity="center" />
+
+                </TableRow>
+
+            </TableLayout>
         </LinearLayout>
 
         <!--
diff --git a/mobile/src/main/res/layout/server_dialog.xml b/mobile/src/main/res/layout/server_dialog.xml
new file mode 100644 (file)
index 0000000..096a0be
--- /dev/null
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical" android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/menutext_mqtt_label"
+        android:labelFor="@+id/server_text"/>
+
+    <EditText
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:ems="10"
+        android:id="@+id/server_text"
+        android:inputType="text" />
+</LinearLayout>
\ No newline at end of file
diff --git a/mobile/src/main/res/menu/mainmenu.xml b/mobile/src/main/res/menu/mainmenu.xml
new file mode 100644 (file)
index 0000000..04f1e79
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item
+        android:visible="true"
+        android:enabled="true"
+        android:title="@string/menutext_mqtt"
+        android:id="@+id/menu_mqtt"
+        android:icon="@android:drawable/ic_menu_manage" />
+</menu>
\ No newline at end of file
index c385cc949e2a51c3a090a4d446af5dd3e7ca7b3f..82df3b7c3f7962ee96e48e7ff440175e5eb4e0fb 100644 (file)
@@ -9,4 +9,18 @@
     <string name="header_gamestate">Game State:</string>
     <string name="header_gametimeela">Game\nTime\nElapsed</string>
     <string name="header_messages">Messages:</string>
+
+    <string name="dialog_ok">OK</string>
+    <string name="dialog_cancel">Cancel</string>
+
+    <string name="menutext_mqtt">Set MQTT Server</string>
+    <string name="menutext_mqtt_label">Server URI:</string>
+
+    <string name="mqtt_header">Connection Metadata:</string>
+    <string name="mqtt_state_label">Server State:</string>
+    <string name="mqtt_conn">Connected</string>
+    <string name="mqtt_disconn">Disconnected</string>
+    <string name="mqtt_subbed">Subscribed</string>
+
+    <string name="string_null">&lt;&lt;null&gt;&gt;</string>
 </resources>