From c5786488e8f1b5135bad5ee4038d511fd9cbe62e Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Mon, 17 Sep 2018 17:22:31 +0200 Subject: [PATCH] create groups and verified groups create groups and verified groups --- jni/dc_wrapper.c | 4 +- res/values/strings.xml | 2 + src/com/b44t/messenger/DcContext.java | 2 +- .../ContactSelectionListFragment.java | 21 +- .../securesms/GroupCreateActivity.java | 198 +++++++----------- .../securesms/NewConversationActivity.java | 1 + .../securesms/connect/DcContactsLoader.java | 19 +- .../util/SelectedRecipientsAdapter.java | 6 +- 8 files changed, 112 insertions(+), 141 deletions(-) diff --git a/jni/dc_wrapper.c b/jni/dc_wrapper.c index 72b933137..34110ae11 100644 --- a/jni/dc_wrapper.c +++ b/jni/dc_wrapper.c @@ -434,9 +434,9 @@ JNIEXPORT jint Java_com_b44t_messenger_DcContext_createGroupChat(JNIEnv *env, jo } -JNIEXPORT jint Java_com_b44t_messenger_DcContext_isContactInChat(JNIEnv *env, jobject obj, jint chat_id, jint contact_id) +JNIEXPORT jboolean Java_com_b44t_messenger_DcContext_isContactInChat(JNIEnv *env, jobject obj, jint chat_id, jint contact_id) { - return (jint)dc_is_contact_in_chat(get_dc_context(env, obj), chat_id, contact_id); + return (jboolean)dc_is_contact_in_chat(get_dc_context(env, obj), chat_id, contact_id); } diff --git a/res/values/strings.xml b/res/values/strings.xml index 6f0d06fac..821e2578d 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -316,6 +316,7 @@ New group + New verified group Edit group Group name New MMS group @@ -1427,5 +1428,6 @@ Type email address above New chat https://delta.chat/en/help + Please enter a name for the group. diff --git a/src/com/b44t/messenger/DcContext.java b/src/com/b44t/messenger/DcContext.java index 3d3e4e66e..086191287 100644 --- a/src/com/b44t/messenger/DcContext.java +++ b/src/com/b44t/messenger/DcContext.java @@ -119,7 +119,7 @@ public class DcContext { public native int createChatByContactId(int contact_id); public native int createChatByMsgId (int msg_id); public native int createGroupChat (boolean verified, String name); - public native int isContactInChat (int chat_id, int contact_id); + public native boolean isContactInChat (int chat_id, int contact_id); public native int addContactToChat (int chat_id, int contact_id); public native int removeContactFromChat(int chat_id, int contact_id); public native void setDraft (int chat_id, String draft/*null=delete*/); diff --git a/src/org/thoughtcrime/securesms/ContactSelectionListFragment.java b/src/org/thoughtcrime/securesms/ContactSelectionListFragment.java index bdeaa18fe..67e770b1e 100644 --- a/src/org/thoughtcrime/securesms/ContactSelectionListFragment.java +++ b/src/org/thoughtcrime/securesms/ContactSelectionListFragment.java @@ -38,6 +38,7 @@ import android.widget.Button; import android.widget.TextView; import android.widget.Toast; +import com.b44t.messenger.DcContext; import com.pnikosis.materialishprogress.ProgressWheel; import org.thoughtcrime.securesms.components.RecyclerViewFastScroller; @@ -68,10 +69,11 @@ public class ContactSelectionListFragment extends Fragment @SuppressWarnings("unused") private static final String TAG = ContactSelectionListFragment.class.getSimpleName(); - public static final String DISPLAY_MODE = "display_mode"; - public static final String MULTI_SELECT = "multi_select"; - public static final String REFRESHABLE = "refreshable"; - public static final String RECENTS = "recents"; + public static final String DISPLAY_MODE = "display_mode"; + public static final String MULTI_SELECT = "multi_select"; + public static final String REFRESHABLE = "refreshable"; + public static final String RECENTS = "recents"; + public static final String SELECT_VERIFIED_EXTRA = "select_verified"; private TextView emptyText; private Set selectedContacts; @@ -156,6 +158,10 @@ public class ContactSelectionListFragment extends Fragment return getActivity().getIntent().getBooleanExtra(MULTI_SELECT, false); } + private boolean isSelectVerfied() { + return getActivity().getIntent().getBooleanExtra(SELECT_VERIFIED_EXTRA, false); + } + private void initializeCursor() { ContactSelectionListAdapter adapter = new ContactSelectionListAdapter(getActivity(), GlideApp.with(this), @@ -212,7 +218,12 @@ public class ContactSelectionListFragment extends Fragment @Override public Loader onCreateLoader(int id, Bundle args) { - return new DcContactsLoader(getActivity(), 0, cursorFilter); + boolean addCreateGroupLinks = !isMulti(); + int listflags = 0; + if(isSelectVerfied()) { + listflags = DcContext.DC_GCL_VERIFIED_ONLY; + } + return new DcContactsLoader(getActivity(), listflags, cursorFilter, addCreateGroupLinks); } @Override diff --git a/src/org/thoughtcrime/securesms/GroupCreateActivity.java b/src/org/thoughtcrime/securesms/GroupCreateActivity.java index 9b06a2d08..685256807 100644 --- a/src/org/thoughtcrime/securesms/GroupCreateActivity.java +++ b/src/org/thoughtcrime/securesms/GroupCreateActivity.java @@ -25,8 +25,6 @@ import android.os.AsyncTask; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.text.TextUtils; -import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; @@ -44,6 +42,8 @@ import com.soundcloud.android.crop.Crop; import org.thoughtcrime.securesms.components.PushRecipientsPanel; import org.thoughtcrime.securesms.components.PushRecipientsPanel.RecipientsPanelChangedListener; +import org.thoughtcrime.securesms.connect.ApplicationDcContext; +import org.thoughtcrime.securesms.connect.DcHelper; import org.thoughtcrime.securesms.contacts.ContactsCursorLoader.DisplayMode; import org.thoughtcrime.securesms.contacts.RecipientsEditor; import org.thoughtcrime.securesms.contacts.avatars.ContactColors; @@ -53,8 +53,6 @@ import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.GroupDatabase; import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord; import org.thoughtcrime.securesms.database.ThreadDatabase; -import org.thoughtcrime.securesms.groups.GroupManager; -import org.thoughtcrime.securesms.groups.GroupManager.GroupActionResult; import org.thoughtcrime.securesms.mms.GlideApp; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.BitmapUtil; @@ -65,7 +63,6 @@ import org.thoughtcrime.securesms.util.SelectedRecipientsAdapter.OnRecipientDele import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask; import org.whispersystems.libsignal.util.guava.Optional; -import org.whispersystems.signalservice.api.util.InvalidNumberException; import java.io.File; import java.util.Collection; @@ -88,6 +85,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity public static final String GROUP_ADDRESS_EXTRA = "group_recipient"; public static final String GROUP_THREAD_EXTRA = "group_thread"; + public static final String GROUP_CREATE_VERIFIED_EXTRA = "group_create_verified"; private final DynamicTheme dynamicTheme = new DynamicTheme(); private final DynamicLanguage dynamicLanguage = new DynamicLanguage(); @@ -95,6 +93,9 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity private static final int PICK_CONTACT = 1; public static final int AVATAR_SIZE = 210; + private ApplicationDcContext dcContext; + + private boolean createVerified; private EditText groupName; private ListView lv; private ImageView avatar; @@ -111,8 +112,10 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity @Override protected void onCreate(Bundle state, boolean ready) { + dcContext = DcHelper.getContext(this); setContentView(R.layout.group_create_activity); //noinspection ConstantConditions + createVerified = getIntent().getBooleanExtra(GROUP_CREATE_VERIFIED_EXTRA, false); getSupportActionBar().setDisplayHomeAsUpEnabled(true); initializeResources(); initializeExistingGroup(); @@ -130,9 +133,18 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity private void updateViewState() { avatar.setEnabled(true); groupName.setEnabled(true); - getSupportActionBar().setTitle(groupToUpdate.isPresent() - ? R.string.GroupCreateActivity_actionbar_edit_title - : R.string.GroupCreateActivity_actionbar_title); + + String title; + if(groupToUpdate.isPresent()) { + title = getString(R.string.GroupCreateActivity_actionbar_edit_title); + } + else if(createVerified) { + title = getString(R.string.GroupCreateActivity_actionbar_verified_title); + } + else { + title = getString(R.string.GroupCreateActivity_actionbar_title); + } + getSupportActionBar().setTitle(title); } private void addSelectedContacts(@NonNull Recipient... recipients) { @@ -206,25 +218,47 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity } private void handleGroupCreate() { - if (getAdapter().getCount() < 1) { - Log.i(TAG, getString(R.string.GroupCreateActivity_contacts_no_members)); - Toast.makeText(getApplicationContext(), R.string.GroupCreateActivity_contacts_no_members, Toast.LENGTH_SHORT).show(); + String groupName = getGroupName(); + if(groupName==null) { + Toast.makeText(this, getString(R.string.GroupCreateActivity_please_enter_group_name), Toast.LENGTH_LONG).show(); return; } - new CreateSignalGroupTask(this, avatarBmp, getGroupName(), getAdapter().getRecipients()).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + + int chatId = dcContext.createGroupChat(createVerified, groupName); + + Set members = getAdapter().getRecipients(); + for(Recipient member : members) { + Address address = member.getAddress(); + if(address.isDcContact()) { + int contactId = address.getDcContactId(); + dcContext.addContactToChat(chatId, contactId); + } + } + + // TODO: handle avatarBmp + + Intent intent = new Intent(this, ConversationActivity.class); + intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, (long)chatId); + intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, ThreadDatabase.DistributionTypes.DEFAULT); + intent.putExtra(ConversationActivity.ADDRESS_EXTRA, Address.fromChat(dcContext.getChat((int)chatId))); + startActivity(intent); + finish(); } private void handleGroupUpdate() { - new UpdateSignalGroupTask(this, groupToUpdate.get().id, avatarBmp, - getGroupName(), getAdapter().getRecipients()).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } + int chatId = 0;// TODO: get correct id from groupToUpdate.get().id; or so + + String groupName = getGroupName(); + if(groupName!=null) { + dcContext.setChatName(chatId, groupName); + } + + // TODO: compare dcContext.getChatContacts(chatId); against getAdapter().getRecipients(); + // and add/remove contacts + + + // TODO: handle avatarBmp - private void handleOpenConversation(long threadId, Recipient recipient) { - Intent intent = new Intent(this, ConversationActivity.class); - intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId); - intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, ThreadDatabase.DistributionTypes.DEFAULT); - intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.getAddress()); - startActivity(intent); finish(); } @@ -233,7 +267,14 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity } private @Nullable String getGroupName() { - return groupName.getText() != null ? groupName.getText().toString() : null; + String ret = groupName.getText() != null ? groupName.getText().toString() : null; + if(ret!=null) { + ret = ret.trim(); + if(ret.isEmpty()) { + ret = null; + } + } + return ret; } @Override @@ -280,6 +321,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity @Override public void onClick(View v) { Intent intent = new Intent(GroupCreateActivity.this, PushContactSelectionActivity.class); + intent.putExtra(ContactSelectionListFragment.SELECT_VERIFIED_EXTRA, createVerified); if (groupToUpdate.isPresent()) { intent.putExtra(ContactSelectionListFragment.DISPLAY_MODE, DisplayMode.FLAG_PUSH); } else { @@ -289,105 +331,6 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity } } - private abstract static class SignalGroupTask extends AsyncTask> { - - protected GroupCreateActivity activity; - protected Bitmap avatar; - protected Set members; - protected String name; - - public SignalGroupTask(GroupCreateActivity activity, - Bitmap avatar, - String name, - Set members) - { - this.activity = activity; - this.avatar = avatar; - this.name = name; - this.members = members; - } - - @Override - protected void onPreExecute() { - activity.findViewById(R.id.group_details_layout).setVisibility(View.GONE); - activity.findViewById(R.id.creating_group_layout).setVisibility(View.VISIBLE); - activity.findViewById(R.id.menu_create_group).setVisibility(View.GONE); - final int titleResId = activity.groupToUpdate.isPresent() - ? R.string.GroupCreateActivity_updating_group - : R.string.GroupCreateActivity_creating_group; - activity.creatingText.setText(activity.getString(titleResId, activity.getGroupName())); - } - - @Override - protected void onPostExecute(Optional groupActionResultOptional) { - if (activity.isFinishing()) return; - activity.findViewById(R.id.group_details_layout).setVisibility(View.VISIBLE); - activity.findViewById(R.id.creating_group_layout).setVisibility(View.GONE); - activity.findViewById(R.id.menu_create_group).setVisibility(View.VISIBLE); - } - } - - private static class CreateSignalGroupTask extends SignalGroupTask { - public CreateSignalGroupTask(GroupCreateActivity activity, Bitmap avatar, String name, Set members) { - super(activity, avatar, name, members); - } - - @Override - protected Optional doInBackground(Void... aVoid) { - return Optional.of(GroupManager.createGroup(activity, members, avatar, name, false)); - } - - @Override - protected void onPostExecute(Optional result) { - if (result.isPresent() && result.get().getThreadId() > -1) { - if (!activity.isFinishing()) { - activity.handleOpenConversation(result.get().getThreadId(), result.get().getGroupRecipient()); - } - } else { - super.onPostExecute(result); - Toast.makeText(activity.getApplicationContext(), - R.string.GroupCreateActivity_contacts_invalid_number, Toast.LENGTH_LONG).show(); - } - } - } - - private static class UpdateSignalGroupTask extends SignalGroupTask { - private String groupId; - - public UpdateSignalGroupTask(GroupCreateActivity activity, String groupId, - Bitmap avatar, String name, Set members) - { - super(activity, avatar, name, members); - this.groupId = groupId; - } - - @Override - protected Optional doInBackground(Void... aVoid) { - try { - return Optional.of(GroupManager.updateGroup(activity, groupId, members, avatar, name)); - } catch (InvalidNumberException e) { - return Optional.absent(); - } - } - - @Override - protected void onPostExecute(Optional result) { - if (result.isPresent() && result.get().getThreadId() > -1) { - if (!activity.isFinishing()) { - Intent intent = activity.getIntent(); - intent.putExtra(GROUP_THREAD_EXTRA, result.get().getThreadId()); - intent.putExtra(GROUP_ADDRESS_EXTRA, result.get().getGroupRecipient().getAddress()); - activity.setResult(RESULT_OK, intent); - activity.finish(); - } - } else { - super.onPostExecute(result); - Toast.makeText(activity.getApplicationContext(), - R.string.GroupCreateActivity_contacts_invalid_number, Toast.LENGTH_LONG).show(); - } - } - } - private static class AddMembersTask extends AsyncTask> { static class Result { Optional recipient; @@ -418,12 +361,17 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity @Override protected void onPostExecute(List results) { if (activity.isFinishing()) return; + ApplicationDcContext dcContext = DcHelper.getContext(activity); for (Result result : results) { - if (result.recipient.isPresent()) { - activity.getAdapter().add(result.recipient.get(), true); - } else { - Toast.makeText(activity, result.reason, Toast.LENGTH_SHORT).show(); + Recipient recipient = result.recipient.get(); + Address address = recipient.getAddress(); + if(address.isDcContact()) { + activity.getAdapter().add(recipient, true); + } + else if(dcContext.mayBeValidAddr(address.toString())) { + int contactId = DcHelper.getContext(activity).createContact(null, address.toString()); + activity.getAdapter().add(dcContext.getRecipient(dcContext.getContact(contactId)), true); } } activity.updateViewState(); diff --git a/src/org/thoughtcrime/securesms/NewConversationActivity.java b/src/org/thoughtcrime/securesms/NewConversationActivity.java index bcdd134a9..07a10d803 100644 --- a/src/org/thoughtcrime/securesms/NewConversationActivity.java +++ b/src/org/thoughtcrime/securesms/NewConversationActivity.java @@ -59,6 +59,7 @@ public class NewConversationActivity extends ContactSelectionActivity { final DcContext dcContext = DcHelper.getContext(this); if(specialId==DcContact.DC_CONTACT_ID_NEW_GROUP || specialId==DcContact.DC_CONTACT_ID_NEW_VERIFIED_GROUP) { Intent intent = new Intent(this, GroupCreateActivity.class); + intent.putExtra(GroupCreateActivity.GROUP_CREATE_VERIFIED_EXTRA, specialId==DcContact.DC_CONTACT_ID_NEW_VERIFIED_GROUP); startActivity(intent); finish(); } diff --git a/src/org/thoughtcrime/securesms/connect/DcContactsLoader.java b/src/org/thoughtcrime/securesms/connect/DcContactsLoader.java index 3b005274d..46f772854 100644 --- a/src/org/thoughtcrime/securesms/connect/DcContactsLoader.java +++ b/src/org/thoughtcrime/securesms/connect/DcContactsLoader.java @@ -15,13 +15,15 @@ public class DcContactsLoader extends AsyncLoader { private static final String TAG = DcContactsLoader.class.getName(); - private final int listflags; - private final String query; + private final int listflags; + private final String query; + private final boolean addCreateGroupLinks; - public DcContactsLoader(Context context, int listflags, String query) { + public DcContactsLoader(Context context, int listflags, String query, boolean addCreateGroupLinks) { super(context); - this.listflags = listflags; - this.query = (query==null||query.isEmpty())? null : query; + this.listflags = listflags; + this.query = (query==null||query.isEmpty())? null : query; + this.addCreateGroupLinks = addCreateGroupLinks; } @Override @@ -31,12 +33,12 @@ public class DcContactsLoader extends AsyncLoader { int[] contact_ids = dcContext.getContacts(listflags, query); if(query!=null) { // show the "new contact" link also for partly typed e-mail addresses, so that the user knows he can continue - if( dcContext.lookupContactIdByAddr(query)==0) { + if (dcContext.lookupContactIdByAddr(query)==0 && (listflags&DcContext.DC_GCL_VERIFIED_ONLY)==0) { contact_ids = ArrayUtils.appendInt(contact_ids, DcContact.DC_CONTACT_ID_NEW_CONTACT); } return new DcContactsLoader.Ret(contact_ids, query); } - else { + else if(addCreateGroupLinks) { // add "new group" and "new verified group" links final int additional_items = 2; // if someone knows an easier way to prepend sth. to int[] please pr :) int all_ids[] = new int[contact_ids.length+additional_items]; @@ -47,6 +49,9 @@ public class DcContactsLoader extends AsyncLoader { } return new DcContactsLoader.Ret(all_ids, query); } + else { + return new DcContactsLoader.Ret(contact_ids, query); + } } public class Ret { diff --git a/src/org/thoughtcrime/securesms/util/SelectedRecipientsAdapter.java b/src/org/thoughtcrime/securesms/util/SelectedRecipientsAdapter.java index 6ddded9bf..929fc1bf9 100644 --- a/src/org/thoughtcrime/securesms/util/SelectedRecipientsAdapter.java +++ b/src/org/thoughtcrime/securesms/util/SelectedRecipientsAdapter.java @@ -99,7 +99,11 @@ public class SelectedRecipientsAdapter extends BaseAdapter { final RecipientWrapper rw = (RecipientWrapper)getItem(position); final Recipient p = rw.getRecipient(); final boolean modifiable = rw.isModifiable(); - final DcContact dcContact = dcContext.getContact(p.getAddress().getDcContactId()); + DcContact dcContact = new DcContact(0); + + if(p.getAddress().isDcContact()) { + dcContact = dcContext.getContact(p.getAddress().getDcContactId()); + } TextView name = (TextView) v.findViewById(R.id.name); TextView phone = (TextView) v.findViewById(R.id.phone);