Android Open Source - Expenses Time Stats






From Project

Back to project page Expenses.

License

The source code is released under:

GNU General Public License

If you think the Android project Expenses listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 *   Copyright 2013, 2014 Daniel Pereira Coelho
 *   /*from ww  w.j  a v  a 2s.  c  o  m*/
 *   This file is part of the Expenses Android Application.
 *
 *   Expenses is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation in version 3.
 *
 *   Expenses is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with Expenses.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */

package com.dpcsoftware.mn;

import java.util.Calendar;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import com.actionbarsherlock.app.SherlockActivity;
import com.actionbarsherlock.view.Menu;


public class TimeStats extends SherlockActivity {  
  private App app;
  private String[] labels;
  private TimeChart chart;
  private int numberOfItems;
  private Calendar referenceDate;
  private boolean periodIsYear = true;
  private Runnable menuCallback = new Runnable() {
    public void run() {
      renderGraph();
    }
  };
  private View.OnClickListener changePageListener = new View.OnClickListener() {
    public void onClick(View v) {
      int n = 0;
      switch(v.getId()) {
      case R.id.imageButton1:
        n = -1;
        break;
      case R.id.imageButton2:
        n = 1;
      }
      
      if(periodIsYear)
        referenceDate.add(Calendar.YEAR,n);
      else
        referenceDate.add(Calendar.DAY_OF_MONTH,n*7);
      
      renderGraph();
    }
  };
    
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    app = (App) getApplication();
    
    setContentView(R.layout.timestats);
    
    ((RadioGroup) findViewById(R.id.radioGroup1)).setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
      public void onCheckedChanged (RadioGroup group, int checkedId) {
        if(checkedId == R.id.radio1)
          periodIsYear = true;
        else
          periodIsYear = false;        
        renderGraph();
      }
    });
    
    ((ImageButton) findViewById(R.id.imageButton1)).setOnClickListener(changePageListener);
    ((ImageButton) findViewById(R.id.imageButton2)).setOnClickListener(changePageListener);
    
    referenceDate = Calendar.getInstance();
  }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
      app.new SpinnerMenu(this,menuCallback);
      
      return true;
    }
    
  public void renderGraph() {
    
    if(!periodIsYear) {
      int x = 0;
      int firstDay = referenceDate.getFirstDayOfWeek();
      int today = referenceDate.get(Calendar.DAY_OF_WEEK);
      int diff = Math.abs(today - firstDay);
      if(today != firstDay) {  
        if(today > firstDay)
          x = -diff;
        else if(today < firstDay)
          x = -7 + diff;
      }
      referenceDate.add(Calendar.DAY_OF_MONTH, x);
    }
      
    String queryModifier, datePattern, datePatternDb;
    if(periodIsYear) {
      numberOfItems = 12;
      queryModifier = "";
      datePatternDb = "yyyy-MM";
      datePattern = "MMMMM";
    }
    else {
      numberOfItems = 7;
      queryModifier = "-%d";
      datePattern = "EEEEE";
      datePatternDb = "yyyy-MM-dd";
    }
    
    float[] values = new float[numberOfItems];
    labels = new String[values.length];
    int i = 0;
    Calendar iDate = Calendar.getInstance();
    iDate.setTime(referenceDate.getTime());
    if(periodIsYear)
      iDate.set(Calendar.MONTH, 0);
    SQLiteDatabase db = DatabaseHelper.quickDb(this, 0);
    while(i < numberOfItems) {  
        Cursor c = db.rawQuery("SELECT SUM(" + Db.Table1.COLUMN_VALORT + ")," +
            " strftime('%Y-%m" + queryModifier + "'," + Db.Table1.COLUMN_DATAT + ") AS timeUnit" +
            " FROM " + Db.Table1.TABLE_NAME +
            " WHERE " +
            Db.Table1.COLUMN_IDGRUPO + " = " + app.activeGroupId +
            " AND timeUnit = '" + app.dateToDb(datePatternDb, iDate.getTime()) + "'" +
            " GROUP BY timeUnit",null);
        c.moveToFirst();
        
        float val;
        if(c.getCount() > 0)
          val = c.getFloat(0);
        else
          val = 0;
        values[i] = val;
        labels[i] = app.dateToUser(datePattern, iDate.getTime()).substring(0, 1).toUpperCase();
        i++;
        if(periodIsYear)
          iDate.add(Calendar.MONTH,1);
        else
          iDate.add(Calendar.DAY_OF_MONTH,1);
    }
    db.close();
    
    FrameLayout graphLayout = ((FrameLayout) findViewById(R.id.FrameLayoutTimeChart));
    if(chart == null) {
      chart = new TimeChart(this, values, labels);
      graphLayout.addView(chart);
    }
    else
      chart.setNewData(values, labels);
    
    if(periodIsYear)
      ((TextView) findViewById(R.id.textView2)).setText(app.dateToUser("yyyy", referenceDate.getTime()));
    else {
      iDate.add(Calendar.DAY_OF_MONTH,-1);
      ((TextView) findViewById(R.id.textView2)).setText(app.dateToUser(null, referenceDate.getTime()) + " - " + app.dateToUser(null, iDate.getTime()));
    }
  }
  
  private class TimeChart extends View {
    private Paint paintModel, paintAxe, paintScale, paintPoints, paintUnderPoints, paintLinePoints, paintTextV, paintTextH;
    private float left, right, top, bottom;
    private float values[], points[], max, min;
    private Path pathUnder;
    private String labels[];
    private float numberOfIntervals, gridStep;
    private int gridStepMoney;
    private float horizontalStep;
    
    private GestureDetector touchDetector;
    
    public TimeChart(Context ct, float[] val, String[] lbs) {
      super(ct);
      
      paintModel = new Paint(Paint.ANTI_ALIAS_FLAG);
      paintModel.setStyle(Paint.Style.FILL);
      
      paintAxe = new Paint(paintModel);
      paintAxe.setColor(Color.BLACK);
      paintAxe.setStrokeWidth(3);
      
      paintScale = new Paint(paintModel);
      paintScale.setColor(Color.GRAY);
      paintScale.setStrokeWidth(2);
      
      paintUnderPoints = new Paint(paintModel);
      paintUnderPoints.setColor(Color.RED);
      paintUnderPoints.setAlpha(120);
      
      paintLinePoints = new Paint(Paint.ANTI_ALIAS_FLAG);
      paintLinePoints.setStyle(Paint.Style.STROKE);
      paintLinePoints.setColor(Color.RED);
      paintLinePoints.setStrokeWidth(4);
      
      paintPoints = new Paint(paintModel);
      paintPoints.setColor(Color.RED);
      paintPoints.setStrokeWidth(10);
      paintPoints.setStrokeCap(Paint.Cap.ROUND);
      
      paintTextV = new Paint(paintModel);
      paintTextV.setColor(Color.BLACK);
      paintTextV.setTextSize(20);
      paintTextV.setTextAlign(Paint.Align.LEFT);
      
      paintTextH = new Paint(paintTextV);
      paintTextH.setTextAlign(Paint.Align.CENTER);
      
      setPadding(10,10,10,10);
      
      values = val;
      labels = lbs;
      touchDetector = new GestureDetector(ct, new TouchListener());
    }
    
    public void setNewData(float[] val, String[] lbs) {
      values = val;
      labels = lbs;
      
      calculateMaxMin();
      calculatePoints();
      invalidate();
    }
    
    private void calculateMaxMin() {
      int i;
      max = values[0];
      for(i = 1;i < values.length;i++) {
        if(values[i] > max)
          max = values[i];
      }
      min = values[0];
      for(i = 1;i < values.length;i++) {
        if(values[i] < min)
          min = values[i];
      }
    
      max = (float) Math.ceil(max);
      min = (float) Math.floor(min);
      
      if(max == min)
        max +=10;
            
      gridStepMoney = 1;
      numberOfIntervals = (bottom - top)/40;
      while(gridStepMoney*numberOfIntervals < (max - min)) {
        gridStepMoney *= 10;        
      }
      
      max = (float) Math.ceil(max/gridStepMoney)*gridStepMoney;
      min = (float) Math.floor(min/gridStepMoney)*gridStepMoney;
      
      numberOfIntervals = Math.round((max - min)/gridStepMoney);
      gridStep = (bottom - top)/numberOfIntervals;
      
      left = getPaddingLeft() + String.valueOf((int)max).length()*15;
    }
    
    private void calculatePoints() {
      points = new float[values.length*2];
      pathUnder = new Path();
      pathUnder.moveTo(left,bottom);
      
      int i;
      horizontalStep = (right - left)/(values.length-1);
      for(i = 0;i < values.length;i++) {
        float yPoint = top + ((max - values[i])/(max - min))*(bottom - top);
        points[2*i] = left + horizontalStep*i;
        points[2*i+1] = yPoint;
        pathUnder.lineTo(points[2*i], yPoint);
      }
      pathUnder.lineTo(right, bottom);
      pathUnder.lineTo(left, bottom);
    }
    
    @Override
    public void onSizeChanged(int w, int h, int oldw, int oldh) {
      top = getPaddingTop() + 20;
      bottom = h - getPaddingBottom() - 30;
      
      calculateMaxMin();
            
      right = w - getPaddingRight() - 20;
      
      calculatePoints();      
    }
    
    @Override
    public void onDraw(Canvas canvas) {
      
      //Scale and Vertical Labels
      float j = top;
      int jm = (int)max;
      float leftPadding = getPaddingLeft();
      while(j < bottom) {
        canvas.drawLine(left, j, right, j, paintScale);
        canvas.drawText(String.valueOf(jm), leftPadding, j+7, paintTextV);
        j += gridStep;
        jm -= gridStepMoney;
      }      
      canvas.drawText(String.valueOf((int)min), leftPadding, bottom+7, paintTextV);
      
      //Axes
      canvas.drawLine(left, bottom, left, top, paintAxe);
      canvas.drawLine(left, bottom, right, bottom, paintAxe);
            
      //Points and Horizontal Labels
      int i, end;
      float xText, yText;
      end = values.length - 1;
      canvas.drawPath(pathUnder, paintUnderPoints);
      for(i = 0;i <= end;i++) {
        if(i != end)
          canvas.drawLine(points[2*i], points[2*i+1], points[2*i+2], points[2*i+3], paintLinePoints);
        xText = left + i*horizontalStep;
        yText = bottom + 25;
        canvas.drawText(labels[i], xText, yText, paintTextH);
      }
      canvas.drawPoints(points, paintPoints);

    }
    
    @Override
    public boolean onTouchEvent(MotionEvent event) {
       boolean result = touchDetector.onTouchEvent(event);
       if (!result) {
           if (event.getAction() == MotionEvent.ACTION_UP) {
             //int index = (int)Math.round((event.getX()-left)/(right-left));
             //App.Toast(context, app.printMoney(values[index]));
           }
           else if(event.getAction() == MotionEvent.ACTION_MOVE) {

           }
       }
       return result;
    }
    
    private class TouchListener extends GestureDetector.SimpleOnGestureListener {
      @Override
      public boolean onDown(MotionEvent e) {
        return true;
      }
    }
  }
}




Java Source Code List

com.dpcsoftware.mn.About.java
com.dpcsoftware.mn.AddEx.java
com.dpcsoftware.mn.App.java
com.dpcsoftware.mn.CategoryStats.java
com.dpcsoftware.mn.DatabaseHelper.java
com.dpcsoftware.mn.Db.java
com.dpcsoftware.mn.EditCategories.java
com.dpcsoftware.mn.EditGroups.java
com.dpcsoftware.mn.EditPreferences.java
com.dpcsoftware.mn.ExpensesList.java
com.dpcsoftware.mn.ExportData.java
com.dpcsoftware.mn.FolderPicker.java
com.dpcsoftware.mn.TimeStats.java
com.dpcsoftware.mn.Widget1Config.java
com.dpcsoftware.mn.Widget1.java