wip: new status message dialog

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/entities/PresenceTemplate.java               |  5 
src/main/java/eu/siacs/conversations/ui/ConversationFragment.java                 | 22 
src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java                  | 28 
src/main/java/eu/siacs/conversations/ui/ManageAccountActivity.java                | 11 
src/main/java/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java            |  9 
src/main/java/eu/siacs/conversations/ui/adapter/PresenceTemplateAdapter.java      | 92 
src/main/java/eu/siacs/conversations/ui/widget/ImmediateAutoCompleteTextView.java | 49 
src/main/res/layout/dialog_presence.xml                                           | 53 
src/main/res/menu/editaccount.xml                                                 | 12 
src/main/res/menu/manageaccounts_context.xml                                      |  3 
10 files changed, 242 insertions(+), 42 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/ui/ConversationFragment.java 🔗

@@ -852,22 +852,16 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
 				}
 			}
 			Account account = message.getConversation().getAccount();
-			Intent intent;
-			if (activity.manuallyChangePresence() && !received) {
-				intent = new Intent(activity, SetPresenceActivity.class);
-				intent.putExtra(EXTRA_ACCOUNT, account.getJid().toBareJid().toString());
+			Intent intent = new Intent(activity, EditAccountActivity.class);
+			intent.putExtra("jid", account.getJid().toBareJid().toString());
+			String fingerprint;
+			if (message.getEncryption() == Message.ENCRYPTION_PGP
+					|| message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
+				fingerprint = "pgp";
 			} else {
-				intent = new Intent(activity, EditAccountActivity.class);
-				intent.putExtra("jid", account.getJid().toBareJid().toString());
-				String fingerprint;
-				if (message.getEncryption() == Message.ENCRYPTION_PGP
-						|| message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
-					fingerprint = "pgp";
-				} else {
-					fingerprint = message.getFingerprint();
-				}
-				intent.putExtra("fingerprint", fingerprint);
+				fingerprint = message.getFingerprint();
 			}
+			intent.putExtra("fingerprint", fingerprint);
 			startActivity(intent);
 		});
 		messageListAdapter.setOnContactPictureLongClicked(message -> {

src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java 🔗

@@ -10,6 +10,7 @@ import android.graphics.Bitmap;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
+import android.preference.PreferenceManager;
 import android.provider.Settings;
 import android.security.KeyChain;
 import android.security.KeyChainAliasCallback;
@@ -20,10 +21,12 @@ import android.support.v7.app.AlertDialog;
 import android.support.v7.app.AlertDialog.Builder;
 import android.text.Editable;
 import android.text.TextWatcher;
+import android.util.Log;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.View.OnClickListener;
+import android.widget.AdapterView;
 import android.widget.AutoCompleteTextView;
 import android.widget.Button;
 import android.widget.CheckBox;
@@ -52,12 +55,15 @@ import eu.siacs.conversations.R;
 import eu.siacs.conversations.crypto.axolotl.AxolotlService;
 import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession;
 import eu.siacs.conversations.databinding.ActivityEditAccountBinding;
+import eu.siacs.conversations.databinding.DialogPresenceBinding;
 import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.entities.PresenceTemplate;
 import eu.siacs.conversations.services.BarcodeProvider;
 import eu.siacs.conversations.services.XmppConnectionService;
 import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
 import eu.siacs.conversations.services.XmppConnectionService.OnCaptchaRequested;
 import eu.siacs.conversations.ui.adapter.KnownHostsAdapter;
+import eu.siacs.conversations.ui.adapter.PresenceTemplateAdapter;
 import eu.siacs.conversations.ui.widget.DisabledActionModeCallback;
 import eu.siacs.conversations.utils.CryptoHelper;
 import eu.siacs.conversations.utils.UIHelper;
@@ -622,7 +628,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
 				changePassword.setVisible(false);
 			}
 			mamPrefs.setVisible(mAccount.getXmppConnection().getFeatures().mam());
-			changePresence.setVisible(manuallyChangePresence());
+			changePresence.setVisible(true);
 		} else {
 			showBlocklist.setVisible(false);
 			showMoreInfo.setVisible(false);
@@ -833,9 +839,23 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
 	}
 
 	private void changePresence() {
-		Intent intent = new Intent(this, SetPresenceActivity.class);
-		intent.putExtra(SetPresenceActivity.EXTRA_ACCOUNT, mAccount.getJid().toBareJid().toString());
-		startActivity(intent);
+		SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
+		boolean manualStatus = sharedPreferences.getBoolean(SettingsActivity.MANUALLY_CHANGE_PRESENCE, getResources().getBoolean(R.bool.manually_change_presence));
+		AlertDialog.Builder builder = new AlertDialog.Builder(this);
+		final DialogPresenceBinding binding = DataBindingUtil.inflate(getLayoutInflater(),R.layout.dialog_presence,null,false);
+		binding.show.setVisibility(manualStatus ? View.VISIBLE : View.GONE);
+		List<PresenceTemplate> templates = xmppConnectionService.getPresenceTemplates(mAccount);
+		PresenceTemplateAdapter presenceTemplateAdapter = new PresenceTemplateAdapter(this,R.layout.simple_list_item,templates);
+		binding.statusMessage.setAdapter(presenceTemplateAdapter);
+		binding.statusMessage.setOnItemClickListener((parent, view, position, id) -> {
+			PresenceTemplate template = (PresenceTemplate) parent.getItemAtPosition(position);
+			Log.d(Config.LOGTAG,"selected: "+template.getStatusMessage());
+		});
+		builder.setTitle(R.string.change_presence);
+		builder.setView(binding.getRoot());
+		builder.setNegativeButton(R.string.cancel,null);
+		builder.setPositiveButton(R.string.confirm,null);
+		builder.create().show();
 	}
 
 	@Override

src/main/java/eu/siacs/conversations/ui/ManageAccountActivity.java 🔗

@@ -128,12 +128,10 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
 		if (this.selectedAccount.isEnabled()) {
 			menu.findItem(R.id.mgmt_account_enable).setVisible(false);
 			menu.findItem(R.id.mgmt_account_announce_pgp).setVisible(Config.supportOpenPgp());
-			menu.findItem(R.id.mgmt_account_change_presence).setVisible(manuallyChangePresence());
 		} else {
 			menu.findItem(R.id.mgmt_account_disable).setVisible(false);
 			menu.findItem(R.id.mgmt_account_announce_pgp).setVisible(false);
 			menu.findItem(R.id.mgmt_account_publish_avatar).setVisible(false);
-			menu.findItem(R.id.mgmt_account_change_presence).setVisible(false);
 		}
 		menu.setHeaderTitle(this.selectedAccount.getJid().toBareJid().toString());
 	}
@@ -194,9 +192,6 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
 			case R.id.mgmt_account_announce_pgp:
 				publishOpenPGPPublicKey(selectedAccount);
 				return true;
-			case R.id.mgmt_account_change_presence:
-				changePresence(selectedAccount);
-				return true;
 			default:
 				return super.onContextItemSelected(item);
 		}
@@ -245,12 +240,6 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
 		}
 	}
 
-	private void changePresence(Account account) {
-		Intent intent = new Intent(this, SetPresenceActivity.class);
-		intent.putExtra(SetPresenceActivity.EXTRA_ACCOUNT,account.getJid().toBareJid().toString());
-		startActivity(intent);
-	}
-
 	public void onClickTglAccountState(Account account, boolean enable) {
 		if (enable) {
 			enableAccount(account);

src/main/java/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java 🔗

@@ -1,6 +1,7 @@
 package eu.siacs.conversations.ui.adapter;
 
 import android.content.Context;
+import android.support.annotation.NonNull;
 import android.widget.ArrayAdapter;
 import android.widget.Filter;
 
@@ -45,10 +46,9 @@ public class KnownHostsAdapter extends ArrayAdapter<String> {
 		}
 
 		@Override
-		protected void publishResults(CharSequence constraint,
-				FilterResults results) {
+		protected void publishResults(CharSequence constraint, FilterResults results) {
 			ArrayList filteredList = (ArrayList) results.values;
-			if (results != null && results.count > 0) {
+			if (results.count > 0) {
 				clear();
 				for (Object c : filteredList) {
 					add((String) c);
@@ -59,11 +59,12 @@ public class KnownHostsAdapter extends ArrayAdapter<String> {
 	};
 
 	public KnownHostsAdapter(Context context, int viewResourceId, List<String> mKnownHosts) {
-		super(context, viewResourceId, new ArrayList<String>());
+		super(context, viewResourceId, new ArrayList<>());
 		domains = new ArrayList<>(mKnownHosts);
 	}
 
 	@Override
+	@NonNull
 	public Filter getFilter() {
 		return domainFilter;
 	}

src/main/java/eu/siacs/conversations/ui/adapter/PresenceTemplateAdapter.java 🔗

@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2018, Daniel Gultsch All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package eu.siacs.conversations.ui.adapter;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.widget.ArrayAdapter;
+import android.widget.Filter;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import eu.siacs.conversations.entities.PresenceTemplate;
+
+
+public class PresenceTemplateAdapter extends ArrayAdapter<PresenceTemplate> {
+
+	private final List<PresenceTemplate> templates;
+
+	private final Filter filter = new Filter() {
+
+		@Override
+		protected FilterResults performFiltering(CharSequence constraint) {
+			FilterResults results = new FilterResults();
+			if (constraint == null || constraint.length() == 0) {
+				results.values = new ArrayList<>(templates);
+				results.count = templates.size();
+			} else {
+				ArrayList<PresenceTemplate> suggestions = new ArrayList<>();
+				final String needle = constraint.toString().trim().toLowerCase(Locale.getDefault());
+				for(PresenceTemplate template : templates) {
+					final String lc = template.getStatusMessage().toLowerCase(Locale.getDefault());
+					if (needle.isEmpty() || lc.contains(needle)) {
+						suggestions.add(template);
+					}
+				}
+				results.values = suggestions;
+				results.count = suggestions.size();
+			}
+			return results;
+		}
+
+		@Override
+		protected void publishResults(CharSequence constraint, FilterResults results) {
+			ArrayList filteredList = (ArrayList) results.values;
+			clear();
+			for (Object c : filteredList) {
+				add((PresenceTemplate) c);
+			}
+			notifyDataSetChanged();
+		}
+	};
+
+	public PresenceTemplateAdapter(@NonNull Context context, int resource, @NonNull List<PresenceTemplate> templates) {
+		super(context, resource, new ArrayList<>());
+		this.templates = new ArrayList<>(templates);
+	}
+
+	@Override
+	@NonNull
+	public Filter getFilter() {
+		return this.filter;
+	}
+}

src/main/java/eu/siacs/conversations/ui/widget/ImmediateAutoCompleteTextView.java 🔗

@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2018, Daniel Gultsch All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package eu.siacs.conversations.ui.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+public class ImmediateAutoCompleteTextView extends android.support.v7.widget.AppCompatAutoCompleteTextView {
+
+	public ImmediateAutoCompleteTextView(Context context, AttributeSet attrs) {
+		super(context, attrs);
+	}
+
+	public ImmediateAutoCompleteTextView(Context context, AttributeSet attrs, int defStyleAttr) {
+		super(context, attrs, defStyleAttr);
+	}
+
+	@Override
+	public boolean enoughToFilter() {
+		return true;
+	}
+}

src/main/res/layout/dialog_presence.xml 🔗

@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
+<LinearLayout android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:paddingLeft="?attr/dialog_horizontal_padding"
+              android:paddingRight="?attr/dialog_horizontal_padding"
+              android:paddingBottom="?attr/dialog_vertical_padding"
+              android:paddingTop="?attr/dialog_vertical_padding">
+
+    <RadioGroup
+        android:id="@+id/show"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="?attr/dialog_vertical_padding">
+
+        <RadioButton
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/presence_online"/>
+
+        <RadioButton
+            android:id="@+id/radioButton"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/presence_away"/>
+
+        <RadioButton
+            android:id="@+id/radioButton2"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/presence_xa"/>
+
+        <RadioButton
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/presence_dnd"/>
+    </RadioGroup>
+
+    <android.support.design.widget.TextInputLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+    <eu.siacs.conversations.ui.widget.ImmediateAutoCompleteTextView
+        android:id="@+id/status_message"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:ems="10"
+        android:hint="@string/status_message"
+        android:inputType="textPersonName"/>
+    </android.support.design.widget.TextInputLayout>
+
+</LinearLayout>
+</layout>

src/main/res/menu/editaccount.xml 🔗

@@ -1,6 +1,12 @@
 <menu xmlns:android="http://schemas.android.com/apk/res/android"
       xmlns:app="http://schemas.android.com/apk/res-auto">
 
+    <item
+        android:id="@+id/action_change_presence"
+        android:icon="@drawable/ic_announcement_white_24dp"
+        app:showAsAction="always"
+        android:title="@string/change_presence"/>
+
     <item
         android:id="@+id/action_share"
         android:icon="?attr/icon_share"
@@ -22,12 +28,6 @@
         </menu>
     </item>
 
-    <item
-        android:id="@+id/action_change_presence"
-        android:icon="@drawable/ic_announcement_white_24dp"
-        app:showAsAction="always"
-        android:title="@string/change_presence"/>
-
     <item
         android:id="@+id/action_show_block_list"
         app:showAsAction="never"

src/main/res/menu/manageaccounts_context.xml 🔗

@@ -5,9 +5,6 @@
     <item
         android:id="@+id/mgmt_account_enable"
         android:title="@string/mgmt_account_enable"/>
-    <item
-        android:id="@+id/mgmt_account_change_presence"
-        android:title="@string/change_presence"/>
     <item
         android:id="@+id/mgmt_account_publish_avatar"
         android:title="@string/mgmt_account_publish_avatar"/>