From ae4e56964e32be2edb24047034dbf9e1447acf24 Mon Sep 17 00:00:00 2001 From: Nathaniel Wesley Filardo Date: Thu, 9 Feb 2017 22:46:59 -0500 Subject: [PATCH] UI improvements Dialog for setting server URI preference Feedback TextViews at the bottom --- .../ctfwstimer/CtFwSDisplay.java | 18 +-- .../ctfwstimer/MainActivity.java | 103 ++++++++++++++---- .../StringSettingDialogFragment.java | 68 ++++++++++++ mobile/src/main/res/layout/activity_main.xml | 58 +++++++++- mobile/src/main/res/layout/server_dialog.xml | 18 +++ mobile/src/main/res/menu/mainmenu.xml | 10 ++ mobile/src/main/res/values/strings.xml | 14 +++ 7 files changed, 260 insertions(+), 29 deletions(-) create mode 100644 mobile/src/main/java/com/acmetensortoys/ctfwstimer/StringSettingDialogFragment.java create mode 100644 mobile/src/main/res/layout/server_dialog.xml create mode 100644 mobile/src/main/res/menu/mainmenu.xml diff --git a/mobile/src/main/java/com/acmetensortoys/ctfwstimer/CtFwSDisplay.java b/mobile/src/main/java/com/acmetensortoys/ctfwstimer/CtFwSDisplay.java index 4d3b3ca..cc66d91 100644 --- a/mobile/src/main/java/com/acmetensortoys/ctfwstimer/CtFwSDisplay.java +++ b/mobile/src/main/java/com/acmetensortoys/ctfwstimer/CtFwSDisplay.java @@ -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(); diff --git a/mobile/src/main/java/com/acmetensortoys/ctfwstimer/MainActivity.java b/mobile/src/main/java/com/acmetensortoys/ctfwstimer/MainActivity.java index a9d3ea2..2c5c0de 100644 --- a/mobile/src/main/java/com/acmetensortoys/ctfwstimer/MainActivity.java +++ b/mobile/src/main/java/com/acmetensortoys/ctfwstimer/MainActivity.java @@ -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 index 0000000..08b049d --- /dev/null +++ b/mobile/src/main/java/com/acmetensortoys/ctfwstimer/StringSettingDialogFragment.java @@ -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, "")); + } + } +} diff --git a/mobile/src/main/res/layout/activity_main.xml b/mobile/src/main/res/layout/activity_main.xml index 381648e..349ad30 100644 --- a/mobile/src/main/res/layout/activity_main.xml +++ b/mobile/src/main/res/layout/activity_main.xml @@ -133,10 +133,64 @@ 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" /> + + + + + + + + + + + + + + + + + + + + + + + + +