package net.coding.program.project.detail;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Intent;
import android.graphics.PorterDuff;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.SectionIndexer;
import android.widget.TextView;
import android.widget.Toast;
import com.loopj.android.http.RequestParams;
import com.melnykov.fab.FloatingActionButton;
import net.coding.program.MyApp;
import net.coding.program.R;
import net.coding.program.common.BlankViewDisplay;
import net.coding.program.common.Global;
import net.coding.program.common.ListModify;
import net.coding.program.common.network.RefreshBaseFragment;
import net.coding.program.common.umeng.UmengEvent;
import net.coding.program.common.widget.FlowLabelLayout;
import net.coding.program.model.AccountInfo;
import net.coding.program.model.ProjectObject;
import net.coding.program.model.TaskObject;
import net.coding.program.task.TaskListUpdate;
import net.coding.program.task.add.TaskAddActivity_;
import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.Click;
import org.androidannotations.annotations.EFragment;
import org.androidannotations.annotations.FragmentArg;
import org.androidannotations.annotations.OptionsItem;
import org.androidannotations.annotations.ViewById;
import org.androidannotations.annotations.res.StringArrayRes;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.WeakHashMap;
import se.emilsjolander.stickylistheaders.ExpandableStickyListHeadersListView;
import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter;
import se.emilsjolander.stickylistheaders.StickyListHeadersListView;
@EFragment(R.layout.fragment_task_list)
public class TaskListFragment extends RefreshBaseFragment implements TaskListUpdate {
public static final String hostTaskDelete = Global.HOST_API + "/user/%s/project/%s/task/%s";
final SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd");
final String urlTaskCountProject = Global.HOST_API + "/project/%d/task/user/count";
final String urlTaskCountMy = Global.HOST_API + "/tasks/projects/count";
final String URL_TASK_SATUS = Global.HOST_API + "/task/%s/status";
@FragmentArg
boolean mShowAdd = false;
@FragmentArg
TaskObject.Members mMembers;
@FragmentArg
ProjectObject mProjectObject;
@ViewById
View blankLayout;
@ViewById
FloatingActionButton fab;
@ViewById
StickyListHeadersListView listView;
@StringArrayRes
String[] task_titles;
boolean mNeedUpdate = true;
ArrayList<TaskObject.SingleTask> mData = new ArrayList<>();
int mSectionId;
int mTaskCount[] = new int[2];
boolean mUpdateAll = true;
String urlAll = "";
View.OnClickListener onClickRetry = v -> onRefresh();
TestBaseAdapter mAdapter;
String mToday = "";
String mTomorrow = "";
WeakHashMap<View, Integer> mOriginalViewHeightPool = new WeakHashMap<>();
private net.coding.program.task.TaskListParentUpdate mParent;
public void setParent(net.coding.program.task.TaskListParentUpdate parent) {
mParent = parent;
}
@Override
public void onCreate(Bundle saveInstanceState) {
super.onCreate(saveInstanceState);
setHasOptionsMenu(true);
}
@Override
public void taskListUpdate(boolean must) {
if (must) {
mNeedUpdate = true;
}
if (mNeedUpdate) {
mNeedUpdate = false;
initSetting();
loadData();
}
}
@Override
public void onRefresh() {
initSetting();
loadData();
}
@OptionsItem
public void action_add() {
mNeedUpdate = true;
Intent intent = new Intent(getActivity(), TaskAddActivity_.class);
TaskObject.SingleTask task = new TaskObject.SingleTask();
task.project = mProjectObject;
task.project_id = mProjectObject.getId();
task.owner = AccountInfo.loadAccount(getActivity());
task.owner_id = task.owner.id;
intent.putExtra("mSingleTask", task);
intent.putExtra("mUserOwner", mMembers.user);
getParentFragment().startActivityForResult(intent, ListModify.RESULT_EDIT_LIST);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mNeedUpdate = true;
return super.onCreateView(inflater, container, savedInstanceState);
}
String createHost(String userId, String type) {
String BASE_HOST = Global.HOST_API + "%s/tasks%s?";
String userType;
if (mProjectObject.isEmpty()) {
userType = type;
} else {
if (userId.isEmpty()) {
userType = type;
} else {
userType = "/user/" + userId + type;
}
}
return String.format(BASE_HOST, mProjectObject.backend_project_path, userType);
}
@AfterViews
protected void init() {
initRefreshLayout();
Calendar calendar = Calendar.getInstance();
mToday = mDateFormat.format(calendar.getTimeInMillis());
mTomorrow = mDateFormat.format(calendar.getTimeInMillis() + 1000 * 60 * 60 * 24);
mNeedUpdate = true;
mAdapter = new TestBaseAdapter();
fab.attachToListView(listView.getWrappedList());
fab.setVisibility(View.GONE);
View footer = getActivity().getLayoutInflater().inflate(R.layout.divide_15_top, null);
listView.addFooterView(footer, null, false);
listView.setAdapter(mAdapter);
listView.setOnItemClickListener((parent, view, position, id) -> {
TaskObject.SingleTask singleTask = (TaskObject.SingleTask) mAdapter.getItem(position);
mNeedUpdate = true;
TaskAddActivity_.intent(getParentFragment())
.mSingleTask(singleTask)
.canPickProject(false)
.startForResult(ListModify.RESULT_EDIT_LIST);
});
listView.setOnItemLongClickListener((parent, view, position, id) -> {
String content = mData.get(position).content;
showDialog("删除任务", content, (dialog, which) -> deleteTask(position));
return true;
});
urlAll = createHost(mMembers.user.global_key, "/all");
loadData();
}
@Click
void fab() {
action_add();
}
private void loadData() {
getNextPageNetwork(urlAll, urlAll);
if (mUpdateAll) {
if (mProjectObject.isEmpty()) {
getNetwork(urlTaskCountMy, urlTaskCountMy);
} else {
String url = String.format(urlTaskCountProject, mProjectObject.getId());
getNetwork(url, urlTaskCountProject);
}
}
}
@Override
protected void initSetting() {
super.initSetting();
mTaskCount[0] = 0;
mTaskCount[1] = 0;
mSectionId = 0;
mUpdateAll = true;
}
@Override
public void parseJson(int code, JSONObject respanse, String tag, int pos, Object data) throws JSONException {
if (tag.equals(urlAll)) {
setRefreshing(false);
if (code == 0) {
if (mUpdateAll) {
mData.clear();
mUpdateAll = false;
}
JSONObject jsonData = respanse.getJSONObject("data");
JSONArray array = jsonData.getJSONArray("list");
for (int i = 0; i < array.length(); ++i) {
TaskObject.SingleTask task = new TaskObject.SingleTask(array.getJSONObject(i));
mData.add(task);
}
mAdapter.notifyDataSetChanged();
AccountInfo.saveTasks(getActivity(), mData, mProjectObject.getId(), mMembers.id);
BlankViewDisplay.setBlank(mData.size(), this, true, blankLayout, onClickRetry);
} else {
showErrorMsg(code, respanse);
BlankViewDisplay.setBlank(mData.size(), this, false, blankLayout, onClickRetry);
}
mUpdateAll = false;
} else if (tag.equals(urlTaskCountMy)) {
if (code == 0) {
JSONArray array = respanse.getJSONArray("data");
for (int i = 0; i < array.length(); ++i) {
JSONObject item = array.getJSONObject(i);
if (item.optInt("project") == (mProjectObject.getId())) {
mTaskCount[0] = item.getInt("processing");
mTaskCount[1] = item.getInt("done");
break;
}
}
mAdapter.notifyDataSetChanged();
}
} else if (tag.equals(urlTaskCountProject)) {
if (code == 0) {
JSONArray array = respanse.getJSONArray("data");
for (int i = 0; i < array.length(); ++i) {
JSONObject item = array.getJSONObject(i);
if (Integer.valueOf(item.getString("user")) == mMembers.id) {
mTaskCount[0] = item.getInt("processing");
mTaskCount[1] = item.getInt("done");
break;
}
}
mAdapter.notifyDataSetChanged();
}
} else if (tag.equals(hostTaskDelete)) {
if (code == 0) {
umengEvent(UmengEvent.TASK, "删除任务");
mData.remove(pos);
mAdapter.notifyDataSetChanged();
if (mParent != null) {
mNeedUpdate = false;
mParent.taskListParentUpdate();
}
} else {
showErrorMsg(code, respanse);
}
} else if (tag.equals(URL_TASK_SATUS)) {
if (code == 0) {
umengEvent(UmengEvent.TASK, "修改任务");
TaskParam param = (TaskParam) data;
TaskObject.SingleTask task = param.mTask;
task.status = param.mStatus;
if (mParent != null) {
mNeedUpdate = false;
mParent.taskListParentUpdate();
}
} else {
Toast.makeText(getActivity(), "修改任务失败", Toast.LENGTH_SHORT).show();
}
mAdapter.notifyDataSetChanged();
}
}
void deleteTask(final int pos) {
TaskObject.SingleTask task = mData.get(pos);
String url = String.format(hostTaskDelete, task.project.owner_user_name, task.project.name, task.getId());
deleteNetwork(url, hostTaskDelete, pos, null);
}
void statusTask(final int pos, final int id, final boolean complete) {
RequestParams params = new RequestParams();
int completeStatus = complete ? 2 : 1;
params.put("status", completeStatus); // 任务完成2,任务正在进行1
putNetwork(String.format(URL_TASK_SATUS, id), params, URL_TASK_SATUS, new TaskParam(mData.get(pos), completeStatus));
}
public interface FloatButton {
void showFloatButton(boolean show);
}
static class TaskParam {
TaskObject.SingleTask mTask;
int mStatus;
TaskParam(TaskObject.SingleTask mTask, int mStatus) {
this.mTask = mTask;
this.mStatus = mStatus;
}
}
public class TestBaseAdapter extends BaseAdapter implements
StickyListHeadersAdapter, SectionIndexer {
public TestBaseAdapter() {
}
@Override
public void notifyDataSetChanged() {
mSectionId = 0;
for (TaskObject.SingleTask item : mData) {
if (item.status == TaskObject.STATUS_PRECESS) {
++mSectionId;
} else {
break;
}
}
super.notifyDataSetChanged();
}
@Override
public int getCount() {
return mData.size();
}
@Override
public Object getItem(int position) {
return mData.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
convertView = mInflater.inflate(R.layout.fragment_task_list_item, parent, false);
holder.mCheckBox = (CheckBox) convertView.findViewById(R.id.checkbox);
holder.mTitle = (TextView) convertView.findViewById(R.id.title);
holder.mDeadline = (TextView) convertView.findViewById(R.id.deadline);
holder.mDeadline.setBackgroundResource(R.drawable.task_list_item_deadline_background);
holder.mName = (TextView) convertView.findViewById(R.id.name);
holder.mTime = (TextView) convertView.findViewById(R.id.time);
holder.mDiscuss = (TextView) convertView.findViewById(R.id.discuss);
holder.mIcon = (ImageView) convertView.findViewById(R.id.icon);
holder.mTaskPriority = convertView.findViewById(R.id.taskPriority);
holder.mTaskDes = convertView.findViewById(R.id.taskDes);
holder.mLayoutDeadline = convertView.findViewById(R.id.layoutDeadline);
holder.mRefId = (TextView) convertView.findViewById(R.id.referenceId);
holder.flowLabelLayout = (FlowLabelLayout) convertView.findViewById(R.id.flowLayout);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
final TaskObject.SingleTask data = (TaskObject.SingleTask) getItem(position);
holder.mTitle.setText(" " + data.content);
holder.mRefId.setText(data.getNumber());
holder.mName.setText(data.creator.name);
holder.mTime.setText(Global.dayToNow(data.created_at));
holder.mDiscuss.setText(String.valueOf(data.comments));
iconfromNetwork(holder.mIcon, data.owner.avatar);
int flowWidth = MyApp.sWidthPix - Global.dpToPx(100 + 12); // item 左边空 100 dp,右边空12dp
if (!data.deadline.isEmpty()) {
flowWidth -= Global.dpToPx(55);
}
holder.flowLabelLayout.setLabels(data.labels, flowWidth);
final int pos = position;
holder.mCheckBox.setOnCheckedChangeListener(null);
if (data.status == 1) {
holder.mCheckBox.setChecked(false);
} else {
holder.mCheckBox.setChecked(true);
}
holder.mTaskDes.setVisibility(data.has_description ? View.VISIBLE : View.INVISIBLE);
final int priorityIcons[] = new int[]{
R.drawable.task_mark_0,
R.drawable.task_mark_1,
R.drawable.task_mark_2,
R.drawable.task_mark_3,
};
int priority = data.priority;
if (priorityIcons.length <= priority) {
priority = priorityIcons.length - 1;
}
holder.mTaskPriority.setBackgroundResource(priorityIcons[priority]);
if (data.deadline.isEmpty() && data.labels.isEmpty()) {
holder.mLayoutDeadline.setVisibility(View.GONE);
} else {
holder.mLayoutDeadline.setVisibility(View.VISIBLE);
}
int[] taskColors = new int[]{
0xfff49f31,
0xff97ba66,
0xfff24b4b,
0xffb2c6d0,
0xffc7c8c7
};
if (data.deadline.isEmpty()) {
holder.mDeadline.setVisibility(View.GONE);
} else {
holder.mDeadline.setVisibility(View.VISIBLE);
if (data.deadline.equals(mToday)) {
holder.mDeadline.setText("今天");
holder.setDeadlineColor(taskColors[0]);
} else if (data.deadline.equals(mTomorrow)) {
holder.mDeadline.setText("明天");
holder.setDeadlineColor(taskColors[1]);
} else {
if (data.deadline.compareTo(mToday) < 0) {
holder.setDeadlineColor(taskColors[2]);
} else {
holder.setDeadlineColor(taskColors[3]);
}
String num[] = data.deadline.split("-");
holder.mDeadline.setText(String.format("%s/%s", num[1], num[2]));
}
if (data.isDone()) {
holder.setDeadlineColor(taskColors[4]);
}
}
holder.mCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
statusTask(pos, data.getId(), isChecked);
}
});
if (position == mData.size() - 1) {
loadData();
}
return convertView;
}
@Override
public View getHeaderView(int position, View convertView, ViewGroup parent) {
HeaderViewHolder holder;
if (convertView == null) {
holder = new HeaderViewHolder();
convertView = mInflater.inflate(R.layout.fragment_project_dynamic_list_head, parent, false);
holder.mHead = (TextView) convertView.findViewById(R.id.head);
convertView.setTag(holder);
} else {
holder = (HeaderViewHolder) convertView.getTag();
}
int type = getSectionForPosition(position);
String title = task_titles[type];
holder.mHead.setText(title);
return convertView;
}
@Override
public long getHeaderId(int position) {
return getSectionForPosition(position);
}
@Override
public int getPositionForSection(int section) {
return section;
}
@Override
public int getSectionForPosition(int position) {
if (position < mSectionId) {
return 0;
} else {
return 1;
}
}
@Override
public Object[] getSections() {
return task_titles;
}
class HeaderViewHolder {
TextView mHead;
}
class ViewHolder {
CheckBox mCheckBox;
ImageView mIcon;
TextView mTitle;
TextView mDeadline;
TextView mName;
TextView mTime;
TextView mDiscuss;
View mTaskPriority;
View mTaskDes;
View mLayoutDeadline;
FlowLabelLayout flowLabelLayout;
TextView mRefId;
public void setDeadlineColor(int color) {
mDeadline.getBackground().setColorFilter(color, PorterDuff.Mode.SRC_IN);
mDeadline.setTextColor(color);
}
}
}
//animation executor
class AnimationExecutor implements ExpandableStickyListHeadersListView.IAnimationExecutor {
@Override
public void executeAnim(final View target, final int animType) {
if (ExpandableStickyListHeadersListView.ANIMATION_EXPAND == animType && target.getVisibility() == View.VISIBLE) {
return;
}
if (ExpandableStickyListHeadersListView.ANIMATION_COLLAPSE == animType && target.getVisibility() != View.VISIBLE) {
return;
}
if (mOriginalViewHeightPool.get(target) == null) {
mOriginalViewHeightPool.put(target, target.getHeight());
}
final int viewHeight = mOriginalViewHeightPool.get(target);
float animStartY = animType == ExpandableStickyListHeadersListView.ANIMATION_EXPAND ? 0f : viewHeight;
float animEndY = animType == ExpandableStickyListHeadersListView.ANIMATION_EXPAND ? viewHeight : 0f;
final ViewGroup.LayoutParams lp = target.getLayoutParams();
ValueAnimator animator = ValueAnimator.ofFloat(animStartY, animEndY);
animator.setDuration(200);
target.setVisibility(View.VISIBLE);
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
}
@Override
public void onAnimationEnd(Animator animator) {
if (animType == ExpandableStickyListHeadersListView.ANIMATION_EXPAND) {
target.setVisibility(View.VISIBLE);
} else {
target.setVisibility(View.GONE);
}
target.getLayoutParams().height = viewHeight;
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
lp.height = ((Float) valueAnimator.getAnimatedValue()).intValue();
target.setLayoutParams(lp);
target.requestLayout();
}
});
animator.start();
}
}
}