adapt group creation

display selected group members correctly

add items to create groups/verified-groups/contacts directly to the contact list

adapt main menu, create chat, help

forward from chat to group creation
This commit is contained in:
B. Petersen
2018-09-17 00:57:03 +02:00
parent 157f3498f9
commit ffb14ec088
17 changed files with 141 additions and 111 deletions
-21
View File
@@ -66,27 +66,6 @@
android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>
<RelativeLayout android:id="@+id/push_disabled"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minHeight="106dp"
android:padding="15dp"
android:gravity="center_vertical|center_horizontal"
android:background="#aa000000"
android:visibility="gone">
<TextView android:id="@+id/push_disabled_reason"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:padding="8dp"
android:background="#dd222222"
android:textColor="#ffeeeeee"
android:fontFamily="sans-serif-light"
android:textSize="16sp"
android:text="@string/GroupCreateActivity_contacts_dont_support_push" />
</RelativeLayout>
</RelativeLayout>
<org.thoughtcrime.securesms.components.PushRecipientsPanel android:id="@+id/recipients"
+2 -2
View File
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:title="@string/text_secure_normal__menu_new_group"
android:id="@+id/menu_new_group" />
<item android:title="@string/text_secure_normal__menu_new_chat"
android:id="@+id/menu_new_chat" />
<item android:title="@string/text_secure_normal__menu_clear_passphrase"
android:id="@+id/menu_clear_passphrase" />
+6
View File
@@ -1421,5 +1421,11 @@
<string name="loading">Loading …</string>
<string name="one_moment">One moment …</string>
<string name="new_conversation_activity__ask_start_chat_with">Chat with %1$s?</string>
<string name="contact_selection_list__new_group">New group</string>
<string name="contact_selection_list__new_verified_group">New verified group</string>
<string name="contact_selection_list__new_contact">New contact</string>
<string name="contact_selection_list__type_email_above">Type email address above</string>
<string name="text_secure_normal__menu_new_chat">New chat</string>
<string name="help_url">https://delta.chat/en/help</string>
</resources>
+6 -4
View File
@@ -25,10 +25,12 @@ package com.b44t.messenger;
public class DcContact {
public final static int DC_CONTACT_ID_SELF = 1;
public final static int DC_CONTACT_ID_DEVICE = 2;
public final static int DC_CONTACT_ID_LAST_SPECIAL = 9;
public final static int DC_CONTACT_ID_NEW_CONTACT = -1; // used by the UI, not valid to the core
public final static int DC_CONTACT_ID_SELF = 1;
public final static int DC_CONTACT_ID_DEVICE = 2;
public final static int DC_CONTACT_ID_LAST_SPECIAL = 9;
public final static int DC_CONTACT_ID_NEW_CONTACT = -1; // used by the UI, not valid to the core
public final static int DC_CONTACT_ID_NEW_GROUP = -2; // - " -
public final static int DC_CONTACT_ID_NEW_VERIFIED_GROUP = -3; // - " -
public DcContact(long contactCPtr) {
this.contactCPtr = contactCPtr;
@@ -112,10 +112,10 @@ public abstract class ContactSelectionActivity extends PassphraseRequiredActionB
}
@Override
public void onContactSelected(String number) {}
public void onContactSelected(int specialId, String number) {}
@Override
public void onContactDeselected(String number) {}
public void onContactDeselected(int specialId, String number) {}
private static class RefreshDirectoryTask extends AsyncTask<Context, Void, Void> {
@@ -280,11 +280,11 @@ public class ContactSelectionListFragment extends Fragment
if (!isMulti() || !selectedContacts.contains(contact.getNumber())) {
selectedContacts.add(contact.getNumber());
contact.setChecked(true);
if (onContactSelectedListener != null) onContactSelectedListener.onContactSelected(contact.getNumber());
if (onContactSelectedListener != null) onContactSelectedListener.onContactSelected(contact.getSpecialId(), contact.getNumber());
} else {
selectedContacts.remove(contact.getNumber());
contact.setChecked(false);
if (onContactSelectedListener != null) onContactSelectedListener.onContactDeselected(contact.getNumber());
if (onContactSelectedListener != null) onContactSelectedListener.onContactDeselected(contact.getSpecialId(), contact.getNumber());
}
}
}
@@ -298,8 +298,8 @@ public class ContactSelectionListFragment extends Fragment
}
public interface OnContactSelectedListener {
void onContactSelected(String number);
void onContactDeselected(String number);
void onContactSelected(int specialId, String number);
void onContactDeselected(int specialId, String number);
}
}
@@ -114,7 +114,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
inflater.inflate(R.menu.text_secure_normal, menu);
menu.findItem(R.id.menu_clear_passphrase).setVisible(!TextSecurePreferences.isPasswordDisabled(this));
menu.findItem(R.id.menu_clear_passphrase).setVisible(false/*!TextSecurePreferences.isPasswordDisabled(this)*/);
super.onPrepareOptionsMenu(menu);
return true;
@@ -169,7 +169,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
super.onOptionsItemSelected(item);
switch (item.getItemId()) {
case R.id.menu_new_group: createGroup(); return true;
case R.id.menu_new_chat: createChat(); return true;
case R.id.menu_settings: handleDisplaySettings(); return true;
case R.id.menu_clear_passphrase: handleClearPassphrase(); return true;
case R.id.menu_mark_all_read: handleMarkAllRead(); return true;
@@ -212,8 +212,8 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
else super.onBackPressed();
}
private void createGroup() {
Intent intent = new Intent(this, GroupCreateActivity.class);
private void createChat() {
Intent intent = new Intent(this, NewConversationActivity.class);
startActivity(intent);
}
@@ -246,7 +246,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
private void handleHelp() {
try {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://support.whispersystems.org")));
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.help_url))));
} catch (ActivityNotFoundException e) {
Toast.makeText(this, R.string.ConversationListActivity_there_is_no_browser_installed_on_your_device, Toast.LENGTH_LONG).show();
}
@@ -52,7 +52,6 @@ import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.groups.GroupManager;
import org.thoughtcrime.securesms.groups.GroupManager.GroupActionResult;
@@ -63,7 +62,6 @@ import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.SelectedRecipientsAdapter;
import org.thoughtcrime.securesms.util.SelectedRecipientsAdapter.OnRecipientDeletedListener;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
import org.whispersystems.libsignal.util.guava.Optional;
@@ -128,23 +126,10 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
updateViewState();
}
private void disableSignalGroupViews(int reasonResId) {
View pushDisabled = findViewById(R.id.push_disabled);
pushDisabled.setVisibility(View.VISIBLE);
((TextView) findViewById(R.id.push_disabled_reason)).setText(reasonResId);
avatar.setEnabled(false);
groupName.setEnabled(false);
}
private void enableSignalGroupViews() {
findViewById(R.id.push_disabled).setVisibility(View.GONE);
avatar.setEnabled(true);
groupName.setEnabled(true);
}
@SuppressWarnings("ConstantConditions")
private void updateViewState() {
enableSignalGroupViews();
avatar.setEnabled(true);
groupName.setEnabled(true);
getSupportActionBar().setTitle(groupToUpdate.isPresent()
? R.string.GroupCreateActivity_actionbar_edit_title
: R.string.GroupCreateActivity_actionbar_title);
@@ -55,30 +55,36 @@ public class NewConversationActivity extends ContactSelectionActivity {
}
@Override
public void onContactSelected(String addr) {
public void onContactSelected(int specialId, String addr) {
final DcContext dcContext = DcHelper.getContext(this);
final int contactId = dcContext.createContact(null, addr);
if (contactId == 0) {
Toast.makeText(this, R.string.bad_email_address, Toast.LENGTH_LONG).show();
return;
}
DcContact dcContact = dcContext.getContact(contactId);
int chatId = dcContext.getChatIdByContactId(contactId);
if (chatId == 0) {
new AlertDialog.Builder(this)
.setMessage(getString(R.string.new_conversation_activity__ask_start_chat_with, dcContact.getNameNAddr()))
.setCancelable(true)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
openConversation(dcContext.createChatByContactId(contactId));
}
}).show();
if(specialId==DcContact.DC_CONTACT_ID_NEW_GROUP || specialId==DcContact.DC_CONTACT_ID_NEW_VERIFIED_GROUP) {
Intent intent = new Intent(this, GroupCreateActivity.class);
startActivity(intent);
finish();
}
else {
openConversation(chatId);
final int contactId = dcContext.createContact(null, addr);
if (contactId == 0) {
Toast.makeText(this, R.string.bad_email_address, Toast.LENGTH_LONG).show();
return;
}
DcContact dcContact = dcContext.getContact(contactId);
int chatId = dcContext.getChatIdByContactId(contactId);
if (chatId == 0) {
new AlertDialog.Builder(this)
.setMessage(getString(R.string.new_conversation_activity__ask_start_chat_with, dcContact.getNameNAddr()))
.setCancelable(true)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
openConversation(dcContext.createChatByContactId(contactId));
}
}).show();
} else {
openConversation(chatId);
}
}
}
@@ -128,9 +134,11 @@ public class NewConversationActivity extends ContactSelectionActivity {
@Override
protected boolean onPrepareOptionsPanel(View view, Menu menu) {
/* currently not needed
MenuInflater inflater = this.getMenuInflater();
menu.clear();
inflater.inflate(R.menu.new_conversation_activity, menu);
*/
super.onPrepareOptionsMenu(menu);
return true;
}
@@ -272,14 +272,14 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
}
@Override
public void onContactSelected(String number) {
public void onContactSelected(int specialId, String number) {
Recipient recipient = Recipient.from(this, Address.fromExternal(this, number), true);
long existingThread = DatabaseFactory.getThreadDatabase(this).getThreadIdIfExistsFor(recipient);
createConversation(existingThread, recipient.getAddress(), ThreadDatabase.DistributionTypes.DEFAULT);
}
@Override
public void onContactDeselected(String number) {
public void onContactDeselected(int specialId, String number) {
}
@@ -57,7 +57,7 @@ public class AvatarImageView extends AppCompatImageView {
.into(this);
setAvatarClickHandler(recipient, quickContactEnabled);
} else {
setImageDrawable(new GeneratedContactPhoto("#").asDrawable(getContext(), ContactColors.UNKNOWN_COLOR.toConversationColor(getContext()), inverted));
setImageDrawable(new GeneratedContactPhoto("+").asDrawable(getContext(), ContactColors.UNKNOWN_COLOR.toConversationColor(getContext()), inverted));
super.setOnClickListener(listener);
}
}
@@ -28,14 +28,25 @@ public class DcContactsLoader extends AsyncLoader<DcContactsLoader.Ret> {
public @NonNull
DcContactsLoader.Ret loadInBackground() {
DcContext dcContext = DcHelper.getContext(getContext());
int[] ids = dcContext.getContacts(listflags, query);
int[] contact_ids = dcContext.getContacts(listflags, query);
if(query!=null) {
// show the "new" link also for partly typed e-mail addresses, so that the user knows he can continue
// 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) {
ids = ArrayUtils.appendInt(ids, DcContact.DC_CONTACT_ID_NEW_CONTACT);
contact_ids = ArrayUtils.appendInt(contact_ids, DcContact.DC_CONTACT_ID_NEW_CONTACT);
}
return new DcContactsLoader.Ret(contact_ids, query);
}
else {
// 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];
all_ids[0] = DcContact.DC_CONTACT_ID_NEW_GROUP;
all_ids[1] = DcContact.DC_CONTACT_ID_NEW_VERIFIED_GROUP;
for(int i=0; i<contact_ids.length; i++) {
all_ids[i+additional_items] = contact_ids[i];
}
return new DcContactsLoader.Ret(all_ids, query);
}
return new DcContactsLoader.Ret(ids, query);
}
public class Ret {
@@ -189,27 +189,37 @@ public class ContactSelectionListAdapter extends RecyclerView.Adapter
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int i) {
int id = dcContactList[i];
int type = id==DcContact.DC_CONTACT_ID_NEW_CONTACT? ContactsDatabase.NEW_TYPE : ContactsDatabase.NORMAL_TYPE;
int color = drawables.getColor(0, 0xff000000);
DcContact dcContact = null;
String label = null;
String name;
String addr;
String addr = null;
if(id==DcContact.DC_CONTACT_ID_NEW_CONTACT) {
name = context.getString(R.string.contact_selection_list__unknown_contact);
addr = query==null? "" : query;
label = "\u21e2";
name = context.getString(R.string.contact_selection_list__new_contact);
if(dcContext.mayBeValidAddr(query)) {
addr = query == null ? "" : query;
label = "\u2026";
}
else {
addr = context.getString(R.string.contact_selection_list__type_email_above);
}
}
else if(id==DcContact.DC_CONTACT_ID_NEW_GROUP) {
name = context.getString(R.string.contact_selection_list__new_group);
}
else if(id==DcContact.DC_CONTACT_ID_NEW_VERIFIED_GROUP) {
name = context.getString(R.string.contact_selection_list__new_verified_group);
}
else {
dcContact = id==DcContact.DC_CONTACT_ID_NEW_CONTACT? null : dcContext.getContact(id);
dcContact = dcContext.getContact(id);
name = dcContact.getDisplayName();
addr = dcContact.getAddr();
}
ViewHolder holder = (ViewHolder)viewHolder;
holder.unbind(glideRequests);
holder.bind(glideRequests, type, dcContact, name, addr, label, color, multiSelect);
holder.bind(glideRequests, id, dcContact, name, addr, label, color, multiSelect);
holder.setChecked(selectedContacts.contains(addr));
}
@@ -27,11 +27,13 @@ public class ContactSelectionListItem extends LinearLayout implements RecipientM
private static final String TAG = ContactSelectionListItem.class.getSimpleName();
private AvatarImageView contactPhotoImage;
private View numberContainer;
private TextView numberView;
private TextView nameView;
private TextView labelView;
private CheckBox checkBox;
private int specialId;
private String number;
private Recipient recipient;
private GlideRequests glideRequests;
@@ -48,6 +50,7 @@ public class ContactSelectionListItem extends LinearLayout implements RecipientM
protected void onFinishInflate() {
super.onFinishInflate();
this.contactPhotoImage = findViewById(R.id.contact_photo_image);
this.numberContainer = findViewById(R.id.number_container);
this.numberView = findViewById(R.id.number);
this.labelView = findViewById(R.id.label);
this.nameView = findViewById(R.id.name);
@@ -56,11 +59,12 @@ public class ContactSelectionListItem extends LinearLayout implements RecipientM
ViewUtil.setTextViewGravityStart(this.nameView, getContext());
}
public void set(@NonNull GlideRequests glideRequests, int type, DcContact contact, String name, String number, String label, int color, boolean multiSelect) {
public void set(@NonNull GlideRequests glideRequests, int specialId, DcContact contact, String name, String number, String label, int color, boolean multiSelect) {
this.glideRequests = glideRequests;
this.specialId = specialId;
this.number = number;
if(type == ContactsDatabase.NEW_TYPE) {
if(specialId==DcContact.DC_CONTACT_ID_NEW_CONTACT || specialId==DcContact.DC_CONTACT_ID_NEW_GROUP || specialId==DcContact.DC_CONTACT_ID_NEW_VERIFIED_GROUP) {
this.recipient = null;
this.contactPhotoImage.setAvatar(glideRequests, Recipient.from(getContext(), Address.UNKNOWN, true), false);
}
@@ -76,7 +80,7 @@ public class ContactSelectionListItem extends LinearLayout implements RecipientM
this.numberView.setTextColor(color);
this.contactPhotoImage.setAvatar(glideRequests, recipient, false);
setText(type, name, number, label);
setText(name, number, label);
if (multiSelect) this.checkBox.setVisibility(View.VISIBLE);
else this.checkBox.setVisibility(View.GONE);
@@ -95,23 +99,22 @@ public class ContactSelectionListItem extends LinearLayout implements RecipientM
contactPhotoImage.clear(glideRequests);
}
private void setText(int type, String name, String number, String label) {
if (number == null || number.isEmpty() || GroupUtil.isEncodedGroup(number)) {
this.nameView.setEnabled(false);
this.numberView.setText("");
this.labelView.setVisibility(View.GONE);
} else if (type == ContactsDatabase.PUSH_TYPE) {
this.numberView.setText(number);
this.nameView.setEnabled(true);
this.labelView.setVisibility(View.GONE);
} else {
this.numberView.setText(number);
this.nameView.setEnabled(true);
this.labelView.setText(label);
this.labelView.setVisibility(View.VISIBLE);
}
private void setText(String name, String number, String label) {
this.nameView.setEnabled(true);
this.nameView.setText(name==null? "#" : name);
this.nameView.setText(name);
if(number!=null) {
this.numberView.setText(number == null ? "" : number);
this.labelView.setText(label==null? "" : label);
this.numberContainer.setVisibility(View.VISIBLE);
}
else {
this.numberContainer.setVisibility(View.GONE);
}
}
public int getSpecialId() {
return specialId;
}
public String getNumber() {
@@ -136,6 +136,8 @@ public class Address implements Parcelable, Comparable<Address> {
public boolean isDcChat() { return address.startsWith("dc:"); };
public boolean isDcContact() { return address.startsWith("dcc:"); };
public @NonNull String toGroupString() {
if (!isGroup()) throw new AssertionError("Not group: " + address);
return address;
@@ -156,6 +158,11 @@ public class Address implements Parcelable, Comparable<Address> {
return Integer.valueOf(address.substring("dc:".length()));
}
public int getDcContactId() {
if(!isDcContact()) throw new AssertionError("Not dc contact: " + address);
return Integer.valueOf(address.substring("dcc:".length()));
}
@Override
public String toString() {
return address;
@@ -29,6 +29,8 @@ import com.annimon.stream.function.Consumer;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.connect.ApplicationDcContext;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.FallbackContactPhoto;
@@ -96,6 +98,16 @@ public class Recipient implements RecipientModifiedListener {
@SuppressWarnings("ConstantConditions")
public static @NonNull Recipient from(@NonNull Context context, @NonNull Address address, boolean asynchronous) {
if (address == null) throw new AssertionError(address);
ApplicationDcContext dcContext = DcHelper.getContext(context);
if(address.isDcContact()) {
return dcContext.getRecipient(dcContext.getContact(address.getDcContactId()));
}
else if(address.isEmail()) {
int contactId = dcContext.lookupContactIdByAddr(address.toEmailString());
if(contactId!=0) {
return dcContext.getRecipient(dcContext.getContact(contactId));
}
}
return provider.getRecipient(context, address, Optional.absent(), Optional.absent(), asynchronous);
}
@@ -10,7 +10,11 @@ import android.widget.BaseAdapter;
import android.widget.ImageButton;
import android.widget.TextView;
import com.b44t.messenger.DcContact;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.connect.ApplicationDcContext;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.whispersystems.libsignal.util.guava.Optional;
@@ -25,6 +29,7 @@ public class SelectedRecipientsAdapter extends BaseAdapter {
@NonNull private Context context;
@Nullable private OnRecipientDeletedListener onRecipientDeletedListener;
@NonNull private List<RecipientWrapper> recipients;
@NonNull private final ApplicationDcContext dcContext;
public SelectedRecipientsAdapter(@NonNull Context context) {
this(context, Collections.<Recipient>emptyList());
@@ -34,6 +39,7 @@ public class SelectedRecipientsAdapter extends BaseAdapter {
@NonNull Collection<Recipient> existingRecipients)
{
this.context = context;
this.dcContext = DcHelper.getContext(context);
this.recipients = wrapExistingMembers(existingRecipients);
}
@@ -93,13 +99,14 @@ 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());
TextView name = (TextView) v.findViewById(R.id.name);
TextView phone = (TextView) v.findViewById(R.id.phone);
ImageButton delete = (ImageButton) v.findViewById(R.id.delete);
name.setText(p.getName());
phone.setText(p.getAddress().serialize());
name.setText(dcContact.getDisplayName());
phone.setText(dcContact.getAddr());
delete.setVisibility(modifiable ? View.VISIBLE : View.GONE);
delete.setOnClickListener(new View.OnClickListener() {
@Override