/* * Created by Itzik Braun on 12/3/2015. * Copyright (c) 2015 deluge. All rights reserved. * * Last Modification at: 3/12/15 4:27 PM */ package com.braunster.chatsdk.fragments.abstracted; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; 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.view.Window; import android.widget.AdapterView; import android.widget.ListView; import android.widget.ProgressBar; import com.braunster.chatsdk.R; import com.braunster.chatsdk.Utils.Debug; import com.braunster.chatsdk.Utils.helper.ChatSDKChatHelper; import com.braunster.chatsdk.activities.ChatSDKChatActivity; import com.braunster.chatsdk.activities.ChatSDKSearchActivity; import com.braunster.chatsdk.adapter.ChatSDKUsersListAdapter; import com.braunster.chatsdk.adapter.abstracted.ChatSDKAbstractUsersListAdapter; import com.braunster.chatsdk.dao.BThread; import com.braunster.chatsdk.dao.BThreadDao; import com.braunster.chatsdk.dao.BUser; import com.braunster.chatsdk.dao.core.DaoCore; import com.braunster.chatsdk.fragments.ChatSDKBaseFragment; import com.braunster.chatsdk.network.BNetworkManager; import com.braunster.chatsdk.network.events.BatchedEvent; import com.braunster.chatsdk.network.events.Event; import com.braunster.chatsdk.object.BError; import com.braunster.chatsdk.object.Batcher; import com.braunster.chatsdk.object.ChatSDKThreadPool; import com.braunster.chatsdk.object.UIUpdater; import org.apache.commons.lang3.StringUtils; import org.jdeferred.DoneCallback; import org.jdeferred.FailCallback; import java.util.ArrayList; import java.util.List; import timber.log.Timber; /** * Created by itzik on 6/17/2014. */ public class ChatSDKAbstractContactsFragment extends ChatSDKBaseFragment { private static final String TAG = ChatSDKAbstractContactsFragment.class.getSimpleName(); private static boolean DEBUG = Debug.ContactsFragment; /** Loading all the current user contacts.*/ public static final int MODE_LOAD_CONTACTS = 1991; /** Loading all users for given thread id mode*/ public static final int MODE_LOAD_THREAD_USERS = 1992; public static final int MODE_LOAD_FOLLOWERS = 1993; public static final int MODE_LOAD_FOLLOWS = 1994; /** Using the users that was given to the fragment in to initializer;*/ public static final int MODE_USE_SOURCE = 1995; public static final int MODE_LOAD_CONTACT_THAT_NOT_IN_THREAD = 1996; /** When a user clicked he will be added to the current thread.*/ public static final int CLICK_MODE_ADD_USER_TO_THREAD = 2991; /** Used for the share intent, When a user press on a user the attached data from the share intent will be sent to the selected user.*/ public static final int CLICK_MODE_SHARE_CONTENT = 2992; /** Open profile activity when user is clicked.*/ public static final int CLICK_MODE_SHOW_PROFILE = 2993; /** Nothing happen on list item click.*/ public static final int CLICK_MODE_NONE = 2994; public static final String LOADING_MODE = "Loading_Mode"; public static final String CLICK_MODE = "Click_Mode"; public static final String EVENT_TAG = "EventTag"; public static final String IS_DIALOG = "is_dialog"; /** The text color that the adapter will use, Use -1 to set adapter to default color.*/ protected int textColor = -1991; protected ChatSDKAbstractUsersListAdapter adapter; protected ProgressBar progressBar; protected ListView listView; private ContactListListener contactListListener; /** Users that will be used to fill the adapter, This could be set manually or it will be filled when loading users for * {@link #loadingMode}*/ protected List<BUser> sourceUsers = null; /** Used when the fragment is shown as a dialog*/ protected String title = ""; /** Determine which users will be loaded to this fragment. * * @see * #MODE_LOAD_CONTACT_THAT_NOT_IN_THREAD, * #MODE_LOAD_CONTACTS * #MODE_LOAD_FOLLOWERS * #MODE_LOAD_FOLLOWS * #MODE_LOAD_THREAD_USERS * #MODE_USE_SOURCE * */ protected int loadingMode; /** Determine what happen after a user is clicked. * * @see * #CLICK_MODE_ADD_USER_TO_THREAD * #CLICK_MODE_SHARE_CONTENT * #CLICK_MODE_SHOW_PROFILE */ protected int clickMode; /** Extra data for the loading mode/ click mode, for example this is used as thread id/entityID for loading mode {@link #CLICK_MODE_ADD_USER_TO_THREAD} * Look in {@link #loadSourceUsers()} or in {@link #setListClickMode()} for more examples. */ protected Object extraData =""; /** This is passed to the {@link com.braunster.chatsdk.adapter.abstracted.ChatSDKAbstractUsersListAdapter}, If true the list adapter will remove all duplicates. * @see com.braunster.chatsdk.adapter.abstracted.ChatSDKAbstractUsersListAdapter*/ protected boolean removeDuplicates = true; /** This is passed to the list adapter, If true the list will be with headers. * @see com.braunster.chatsdk.adapter.abstracted.ChatSDKAbstractUsersListAdapter*/ protected boolean withHeaders = false; /** If true the fragent will listen to users details change and updates.*/ protected boolean withUpdates = true; /** Set to false if you dont want any menu item to be inflated for this fragment. * This should be set before the fragment transaction, * if you extends the fragment you can call it in {@link #onCreate(android.os.Bundle)} * <B>see </B>{@link #setInflateMenu(boolean inflate)}*/ protected boolean inflateMenu = true; protected String eventTAG; protected UIUpdater uiUpdater; private ChatSDKAbstractUsersListAdapter.ProfilePicClickListener profilePicClickListener; private AdapterView.OnItemClickListener onItemClickListener; /** When isDialog = true the dialog will always show the list of users given to him or pulled by the thread id.*/ private boolean isDialog = false; public void setEventTAG(String eventTAG) { this.eventTAG = eventTAG; } public void setDialog(){ this.isDialog = true; } public void setTitle(String title){ this.title = title; } public void setLoadingMode(int loadingMode){ this.loadingMode = loadingMode; } public void setExtraData(Object extraData){ this.extraData = extraData; } public void setClickMode(int clickMode) { this.clickMode = clickMode; } public void setSourceUsers(List<BUser> sourceUsers) { this.sourceUsers = sourceUsers; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState != null) { loadingMode = savedInstanceState.getInt(LOADING_MODE); clickMode = savedInstanceState.getInt(CLICK_MODE); isDialog = savedInstanceState.getBoolean(IS_DIALOG); eventTAG = savedInstanceState.getString(EVENT_TAG); } if (!isDialog) { setHasOptionsMenu(true); setRetainInstance(true); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { if (isDialog) { if(title.equals("")) getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE); else getDialog().setTitle(title); } return mainView; } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putInt(LOADING_MODE, loadingMode); outState.putBoolean(IS_DIALOG, isDialog); outState.putString(EVENT_TAG, eventTAG); } @Override public void initViews(){ listView = (ListView) mainView.findViewById(R.id.chat_sdk_list_contacts); progressBar = (ProgressBar) mainView.findViewById(R.id.chat_sdk_progressbar); // Create the adpater only if null, // This is here so we wont override the adapter given from the extended class with setAdapter. if (adapter == null) adapter = new ChatSDKUsersListAdapter(getActivity()); adapter.setProfilePicClickListener(profilePicClickListener); setTextColor(textColor); listView.setAdapter(adapter); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); if (!inflateMenu) return; MenuItem item = menu.add(Menu.NONE, R.id.action_chat_sdk_add, 10, "Add Chat"); item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); item.setIcon(R.drawable.ic_plus); } @Override public boolean onOptionsItemSelected(MenuItem item) { /* Cant use switch in the library*/ int id = item.getItemId(); // Each user that will be found in the search activity will be automatically added as a contact. if (id == R.id.action_chat_sdk_add) { Intent intent = new Intent(getActivity(), chatSDKUiHelper.searchActivity); startActivityForResult(intent, ChatSDKSearchActivity.GET_CONTACTS_ADDED_REQUEST); return true; } return super.onOptionsItemSelected(item); } @Override public void loadData(){ if (mainView == null || getActivity() == null) return; loadSourceUsers(); if (BNetworkManager.sharedManager().getNetworkAdapter() != null) { adapter.setUserItems(adapter.makeList(sourceUsers, withHeaders, removeDuplicates)); setListClickMode(); } } @Override public void loadDataOnBackground(){ if (mainView == null || getActivity() == null) { return; } final boolean isFirst; if (uiUpdater != null) { isFirst = false; uiUpdater.setKilled(true); ChatSDKThreadPool.getInstance().removeSchedule(uiUpdater); } else { isFirst = true; if (adapter != null && adapter.getUserItems().size() < 2) { progressBar.setVisibility(View.VISIBLE); listView.setVisibility(View.INVISIBLE); } } uiUpdater = new UIUpdater() { @Override public void run() { if (isKilled()) { return; } loadSourceUsers(); Message message = new Message(); message.what = 1; message.obj = adapter.makeList(sourceUsers, withHeaders, removeDuplicates); handler.sendMessage(message); uiUpdater = null; } }; ChatSDKThreadPool.getInstance().scheduleExecute(uiUpdater, isFirst ? 0 : loadingMode == MODE_LOAD_CONTACTS ? 4 : 0); } @Override public void clearData() { if (adapter != null) { if (uiUpdater != null) uiUpdater.setKilled(true); adapter.getUserItems().clear(); adapter.notifyDataSetChanged(); } } private Handler handler = new Handler(Looper.getMainLooper()){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case 1: adapter.setUserItems(((List) msg.obj)); if (progressBar.getVisibility() == View.VISIBLE) { hideLoading(); } setListClickMode(); } } }; private void setListClickMode(){ if (onItemClickListener!=null) { listView.setOnItemClickListener(onItemClickListener); } else listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { if (adapter.getItem(position).getType() == ChatSDKUsersListAdapter.TYPE_HEADER) return; final BUser clickedUser = DaoCore.fetchEntityWithEntityID(BUser.class, adapter.getItem(position).getEntityID()); switch (clickMode) { case CLICK_MODE_ADD_USER_TO_THREAD: BThread thread; if (extraData instanceof Long) thread = DaoCore.fetchEntityWithProperty(BThread.class, BThreadDao.Properties.Id, extraData); else thread = DaoCore.fetchEntityWithEntityID(BThread.class, extraData); getNetworkAdapter().addUsersToThread(thread, clickedUser) .done(new DoneCallback<BThread>() { @Override public void onDone(BThread thread) { showToast( getString(R.string.abstract_contact_fragment_user_added_to_thread_toast_success) + clickedUser.getMetaName()); if (contactListListener!= null) contactListListener.onContactClicked(clickedUser); if (isDialog) { getDialog().dismiss(); } } }) .fail(new FailCallback<BError>() { @Override public void onFail(BError error) { chatSDKUiHelper.showAlertToast( getString(R.string.abstract_contact_fragment_user_added_to_thread_toast_fail) ); } }); break; case CLICK_MODE_SHARE_CONTENT: createAndOpenThreadWithUsers(clickedUser.getMetaName(), clickedUser, getNetworkAdapter().currentUserModel()) .done(new DoneCallback<BThread>() { @Override public void onDone(BThread thread) { Intent intent = new Intent(getActivity(), chatSDKUiHelper.chatActivity); intent.putExtra(ChatSDKChatActivity.THREAD_ID, thread.getId()); // Checking the kind of the instace data // Uri is used for images if (extraData instanceof Uri) intent.putExtra(ChatSDKChatHelper.SHARED_FILE_URI, ((Uri) extraData)); // String is for text. else if (extraData instanceof String) intent.putExtra(ChatSDKChatHelper.SHARED_TEXT, ((String) extraData)); else { showToast(getString(R.string.abstract_contact_fragment_share_with_contact_toast_fail_unknown_type)); return; } if (contactListListener!= null) contactListListener.onContactClicked(clickedUser); intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); startActivity(intent); } }) .fail(new FailCallback<BError>() { @Override public void onFail(BError error) { } }); break; case CLICK_MODE_NONE: break; default: createAndOpenThreadWithUsers(clickedUser.getMetaName(), clickedUser, getNetworkAdapter().currentUserModel()) .done(new DoneCallback<BThread>() { @Override public void onDone(BThread thread) { if (contactListListener!= null) contactListListener.onContactClicked(clickedUser); // This listener is used only because that if we dismiss the dialog before the thread creation has been done // The contact dialog could not open the new chat activity because getActivity() will be null. if (isDialog) getDialog().dismiss(); } }) .fail(new FailCallback<BError>() { @Override public void onFail(BError error) { } }); } } }); } public void filterListStartWith(String filter){ adapter.filterStartWith(filter); } private void loadSourceUsers(){ if (loadingMode!=MODE_USE_SOURCE) // If this is not a dialog we will load the contacts of the user. switch (loadingMode) { case MODE_LOAD_CONTACTS: if (DEBUG) Timber.d("Mode - Contacts"); sourceUsers = getNetworkAdapter().currentUserModel().getContacts(); break; case MODE_LOAD_THREAD_USERS: if (DEBUG) Timber.d("Mode - Thread Users"); BThread thread = DaoCore.fetchEntityWithEntityID(BThread.class, extraData); // Remove the current user from the list. List<BUser> users = thread.getUsers(); users.remove(getNetworkAdapter().currentUserModel()); sourceUsers = users; break; case MODE_LOAD_CONTACT_THAT_NOT_IN_THREAD: List<BUser> users1 = getNetworkAdapter().currentUserModel().getContacts(); thread = DaoCore.fetchEntityWithProperty(BThread.class, BThreadDao.Properties.Id, extraData); List<BUser> threadUser = thread.getUsers(); users1.removeAll(threadUser); sourceUsers = users1; break; case MODE_LOAD_FOLLOWERS: if (extraData instanceof String && StringUtils.isNotEmpty((String) extraData)) { sourceUsers = new ArrayList<BUser>(); showLoading(); getNetworkAdapter().getFollowers((String) extraData) .done(new DoneCallback<List<BUser>>() { @Override public void onDone(List<BUser> users) { users.remove(getNetworkAdapter().currentUserModel()); hideLoading(); sourceUsers = users; adapter.addBUsersRows(users); adapter.notifyDataSetChanged(); } }) .fail(new FailCallback<BError>() { @Override public void onFail(BError error) { //TODO handle error } }); } else sourceUsers = getNetworkAdapter().currentUserModel().getFollowers(); break; case MODE_LOAD_FOLLOWS: if (extraData instanceof String && StringUtils.isNotEmpty((String) extraData)) { sourceUsers = new ArrayList<BUser>(); showLoading(); getNetworkAdapter().getFollows((String) extraData) .done(new DoneCallback<List<BUser>>() { @Override public void onDone(List<BUser> users) { users.remove(getNetworkAdapter().currentUserModel()); hideLoading(); sourceUsers = users; adapter.addBUsersRows(users); adapter.notifyDataSetChanged(); } }); } else sourceUsers = getNetworkAdapter().currentUserModel().getFollows(); break; } } public void showLoading(){ progressBar.setVisibility(View.VISIBLE); listView.setVisibility(View.INVISIBLE); } public void hideLoading(){ progressBar.setVisibility(View.INVISIBLE); listView.setVisibility(View.VISIBLE); } @Override public void onResume() { super.onResume(); if (withUpdates) { BatchedEvent userDetailsBatch = new BatchedEvent(eventTAG, "", Event.Type.UserDetailsEvent, handler); userDetailsBatch.setBatchedAction(Event.Type.UserDetailsEvent, 1000, new Batcher.BatchedAction<String>() { @Override public void triggered(List<String> list) { loadDataOnBackground(); } }); if (StringUtils.isNotEmpty(eventTAG)) { getNetworkAdapter().getEventManager().removeEventByTag(eventTAG); getNetworkAdapter().getEventManager().addEvent(userDetailsBatch); } } } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == ChatSDKSearchActivity.GET_CONTACTS_ADDED_REQUEST) if (resultCode == Activity.RESULT_OK) { loadDataOnBackground(); } } @Override public void onDestroy() { super.onDestroy(); getNetworkAdapter().getEventManager().removeEventByTag(eventTAG); } public void setAdapter(ChatSDKAbstractUsersListAdapter adapter) { this.adapter = adapter; } public void setContactListListener(ContactListListener contactListListener) { this.contactListListener = contactListListener; } public interface ContactListListener{ public void onContactClicked(BUser user); } public void setRemoveDuplicates(boolean removeDuplicates) { this.removeDuplicates = removeDuplicates; } public void setWithHeaders(boolean withHeaders) { this.withHeaders = withHeaders; } public void setInflateMenu(boolean inflateMenu) { this.inflateMenu = inflateMenu; } public void setTextColor(int textColor) { this.textColor = textColor; if (adapter!=null) { adapter.setTextColor(textColor); adapter.notifyDataSetChanged(); } } public ChatSDKAbstractUsersListAdapter getAdapter() { return adapter; } public void setProfilePicClickListener(ChatSDKAbstractUsersListAdapter.ProfilePicClickListener profilePicClickListener){ this.profilePicClickListener = profilePicClickListener; if (adapter!=null) { adapter.setProfilePicClickListener(profilePicClickListener); adapter.notifyDataSetChanged(); } } public void withUpdates(boolean withUpdates) { this.withUpdates = withUpdates; } public void setOnItemClickListener(AdapterView.OnItemClickListener onItemClickListener) { this.onItemClickListener = onItemClickListener; } }