Skip to content

Commit

Permalink
small UX improvements
Browse files Browse the repository at this point in the history
- disabling connection check until host is set fixes #12
- introducing more strict checking on host means less errors are only
  discovered during connection check
- allow removal of optional config values (username, password, port)
  by just emptying out the text field
- show if password is set or not
- use formatted string resources instead of formatting them manually
  • Loading branch information
ostrya committed Nov 19, 2019
1 parent 8f5f7d5 commit 880c832
Show file tree
Hide file tree
Showing 12 changed files with 99 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public void sendMessages(List<Message> messages) throws MqttException {
}
mqttClient.connect(options);
for (Message message : messages) {
mqttClient.publish(message.getTopic(), message.getContent().getBytes(Charset.forName("UTF-8")), 0, false);
mqttClient.publish(message.getTopic(), message.getContent().getBytes(Charset.forName("UTF-8")), 1, false);
}
mqttClient.disconnect(5);
mqttClient.close(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import org.ostrya.presencepublisher.ui.preference.UseTlsPreference;
import org.ostrya.presencepublisher.ui.preference.UsernamePreference;

import static org.ostrya.presencepublisher.ui.preference.HostPreference.HOST;
import static org.ostrya.presencepublisher.ui.preference.UseTlsPreference.USE_TLS;

public class ConnectionFragment extends PreferenceFragmentCompat {
Expand Down Expand Up @@ -47,6 +48,7 @@ public void onCreatePreferences(final Bundle savedInstanceState, final String ro

setPreferenceScreen(screen);

checkConnection.setDependency(HOST);
clientCertificate.setDependency(USE_TLS);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,24 @@ private void setContext(Context context) {
this.context = context;
}

private String getErrorString(Throwable e) {
String message;
if (e instanceof MqttException) {
if (((MqttException) e).getReasonCode() == MqttException.REASON_CODE_CLIENT_EXCEPTION) {
message = genericExceptionToString(e.getCause());
} else {
message = e.getLocalizedMessage();
}
} else {
message = genericExceptionToString(e);
}
return context.getString(R.string.dialog_check_connection_summary_failure, message);
}

private String genericExceptionToString(Throwable e) {
return e.getClass().getSimpleName() + ": " + e.getLocalizedMessage();
}

private class ConnectionTestWorker implements Runnable {
private final AlertDialog alertDialog;

Expand All @@ -69,9 +87,9 @@ public void run() {
try {
mqttService.sendMessages(Collections.singletonList(messageForTopic("test").withContent("test")));
message = getResources().getString(R.string.dialog_check_connection_summary_success);
} catch (MqttException e) {
} catch (MqttException | RuntimeException e) {
HyperLog.w(TAG, "Error while sending message", e);
message = String.format(context.getString(R.string.dialog_check_connection_summary_failure), e.getCause().getMessage());
message = getErrorString(e);
}
final String result = message;
requireActivity().runOnUiThread(() -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,11 @@ public static Notification getNotification(Context context, long lastSuccess, lo
}

private static String getLastPing(Context context, long lastSuccess) {
return String.format(context.getString(R.string.notification_last_ping), getFormattedTimestamp(context, lastSuccess));
return context.getString(R.string.notification_last_ping, getFormattedTimestamp(context, lastSuccess));
}

private static String getNextPing(Context context, long nextSchedule) {
return String.format(context.getString(R.string.notification_next_ping), getFormattedTimestamp(context, nextSchedule));
return context.getString(R.string.notification_next_ping, getFormattedTimestamp(context, nextSchedule));
}

private static String getFormattedTimestamp(Context context, long timestamp) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ private AbstractTextPreference(Context context, String key, Validator validator,
if (!result) {
String text = context.getString(R.string.toast_invalid_input);
Toast.makeText(context, text, Toast.LENGTH_SHORT).show();
} else if (((String) newValue).isEmpty()) {
setText(null);
return false;
}
return result;
}));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
package org.ostrya.presencepublisher.ui.preference;

import android.content.Context;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.ostrya.presencepublisher.R;
import org.ostrya.presencepublisher.ui.util.RegexValidator;

import java.net.URI;
import java.net.URISyntaxException;

public class HostPreference extends AbstractTextPreference {
public static final String HOST = "host";

public HostPreference(Context context) {
super(context, HOST, new RegexValidator("[^:/]+"), R.string.host_title, R.string.host_summary);
super(context, HOST, value -> {
try {
String testUri = "tcp://" + value;
MqttConnectOptions.validateURI(testUri);
return new URI(testUri).getHost() != null;
} catch (IllegalArgumentException | URISyntaxException e) {
return false;
}
}, R.string.host_title, R.string.host_summary);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@
import android.view.inputmethod.EditorInfo;
import org.ostrya.presencepublisher.R;
import org.ostrya.presencepublisher.security.SecurePreferencesHelper;
import org.ostrya.presencepublisher.ui.util.PasswordSummaryProvider;
import org.ostrya.presencepublisher.ui.util.RegexValidator;

public class PasswordPreference extends AbstractTextPreference {
public static final String PASSWORD = "password";

public PasswordPreference(Context context) {
super(context, PASSWORD, new RegexValidator(".+"), R.string.password_title, R.string.password_summary);
super(context, PASSWORD, new RegexValidator(".*"), R.string.password_title, R.string.password_summary);
setOnBindEditTextListener(editText -> {
editText.setInputType(EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_PASSWORD);
editText.setSelection(editText.getText().length());
Expand All @@ -25,6 +26,6 @@ public PasswordPreference(Context context) {

@Override
protected void configureSummary(int summaryId) {
setSummary(summaryId);
setSummaryProvider(new PasswordSummaryProvider(summaryId));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public ExplanationSummaryProvider(int summaryId, PreferenceType type) {

@Override
public CharSequence provideSummary(T preference) {
return String.format(preference.getContext().getString(summaryId), getValue(preference));
return preference.getContext().getString(summaryId, getValue(preference));
}

private String getValue(T preference) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.ostrya.presencepublisher.ui.util;

import androidx.preference.Preference;
import org.ostrya.presencepublisher.R;
import org.ostrya.presencepublisher.ui.preference.PasswordPreference;

public class PasswordSummaryProvider implements Preference.SummaryProvider<PasswordPreference> {
private final int summaryId;

public PasswordSummaryProvider(int summaryId) {
this.summaryId = summaryId;
}

@Override
public CharSequence provideSummary(PasswordPreference preference) {
return preference.getContext().getString(summaryId, getValue(preference));
}

private String getValue(PasswordPreference preference) {
if (preference.getText() != null) {
return preference.getContext().getString(R.string.password_placeholder);
} else {
return preference.getContext().getString(R.string.value_undefined);
}
}
}
20 changes: 3 additions & 17 deletions app/src/main/play/release-notes/en-US/default.txt
Original file line number Diff line number Diff line change
@@ -1,17 +1,3 @@
v1.6.4
• Next attempt to fix F-Droid build.

v1.6.3:
• More minor build script changes to fix F-Droid build.

v1.6.2:
• Minor build script changes.

v1.6.1:
• Minor bugfix related to handling of VPN connections.

v1.6.0:
• Added option to send offline messages while connected to mobile network.
• Added option to send battery level to a separate topic.
• On Android 6+, encrypt login password.
• Migrate from foreground service with scheduled thread pool to Android alarm manager and request disabling battery optimization. This should make sending messages more reliable during standby.
v1.6.5
• Re-enable schedule periods down to 1 minute.
• Small UX improvements.
24 changes: 12 additions & 12 deletions app/src/main/res/values-de/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
<resources>
<string name="app_name">Presence Publisher</string>
<string name="host_title">MQTT Host</string>
<string name="host_summary">IP-Adresse oder Hostname.%nAktueller Wert: %s</string>
<string name="host_summary" formatted="true">IP-Adresse oder Hostname.%nAktueller Wert: %1$s</string>
<string name="presence_topic_title">Präsenz-Topic</string>
<string name="presence_topic_summary">Das Topic, zu dem Präsenznachrichten gesendet werden.%nAktueller Wert: %s</string>
<string name="presence_topic_summary" formatted="true">Das Topic, zu dem Präsenznachrichten gesendet werden.%nAktueller Wert: %1$s</string>
<string name="message_schedule_title">Sendeperiode</string>
<string name="message_schedule_summary">Zeit zwischen Benachrichtigungen in Minuten.</string>
<string name="message_schedule_dialog_text">Die Periode auf unter 15 Minuten zu setzen wird den Batterieverbrauch erhöhen. Fortfahren?</string>
<string name="ssid_list_title">Ziel-WLAN-Netzwerke</string>
<string name="ssid_list_summary">Netzwerke, in denen benachrichtigt wird.%nAktueller Wert: %s</string>
<string name="ssid_list_summary" formatted="true">Netzwerke, in denen benachrichtigt wird.%nAktueller Wert: %1$s</string>
<string name="permission_dialog_title">Standortberechtigung</string>
<string name="permission_dialog_message">Bitte erlaube den Zugriff auf ungefähre Position. Andernfalls kann diese App den
Namen des aktuell verbundenen WLANs nicht bestimmen. Du kannst das Setzen der Berechtigung überspringen, aber
Expand All @@ -25,11 +25,11 @@
</string>
<string name="tab_connection_title">Verbindung</string>
<string name="tab_schedule_title">Zeitplan</string>
<string name="notification_last_ping">Letzter Erfolg: %s</string>
<string name="notification_next_ping">Geplant für: %s</string>
<string name="notification_last_ping" formatted="true">Letzter Erfolg: %1$s</string>
<string name="notification_next_ping" formatted="true">Geplant für: %1$s</string>
<string name="use_tls_title">TLS</string>
<string name="port_title">MQTT Port</string>
<string name="port_summary">Standardwert 1883, bzw. 8883 bei TLS.%nAktueller Wert: %s</string>
<string name="port_summary" formatted="true">Standardwert 1883, bzw. 8883 bei TLS.%nAktueller Wert: %1$s</string>
<string name="use_tls_summary">Transportverschlüsselung verwenden?</string>
<string name="toast_invalid_input">Ungültige Eingabe!</string>
<string name="check_connection_summary">Tippe hier, um eine Testbenachrichtigung zu senden.</string>
Expand All @@ -41,21 +41,21 @@
<string name="dialog_check_connection_summary_success">Benachrichtigung erfolgreich gesendet.</string>
<string name="value_undefined"><![CDATA[<nicht gesetzt>]]></string>
<string name="autostart_summary">Soll diese App beim Boot starten?</string>
<string name="dialog_check_connection_summary_failure">Verbindung fehlgeschlagen:%n%s</string>
<string name="dialog_check_connection_summary_failure" formatted="true">Verbindung fehlgeschlagen:%n%1$s</string>
<string name="client_certificate_title">Client-Zertifikat</string>
<string name="client_certificate_summary">Das Client-Zertifikat, mit dem sich das Gerät authentifizieren soll.%nAktueller Wert: %s</string>
<string name="client_certificate_summary">Das Client-Zertifikat, mit dem sich das Gerät authentifizieren soll.%nAktueller Wert: %1$s</string>
<string name="last_success_title">Letzter Erfolg</string>
<string name="next_schedule_title">Geplant für</string>
<string name="username_title">MQTT Anmeldung</string>
<string name="username_summary">Anmeldung.%nAktueller Wert: %s</string>
<string name="username_summary" formatted="true">Anmeldung.%nAktueller Wert: %1$s</string>
<string name="password_title">MQTT Passwort</string>
<string name="password_summary">Passwort.</string>
<string name="password_summary" formatted="true">Passwort.%nAktueller Wert: %1$s</string>
<string name="send_offline_message_title">Offline-Nachricht senden</string>
<string name="send_offline_message_summary">Nachricht senden, wenn Ziel-WLAN nicht verbunden ist</string>
<string name="send_via_mobile_network_title">Nachricht ohne WiFi senden</string>
<string name="send_via_mobile_network_summary">Offline-Nachricht notfalls über mobile Daten senden</string>
<string name="tab_content_title">Inhalt</string>
<string name="content_summary">Aktueller Wert: %s</string>
<string name="content_summary" formatted="true">Aktueller Wert: %1$s</string>
<string name="offline_content_title">Offline-Nachricht</string>
<string name="content_category_other">Anderes</string>
<string name="content_category_wifi">WLAN</string>
Expand All @@ -67,7 +67,7 @@
<string name="button_clear">Löschen</string>
<string name="tab_licenses_title">Lizenzen</string>
<string name="battery_topic_title">Batterie-Topic</string>
<string name="battery_topic_summary">Das Topic, zu dem Batterienachrichten gesendet werden.%nAktueller Wert: %s</string>
<string name="battery_topic_summary" formatted="true">Das Topic, zu dem Batterienachrichten gesendet werden.%nAktueller Wert: %1$s</string>
<string name="send_battery_message_title">Batteriestand senden</string>
<string name="send_battery_message_summary">Batteriestand in Prozent zusätzlich zu Präsenznachricht senden.</string>
<string name="battery_optimization_dialog_title">Akku-Optimierung</string>
Expand Down
25 changes: 13 additions & 12 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
<resources>
<string name="app_name">Presence Publisher</string>
<string name="host_title">MQTT Host</string>
<string name="host_summary">IP address or hostname.%nCurrent value: %s</string>
<string name="host_summary" formatted="true">IP address or hostname.%nCurrent value: %1$s</string>
<string name="username_title">MQTT Login</string>
<string name="username_summary">User Login.%nCurrent value: %s</string>
<string name="username_summary" formatted="true">User Login.%nCurrent value: %1$s</string>
<string name="password_title">MQTT Password</string>
<string name="password_summary">User Password.</string>
<string name="password_summary" formatted="true">User Password.%nCurrent value: %1$s</string>
<string name="password_placeholder" translatable="false">••••••••</string>
<string name="presence_topic_title">Presence Topic</string>
<string name="presence_topic_summary">The topic to publish presence messages to.%nCurrent value: %s</string>
<string name="presence_topic_summary" formatted="true">The topic to publish presence messages to.%nCurrent value: %1$s</string>
<string name="send_battery_message_title">Send battery level</string>
<string name="send_battery_message_summary">Send battery level percentage in addition to presence information.</string>
<string name="battery_topic_title">Battery Topic</string>
<string name="battery_topic_summary">The topic to publish battery level to.%nCurrent value: %s</string>
<string name="battery_topic_summary" formatted="true">The topic to publish battery level to.%nCurrent value: %1$s</string>
<string name="message_schedule_title">Publish period</string>
<string name="message_schedule_summary">The time between messages in minutes.</string>
<string name="message_schedule_dialog_text">Setting the interval lower than 15 minutes will increase your battery usage. Do you want to continue?</string>
<string name="ssid_list_title">Target WiFi networks</string>
<string name="ssid_list_summary">WiFi networks for which to send messages.%nCurrent value: %s</string>
<string name="ssid_list_summary" formatted="true">WiFi networks for which to send messages.%nCurrent value: %1$s</string>
<string name="permission_dialog_title">Location permission</string>
<string name="permission_dialog_message">Please allow access to coarse location. Otherwise, this app will not be able to
retrieve the currently connected WiFi name. You can skip granting the permission, but then the app will not send
Expand All @@ -34,11 +35,11 @@
<string name="battery_optimization_dialog_message">Please disable battery optimization. Otherwise, Android may doze this app and stop it from sending messages during standby.</string>
<string name="tab_connection_title">Connection</string>
<string name="tab_schedule_title">Schedule</string>
<string name="notification_last_ping">Last success: %s</string>
<string name="notification_next_ping">Scheduled for: %s</string>
<string name="notification_last_ping" formatted="true">Last success: %1$s</string>
<string name="notification_next_ping" formatted="true">Scheduled for: %1$s</string>
<string name="use_tls_title">TLS</string>
<string name="port_title">MQTT Port</string>
<string name="port_summary">Defaults to 1883, or 8883 for TLS.%nCurrent value: %s</string>
<string name="port_summary" formatted="true">Defaults to 1883, or 8883 for TLS.%nCurrent value: %1$s</string>
<string name="use_tls_summary">Use transport encryption?</string>
<string name="toast_invalid_input">Invalid input!</string>
<string name="check_connection_summary">Click here to send test message.</string>
Expand All @@ -50,17 +51,17 @@
<string name="dialog_check_connection_summary_success">Message successfully sent.</string>
<string name="value_undefined"><![CDATA[<undefined>]]></string>
<string name="autostart_summary">Should this app start on boot?</string>
<string name="dialog_check_connection_summary_failure">Connection failed:%n%s</string>
<string name="dialog_check_connection_summary_failure" formatted="true">Connection failed:%n%1$s</string>
<string name="client_certificate_title">Client certificate</string>
<string name="client_certificate_summary">Client certificate to authenticate this device.%nCurrent value: %s</string>
<string name="client_certificate_summary" formatted="true">Client certificate to authenticate this device.%nCurrent value: %1$s</string>
<string name="last_success_title">Last success</string>
<string name="next_schedule_title">Scheduled for</string>
<string name="send_offline_message_title">Send offline message</string>
<string name="send_offline_message_summary">Send message when not connected to target network</string>
<string name="send_via_mobile_network_title">Send without WiFi</string>
<string name="send_via_mobile_network_summary">Send offline message via mobile network if necessary</string>
<string name="tab_content_title">Content</string>
<string name="content_summary">Current value: %s</string>
<string name="content_summary" formatted="true">Current value: %1$s</string>
<string name="offline_content_title">Offline message</string>
<string name="content_category_other">Other</string>
<string name="content_category_wifi">WiFi</string>
Expand Down

0 comments on commit 880c832

Please sign in to comment.