package com.dinhcv.lifelogpedometer.activity; import android.app.DatePickerDialog; import android.content.Context; import android.graphics.Color; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Bundle; import android.support.annotation.Nullable; import android.util.Pair; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.View; import android.view.ViewGroup; import android.widget.DatePicker; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; import com.dinhcv.lifelogpedometer.R; import com.dinhcv.lifelogpedometer.feature.Database; import com.dinhcv.lifelogpedometer.interfaces.LLAPIManagerListener; import com.dinhcv.lifelogpedometer.model.StepModel; import com.dinhcv.lifelogpedometer.model.structure.top.StepHourInfo; import com.dinhcv.lifelogpedometer.model.structure.top.TagetTopInfo; import com.dinhcv.lifelogpedometer.portal.LLAPIManager; import com.dinhcv.lifelogpedometer.utils.Const; import com.dinhcv.lifelogpedometer.utils.DayAxisValueFormatter; import com.dinhcv.lifelogpedometer.utils.Debug; import com.dinhcv.lifelogpedometer.utils.Utils; import com.github.mikephil.charting.components.XAxis; import com.github.mikephil.charting.components.YAxis; import com.github.mikephil.charting.charts.BarChart; import com.github.mikephil.charting.data.BarData; import com.github.mikephil.charting.data.BarDataSet; import com.github.mikephil.charting.data.BarEntry; import com.github.mikephil.charting.interfaces.datasets.IBarDataSet; import org.eazegraph.lib.charts.PieChart; import org.eazegraph.lib.models.PieModel; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.Locale; import static com.github.mikephil.charting.utils.ColorTemplate.rgb; public class TopFragment extends FragmentBase implements SettingFragmentPresenter, SensorEventListener { private TextView stepsView; private TextView tvStepGoal; private TextView tvDistance; private TextView tvStepRemain; private TextView tvStepRateDone; private boolean showSteps = true; private PieModel sliceGoal, sliceCurrent; private PieChart pg; private TextView tvDate; private ImageView ivBack; private ImageView ivNext; private ImageView ivPlay; private LinearLayout llBike; private LinearLayout llWalking; private LinearLayout llRunning; private Const.STEP_TYPE stepType; private Date mAnaDate; private Calendar mCalendar; private int mAnaDay; private int mAnaMonth; private int mAnaYear; public static int STEP_SIZE = 75; private StepModel mStepModel; private TextView tvSmallStepGoal; private TextView tvSmallRemain; private Context mContext; private SensorManager sensorManager; private boolean activityRunning; private int stepTotal = 0; private int stepRemain = 0; private int stepCount = 0; private Date mFromDate; private Date mToDate; private TagetTopInfo mTagetTopInfo = new TagetTopInfo(); private BarChart mChart; private List dateList; private String[] mParties; private Integer[] mStep; @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); } @Override public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) { final View v = inflater.inflate(R.layout.fragment_top, null); mContext = getActivity(); sensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE); initView(v); // slice for the steps taken today sliceCurrent = new PieModel("", 0, Color.parseColor("#6FE7F7")); pg.addPieSlice(sliceCurrent); // slice for the "missing" steps until reaching the goal sliceGoal = new PieModel("", Const.STEP_GOAL, Color.parseColor("#B7B8B6")); pg.addPieSlice(sliceGoal); pg.setDrawValueInPie(false); pg.setUsePieRotation(false); pg.startAnimation(); pg.setAutoCenterInSlice(false); mCalendar = Calendar.getInstance(); mCalendar.setTime(new Date()); mAnaDate = mCalendar.getTime(); mAnaYear = mCalendar.get(Calendar.YEAR); mAnaMonth = mCalendar.get(Calendar.MONTH); mAnaDay = mCalendar.get(Calendar.DAY_OF_MONTH); tvDate.setText(Utils.dateToStringFormatDayMonthYearJp(mAnaDate)); handleEvent(); return v; } private void initView(View v){ stepsView = (TextView) v.findViewById(R.id.steps); tvDistance = (TextView) v.findViewById(R.id.tv_distance); tvStepGoal = (TextView) v.findViewById(R.id.tv_stepGoal); tvStepRemain = (TextView) v.findViewById(R.id.tv_stepRemain); tvStepRateDone = (TextView) v.findViewById(R.id.tv_stepRateDone); tvSmallStepGoal = (TextView) v.findViewById(R.id.tv_smallStepGoal); tvSmallRemain = (TextView) v.findViewById(R.id.tv_smallRemain); tvDate = (TextView) v.findViewById(R.id.tv_date); ivBack = (ImageView) v.findViewById(R.id.iv_back); ivNext = (ImageView) v.findViewById(R.id.iv_next); ivPlay = (ImageView) v.findViewById(R.id.iv_play); mChart = (BarChart) v.findViewById(R.id.chart); pg = (PieChart) v.findViewById(R.id.graph); } private void stepsDistanceChanged() { updatePie(); updateBars(); } @Override public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { inflater.inflate(R.menu.main, menu); } private void updatePie() { // todayOffset might still be Integer.MIN_VALUE on first start int steps_today = Math.max(todayOffset + since_boot, 0); sliceCurrent.setValue(steps_today); if (Const.STEP_GOAL - steps_today > 0) { // goal not reached yet if (pg.getData().size() == 1) { pg.addPieSlice(sliceGoal); } sliceGoal.setValue(Const.STEP_GOAL - steps_today); } else { // goal reached pg.clearChart(); pg.addPieSlice(sliceCurrent); } pg.update(); stepsView.setText(formatter.format(steps_today)); int remain = Const.STEP_GOAL - steps_today; tvStepRemain.setText(String.valueOf(remain)); tvStepRateDone.setText(getResources().getString(R.string.percent_unit, Utils.convert2String2Decimal(steps_today *100/ Const.STEP_GOAL))); tvSmallRemain.setText(getResources().getString(R.string.pie_text_content3a, remain)); double distance_today = steps_today * STEP_SIZE; distance_today /= 100000; tvDistance.setText(Utils.convert2String2Decimal(distance_today)); } /** * Updates the bar graph to show the steps/distance of the last week. Should * be called when switching from step count to distance. */ private void updateBars() { dateList = new ArrayList<>(); List stepList = new ArrayList<>(); Database db = Database.getInstance(getActivity()); List> last = db.getLastEntries(8, mAnaDate); db.close(); for (int i = last.size() - 1; i > 0; i--) { Pair current = last.get(i); int step = current.second; Date date = new Date(current.first); stepList.add(step); dateList.add(String.valueOf(Utils.getDay(date))); } mStep = stepList.toArray(new Integer[0]); mParties = dateList.toArray(new String[0]); initGraph(); } private void initGraph(){ mChart.setDrawBarShadow(false); mChart.setDrawValueAboveBar(true); // if more than 60 entries are displayed in the chart, no values will be // drawn mChart.setMaxVisibleValueCount(60); mChart.getDescription().setEnabled(false); // scaling can now only be done on x- and y-axis separately mChart.setPinchZoom(false); mChart.setDrawGridBackground(false); // mChart.setDrawYLabels(false); DayAxisValueFormatter xValueFormatter = new DayAxisValueFormatter(dateList); XAxis xAxis = mChart.getXAxis(); xAxis.setLabelRotationAngle(0); xAxis.setPosition(XAxis.XAxisPosition.TOP); xAxis.setDrawGridLines(true); xAxis.setLabelCount(10); xAxis.setTextColor(Color.WHITE); xAxis.setValueFormatter(xValueFormatter); YAxis leftAxis = mChart.getAxisLeft(); leftAxis.setDrawLabels(false); leftAxis.setDrawGridLines(false); leftAxis.setAxisMinimum(0f); leftAxis.setAxisMaximum(10000f); leftAxis.setDrawZeroLine(false); leftAxis.setEnabled(false); mChart.setDrawValueAboveBar(false); mChart.getAxisRight().setEnabled(false); // set auto scale min max mChart.setAutoScaleMinMaxEnabled(true); mChart.notifyDataSetChanged(); // Set enimate y mChart.animateY(2000); setData(); mChart.getLegend().setEnabled(false); } private void setData() { ArrayList xVals = new ArrayList<>(); for (int i = 0; i < mStep.length; i++) { xVals.add(mParties[i % mStep.length]); } ArrayList yVals1 = new ArrayList<>(); for (int i = 0; i < mStep.length; i++) { float val = (float) (mStep[i]*1); yVals1.add(new BarEntry(i, val)); } BarDataSet set1; if (mChart.getData() != null && mChart.getData().getDataSetCount() > 0) { set1 = (BarDataSet)mChart.getData().getDataSetByIndex(0); set1.setValues(yVals1); mChart.getData().notifyDataChanged(); mChart.notifyDataSetChanged(); } else { ArrayList colors = new ArrayList<>(); int[] MATERIAL_COLORS = {rgb("#40CDEF")}; for (int c : MATERIAL_COLORS) colors.add(c); set1 = new BarDataSet(yVals1, null); set1.setColors(colors); ArrayList dataSets = new ArrayList<>(); dataSets.add(set1); BarData data = new BarData(dataSets); data.setValueTextSize(10f); mChart.setData(data); } } private void handleEvent(){ tvDate.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { handleAnaDatePicker(); } }); ivBack.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { mCalendar = Calendar.getInstance(); mCalendar.setTime(mAnaDate); mCalendar.add(Calendar.DAY_OF_MONTH, -1); Date date = mCalendar.getTime(); tvDate.setText(Utils.dateToStringFormatDayMonthYearJp(date)); mAnaDate = date; } }); ivNext.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { mCalendar = Calendar.getInstance(); mCalendar.setTime(mAnaDate); mCalendar.add(Calendar.DAY_OF_MONTH, +1); Date date = mCalendar.getTime(); tvDate.setText(Utils.dateToStringFormatDayMonthYearJp(date)); mAnaDate = date; } }); llWalking.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { stepType = Const.STEP_TYPE.WALKING; updateUiStepType(false, true, false); // add data getTopData(mAnaDate, stepType); } }); llRunning.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { stepType = Const.STEP_TYPE.RUNNING; updateUiStepType(false, false, true); // add getTopData(mAnaDate, stepType); } }); llBike.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { stepType = Const.STEP_TYPE.BIKE; updateUiStepType(true, false, false); // add data getTopData(mAnaDate, stepType); } }); } private void updateUiStepType(boolean b1, boolean b2, boolean b3) { llBike.setSelected(b1); llWalking.setSelected(b2); llRunning.setSelected(b3); } /** * Show date picker dialog */ private void handleAnaDatePicker() { new DatePickerDialog(getActivity(), new DatePickerDialog.OnDateSetListener() { @Override public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { mCalendar = Calendar.getInstance(); mCalendar.set(year, monthOfYear, dayOfMonth); mAnaYear = year; mAnaMonth = monthOfYear; mAnaDay = dayOfMonth; Date date = mCalendar.getTime(); tvDate.setText(Utils.dateToStringFormatDayMonthYearJp(date)); mAnaDate = date; } }, mAnaYear, mAnaMonth, mAnaDay).show(); } private void getTopData(Date date, Const.STEP_TYPE stepType){ showDialog(mContext); LLAPIManager.topInfo(date, stepType, new LLAPIManagerListener() { @Override public void onError(Error error) { Debug.error("Get data history error"); hiddenDialog(); showDialogNotData(); } @Override public void onSuccess(String json) { Debug.error("Get data history success"); hiddenDialog(); loadDataDone(json); } @Override public void onSuccess(JSONObject object) { Debug.error("Get data history success"); hiddenDialog(); } }); } private void showDialogNotData(){ showAlerDialog(mContext, getResources().getString(R.string.can_not_get_data)); } private void loadDataDone(String jsonString) { JSONObject jsonObject = null; try { jsonObject = new JSONObject(jsonString); int status = jsonObject.optInt("status"); if (status == 1) { JSONObject jsonObject1 = jsonObject.optJSONObject("result"); JSONObject targetInf = jsonObject1.getJSONObject("targetInf"); JSONArray listNotice = jsonObject1.getJSONArray("listNotice"); if (targetInf != null){ String target = targetInf.optString("target_step"); Debug.normal("Target: "+ target); mTagetTopInfo.setTaget(targetInf.optString("target_step")); mTagetTopInfo.setSteps(targetInf.optString("num_step")); mTagetTopInfo.setStepRemain(targetInf.optString("remaining_step")); mTagetTopInfo.setCompletePercent(targetInf.optString("complete_percent")); } if (listNotice != null && listNotice.length() > 0) { List infoLists = new ArrayList<>(); for (int i = 0; i < listNotice.length(); i++){ StepHourInfo noticeInfo = new StepHourInfo(); JSONObject ob = (JSONObject) listNotice.get(i); noticeInfo.setId(ob.optInt("id")); noticeInfo.setContent(ob.optString("notice_content")); infoLists.add(noticeInfo); } mTagetTopInfo.setStepHourList(infoLists); } } } catch (JSONException e) { e.printStackTrace(); mTagetTopInfo = new TagetTopInfo();; } loadUI(); } private void loadUI(){ tvStep.setText(String.valueOf(mTagetInfo.getSteps())); tvRemain.setText(String.valueOf(mTagetInfo.getStepRemain())); tvRateDone.setText(getResources().getString(R.string.percent_unit, mTagetInfo.getCompletePercent())); List infoLists = mTagetTopInfo.getStepHourList(); if (infoLists != null && infoLists.size() >0){ mNoticeAdapter = new NoticeAdapter(mContext, infoLists); lvNotice.setAdapter(mNoticeAdapter); lvNotice.setExpanded(true); } } private void updateUI(){ stepTotal = stepTotal + stepCount; stepRemain = stepRemain - stepCount; double percentDone = stepTotal *100.0 / (stepTotal + stepRemain); tvStep.setText(String.valueOf(stepTotal)); tvRemain.setText(mTagetInfo.getStepRemain()); tvRateDone.setText(getResources().getString(R.string.percent_unit, Utils.convert2String2Decimal(percentDone))); } @Override public void onAttach(Context context) { super.onAttach(context); } private void initData() { } @Override public void onSaveData() { } @Override public void onInvalidate(boolean isInit) { initData(); } @Override public void onViewStateRestored(@Nullable Bundle savedInstanceState) { super.onViewStateRestored(savedInstanceState); initData(); } @Override public void onResume() { super.onResume(); activityRunning = true; Sensor countSensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER); if (countSensor != null) { sensorManager.registerListener(this, countSensor, SensorManager.SENSOR_DELAY_UI); } else { Toast.makeText(mContext, getResources().getString(R.string.sensor_available), Toast.LENGTH_SHORT).show(); } } @Override public void onSensorChanged(SensorEvent event) { if (activityRunning){ stepCount = (int) event.values[0]; // update UI updateUI(); } } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } @Override public void onPause() { super.onPause(); activityRunning = false; } @Override public void onDestroy() { super.onDestroy(); // create log step creatLogStep(); } private void creatLogStep(){ LLAPIManager.createLog(stepType, stepCount, mFromDate, mToDate, new LLAPIManagerListener() { @Override public void onError(Error error) { Debug.error("Get data history error"); } @Override public void onSuccess(String json) { Debug.error("Get data history success"); } @Override public void onSuccess(JSONObject object) { Debug.error("Get data history success"); } }); } }