package com.dinhcv.lifelogpedometer.activity; import android.app.DatePickerDialog; import android.app.ProgressDialog; 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.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.interfaces.LLAPIManagerListener; import com.dinhcv.lifelogpedometer.interfaces.StepListener; import com.dinhcv.lifelogpedometer.model.StepModel; import com.dinhcv.lifelogpedometer.model.structure.top.StepItemInfo; import com.dinhcv.lifelogpedometer.model.structure.top.TopInfo; import com.dinhcv.lifelogpedometer.portal.ApiServices; 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.SimpleStepDetector; 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.Arrays; 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 TopTodayFragment extends FragmentBase implements SettingFragmentPresenter, SensorEventListener, StepListener { private TextView stepsView; private TextView tvStepGoal; private TextView tvDistance; private TextView tvTime; 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 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; public final static NumberFormat formatter = NumberFormat.getInstance(Locale.getDefault()); private SensorManager sensorManager; private boolean activityRunning; private int stepTotal = 0; private int stepGoal = 0; private int stepCount = 0; private Date mFromDate; private Date mToDate; private TopInfo mTopInfo = new TopInfo(); private BarChart mChart; private List dateList; private String[] mParties; private Integer[] mStep; private ProgressDialog progress; private boolean isAccelo = false; private boolean isBusy = false; private SimpleStepDetector simpleStepDetector; private TopFragment mTopFragment; public void setRootFragment(TopFragment frag) { this.mTopFragment = frag; } @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_today, null); mContext = getActivity(); sensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE); simpleStepDetector = new SimpleStepDetector(); simpleStepDetector.registerListener(this); 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); mFromDate = new Date(); tvDate.setText(Utils.dateToStringFormatDayMonthYearJp(mAnaDate)); initData(); handleEvent(); getTopPage(mAnaDate, stepType); 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); tvTime = (TextView) v.findViewById(R.id.tv_time); tvDate = (TextView) v.findViewById(R.id.tv_date); ivBack = (ImageView) v.findViewById(R.id.iv_back); ivNext = (ImageView) v.findViewById(R.id.iv_next); mChart = (BarChart) v.findViewById(R.id.chart); pg = (PieChart) v.findViewById(R.id.graph); llRunning = (LinearLayout) v.findViewById(R.id.ll_running); llWalking = (LinearLayout) v.findViewById(R.id.ll_walking); llBike = (LinearLayout) v.findViewById(R.id.ll_bike); } private void initData(){ 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); stepType = Const.STEP_TYPE.WALKING; updateUiStepType(false, true, false); tvDate.setText(Utils.dateToStringFormatDayMonthYearJp(mAnaDate)); } private void updateUiStepType(boolean b1, boolean b2, boolean b3) { llBike.setSelected(b1); llWalking.setSelected(b2); llRunning.setSelected(b3); } private void stepsDistanceChanged() { if (progress != null){ progress.dismiss(); } updatePie(); updateBars(); } @Override public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { inflater.inflate(R.menu.main, menu); } private void getTopPage(Date date, Const.STEP_TYPE stepType){ progress = new ProgressDialog(mContext); progress.setMessage(getString(R.string.loading)); progress.setCancelable(false); progress.show(); ApiServices.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"); 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"); if (targetInf != null){ String target = targetInf.optString("target_step"); Debug.normal("Target: "+ target); mTopInfo.setTaget(targetInf.optString("target_step")); mTopInfo.setSteps(targetInf.optString("num_step")); mTopInfo.setStepRemain(targetInf.optString("remaining_step")); mTopInfo.setCompletePercent(targetInf.optString("complete_percent")); } mTopInfo.setKcalo(jsonObject1.optString("kcal")); mTopInfo.setDistance(jsonObject1.optString("distance")); mTopInfo.setTime(jsonObject1.optString("time")); JSONArray stepArr = jsonObject1.optJSONArray("dataChart"); if (stepArr != null && stepArr.length() > 0) { List infoLists = new ArrayList<>(); for (int i = 0; i < stepArr.length(); i++){ StepItemInfo stepItemInfo = new StepItemInfo(); JSONObject ob = (JSONObject) stepArr.get(i); stepItemInfo.setHour(ob.optInt("hour")); stepItemInfo.setNumStep(ob.optInt("numStep")); infoLists.add(stepItemInfo); } mTopInfo.setStepList(infoLists); } } } catch (JSONException e) { e.printStackTrace(); mTopInfo = new TopInfo();; } stepsDistanceChanged(); } private void updatePie() { // todayOffset might still be Integer.MIN_VALUE on first start int stepsToday = 0; int stepTarget = 0; if (mTopInfo != null) { if (mTopInfo.getSteps().contains(",")){ stepsToday = Integer.valueOf(mTopInfo.getSteps().replace(",", "")); }else { stepsToday = Integer.valueOf(mTopInfo.getSteps()); } if (mTopInfo.getTaget().contains(",")) { stepTarget = Integer.valueOf(mTopInfo.getTaget().replace(",", "")); }else { stepTarget = Integer.valueOf(mTopInfo.getTaget()); } } sliceCurrent.setValue(stepsToday); if (stepTarget - stepsToday > 0) { // goal not reached yet if (pg.getData().size() == 1) { pg.addPieSlice(sliceGoal); } sliceGoal.setValue(stepTarget - stepsToday); } else { // goal reached pg.clearChart(); pg.addPieSlice(sliceCurrent); } pg.update(); stepGoal = stepTarget; stepTotal = stepsToday; stepsView.setText(formatter.format(stepsToday)); int stepRemain = stepTarget - stepsToday; tvStepRemain.setText(String.valueOf(stepRemain)); tvStepRateDone.setText(getResources().getString(R.string.percent_unit, Utils.convert2String2Decimal(stepsToday *100/ stepTarget))); tvSmallRemain.setText(getResources().getString(R.string.pie_text_content3a, stepRemain)); tvStepGoal.setText(mTopInfo.getTaget()); tvSmallStepGoal.setText(mTopInfo.getTaget()); tvDistance.setText(mTopInfo.getDistance()); tvTime.setText(mTopInfo.getTime()); double distanceToday = stepsToday * STEP_SIZE; distanceToday /= 100000; tvDistance.setText(Utils.convert2String2Decimal(distanceToday)); } /** * 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 dateList = new ArrayList<>(); List stepList = new ArrayList<>(); List stepItemInfos = mTopInfo.getStepList(); if (stepItemInfos != null && stepItemInfos.size() >0) { for (int i = 0; i < stepItemInfos.size(); i++){ dateList.add(String.valueOf(stepItemInfos.get(i).getHour())); stepList.add(stepItemInfos.get(i).getNumStep()); } } 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); List listx = Arrays.asList(mParties); DayAxisValueFormatter xValueFormatter = new DayAxisValueFormatter(listx); 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; getTopPage(mAnaDate, stepType); } }); 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; getTopPage(mAnaDate, stepType); } }); llBike.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { stepType = Const.STEP_TYPE.BIKE; updateUiStepType(true, false, false); getTopPage(mAnaDate, stepType); } }); llRunning.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { stepType = Const.STEP_TYPE.RUNNING; updateUiStepType(false, false, true); getTopPage(mAnaDate, stepType); } }); llWalking.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { stepType = Const.STEP_TYPE.WALKING; updateUiStepType(false, true, false); getTopPage(mAnaDate, stepType); } }); } /** * 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; getTopPage(mAnaDate, stepType); } }, mAnaYear, mAnaMonth, mAnaDay).show(); } private void updateUI(){ creatLogStep(); Debug.normal("Step total================ "+ stepTotal); int stepRemain = stepGoal - stepTotal; double percentDone = stepTotal *100.0 / stepGoal; stepsView.setText(String.valueOf(stepTotal)); tvStepRemain.setText(String.valueOf(stepRemain)); tvStepRateDone.setText(getResources().getString(R.string.percent_unit, Utils.convert2String2Decimal(percentDone))); tvSmallRemain.setText(String.valueOf(stepRemain)); } @Override public void onAttach(Context context) { super.onAttach(context); } @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; Debug.normal("Today: "+ "Onresume "); Sensor countSensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER); if (countSensor == null) { isAccelo = true; countSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); } if (countSensor != null) { Debug.normal("Today: " + "countSensor not null "); sensorManager.registerListener(this, countSensor, SensorManager.SENSOR_DELAY_UI); } else { Debug.normal("Today: " + "countSensor is null "); Toast.makeText(mContext, getResources().getString(R.string.sensor_available), Toast.LENGTH_SHORT).show(); } } @Override public void onSensorChanged(SensorEvent event) { //Debug.normal("Sensor count step active"); if (activityRunning){ if (isAccelo) { simpleStepDetector.updateAccel( event.timestamp, event.values[0], event.values[1], event.values[2]); }else { stepCount = (int) event.values[0]; Debug.normal("Step change: " + stepCount); stepTotal++; // update UI updateUI(); } } } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } @Override public void onPause() { super.onPause(); activityRunning = false; Debug.normal("Start create log"); if (sensorManager != null) { sensorManager.unregisterListener(this); } // create log step //creatLogStep(); } @Override public void onDestroy() { super.onDestroy(); } private void creatLogStep(){ Debug.normal("Today: "+ "Create log "+ stepCount); mToDate = new Date(); ApiServices.createLog(stepType, stepCount, mFromDate, mToDate, new LLAPIManagerListener() { @Override public void onError(Error error) { isBusy = false; Debug.error("Get data history error"); } @Override public void onSuccess(String json) { isBusy = false; Debug.error("Get data history success"); } @Override public void onSuccess(JSONObject object) { isBusy = false; Debug.error("Get data history success"); } }); } @Override public void step(long timeNs) { if (!isBusy) { isBusy = true; stepCount = 1; stepTotal++; // update UI updateUI(); } } }