diff --git a/ring-android/app/src/main/java/cx/ring/adapters/SmartListAdapter.java b/ring-android/app/src/main/java/cx/ring/adapters/SmartListAdapter.java index c80e014cf42a956430696bf2de35104a223aaade..25f32b8ba8cd2e11722d86fd8956c0b43ba963b8 100644 --- a/ring-android/app/src/main/java/cx/ring/adapters/SmartListAdapter.java +++ b/ring-android/app/src/main/java/cx/ring/adapters/SmartListAdapter.java @@ -21,9 +21,9 @@ package cx.ring.adapters; import android.content.Context; import android.graphics.Typeface; -import android.net.Uri; -import android.provider.ContactsContract; +import android.os.Bundle; import android.support.v4.content.ContextCompat; +import android.support.v7.util.DiffUtil; import android.support.v7.widget.RecyclerView; import android.text.format.DateUtils; import android.view.LayoutInflater; @@ -36,11 +36,9 @@ import com.bumptech.glide.signature.StringSignature; import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import cx.ring.R; -import cx.ring.model.HistoryCall; -import cx.ring.model.HistoryEntry; -import cx.ring.model.TextMessage; import cx.ring.smartlist.SmartListViewModel; import cx.ring.utils.CircleTransform; import cx.ring.viewholders.SmartListViewHolder; @@ -51,8 +49,9 @@ public class SmartListAdapter extends RecyclerView.Adapter<SmartListViewHolder> private SmartListViewHolder.SmartListListeners listener; public SmartListAdapter(ArrayList<SmartListViewModel> smartListViewModels, SmartListViewHolder.SmartListListeners listener) { - this.mSmartListViewModels = new ArrayList<>(smartListViewModels); this.listener = listener; + this.mSmartListViewModels = new ArrayList<>(); + this.mSmartListViewModels.addAll(smartListViewModels); } @Override @@ -85,18 +84,17 @@ public class SmartListAdapter extends RecyclerView.Adapter<SmartListViewHolder> holder.convStatus.setVisibility(View.VISIBLE); holder.convTime.setVisibility(View.VISIBLE); holder.contactRequest.setVisibility(View.GONE); - long lastInteraction = smartListViewModel.getLastInteractionTime(); - holder.convTime.setText(lastInteraction == 0 ? "" : - DateUtils.getRelativeTimeSpanString(lastInteraction, System.currentTimeMillis(), 0L, DateUtils.FORMAT_ABBREV_ALL)); break; } holder.convParticipants.setText(smartListViewModel.getContactName()); - + holder.convTime.setText(smartListViewModel.getLastInteractionTime()); if (smartListViewModel.hasOngoingCall()) { holder.convStatus.setText(holder.itemView.getContext().getString(R.string.ongoing_call)); } else if (smartListViewModel.getLastInteraction() != null) { - holder.convStatus.setText(getLastInteractionSummary(smartListViewModel.getLastInteraction(), holder.itemView.getContext())); + holder.convStatus.setText(getLastInteractionSummary(smartListViewModel.getLastEntryType(), + smartListViewModel.getLastInteraction(), + holder.itemView.getContext())); } else { holder.convStatus.setVisibility(View.GONE); } @@ -111,20 +109,7 @@ public class SmartListAdapter extends RecyclerView.Adapter<SmartListViewHolder> holder.convStatus.setTypeface(null, Typeface.NORMAL); } - String photoUri = smartListViewModel.getPhotoUri(); - - if (photoUri != null) { - if (isContentUri(photoUri)) { - Glide.with(holder.itemView.getContext()) - .load(Uri.withAppendedPath(Uri.parse(photoUri), ContactsContract.Contacts.Photo.DISPLAY_PHOTO)) - .crossFade() - .signature(new StringSignature(smartListViewModel.getUuid())) - .placeholder(R.drawable.ic_contact_picture) - .transform(new CircleTransform(holder.itemView.getContext())) - .error(R.drawable.ic_contact_picture) - .into(holder.photo); - } - } else if (smartListViewModel.getPhotoData() != null) { + if (smartListViewModel.getPhotoData() != null) { Glide.with(holder.itemView.getContext()) .fromBytes() .diskCacheStrategy(DiskCacheStrategy.NONE) @@ -155,36 +140,26 @@ public class SmartListAdapter extends RecyclerView.Adapter<SmartListViewHolder> return mSmartListViewModels.size(); } - public void replaceAll(ArrayList<SmartListViewModel> list) { - mSmartListViewModels.clear(); - mSmartListViewModels.addAll(list); - notifyDataSetChanged(); - } + public void update(ArrayList<SmartListViewModel> smartListViewModels) { + final DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new SmartListDiffUtil(this.mSmartListViewModels, smartListViewModels)); + diffResult.dispatchUpdatesTo(this); - private boolean isContentUri(String uri) { - return uri.contains("content://"); + this.mSmartListViewModels.clear(); + this.mSmartListViewModels.addAll(smartListViewModels); } - private String getLastInteractionSummary(HistoryEntry e, Context context) { - long lastTextTimestamp = e.getTextMessages().isEmpty() ? 0 : e.getTextMessages().lastEntry().getKey(); - long lastCallTimestamp = e.getCalls().isEmpty() ? 0 : e.getCalls().lastEntry().getKey(); - if (lastTextTimestamp > 0 && lastTextTimestamp > lastCallTimestamp) { - TextMessage msg = e.getTextMessages().lastEntry().getValue(); - String msgString = msg.getMessage(); - if (msgString != null && !msgString.isEmpty() && msgString.contains("\n")) { - int lastIndexOfChar = msgString.lastIndexOf("\n"); - if (lastIndexOfChar + 1 < msgString.length()) { - msgString = msgString.substring(msgString.lastIndexOf("\n") + 1); - } - } - return (msg.isIncoming() ? "" : context.getText(R.string.you_txt_prefix) + " ") + msgString; - } - if (lastCallTimestamp > 0) { - HistoryCall lastCall = e.getCalls().lastEntry().getValue(); - return String.format(context.getString(lastCall.isIncoming() - ? R.string.hist_in_call - : R.string.hist_out_call), lastCall.getDurationString()); + private String getLastInteractionSummary(int type, String lastInteraction, Context context) { + switch (type) { + case SmartListViewModel.TYPE_INCOMING_CALL: + return String.format(context.getString(R.string.hist_in_call), lastInteraction); + case SmartListViewModel.TYPE_OUTGOING_CALL: + return String.format(context.getString(R.string.hist_out_call), lastInteraction); + case SmartListViewModel.TYPE_INCOMING_MESSAGE: + return lastInteraction; + case SmartListViewModel.TYPE_OUTGOING_MESSAGE: + return context.getText(R.string.you_txt_prefix) + " " + lastInteraction; + default: + return null; } - return null; } } \ No newline at end of file diff --git a/ring-android/app/src/main/java/cx/ring/adapters/SmartListDiffUtil.java b/ring-android/app/src/main/java/cx/ring/adapters/SmartListDiffUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..44687f94ddb4bb4ad5e4dbf5acbe10ef50e2a0f7 --- /dev/null +++ b/ring-android/app/src/main/java/cx/ring/adapters/SmartListDiffUtil.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2016 Savoir-faire Linux Inc. + * + * Author: Hadrien De Sousa <hadrien.desousa@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +package cx.ring.adapters; + +import android.support.v7.util.DiffUtil; + +import java.util.List; + +import cx.ring.smartlist.SmartListViewModel; + +public class SmartListDiffUtil extends DiffUtil.Callback { + + private List<SmartListViewModel> mOldList; + private List<SmartListViewModel> mNewList; + + public SmartListDiffUtil(List<SmartListViewModel> oldList, List<SmartListViewModel> newList) { + this.mOldList = oldList; + this.mNewList = newList; + } + + @Override + public int getOldListSize() { + return mOldList.size(); + } + + @Override + public int getNewListSize() { + return mNewList.size(); + } + + @Override + public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { + return mNewList.get(newItemPosition).getUuid().equals(mOldList.get(oldItemPosition).getUuid()); + } + + @Override + public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { + return mNewList.get(newItemPosition).equals(mOldList.get(oldItemPosition)); + } +} \ No newline at end of file diff --git a/ring-android/app/src/main/java/cx/ring/fragments/SmartListFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/SmartListFragment.java index c840d1bb4ec6c0614a55a8a867c72931dd39bc88..66c740c96a28cade6d6b092962710a285f1d1a44 100644 --- a/ring-android/app/src/main/java/cx/ring/fragments/SmartListFragment.java +++ b/ring-android/app/src/main/java/cx/ring/fragments/SmartListFragment.java @@ -69,7 +69,6 @@ import cx.ring.client.QRCodeScannerActivity; import cx.ring.model.CallContact; import cx.ring.model.Conversation; import cx.ring.mvp.BaseFragment; -import cx.ring.service.LocalService; import cx.ring.smartlist.SmartListPresenter; import cx.ring.smartlist.SmartListView; import cx.ring.smartlist.SmartListViewModel; @@ -85,8 +84,7 @@ public class SmartListFragment extends BaseFragment<SmartListPresenter> implemen ClipboardHelper.ClipboardHelperCallback, SmartListView { - - private static final String TAG = SmartListFragment.class.getSimpleName(); + public static final String TAG = SmartListFragment.class.getSimpleName(); private static final String STATE_LOADING = TAG + ".STATE_LOADING"; @Inject @@ -124,18 +122,6 @@ public class SmartListFragment extends BaseFragment<SmartListPresenter> implemen private Boolean isTabletMode = false; - @Override - public void onAttach(Activity activity) { - Log.d(TAG, "onAttach"); - super.onAttach(activity); - - if (!(activity instanceof LocalService.Callbacks)) { - throw new IllegalStateException("Activity must implement fragment's callbacks."); - } - - } - - @Override public void onResume() { super.onResume(); @@ -220,7 +206,7 @@ public class SmartListFragment extends BaseFragment<SmartListPresenter> implemen @Override public boolean onQueryTextSubmit(String query) { - mNewContact.callOnClick(); + mSmartListPresenter.newContactClicked(); return true; } @@ -264,22 +250,24 @@ public class SmartListFragment extends BaseFragment<SmartListPresenter> implemen return inflatedView; } + public void refresh() { + mSmartListPresenter.refresh(NetworkUtils.isConnectedWifi(getActivity()), + NetworkUtils.isConnectedMobile(getActivity())); + } + @OnClick(R.id.newcontact_element) void newContactClicked(View v) { - mSmartListPresenter.newContactClicked((CallContact) v.getTag()); + mSmartListPresenter.newContactClicked(); } @OnClick(R.id.quick_call) void quickCallClicked(View v) { - CallContact callContact = (CallContact) mNewContact.getTag(); - mSmartListPresenter.quickCallClicked(callContact); + mSmartListPresenter.quickCallClicked(); } @OnClick(R.id.newconv_fab) void fabButtonClicked(View v) { - if (mSearchMenuItem != null) { - mSearchMenuItem.expandActionView(); - } + mSmartListPresenter.fabButtonClicked(); } @Override @@ -400,13 +388,12 @@ public class SmartListFragment extends BaseFragment<SmartListPresenter> implemen }); } - public void displayNewContactRowWithName(final String name, final String address) { + @Override + public void displayNewContactRowWithName(final String name) { getActivity().runOnUiThread(new Runnable() { @Override public void run() { ((TextView) mNewContact.findViewById(R.id.display_name)).setText(name); - CallContact contact = CallContact.buildUnknown(name, address); - mNewContact.setTag(contact); mNewContact.setVisibility(View.VISIBLE); } }); @@ -466,6 +453,13 @@ public class SmartListFragment extends BaseFragment<SmartListPresenter> implemen dialog.show(); } + @Override + public void displayMenuItem() { + if (mSearchMenuItem != null) { + mSearchMenuItem.expandActionView(); + } + } + @Override public void hideSearchRow() { getActivity().runOnUiThread(new Runnable() { @@ -497,20 +491,20 @@ public class SmartListFragment extends BaseFragment<SmartListPresenter> implemen } @Override - public void updateView(final ArrayList<SmartListViewModel> list) { + public void updateList(final ArrayList<SmartListViewModel> smartListViewModels) { getActivity().runOnUiThread(new Runnable() { @Override public void run() { - if (mRecyclerView.getAdapter() != null) { - mSmartListAdapter.replaceAll(list); - } else { - mSmartListAdapter = new SmartListAdapter(list, SmartListFragment.this); + if (mRecyclerView.getAdapter() == null) { + mSmartListAdapter = new SmartListAdapter(smartListViewModels, SmartListFragment.this); mRecyclerView.setAdapter(mSmartListAdapter); mRecyclerView.setHasFixedSize(true); LinearLayoutManager llm = new LinearLayoutManager(getActivity()); llm.setOrientation(LinearLayoutManager.VERTICAL); mRecyclerView.setLayoutManager(llm); } + mSmartListAdapter.update(smartListViewModels); + setLoading(false); } }); } @@ -555,6 +549,16 @@ public class SmartListFragment extends BaseFragment<SmartListPresenter> implemen } } + @Override + public void scrollToTop() { + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + mRecyclerView.scrollToPosition(0); + } + }); + } + @Override protected SmartListPresenter createPresenter() { return mSmartListPresenter; diff --git a/ring-android/app/src/main/java/cx/ring/services/ContactServiceImpl.java b/ring-android/app/src/main/java/cx/ring/services/ContactServiceImpl.java index dbb0eb972ebb3666c450e2b6d3c0c9b98e0067de..4c32d5e1fd086c3996892912ae3c76a3ce968e27 100644 --- a/ring-android/app/src/main/java/cx/ring/services/ContactServiceImpl.java +++ b/ring-android/app/src/main/java/cx/ring/services/ContactServiceImpl.java @@ -454,7 +454,7 @@ public class ContactServiceImpl extends ContactService { return new Tuple<>(contactName, byteArray); } catch (IOException e) { Log.w(TAG, "Error loading photo for system contact"); - return null; + return new Tuple<>(contactName, null); } } } diff --git a/ring-android/app/src/main/java/cx/ring/services/HistoryServiceImpl.java b/ring-android/app/src/main/java/cx/ring/services/HistoryServiceImpl.java index 09e9ad27790eddf9fc1484ebed97ed7423233d98..3fbdf6ec9ce85fd391eca1b70e251b7a267ae281 100644 --- a/ring-android/app/src/main/java/cx/ring/services/HistoryServiceImpl.java +++ b/ring-android/app/src/main/java/cx/ring/services/HistoryServiceImpl.java @@ -23,6 +23,7 @@ package cx.ring.services; import android.content.Context; import android.content.Intent; +import android.text.format.DateUtils; import android.util.Log; import com.j256.ormlite.android.apptools.OpenHelperManager; @@ -83,6 +84,11 @@ public class HistoryServiceImpl extends HistoryService { } } + @Override + public String getRelativeTimeSpanString(long lastInteraction) { + return DateUtils.getRelativeTimeSpanString(lastInteraction, System.currentTimeMillis(), 0L, DateUtils.FORMAT_ABBREV_ALL).toString(); + } + /** * Init Helper for our DB */ diff --git a/ring-android/app/src/main/res/layout/frag_smartlist.xml b/ring-android/app/src/main/res/layout/frag_smartlist.xml index 6ba58abb3049be10be679af5bff8ded90e233a3e..1f0dcab5e8cf1e2f68f3db174f4e161b4c8be156 100644 --- a/ring-android/app/src/main/res/layout/frag_smartlist.xml +++ b/ring-android/app/src/main/res/layout/frag_smartlist.xml @@ -68,7 +68,8 @@ along with this program; if not, write to the Free Software android:layout_below="@+id/error_msg_pane" android:background="?android:attr/selectableItemBackground" android:orientation="vertical" - android:visibility="gone"> + android:visibility="gone" + tools:visibility="visible"> <include layout="@layout/item_contact" diff --git a/ring-android/app/src/main/res/layout/item_smartlist.xml b/ring-android/app/src/main/res/layout/item_smartlist.xml index be24571a0d6d3eeef21447ee549ce9db435c15a2..104b0467a6be169ea376c07811e217cd5b127775 100644 --- a/ring-android/app/src/main/res/layout/item_smartlist.xml +++ b/ring-android/app/src/main/res/layout/item_smartlist.xml @@ -32,12 +32,14 @@ along with this program; if not, write to the Free Software <ImageView android:id="@+id/photo" - android:layout_width="64dp" - android:layout_height="64dp" + android:layout_width="60dp" + android:layout_height="60dp" android:layout_marginEnd="16dp" android:layout_marginRight="16dp" android:layout_centerVertical="true" - android:padding="4dp" + android:paddingRight="4dp" + android:paddingEnd="4dp" + android:paddingBottom="4dp" android:background="@null" android:scaleType="fitCenter" android:src="@drawable/ic_contact_picture" /> diff --git a/ring-android/libringclient/src/main/java/cx/ring/facades/ConversationFacade.java b/ring-android/libringclient/src/main/java/cx/ring/facades/ConversationFacade.java index 5e7f488fa38b20901b6b4eed22819255551f5df7..6a9ae1de6adf05250046e79307e690d335b611fd 100644 --- a/ring-android/libringclient/src/main/java/cx/ring/facades/ConversationFacade.java +++ b/ring-android/libringclient/src/main/java/cx/ring/facades/ConversationFacade.java @@ -402,6 +402,10 @@ public class ConversationFacade extends Observable implements Observer<ServiceEv } } + public void removeConversation(String id) { + mConversationMap.remove(id); + } + private void parseNewMessage(TextMessage txt, String call) { Conversation conversation; if (call != null && !call.isEmpty()) { diff --git a/ring-android/libringclient/src/main/java/cx/ring/services/ContactService.java b/ring-android/libringclient/src/main/java/cx/ring/services/ContactService.java index a60a46b9c1e29afc0f2ebbb46c3121446f096e05..d2b3f3cc2a8f3e481f5ed1086f13dc7ca35084cb 100644 --- a/ring-android/libringclient/src/main/java/cx/ring/services/ContactService.java +++ b/ring-android/libringclient/src/main/java/cx/ring/services/ContactService.java @@ -55,8 +55,6 @@ import cx.ring.utils.Tuple; */ public abstract class ContactService extends Observable { - public static final String CONTACT_NAME_KEY = "CONTACT_NAME"; - public static final String CONTACT_PHOTO_KEY = "CONTACT_PHOTO"; public static final String BANNED = "banned"; public static final String CONFIRMED = "confirmed"; public static final String ID = "id"; diff --git a/ring-android/libringclient/src/main/java/cx/ring/services/HistoryService.java b/ring-android/libringclient/src/main/java/cx/ring/services/HistoryService.java index 68927809969ce2244a7d7611a36bbad824fcf369..adfac17281774590d65987de7ac4ed3f534e012f 100644 --- a/ring-android/libringclient/src/main/java/cx/ring/services/HistoryService.java +++ b/ring-android/libringclient/src/main/java/cx/ring/services/HistoryService.java @@ -68,6 +68,8 @@ public abstract class HistoryService extends Observable { protected abstract Dao<HistoryText, Integer> getTextHistoryDao(); + public abstract String getRelativeTimeSpanString(long lastInteraction); + public boolean insertNewEntry(Conference toInsert) { for (SipCall call : toInsert.getParticipants()) { diff --git a/ring-android/libringclient/src/main/java/cx/ring/smartlist/SmartListPresenter.java b/ring-android/libringclient/src/main/java/cx/ring/smartlist/SmartListPresenter.java index b5d45fb2dc969578ebfff35db274574be477aea6..57a2d483a584e14c4b1e56780f53f8e181834511 100644 --- a/ring-android/libringclient/src/main/java/cx/ring/smartlist/SmartListPresenter.java +++ b/ring-android/libringclient/src/main/java/cx/ring/smartlist/SmartListPresenter.java @@ -21,8 +21,7 @@ package cx.ring.smartlist; import java.lang.ref.WeakReference; import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; +import java.util.Date; import java.util.List; import java.util.Set; @@ -69,6 +68,8 @@ public class SmartListPresenter extends RootPresenter<SmartListView> implements private ArrayList<Conversation> mConversations; private ArrayList<SmartListViewModel> mSmartListViewModels; + private CallContact mCallContact; + @Inject public SmartListPresenter(AccountService accountService, ContactService contactService, HistoryService historyService, ConversationFacade conversationFacade, @@ -135,12 +136,14 @@ public class SmartListPresenter extends RootPresenter<SmartListView> implements if (currentAccount.isSip()) { // sip search - getView().displayNewContactRowWithName(query, null); + mCallContact = CallContact.buildUnknown(query, null); + getView().displayNewContactRowWithName(query); } else { Uri uri = new Uri(query); if (uri.isRingId()) { - getView().displayNewContactRowWithName(query, null); + mCallContact = CallContact.buildUnknown(query, null); + getView().displayNewContactRowWithName(query); } else { getView().hideSearchRow(); } @@ -160,15 +163,15 @@ public class SmartListPresenter extends RootPresenter<SmartListView> implements } } - getView().updateView(filter(mSmartListViewModels, query)); + getView().updateList(filter(mSmartListViewModels, query)); getView().setLoading(false); } - public void newContactClicked(CallContact callContact) { - if (callContact == null) { + public void newContactClicked() { + if (mCallContact == null) { return; } - startConversation(callContact); + startConversation(mCallContact); } public void conversationClicked(SmartListViewModel smartListViewModel) { @@ -192,22 +195,26 @@ public class SmartListPresenter extends RootPresenter<SmartListView> implements } } - public void quickCallClicked(CallContact callContact) { - if (callContact != null) { - if (callContact.getPhones().size() > 1) { - CharSequence numbers[] = new CharSequence[callContact.getPhones().size()]; + public void quickCallClicked() { + if (mCallContact != null) { + if (mCallContact.getPhones().size() > 1) { + CharSequence numbers[] = new CharSequence[mCallContact.getPhones().size()]; int i = 0; - for (Phone p : callContact.getPhones()) { + for (Phone p : mCallContact.getPhones()) { numbers[i++] = p.getNumber().getRawUriString(); } getView().displayChooseNumberDialog(numbers); } else { - getView().goToCallActivity(callContact.getPhones().get(0).getNumber().getRawUriString()); + getView().goToCallActivity(mCallContact.getPhones().get(0).getNumber().getRawUriString()); } } } + public void fabButtonClicked() { + getView().displayMenuItem(); + } + public void startConversation(CallContact c) { mContactService.addContact(c); getView().goToConversation(c); @@ -250,50 +257,28 @@ public class SmartListPresenter extends RootPresenter<SmartListView> implements mConversations = new ArrayList<>(); } subscribePresence(); + mSmartListViewModels = new ArrayList<>(); mConversations.clear(); mConversations.addAll(mConversationFacade.getConversationsList()); if (mConversations != null && mConversations.size() > 0) { - if (mSmartListViewModels == null) { - mSmartListViewModels = new ArrayList<>(); - } else { - mSmartListViewModels.clear(); - } for (int i = 0; i < mConversations.size(); i++) { Conversation conversation = mConversations.get(i); - SmartListViewModel smartListViewModel = getSmartListViewModelByUuid(mSmartListViewModels, conversation.getUuid()); - CallContact contact = conversation.getContact(); - - if (smartListViewModel == null || i >= mSmartListViewModels.size()) { - - if (conversation.getContact().isFromSystem()) { - Tuple<String, String> tuple = mContactService.loadContactDataFromSystem(contact); - smartListViewModel = new SmartListViewModel(conversation, tuple.first, tuple.second, null); - } else { - Tuple<String, byte[]> tuple = mContactService.loadContactData(contact); - smartListViewModel = new SmartListViewModel(conversation, tuple.first, null, tuple.second); - } + SmartListViewModel smartListViewModel; + long lastInteractionTime = conversation.getLastInteraction().getTime(); + String lastInteraction = lastInteractionTime == new Date(0).getTime() ? + "" : mHistoryService.getRelativeTimeSpanString(lastInteractionTime); + Tuple<String, byte[]> tuple = mContactService.loadContactData(conversation.getContact()); + if (tuple != null) { + smartListViewModel = new SmartListViewModel(conversation, + tuple.first, + tuple.second, + lastInteraction); smartListViewModel.setOnline(mPresenceService.isBuddyOnline(conversation.getContact().getIds().get(0))); mSmartListViewModels.add(smartListViewModel); - } else { - smartListViewModel.setOnline(mPresenceService.isBuddyOnline(conversation.getContact().getIds().get(0))); - if (conversation.getContact().isFromSystem()) { - Tuple<String, String> tuple = mContactService.loadContactDataFromSystem(conversation.getContact()); - smartListViewModel.update(conversation, tuple.first, tuple.second, null); - } else { - Tuple<String, byte[]> tuple = mContactService.loadContactData(contact); - smartListViewModel.update(conversation, tuple.first, null, tuple.second); - } } } - Collections.sort(mSmartListViewModels, new Comparator<SmartListViewModel>() { - @Override - public int compare(SmartListViewModel lhs, SmartListViewModel rhs) { - return (int) ((rhs.getLastInteractionTime() - lhs.getLastInteractionTime()) / 1000l); - } - }); - - getView().updateView(mSmartListViewModels); + getView().updateList(mSmartListViewModels); getView().hideNoConversationMessage(); getView().setLoading(false); } else { @@ -324,21 +309,13 @@ public class SmartListPresenter extends RootPresenter<SmartListView> implements return null; } - private SmartListViewModel getSmartListViewModelByUuid(ArrayList<SmartListViewModel> smartListViewModels, String uuid) { - for (SmartListViewModel smartListViewModel : smartListViewModels) { - if (smartListViewModel.getUuid().equals(uuid)) { - return smartListViewModel; - } - } - return null; - } - private void parseEventState(String name, String address, int state) { switch (state) { case 0: // on found if (mLastBlockchainQuery != null && mLastBlockchainQuery.equals(name)) { - getView().displayNewContactRowWithName(name, address); + mCallContact = CallContact.buildUnknown(name, address); + getView().displayNewContactRowWithName(name); mLastBlockchainQuery = null; } else { if (name.equals("") || address.equals("")) { @@ -346,7 +323,6 @@ public class SmartListPresenter extends RootPresenter<SmartListView> implements } getView().hideSearchRow(); mConversationFacade.updateConversationContactWithRingId(name, address); - displayConversations(); } break; case 1: @@ -355,7 +331,8 @@ public class SmartListPresenter extends RootPresenter<SmartListView> implements if (uriName.isRingId() && mLastBlockchainQuery != null && mLastBlockchainQuery.equals(name)) { - getView().displayNewContactRowWithName(name, null); + mCallContact = CallContact.buildUnknown(name, address); + getView().displayNewContactRowWithName(name); } else { getView().hideSearchRow(); } @@ -366,7 +343,8 @@ public class SmartListPresenter extends RootPresenter<SmartListView> implements if (uriAddress.isRingId() && mLastBlockchainQuery != null && mLastBlockchainQuery.equals(name)) { - getView().displayNewContactRowWithName(address, null); + mCallContact = CallContact.buildUnknown(name, address); + getView().displayNewContactRowWithName(name); } else { getView().hideSearchRow(); } @@ -411,10 +389,10 @@ public class SmartListPresenter extends RootPresenter<SmartListView> implements int state = event.getEventInput(ServiceEvent.EventInput.STATE, Integer.class); parseEventState(name, address, state); break; - case INCOMING_MESSAGE: case HISTORY_LOADED: case CONVERSATIONS_CHANGED: displayConversations(); + getView().scrollToTop(); break; } diff --git a/ring-android/libringclient/src/main/java/cx/ring/smartlist/SmartListView.java b/ring-android/libringclient/src/main/java/cx/ring/smartlist/SmartListView.java index 67db8f86ba65ff534dca5c265d6280cbdf99f75d..6428160a509a73613417e6b27cf825e1f4d717bb 100644 --- a/ring-android/libringclient/src/main/java/cx/ring/smartlist/SmartListView.java +++ b/ring-android/libringclient/src/main/java/cx/ring/smartlist/SmartListView.java @@ -31,7 +31,7 @@ public interface SmartListView { void displayMobileDataPanel(); - void displayNewContactRowWithName(String name, String address); + void displayNewContactRowWithName(String name); void displayChooseNumberDialog(CharSequence numbers[]); @@ -41,13 +41,15 @@ public interface SmartListView { void setLoading(boolean display); + void displayMenuItem(); + void hideSearchRow(); void hideErrorPanel(); void hideNoConversationMessage(); - void updateView(ArrayList<SmartListViewModel> list); + void updateList(ArrayList<SmartListViewModel> smartListViewModels); void goToConversation(CallContact callContact); @@ -56,4 +58,6 @@ public interface SmartListView { void goToQRActivity(); void goToContact(CallContact callContact); + + void scrollToTop(); } diff --git a/ring-android/libringclient/src/main/java/cx/ring/smartlist/SmartListViewModel.java b/ring-android/libringclient/src/main/java/cx/ring/smartlist/SmartListViewModel.java index f94fe58b625a770830d9630d59dab11e2008f41f..6d2092624e499b19b53ef7dc76995caf612bdc34 100644 --- a/ring-android/libringclient/src/main/java/cx/ring/smartlist/SmartListViewModel.java +++ b/ring-android/libringclient/src/main/java/cx/ring/smartlist/SmartListViewModel.java @@ -19,69 +19,97 @@ */ package cx.ring.smartlist; +import java.util.Arrays; + import cx.ring.model.CallContact; import cx.ring.model.Conversation; +import cx.ring.model.HistoryCall; import cx.ring.model.HistoryEntry; +import cx.ring.model.TextMessage; public class SmartListViewModel { + public static final int TYPE_INCOMING_MESSAGE = 0; + public static final int TYPE_OUTGOING_MESSAGE = 1; + public static final int TYPE_INCOMING_CALL = 2; + public static final int TYPE_OUTGOING_CALL = 3; + private String uuid; private String contactName; - private HistoryEntry lastInteraction; - private String photoUri; + private String lastInteraction = ""; private byte[] photoData; - private long lastInteractionTime; + private String lastInteractionTime; private boolean hasUnreadTextMessage; private boolean hasOngoingCall; private CallContact.Status status; private boolean isOnline = false; + private int lastEntryType; - public SmartListViewModel(Conversation conversation, String contactName, String photoUri, byte[] photoData) { + public SmartListViewModel(Conversation conversation, String contactName, byte[] photoData, String lastInteractionTime) { this.uuid = conversation.getUuid(); - setData(conversation, contactName, photoUri, photoData); - } - - public void update(Conversation conversation, String contactName, String photoUri, byte[] photoData) { - setData(conversation, contactName, photoUri, photoData); - } - - private void setData(Conversation conversation, String contactName, String photoUri, byte[] photoData) { this.contactName = contactName; - this.photoUri = photoUri; this.photoData = photoData; + this.lastInteractionTime = lastInteractionTime; + this.hasUnreadTextMessage = conversation.hasUnreadTextMessages(); + this.hasOngoingCall = conversation.hasCurrentCall(); + this.status = conversation.getContact().getStatus(); for (HistoryEntry historyEntry : conversation.getHistory().values()) { long lastTextTimestamp = historyEntry.getTextMessages().isEmpty() ? 0 : historyEntry.getTextMessages().lastEntry().getKey(); long lastCallTimestamp = historyEntry.getCalls().isEmpty() ? 0 : historyEntry.getCalls().lastEntry().getKey(); - if (lastTextTimestamp > 0 && lastTextTimestamp > lastCallTimestamp) { - this.lastInteraction = historyEntry; + if (lastTextTimestamp == conversation.getLastInteraction().getTime() + && lastTextTimestamp > 0 + && lastTextTimestamp > lastCallTimestamp) { + TextMessage msg = historyEntry.getTextMessages().lastEntry().getValue(); + String msgString = msg.getMessage(); + if (msgString != null && !msgString.isEmpty() && msgString.contains("\n")) { + int lastIndexOfChar = msgString.lastIndexOf("\n"); + if (lastIndexOfChar + 1 < msgString.length()) { + msgString = msgString.substring(msgString.lastIndexOf("\n") + 1); + } + } + this.lastEntryType = msg.isIncoming() ? TYPE_INCOMING_MESSAGE : TYPE_OUTGOING_MESSAGE; + this.lastInteraction = msgString; break; } - if (lastCallTimestamp > 0) { - this.lastInteraction = historyEntry; + if (lastCallTimestamp == conversation.getLastInteraction().getTime() + && lastCallTimestamp > 0) { + HistoryCall lastCall = historyEntry.getCalls().lastEntry().getValue(); + this.lastEntryType = lastCall.isIncoming() ? TYPE_INCOMING_CALL : TYPE_OUTGOING_CALL; + this.lastInteraction = lastCall.getDurationString(); break; } } + } - this.lastInteractionTime = conversation.getLastInteraction().getTime(); - this.hasUnreadTextMessage = conversation.hasUnreadTextMessages(); - this.hasOngoingCall = conversation.hasCurrentCall(); - this.status = conversation.getContact().getStatus(); + @Override + public boolean equals(Object o) { + if (o instanceof SmartListViewModel) { + SmartListViewModel slvm = (SmartListViewModel) o; + return !(this.photoData != null && !Arrays.equals(this.photoData, slvm.photoData)) + && this.uuid.equals(slvm.getUuid()) + && this.contactName.equals(slvm.getContactName()) + && this.lastInteraction.equals(slvm.getLastInteraction()) + && this.lastInteractionTime.equals(slvm.getLastInteractionTime()) + && this.hasUnreadTextMessage == slvm.hasUnreadTextMessage() + && this.hasOngoingCall == slvm.hasOngoingCall() + && this.lastEntryType == slvm.getLastEntryType() + && this.isOnline == slvm.isOnline() + && this.status == slvm.getStatus(); + } else { + return false; + } } public String getContactName() { return contactName; } - public HistoryEntry getLastInteraction() { + public String getLastInteraction() { return lastInteraction; } - public String getPhotoUri() { - return photoUri; - } - - public long getLastInteractionTime() { + public String getLastInteractionTime() { return lastInteractionTime; } @@ -112,4 +140,8 @@ public class SmartListViewModel { public void setOnline(boolean online) { isOnline = online; } + + public int getLastEntryType() { + return lastEntryType; + } }