From 8cd59bb944ed9373eb04420a32f3b7cfce0a8956 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 15 Mar 2014 15:13:35 +0100 Subject: better muc invitations. clearified the creation of ad hoc mucs with an alert dialog --- .../siacs/conversations/ui/ContactsActivity.java | 608 +++++++++++++++++++++ 1 file changed, 608 insertions(+) create mode 100644 src/eu/siacs/conversations/ui/ContactsActivity.java (limited to 'src/eu/siacs/conversations/ui/ContactsActivity.java') diff --git a/src/eu/siacs/conversations/ui/ContactsActivity.java b/src/eu/siacs/conversations/ui/ContactsActivity.java new file mode 100644 index 000000000..1bd6e72fa --- /dev/null +++ b/src/eu/siacs/conversations/ui/ContactsActivity.java @@ -0,0 +1,608 @@ +package eu.siacs.conversations.ui; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import eu.siacs.conversations.R; +import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.entities.Contact; +import eu.siacs.conversations.entities.Conversation; +import eu.siacs.conversations.utils.CryptoHelper; +import eu.siacs.conversations.utils.UIHelper; +import eu.siacs.conversations.utils.Validator; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.text.Editable; +import android.text.TextWatcher; +import android.util.Log; +import android.util.SparseBooleanArray; +import android.view.ActionMode; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AbsListView; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.AdapterView.OnItemLongClickListener; +import android.widget.ArrayAdapter; +import android.widget.EditText; +import android.widget.ListView; +import android.widget.ProgressBar; +import android.widget.TextView; +import android.widget.ImageView; +import android.widget.Toast; +import android.annotation.SuppressLint; +import android.app.AlertDialog; +import android.app.AlertDialog.Builder; +import android.content.Context; +import android.content.DialogInterface; +import android.content.SharedPreferences; +import android.content.DialogInterface.OnClickListener; +import android.content.Intent; + +public class ContactsActivity extends XmppActivity { + + protected List rosterContacts = new ArrayList(); + protected List aggregatedContacts = new ArrayList(); + protected ListView contactsView; + protected ArrayAdapter contactsAdapter; + + protected EditText search; + protected String searchString = ""; + private TextView contactsHeader; + private List accounts; + private List selectedContacts = new ArrayList(); + + private ContactsActivity activity = this; + + private boolean useSubject = true; + private boolean isActionMode = false; + private boolean inviteIntent = false; + private ActionMode actionMode = null; + private AbsListView.MultiChoiceModeListener actionModeCallback = new AbsListView.MultiChoiceModeListener() { + + @Override + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + menu.clear(); + MenuInflater inflater = mode.getMenuInflater(); + inflater.inflate(R.menu.newconversation_context, menu); + SparseBooleanArray checkedItems = contactsView + .getCheckedItemPositions(); + selectedContacts.clear(); + for (int i = 0; i < aggregatedContacts.size(); ++i) { + if (checkedItems.get(i, false)) { + selectedContacts.add(aggregatedContacts.get(i)); + } + } + if (selectedContacts.size() == 0) { + menu.findItem(R.id.action_start_conversation).setVisible(false); + menu.findItem(R.id.action_contact_details).setVisible(false); + menu.findItem(R.id.action_invite).setVisible(false); + menu.findItem(R.id.action_invite_to_existing).setVisible(false); + } else if ((selectedContacts.size() == 1) && (!inviteIntent)) { + menu.findItem(R.id.action_start_conversation).setVisible(true); + menu.findItem(R.id.action_contact_details).setVisible(true); + menu.findItem(R.id.action_invite).setVisible(false); + menu.findItem(R.id.action_invite_to_existing).setVisible(true); + } else if (!inviteIntent) { + menu.findItem(R.id.action_start_conversation).setVisible(true); + menu.findItem(R.id.action_contact_details).setVisible(false); + menu.findItem(R.id.action_invite).setVisible(false); + menu.findItem(R.id.action_invite_to_existing).setVisible(true); + } else { + menu.findItem(R.id.action_invite).setVisible(true); + menu.findItem(R.id.action_start_conversation).setVisible(false); + menu.findItem(R.id.action_contact_details).setVisible(false); + menu.findItem(R.id.action_invite_to_existing).setVisible(false); + } + return true; + } + + @Override + public void onDestroyActionMode(ActionMode mode) { + // TODO Auto-generated method stub + + } + + @Override + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + return true; + } + + @Override + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + switch (item.getItemId()) { + case R.id.action_start_conversation: + if (selectedContacts.size() == 1) { + startConversation(selectedContacts.get(0)); + } else { + startConference(); + } + break; + case R.id.action_contact_details: + Intent intent = new Intent(getApplicationContext(), + ContactDetailsActivity.class); + intent.setAction(ContactDetailsActivity.ACTION_VIEW_CONTACT); + intent.putExtra("uuid", selectedContacts.get(0).getUuid()); + startActivity(intent); + break; + case R.id.action_invite: + invite(); + break; + case R.id.action_invite_to_existing: + final List mucs = new ArrayList(); + for(Conversation conv : xmppConnectionService.getConversations()) { + if (conv.getMode() == Conversation.MODE_MULTI) { + mucs.add(conv); + } + } + AlertDialog.Builder builder = new AlertDialog.Builder(activity); + builder.setTitle(getString(R.string.invite_contacts_to_existing)); + if (mucs.size() >= 1) { + String[] options = new String[mucs.size()]; + for(int i = 0; i < options.length; ++i) { + options[i] = mucs.get(i).getName(useSubject); + } + builder.setItems(options, new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + Conversation conversation = mucs.get(which); + if (isOnline(conversation.getAccount())) { + xmppConnectionService.inviteToConference(conversation, selectedContacts); + Toast.makeText(activity, getString(R.string.invitation_sent), Toast.LENGTH_SHORT).show(); + actionMode.finish(); + } + } + }); + } else { + builder.setMessage(getString(R.string.no_open_mucs)); + } + builder.setNegativeButton(getString(R.string.cancel),null); + builder.create().show(); + break; + default: + break; + } + return false; + } + + @Override + public void onItemCheckedStateChanged(ActionMode mode, int position, + long id, boolean checked) { + } + }; + + private boolean isOnline(Account account) { + if (account.getStatus() == Account.STATUS_ONLINE) { + return true; + } else { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(getString(R.string.account_offline)); + builder.setMessage(getString(R.string.cant_invite_while_offline)); + builder.setNegativeButton("OK", null); + builder.setIconAttribute(android.R.attr.alertDialogIcon); + builder.create().show(); + return false; + } + } + + private void invite() { + List conversations = xmppConnectionService + .getConversations(); + Conversation conversation = null; + for (Conversation tmpConversation : conversations) { + if (tmpConversation.getUuid().equals( + getIntent().getStringExtra("uuid"))) { + conversation = tmpConversation; + break; + } + } + if (conversation != null) { + xmppConnectionService.inviteToConference(conversation, + selectedContacts); + } + finish(); + } + + private void startConference() { + if (accounts.size() > 1) { + getAccountChooser(new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + startConference(accounts.get(which)); + } + }).show(); + } else { + startConference(accounts.get(0)); + } + + } + + private void startConference(final Account account) { + if (isOnline(account)) { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(getString(R.string.new_conference)); + builder.setMessage(getString(R.string.new_conference_explained)); + builder.setNegativeButton(getString(R.string.cancel), null); + builder.setPositiveButton(getString(R.string.create_invite), + new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + String mucName = CryptoHelper.randomMucName(); + String serverName = account.getXmppConnection() + .getMucServer(); + String jid = mucName + "@" + serverName; + Conversation conversation = xmppConnectionService + .findOrCreateConversation(account, jid, true); + StringBuilder subject = new StringBuilder(); + subject.append(account.getUsername() + ", "); + for (int i = 0; i < selectedContacts.size(); ++i) { + if (i + 1 != selectedContacts.size()) { + subject.append(selectedContacts.get(i) + .getDisplayName() + ", "); + } else { + subject.append(selectedContacts.get(i) + .getDisplayName()); + } + } + xmppConnectionService.sendConversationSubject( + conversation, subject.toString()); + xmppConnectionService.inviteToConference(conversation, + selectedContacts); + switchToConversation(conversation, null); + } + }); + builder.create().show(); + } + } + + protected void updateAggregatedContacts() { + + aggregatedContacts.clear(); + for (Contact contact : rosterContacts) { + if (contact.match(searchString)) + aggregatedContacts.add(contact); + } + + Collections.sort(aggregatedContacts, new Comparator() { + + @SuppressLint("DefaultLocale") + @Override + public int compare(Contact lhs, Contact rhs) { + return lhs.getDisplayName().toLowerCase() + .compareTo(rhs.getDisplayName().toLowerCase()); + } + }); + + if (aggregatedContacts.size() == 0) { + + if (Validator.isValidJid(searchString)) { + String name = searchString.split("@")[0]; + Contact newContact = new Contact(null, name, searchString, null); + newContact.flagAsNotInRoster(); + aggregatedContacts.add(newContact); + contactsHeader.setText("Create new contact"); + } else { + contactsHeader.setText("Contacts"); + } + } else { + contactsHeader.setText("Contacts"); + } + + contactsAdapter.notifyDataSetChanged(); + contactsView.setScrollX(0); + } + + private OnItemLongClickListener onLongClickListener = new OnItemLongClickListener() { + + @Override + public boolean onItemLongClick(AdapterView arg0, View view, + int position, long arg3) { + if (!isActionMode) { + contactsView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); + contactsView.setItemChecked(position, true); + actionMode = contactsView.startActionMode(actionModeCallback); + } + return true; + } + }; + + @Override + protected void onStart() { + super.onStart(); + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity); + this.useSubject = preferences.getBoolean("use_subject_in_muc", true); + inviteIntent = "invite".equals(getIntent().getAction()); + if (inviteIntent) { + contactsHeader.setVisibility(View.GONE); + actionMode = contactsView.startActionMode(actionModeCallback); + search.setVisibility(View.GONE); + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_new_conversation); + + contactsHeader = (TextView) findViewById(R.id.contacts_header); + + search = (EditText) findViewById(R.id.new_conversation_search); + search.addTextChangedListener(new TextWatcher() { + + @Override + public void onTextChanged(CharSequence s, int start, int before, + int count) { + searchString = search.getText().toString(); + updateAggregatedContacts(); + } + + @Override + public void afterTextChanged(Editable s) { + // TODO Auto-generated method stub + + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, + int after) { + // TODO Auto-generated method stub + + } + }); + + contactsView = (ListView) findViewById(R.id.contactList); + contactsAdapter = new ArrayAdapter(getApplicationContext(), + R.layout.contact, aggregatedContacts) { + @Override + public View getView(int position, View view, ViewGroup parent) { + LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); + Contact contact = getItem(position); + if (view == null) { + view = (View) inflater.inflate(R.layout.contact, null); + } + + ((TextView) view.findViewById(R.id.contact_display_name)) + .setText(getItem(position).getDisplayName()); + TextView contactJid = (TextView) view + .findViewById(R.id.contact_jid); + contactJid.setText(contact.getJid()); + ImageView imageView = (ImageView) view + .findViewById(R.id.contact_photo); + imageView.setImageBitmap(UIHelper.getContactPicture(contact, + null, 90, this.getContext())); + return view; + } + }; + contactsView.setAdapter(contactsAdapter); + contactsView.setMultiChoiceModeListener(actionModeCallback); + contactsView.setOnItemClickListener(new OnItemClickListener() { + + @Override + public void onItemClick(AdapterView arg0, final View view, + int pos, long arg3) { + if (!isActionMode) { + Contact clickedContact = aggregatedContacts.get(pos); + startConversation(clickedContact); + + } else { + actionMode.invalidate(); + } + } + }); + contactsView.setOnItemLongClickListener(this.onLongClickListener); + } + + public void startConversation(final Contact contact) { + if ((contact.getAccount() == null) && (accounts.size() > 1)) { + getAccountChooser(new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + contact.setAccount(accounts.get(which)); + showIsMucDialogIfNeeded(contact); + } + }).show(); + } else { + if (contact.getAccount() == null) { + contact.setAccount(accounts.get(0)); + } + showIsMucDialogIfNeeded(contact); + } + } + + protected AlertDialog getAccountChooser(OnClickListener listener) { + String[] accountList = new String[accounts.size()]; + for (int i = 0; i < accounts.size(); ++i) { + accountList[i] = accounts.get(i).getJid(); + } + + AlertDialog.Builder accountChooser = new AlertDialog.Builder(this); + accountChooser.setTitle("Choose account"); + accountChooser.setItems(accountList, listener); + return accountChooser.create(); + } + + public void showIsMucDialogIfNeeded(final Contact clickedContact) { + if (clickedContact.couldBeMuc()) { + AlertDialog.Builder dialog = new AlertDialog.Builder(this); + dialog.setTitle("Multi User Conference"); + dialog.setMessage("Are you trying to join a conference?"); + dialog.setPositiveButton("Yes", new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + startConversation(clickedContact, + clickedContact.getAccount(), true); + } + }); + dialog.setNegativeButton("No", new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + startConversation(clickedContact, + clickedContact.getAccount(), false); + } + }); + dialog.create().show(); + } else { + startConversation(clickedContact, clickedContact.getAccount(), + false); + } + } + + public void startConversation(Contact contact, Account account, boolean muc) { + if (!contact.isInRoster()) { + xmppConnectionService.createContact(contact); + } + Conversation conversation = xmppConnectionService + .findOrCreateConversation(account, contact.getJid(), muc); + + switchToConversation(conversation, null); + } + + @Override + void onBackendConnected() { + this.accounts = xmppConnectionService.getAccounts(); + if (Intent.ACTION_SENDTO.equals(getIntent().getAction())) { + getActionBar().setDisplayHomeAsUpEnabled(false); + getActionBar().setHomeButtonEnabled(false); + String jid; + try { + jid = URLDecoder.decode(getIntent().getData().getEncodedPath(), + "UTF-8").split("/")[1]; + } catch (UnsupportedEncodingException e) { + jid = null; + } + if (jid != null) { + final String finalJid = jid; + if (this.accounts.size() > 1) { + getAccountChooser(new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + Conversation conversation = xmppConnectionService + .findOrCreateConversation( + accounts.get(which), finalJid, + false); + switchToConversation(conversation, null); + finish(); + } + }).show(); + } else { + Conversation conversation = xmppConnectionService + .findOrCreateConversation(this.accounts.get(0), + jid, false); + switchToConversation(conversation, null); + finish(); + } + } + } + + if (xmppConnectionService.getConversationCount() == 0) { + getActionBar().setDisplayHomeAsUpEnabled(false); + getActionBar().setHomeButtonEnabled(false); + } + this.rosterContacts.clear(); + for (int i = 0; i < accounts.size(); ++i) { + rosterContacts.addAll(xmppConnectionService.getRoster(accounts + .get(i))); + } + updateAggregatedContacts(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.newconversation, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.action_refresh_contacts: + refreshContacts(); + break; + default: + break; + } + return super.onOptionsItemSelected(item); + } + + private void refreshContacts() { + final ProgressBar progress = (ProgressBar) findViewById(R.id.progressBar1); + final EditText searchBar = (EditText) findViewById(R.id.new_conversation_search); + final TextView contactsHeader = (TextView) findViewById(R.id.contacts_header); + final ListView contactList = (ListView) findViewById(R.id.contactList); + searchBar.setVisibility(View.GONE); + contactsHeader.setVisibility(View.GONE); + contactList.setVisibility(View.GONE); + progress.setVisibility(View.VISIBLE); + this.accounts = xmppConnectionService.getAccounts(); + this.rosterContacts.clear(); + for (int i = 0; i < accounts.size(); ++i) { + if (accounts.get(i).getStatus() == Account.STATUS_ONLINE) { + xmppConnectionService.updateRoster(accounts.get(i), + new OnRosterFetchedListener() { + + @Override + public void onRosterFetched( + final List roster) { + runOnUiThread(new Runnable() { + + @Override + public void run() { + rosterContacts.addAll(roster); + progress.setVisibility(View.GONE); + searchBar.setVisibility(View.VISIBLE); + contactList.setVisibility(View.VISIBLE); + contactList.setVisibility(View.VISIBLE); + updateAggregatedContacts(); + } + }); + } + }); + } + } + } + + @Override + public void onActionModeStarted(ActionMode mode) { + super.onActionModeStarted(mode); + this.isActionMode = true; + search.setEnabled(false); + } + + @Override + public void onActionModeFinished(ActionMode mode) { + super.onActionModeFinished(mode); + if (inviteIntent) { + finish(); + } else { + this.isActionMode = false; + contactsView.clearChoices(); + contactsView.requestLayout(); + contactsView.post(new Runnable() { + @Override + public void run() { + contactsView.setChoiceMode(ListView.CHOICE_MODE_NONE); + } + }); + search.setEnabled(true); + } + } + +} -- cgit v1.2.3