package com.realtrackandroid.views.projectsactivities; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseExpandableListAdapter; import android.widget.ExpandableListView; import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.TextView; import com.realtrackandroid.R; import com.realtrackandroid.backend.activities.ParticipationDAO; import com.realtrackandroid.common.StyledButton; import com.realtrackandroid.models.activities.Activities; import com.realtrackandroid.models.activities.Participation; import com.realtrackandroid.models.projects.Project; import com.realtrackandroid.views.activities.AddActivitiesActivity; import com.realtrackandroid.views.activities.DisplayActivitiesActivity; import com.realtrackandroid.views.participationsactive.RecordOrEditParticipationActivity; import com.realtrackandroid.views.participationsactive.RecordQuickParticipationActivity; import com.realtrackandroid.views.projects.AddProjectActivity; import com.realtrackandroid.views.projects.DisplayProjectActivity; public class ProjectsActivitiesListAdapter extends BaseExpandableListAdapter { private Context context; private int groupLayoutResourceId; private int childLayoutResourceId; private List<ProjectsActivitiesHolder> projectsActivitiesData = null; private View row; private LayoutInflater inflater; private ExpandableListView listView; private ParticipationDAO participationDAO; private DateFormat parser; public ProjectsActivitiesListAdapter(Context context, int groupLayoutResourceId, int childLayoutResourceId, ExpandableListView expandableListView, List<ProjectsActivitiesHolder> projectsActivitiesData) { super(); this.groupLayoutResourceId = groupLayoutResourceId; this.childLayoutResourceId = childLayoutResourceId; this.context = context; listView = expandableListView; this.projectsActivitiesData = projectsActivitiesData; participationDAO = new ParticipationDAO(context); parser = new SimpleDateFormat("MM/dd/yyyy"); } public void setInflater(LayoutInflater inflater) { this.inflater = inflater; } @Override public int getGroupCount() { return projectsActivitiesData.size(); } @Override public int getChildrenCount(int groupPosition) { return projectsActivitiesData.get(groupPosition).getActivitiesList().size(); } @Override public Object getGroup(int groupPosition) { return projectsActivitiesData.get(groupPosition); } @Override public Object getChild(int groupPosition, int childPosition) { return projectsActivitiesData.get(groupPosition).getActivitiesList().get(childPosition); } @Override public long getGroupId(int groupPosition) { return groupPosition; } @Override public long getChildId(int groupPosition, int childPosition) { return childPosition; } @Override public boolean hasStableIds() { return false; } @Override public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { final int groupPos = groupPosition; final boolean isExp = isExpanded; row = convertView; ParentViewHolder holder = null; if (row == null) { LayoutInflater inflater = ((Activity) context).getLayoutInflater(); row = inflater.inflate(groupLayoutResourceId, parent, false); holder = new ParentViewHolder(); holder.projectLinearLayout = (LinearLayout) row.findViewById(R.id.projectLinearLayout); holder.projectTitle = (TextView) row.findViewById(R.id.projectTitle); holder.projectStartDate = (TextView) row.findViewById(R.id.projectStartDate); holder.expandCollapseProjectBtn = (StyledButton) row .findViewById(R.id.expandCollapseProjectBtn); row.setTag(holder); } else holder = (ParentViewHolder) row.getTag(); final Project project = ((ProjectsActivitiesHolder) getGroup(groupPosition)).getProject(); holder.projectTitle.setText(project.getTitle()); final ParentViewHolder holderFinal = holder; holder.projectLinearLayout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { holderFinal.projectTitle.performClick(); } }); if (project.getId() == -1) { // "add new project..." item. holder.projectStartDate.setVisibility(View.GONE); holder.expandCollapseProjectBtn.setText(context.getResources().getString( R.string.fa_pluscircle)); holder.expandCollapseProjectBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { holderFinal.projectTitle.performClick(); } }); holder.projectTitle.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent i = new Intent(context, AddProjectActivity.class); context.startActivity(i); ((AllProjectsActivitiesActivity) context).overridePendingTransition( R.anim.animation_slideinright, R.anim.animation_slideoutleft); } }); } else { DateFormat parser = new SimpleDateFormat("MM/dd/yyyy"); Date startDate = new Date(project.getStartDate()); Date endDate = new Date(project.getEndDate()); holder.projectStartDate.setVisibility(View.VISIBLE); holder.projectStartDate.setText(parser.format(startDate) + " " + context.getResources().getString(R.string.emdash) + " " + parser.format(endDate)); if (isExp) holder.expandCollapseProjectBtn.setText(context.getResources().getString( R.string.fa_downchevroncircle)); else holder.expandCollapseProjectBtn.setText(context.getResources().getString( R.string.fa_rightchevroncircle)); // handle click on the title and show participation details holder.projectTitle.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent i = new Intent(context, DisplayProjectActivity.class); i.putExtra("projectid", project.getId()); context.startActivity(i); ((AllProjectsActivitiesActivity) context).overridePendingTransition( R.anim.animation_slideinright, R.anim.animation_slideoutleft); } }); holder.projectStartDate.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent i = new Intent(context, DisplayProjectActivity.class); i.putExtra("projectid", project.getId()); context.startActivity(i); ((AllProjectsActivitiesActivity) context).overridePendingTransition( R.anim.animation_slideinright, R.anim.animation_slideoutleft); } }); // expand and collapse groups holder.expandCollapseProjectBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (isExp) { listView.collapseGroup(groupPos); holderFinal.expandCollapseProjectBtn.setText(context.getResources().getString( R.string.fa_rightchevroncircle)); } else { listView.expandGroup(groupPos); holderFinal.expandCollapseProjectBtn.setText(context.getResources().getString( R.string.fa_downchevroncircle)); } } }); } return row; } @Override public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { final int groupPos = groupPosition; row = convertView; ChildViewHolder holder = null; if (row == null) { row = inflater.inflate(childLayoutResourceId, parent, false); holder = new ChildViewHolder(); holder.activityTitle = (TextView) row.findViewById(R.id.activityTitle); holder.activityStartDate = (TextView) row.findViewById(R.id.activityStartDate); holder.quickParticipationBtn = (StyledButton) row.findViewById(R.id.quickParticipationBtn); holder.activityLinearLayout = (LinearLayout) row.findViewById(R.id.activityLinearLayout); holder.participationsLinearLayout = (LinearLayout) row .findViewById(R.id.participationsLinearLayout); holder.expandCollapseActivityBtn = (StyledButton) row .findViewById(R.id.expandCollapseActivityBtn); holder.isExp = true; // show participationsLinearLayout by default row.setTag(holder); } else holder = (ChildViewHolder) row.getTag(); final Activities activity = (Activities) getChild(groupPosition, childPosition); holder.activityTitle.setText(activity.getTitle()); final ChildViewHolder holderFinal = holder; holder.activityLinearLayout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { holderFinal.activityTitle.performClick(); } }); if (activity.getId() == -1) { // "add new activity..." item. holder.quickParticipationBtn.setVisibility(View.GONE); holder.participationsLinearLayout.setVisibility(View.GONE); holder.activityStartDate.setVisibility(View.GONE); holder.expandCollapseActivityBtn.setText(context.getResources().getString( R.string.fa_pluscircle)); holder.expandCollapseActivityBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { holderFinal.activityTitle.performClick(); } }); holder.activityTitle.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent i = new Intent(context, AddActivitiesActivity.class); i.putExtra("projectid", projectsActivitiesData.get(groupPos).getProject().getId()); context.startActivity(i); ((AllProjectsActivitiesActivity) context).overridePendingTransition( R.anim.animation_slideinright, R.anim.animation_slideoutleft); } }); } else { // normal activity item Date startDate = new Date(activity.getStartDate()); Date endDate = new Date(activity.getEndDate()); holder.activityStartDate.setText(parser.format(startDate) + " " + context.getResources().getString(R.string.emdash) + " " + parser.format(endDate)); holder.quickParticipationBtn.setVisibility(View.VISIBLE); holder.activityStartDate.setVisibility(View.VISIBLE); holder.participationsLinearLayout.setVisibility(View.VISIBLE); holder.expandCollapseActivityBtn.setText(context.getResources().getString( R.string.fa_downchevroncircle)); // handle click on the title and show activity details holder.activityTitle.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent i = new Intent(context, DisplayActivitiesActivity.class); i.putExtra("activitiesid", activity.getId()); context.startActivity(i); ((AllProjectsActivitiesActivity) context).overridePendingTransition( R.anim.animation_slideinright, R.anim.animation_slideoutleft); } }); holder.activityStartDate.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent i = new Intent(context, DisplayActivitiesActivity.class); i.putExtra("activitiesid", activity.getId()); context.startActivity(i); ((AllProjectsActivitiesActivity) context).overridePendingTransition( R.anim.animation_slideinright, R.anim.animation_slideoutleft); } }); // handle click on the quick participation icon holder.quickParticipationBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ParticipationDAO pDao = new ParticipationDAO(context); int largestParticipationId = pDao.getLargestParticipationId() + 1; // the new // participation will // have an id one more // than the max so far // recorded Intent i = new Intent(context, RecordQuickParticipationActivity.class); i.putExtra("largestParticipationId", largestParticipationId); i.putExtra("activitiesid", activity.getId()); context.startActivity(i); ((AllProjectsActivitiesActivity) context).overridePendingTransition( R.anim.animation_slideinright, R.anim.animation_slideoutleft); } }); /*--------------------------------------------------------------------------------- * To display the participations, I explored and implemented a number of options * 1. An ExpandableListView as the child of this ExpandableListView. * 2. A ListView embedded in this child below the activity details. * Neither of these solutions play very well. First, because you're not supposed to * nest scrollable views, period. Second, we need to update the height of the children * on participation adds/deletes or activities adds/deletes or the children won't redraw * to fit in the new data. This is updating the height requires some jugglery with * onMeasure and MeasureSpec. * * Dynamically adding views is a much simpler solution. Plus, reading the participations * afresh every time does away with the PITA of managing the same backing data for nested * views. * Going with a programmatically added view *does* add some overhead in terms of simulating * "expanding" and "collapsing" of the activities but this is nowhere as nearly complex * as the other options. * -------------------------------------------------------------------------------*/ holder.participationsLinearLayout.removeAllViews(); // required because child views are // reused. So if you collapse a Project // and re-expand it, it'll already // have the old activity + participation // information final List<Participation> participationList = participationDAO .getServicedParticipationsForActivityId(activity.getId()); if (participationList.isEmpty()) collapseChild(holder); for (final Participation p : participationList) { // the false in the method call below ensures we don't attach the inflated layout right // away. if we did, since all the // participationsLinearLayouts have the same id. the rest of this loop would only refer to // the first participationLinearLayout final RelativeLayout participationRelativeLayout = (RelativeLayout) inflater.inflate( R.layout.row_allparticipations, holder.participationsLinearLayout, false); Date d = new Date(p.getDate()); // handle click on the title and show participation details final TextView participationDetails = (TextView) participationRelativeLayout .findViewById(R.id.participationDetails); participationDetails.setText(parser.format(d) + ": " + p.getTotalParticipants() + " participants"); StyledButton editParticipationBtn = (StyledButton) participationRelativeLayout .findViewById(R.id.editParticipationBtn); editParticipationBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent i = new Intent(context, RecordOrEditParticipationActivity.class); i.putExtra("participationid", p.getId()); i.putExtra("datetime", p.getDate()); i.putExtra("editparticipation", true); context.startActivity(i); ((AllProjectsActivitiesActivity) context).overridePendingTransition( R.anim.animation_slideinright, R.anim.animation_slideoutleft); } }); StyledButton deleteParticipationBtn = (StyledButton) participationRelativeLayout .findViewById(R.id.deleteParticipationBtn); deleteParticipationBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // warn the user first! new AlertDialog.Builder(context) .setMessage( "Are you sure you want to delete this participation? This CANNOT be undone.") .setCancelable(false).setNegativeButton("No", null) .setPositiveButton("Yes", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { participationDAO.deleteParticipation(p.getId()); participationList.remove(p); holderFinal.participationsLinearLayout .removeView(participationRelativeLayout); if (participationList.isEmpty()) collapseChild(holderFinal); } }).show(); } }); holder.participationsLinearLayout.addView(participationRelativeLayout); } // simulate expand collapse clicks for activities holder.expandCollapseActivityBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (holderFinal.isExp) { // "collapse" collapseChild(holderFinal); holderFinal.participationsLinearLayout.setVisibility(View.GONE); } else if (!participationList.isEmpty()) { // "expand". Only if there actually are // participations expandChild(holderFinal); holderFinal.participationsLinearLayout.setVisibility(View.VISIBLE); } } }); } return row; } @Override public boolean isChildSelectable(int groupPosition, int childPosition) { return false; // must be true if you want child to be clickable! } private void expandChild(ChildViewHolder holder) { holder.isExp = true; holder.expandCollapseActivityBtn.setText(context.getResources().getString( R.string.fa_downchevroncircle)); } private void collapseChild(ChildViewHolder holder) { holder.isExp = false; holder.expandCollapseActivityBtn.setText(context.getResources().getString( R.string.fa_rightchevroncircle)); } private class ParentViewHolder { LinearLayout projectLinearLayout; StyledButton expandCollapseProjectBtn; TextView projectTitle; TextView projectStartDate; } private class ChildViewHolder { LinearLayout activityLinearLayout; LinearLayout participationsLinearLayout; boolean isExp; StyledButton expandCollapseActivityBtn; StyledButton quickParticipationBtn; TextView activityTitle; TextView activityStartDate; } }