package com.netease.nim.uikit.contact;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import com.netease.nim.uikit.LoginSyncDataStatusObserver;
import com.netease.nim.uikit.NimUIKit;
import com.netease.nim.uikit.OnlineStateChangeListener;
import com.netease.nim.uikit.R;
import com.netease.nim.uikit.UIKitLogTag;
import com.netease.nim.uikit.cache.FriendDataCache;
import com.netease.nim.uikit.common.fragment.TFragment;
import com.netease.nim.uikit.common.ui.liv.LetterIndexView;
import com.netease.nim.uikit.common.ui.liv.LivIndex;
import com.netease.nim.uikit.common.util.log.LogUtil;
import com.netease.nim.uikit.contact.core.item.AbsContactItem;
import com.netease.nim.uikit.contact.core.item.ContactItem;
import com.netease.nim.uikit.contact.core.item.ItemTypes;
import com.netease.nim.uikit.contact.core.model.ContactDataAdapter;
import com.netease.nim.uikit.contact.core.model.ContactGroupStrategy;
import com.netease.nim.uikit.contact.core.provider.ContactDataProvider;
import com.netease.nim.uikit.contact.core.query.IContactDataProvider;
import com.netease.nim.uikit.contact.core.viewholder.LabelHolder;
import com.netease.nim.uikit.contact.core.viewholder.OnlineStateContactHolder;
import com.netease.nim.uikit.uinfo.UserInfoHelper;
import com.netease.nim.uikit.uinfo.UserInfoObservable;
import com.netease.nimlib.sdk.Observer;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.listener.PauseOnScrollListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* 通讯录Fragment
* <p/>
* Created by huangjun on 2015/9/7.
*/
public class ContactsFragment extends TFragment {
private ContactDataAdapter adapter;
private ListView listView;
private TextView countText;
private LivIndex litterIdx;
private View loadingFrame;
private ContactsCustomization customization;
private ReloadFrequencyControl reloadControl = new ReloadFrequencyControl();
public void setContactsCustomization(ContactsCustomization customization) {
this.customization = customization;
}
private static final class ContactsGroupStrategy extends ContactGroupStrategy {
public ContactsGroupStrategy() {
add(ContactGroupStrategy.GROUP_NULL, -1, "");
addABC(0);
}
}
/**
* ***************************************** 生命周期 *****************************************
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.nim_contacts, container, false);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// 界面初始化
initAdapter();
findViews();
buildLitterIdx(getView());
// 注册观察者
registerObserver(true);
registerOnlineStateChangeListener(true);
// 加载本地数据
reload(false);
}
@Override
public void onDestroy() {
super.onDestroy();
registerObserver(false);
registerOnlineStateChangeListener(false);
}
private void initAdapter() {
IContactDataProvider dataProvider = new ContactDataProvider(ItemTypes.FRIEND);
adapter = new ContactDataAdapter(getActivity(), new ContactsGroupStrategy(), dataProvider) {
@Override
protected List<AbsContactItem> onNonDataItems() {
if (customization != null) {
return customization.onGetFuncItems();
}
return new ArrayList<>();
}
@Override
protected void onPreReady() {
loadingFrame.setVisibility(View.VISIBLE);
}
@Override
protected void onPostLoad(boolean empty, String queryText, boolean all) {
loadingFrame.setVisibility(View.GONE);
int userCount = NimUIKit.getContactProvider().getMyFriendsCount();
countText.setText("共有好友" + userCount + "名");
onReloadCompleted();
}
};
adapter.addViewHolder(ItemTypes.LABEL, LabelHolder.class);
if (customization != null) {
adapter.addViewHolder(ItemTypes.FUNC, customization.onGetFuncViewHolderClass());
}
adapter.addViewHolder(ItemTypes.FRIEND, OnlineStateContactHolder.class);
}
private void findViews() {
// loading
loadingFrame = findView(R.id.contact_loading_frame);
// count
View countLayout = View.inflate(getView().getContext(), R.layout.nim_contacts_count_item, null);
countLayout.setClickable(false);
countText = (TextView) countLayout.findViewById(R.id.contactCountText);
// ListView
listView = findView(R.id.contact_list_view);
listView.addFooterView(countLayout); // 注意:addFooter要放在setAdapter之前,否则旧版本手机可能会add不上
listView.setAdapter(adapter);
listView.setOnScrollListener(new PauseOnScrollListener(ImageLoader.getInstance(), true, true));
ContactItemClickListener listener = new ContactItemClickListener();
listView.setOnItemClickListener(listener);
listView.setOnItemLongClickListener(listener);
}
private void buildLitterIdx(View view) {
LetterIndexView livIndex = (LetterIndexView) view.findViewById(R.id.liv_index);
livIndex.setNormalColor(getResources().getColor(R.color.contacts_letters_color));
ImageView imgBackLetter = (ImageView) view.findViewById(R.id.img_hit_letter);
TextView litterHit = (TextView) view.findViewById(R.id.tv_hit_letter);
litterIdx = adapter.createLivIndex(listView, livIndex, litterHit, imgBackLetter);
litterIdx.show();
}
private final class ContactItemClickListener implements OnItemClickListener, OnItemLongClickListener {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
AbsContactItem item = (AbsContactItem) adapter.getItem(position);
if (item == null) {
return;
}
int type = item.getItemType();
if (type == ItemTypes.FUNC && customization != null) {
customization.onFuncItemClick(item);
return;
}
if (type == ItemTypes.FRIEND && item instanceof ContactItem && NimUIKit.getContactEventListener() != null) {
NimUIKit.getContactEventListener().onItemClick(getActivity(), (((ContactItem) item).getContact()).getContactId());
}
}
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view,
int position, long id) {
AbsContactItem item = (AbsContactItem) adapter.getItem(position);
if (item == null) {
return false;
}
if (item instanceof ContactItem && NimUIKit.getContactEventListener() != null) {
NimUIKit.getContactEventListener().onItemLongClick(getActivity(), (((ContactItem) item).getContact()).getContactId());
}
return true;
}
}
public void scrollToTop() {
if (listView != null) {
int top = listView.getFirstVisiblePosition();
int bottom = listView.getLastVisiblePosition();
if (top >= (bottom - top)) {
listView.setSelection(bottom - top);
listView.smoothScrollToPosition(0);
} else {
listView.smoothScrollToPosition(0);
}
}
}
/**
* *********************************** 通讯录加载控制 *******************************
*/
/**
* 加载通讯录数据并刷新
*
* @param reload true则重新加载数据;false则判断当前数据源是否空,若空则重新加载,不空则不加载
*/
private void reload(boolean reload) {
if (!reloadControl.canDoReload(reload)) {
return;
}
if (adapter == null) {
if (getActivity() == null) {
return;
}
initAdapter();
}
// 开始加载
if (!adapter.load(reload)) {
// 如果不需要加载,则直接当完成处理
onReloadCompleted();
}
}
private void onReloadCompleted() {
if (reloadControl.continueDoReloadWhenCompleted()) {
// 计划下次加载,稍有延迟
getHandler().postDelayed(new Runnable() {
@Override
public void run() {
boolean reloadParam = reloadControl.getReloadParam();
Log.i(UIKitLogTag.CONTACT, "continue reload " + reloadParam);
reloadControl.resetStatus();
reload(reloadParam);
}
}, 50);
} else {
// 本次加载完成
reloadControl.resetStatus();
}
LogUtil.i(UIKitLogTag.CONTACT, "contact load completed");
}
/**
* 通讯录加载频率控制
*/
class ReloadFrequencyControl {
boolean isReloading = false;
boolean needReload = false;
boolean reloadParam = false;
boolean canDoReload(boolean param) {
if (isReloading) {
// 正在加载,那么计划加载完后重载
needReload = true;
if (param) {
// 如果加载过程中又有多次reload请求,多次参数只要有true,那么下次加载就是reload(true);
reloadParam = true;
}
LogUtil.i(UIKitLogTag.CONTACT, "pending reload task");
return false;
} else {
// 如果当前空闲,那么立即开始加载
isReloading = true;
return true;
}
}
boolean continueDoReloadWhenCompleted() {
return needReload;
}
void resetStatus() {
isReloading = false;
needReload = false;
reloadParam = false;
}
boolean getReloadParam() {
return reloadParam;
}
}
/**
* *********************************** 用户资料、好友关系变更、登录数据同步完成观察者 *******************************
*/
private void registerObserver(boolean register) {
if (register) {
UserInfoHelper.registerObserver(userInfoObserver);
} else {
UserInfoHelper.unregisterObserver(userInfoObserver);
}
FriendDataCache.getInstance().registerFriendDataChangedObserver(friendDataChangedObserver, register);
LoginSyncDataStatusObserver.getInstance().observeSyncDataCompletedEvent(loginSyncCompletedObserver);
}
FriendDataCache.FriendDataChangedObserver friendDataChangedObserver = new FriendDataCache.FriendDataChangedObserver() {
@Override
public void onAddedOrUpdatedFriends(List<String> accounts) {
reloadWhenDataChanged(accounts, "onAddedOrUpdatedFriends", true);
}
@Override
public void onDeletedFriends(List<String> accounts) {
reloadWhenDataChanged(accounts, "onDeletedFriends", true);
}
@Override
public void onAddUserToBlackList(List<String> accounts) {
reloadWhenDataChanged(accounts, "onAddUserToBlackList", true);
}
@Override
public void onRemoveUserFromBlackList(List<String> accounts) {
reloadWhenDataChanged(accounts, "onRemoveUserFromBlackList", true);
}
};
private UserInfoObservable.UserInfoObserver userInfoObserver = new UserInfoObservable.UserInfoObserver() {
@Override
public void onUserInfoChanged(List<String> accounts) {
reloadWhenDataChanged(accounts, "onUserInfoChanged", true, false); // 非好友资料变更,不用刷新界面
}
};
private Observer<Void> loginSyncCompletedObserver = new Observer<Void>() {
@Override
public void onEvent(Void aVoid) {
getHandler().postDelayed(new Runnable() {
@Override
public void run() {
reloadWhenDataChanged(null, "onLoginSyncCompleted", false);
}
}, 50);
}
};
private void reloadWhenDataChanged(List<String> accounts, String reason, boolean reload) {
reloadWhenDataChanged(accounts, reason, reload, true);
}
private void reloadWhenDataChanged(List<String> accounts, String reason, boolean reload, boolean force) {
if (accounts == null || accounts.isEmpty()) {
return;
}
boolean needReload = false;
if (!force) {
// 非force:与通讯录无关的(非好友)变更通知,去掉
for (String account : accounts) {
if (FriendDataCache.getInstance().isMyFriend(account)) {
needReload = true;
break;
}
}
} else {
needReload = true;
}
if (!needReload) {
Log.d(UIKitLogTag.CONTACT, "no need to reload contact");
return;
}
// log
StringBuilder sb = new StringBuilder();
sb.append("ContactFragment received data changed as [" + reason + "] : ");
if (accounts != null && !accounts.isEmpty()) {
for (String account : accounts) {
sb.append(account);
sb.append(" ");
}
sb.append(", changed size=" + accounts.size());
}
Log.i(UIKitLogTag.CONTACT, sb.toString());
// reload
reload(reload);
}
/**
* *********************************** 在线状态 *******************************
*/
OnlineStateChangeListener onlineStateChangeListener = new OnlineStateChangeListener() {
@Override
public void onlineStateChange(Set<String> accounts) {
// 更新
adapter.notifyDataSetChanged();
}
};
private void registerOnlineStateChangeListener(boolean register) {
if (!NimUIKit.enableOnlineState()) {
return;
}
if (register) {
NimUIKit.addOnlineStateChangeListeners(onlineStateChangeListener);
} else {
NimUIKit.removeOnlineStateChangeListeners(onlineStateChangeListener);
}
}
}