diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/.DS_Store differ diff --git a/ScientificCalculator.iml b/ScientificCalculator.iml new file mode 100644 index 0000000..0bb6048 --- /dev/null +++ b/ScientificCalculator.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/app.iml b/app/app.iml new file mode 100644 index 0000000..22541f3 --- /dev/null +++ b/app/app.iml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..da28d23 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,26 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 22 + buildToolsVersion "22.0.1" + + defaultConfig { + applicationId "nyc.c4q.ramonaharrison.scientificcalculator" + minSdkVersion 15 + targetSdkVersion 22 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + compile 'com.android.support:appcompat-v7:22.1.1' + compile files('libs/JbcParser.jar') +} diff --git a/app/libs/JbcParser.jar b/app/libs/JbcParser.jar new file mode 100644 index 0000000..ff1e40f Binary files /dev/null and b/app/libs/JbcParser.jar differ diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..523f994 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/mona/Library/Android/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/app/src/androidTest/java/nyc/c4q/ramonaharrison/scientificcalculator/ApplicationTest.java b/app/src/androidTest/java/nyc/c4q/ramonaharrison/scientificcalculator/ApplicationTest.java new file mode 100644 index 0000000..58481fb --- /dev/null +++ b/app/src/androidTest/java/nyc/c4q/ramonaharrison/scientificcalculator/ApplicationTest.java @@ -0,0 +1,13 @@ +package nyc.c4q.ramonaharrison.scientificcalculator; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * Testing Fundamentals + */ +public class ApplicationTest extends ApplicationTestCase { + public ApplicationTest() { + super(Application.class); + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..80640ef --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/main/java/nyc/c4q/ramonaharrison/scientificcalculator/Calculate.java b/app/src/main/java/nyc/c4q/ramonaharrison/scientificcalculator/Calculate.java new file mode 100644 index 0000000..554495a --- /dev/null +++ b/app/src/main/java/nyc/c4q/ramonaharrison/scientificcalculator/Calculate.java @@ -0,0 +1,270 @@ +package nyc.c4q.ramonaharrison.scientificcalculator; + +import com.bestcode.mathparser.IMathParser; +import com.bestcode.mathparser.MathParserFactory; + +import java.util.ArrayList; + +public class Calculate +{ + public static void main(String[] args) + { +// String inputExpression = "4! + 3!"; +// System.out.println(calculate(inputExpression, false)); + + } + + public static ArrayList findFactorialEnds(String parseExpression) { + ArrayList factorialEnds = new ArrayList(); + int start = 0; + int facEnd = 0; + while (facEnd != -1) { + facEnd = parseExpression.indexOf('!', start); + if (facEnd > 0) { + factorialEnds.add(facEnd); + start = facEnd + 1; + + } + } + return factorialEnds; + } + + public static ArrayList findFactorialStarts(String parseExpression, ArrayList factorialEnds) { + + ArrayList factorials = new ArrayList(); + + for (int exclamation : factorialEnds) { + String stringFactorial = ""; + for (int i = exclamation; i >= 0; i--) { + char c = parseExpression.charAt(i); + if (c == '1' || c == '2' || c == '3' || c == '4' || c == '5' || c == '6' || c == '7' || c == '8' || c == '9' || c == '0' || c == '.' || c == 'E' || c == '!') { + stringFactorial = c + stringFactorial; + } else { + factorials.add(stringFactorial); + break; + } + if (i == 0) { + factorials.add(stringFactorial); + } + } + + } + return factorials; + } + + public static ArrayList parseFactorials(ArrayList factorials){ + + ArrayList parsedFacs = new ArrayList(); + + for (String fac: factorials){ + + int factorial = Integer.valueOf(fac.substring(0, fac.length() - 1)); + int n = 1; + + while(factorial != 1) { + n *= factorial; + factorial--; + } + parsedFacs.add(String.valueOf(n)); + } + return parsedFacs; + } + public static String calculate(String inputExpression, boolean degrees) { + + String parseExpression = ""; + + // Makes most string expressions readable by the parser. + if(!inputExpression.equals("")) { + + parseExpression = inputExpression.replaceAll("%", "*.01"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("e", "2.71828182846"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("√\\(", "SQRT("); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("π", "PI"); + inputExpression = parseExpression; + + parseExpression = inputExpression.replaceAll("0p", "0*p"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("0\\(", "0*("); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("0a", "0*a"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("0l", "0*l"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("0s", "0*s"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("0c", "0*c"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("0t", "0*t"); + inputExpression = parseExpression; + + parseExpression = inputExpression.replaceAll("1p", "1*p"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("1\\(", "1*("); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("1a", "1*a"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("1l", "1*l"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("1s", "1*s"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("1c", "1*c"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("1t", "1*t"); + inputExpression = parseExpression; + + parseExpression = inputExpression.replaceAll("2p", "2*p"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("2\\(", "2*("); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("2a", "2*a"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("2l", "2*l"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("2s", "2*s"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("2c", "2*c"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("2t", "2*t"); + inputExpression = parseExpression; + + parseExpression = inputExpression.replaceAll("3p", "3*p"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("3\\(", "3*("); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("3a", "3*a"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("3l", "3*l"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("3s", "3*s"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("3c", "3*c"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("3t", "3*t"); + inputExpression = parseExpression; + + parseExpression = inputExpression.replaceAll("4p", "4*p"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("4\\(", "4*("); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("4a", "4*a"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("4l", "4*l"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("4s", "4*s"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("4c", "4*c"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("4t", "4*t"); + inputExpression = parseExpression; + + parseExpression = inputExpression.replaceAll("5p", "5*p"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("5\\(", "5*("); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("5a", "5*a"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("5l", "5*l"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("5s", "5*s"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("5c", "5*c"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("5t", "5*t"); + inputExpression = parseExpression; + + parseExpression = inputExpression.replaceAll("6p", "6*p"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("6\\(", "6*("); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("6a", "6*a"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("6l", "6*l"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("6s", "6*s"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("6c", "6*c"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("6t", "6*t"); + inputExpression = parseExpression; + + parseExpression = inputExpression.replaceAll("7p", "7*p"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("7\\(", "7*("); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("7a", "7*a"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("7l", "7*l"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("7s", "7*s"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("7c", "7*c"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("7t", "7*t"); + inputExpression = parseExpression; + + parseExpression = inputExpression.replaceAll("8p", "8*p"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("8\\(", "8*("); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("8a", "8*a"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("8l", "8*l"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("8s", "8*s"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("8c", "8*c"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("8t", "8*t"); + inputExpression = parseExpression; + + parseExpression = inputExpression.replaceAll("9p", "9*p"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("9\\(", "9*("); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("9a", "9*a"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("9l", "9*l"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("9s", "9*s"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("9c", "9*c"); + inputExpression = parseExpression; + parseExpression = inputExpression.replaceAll("9t", "9*t"); + inputExpression = parseExpression; + + + ArrayList facEnds = findFactorialEnds(parseExpression); + ArrayList facs = findFactorialStarts(parseExpression, facEnds); + ArrayList parsedFacs = parseFactorials(facs); + for (String fac: facs) { + System.out.println(fac); + } + + for (int i = 0; i <= facs.size()-1; i++){ + parseExpression = inputExpression.replaceAll(facs.get(i), parsedFacs.get(i)); + inputExpression = parseExpression; + } + } + + String result = ""; + try{ + IMathParser parser = MathParserFactory.create(); + Double resultDouble = 0.0; + + parser.setExpression(parseExpression); + + resultDouble = parser.getValue(); + + result = resultDouble.toString(); + + System.out.println(result); + }catch(Exception ex){ + System.out.println(ex.getMessage()); + } + + return result; + } +} \ No newline at end of file diff --git a/app/src/main/java/nyc/c4q/ramonaharrison/scientificcalculator/GraphActivity.java b/app/src/main/java/nyc/c4q/ramonaharrison/scientificcalculator/GraphActivity.java new file mode 100644 index 0000000..178f90b --- /dev/null +++ b/app/src/main/java/nyc/c4q/ramonaharrison/scientificcalculator/GraphActivity.java @@ -0,0 +1,127 @@ +package nyc.c4q.ramonaharrison.scientificcalculator; + +import android.content.Intent; +import android.os.Bundle; +import android.support.v7.app.ActionBar; +import android.support.v7.app.ActionBarActivity; +import android.view.Display; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Toast; + +import java.util.HashMap; + + +public class GraphActivity extends ActionBarActivity { + + private GraphView graph; + private EditText inputEquation; + private EditText inputMin; + private EditText inputMax; + private Button graphIt; + private HashMap coordinates; + private String equation; + private Float min; + private Float max; + private static Display display; + + + @Override + protected void onCreate(Bundle savedInstanceState) { + + //TODO save instance state + + super.onCreate(savedInstanceState); + display = getWindowManager().getDefaultDisplay(); + setContentView(R.layout.activity_graph); + + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayShowTitleEnabled(false); + actionBar.show(); + } + + graph = (GraphView) findViewById(R.id.graph); + inputEquation = (EditText) findViewById(R.id.input_equation); + inputMin = (EditText) findViewById(R.id.input_min); + inputMax = (EditText) findViewById(R.id.input_max); + graphIt = (Button) findViewById(R.id.graph_it); + + + graphIt.setOnClickListener(new View.OnClickListener() { + public void onClick(View v) { + equation = inputEquation.getText().toString(); + min = Float.valueOf(inputMin.getText().toString()); + max = Float.valueOf(inputMax.getText().toString()); + coordinates = new HashMap<>(); + + for (float x = min; x <= max; x++) { + float y = findY(equation, x); + coordinates.put(x, y); + } + + graph.setValues(coordinates, min, max); + graph.drawGraph(); + + } + }); + + } + + public float findY(String equation, float x) { + Float y = Float.valueOf(0); + String xEquation = equation.replaceAll("[x]", "" + x);; + String yString= Calculate.calculate(xEquation, false); + if (isValue(yString)) { + y = Float.valueOf(yString); + } else { + Toast.makeText(getApplicationContext(), "Invalid equation!", Toast.LENGTH_SHORT).show(); + // TODO: get toast out of loop + } + return y; + } + + public boolean isValue(String result) { + for (int i = 0; i < result.length(); i++) { + // checks for only numeric values in result + char c = result.charAt(i); + if ((c < 45 || c > 57) && c != 69) { + return false; + } + } + + return true; + } + + public static int getWidth() { + return display.getWidth(); + } + + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.menu_graph, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle action bar item clicks here. The action bar will + // automatically handle clicks on the Home/Up button, so long + // as you specify a parent activity in AndroidManifest.xml. + switch (item.getItemId()) { + case R.id.action_calculator: + Intent calcIntent = new Intent(this, MainActivity.class); + this.startActivity(calcIntent); + return true; + case R.id.action_graph: + return true; + default: + return super.onOptionsItemSelected(item); + } + } +} diff --git a/app/src/main/java/nyc/c4q/ramonaharrison/scientificcalculator/GraphView.java b/app/src/main/java/nyc/c4q/ramonaharrison/scientificcalculator/GraphView.java new file mode 100644 index 0000000..720a9a8 --- /dev/null +++ b/app/src/main/java/nyc/c4q/ramonaharrison/scientificcalculator/GraphView.java @@ -0,0 +1,183 @@ +package nyc.c4q.ramonaharrison.scientificcalculator; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.Rect; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; + +import java.util.Collections; +import java.util.HashMap; + +/** + * Created by mona on 5/17/15. + */ +public class GraphView extends View { + + private Path drawPath, textPath, gridPath; + private Paint drawPaint, canvasPaint, gridPaint, canvasGridPaint, textPaint, boxPaint; + private Canvas drawCanvas; + private Bitmap canvasBitmap; + private HashMap coordinates; + private Float min, max; + private int width, height, center; + private float yMax; + private float yMin; + + private float scaleX; + private float scaleY; + + private float centerX; + private float centerY; + + + + public GraphView(Context context, AttributeSet attrs){ + super(context, attrs); + } + + public void setValues(HashMap coord, Float mn, Float mx) { + coordinates = coord; + min = mn; + max = mx; + } + + public void drawGraph() { + invalidate(); + } + + public void setupGrid(Canvas canvas, int width) { + textPaint = new Paint(); + textPaint.setStyle(Paint.Style.FILL_AND_STROKE); + textPaint.setAntiAlias(true); + textPaint.setColor(Color.WHITE); + textPaint.setTextSize(48); + textPath = new Path(); + + boxPaint = new Paint(); + boxPaint.setStyle(Paint.Style.FILL); + boxPaint.setAntiAlias(true); + boxPaint.setAlpha(125); + boxPaint.setColor(Color.CYAN); + + gridPath = new Path(); + gridPaint = new Paint(); + gridPaint.setAlpha(125); + gridPaint.setAntiAlias(true); + gridPaint.setStrokeWidth(5); + gridPaint.setStyle(Paint.Style.STROKE); + gridPaint.setStrokeJoin(Paint.Join.BEVEL); + gridPaint.setStrokeCap(Paint.Cap.SQUARE); + canvasGridPaint = new Paint(Paint.DITHER_FLAG); + canvas.drawBitmap(canvasBitmap, 0, 0, canvasGridPaint); + + gridPaint.setColor(Color.LTGRAY); + gridPath.moveTo(width/2, 0); + gridPath.lineTo(width/2, width); + canvas.drawPath(gridPath, gridPaint); + gridPath.moveTo(0, width/2); + gridPath.lineTo(width, width/2); + canvas.drawPath(gridPath, gridPaint); + } + + + @Override + protected void onSizeChanged(int w, int h, int xw, int xh) { + super.onSizeChanged(w, h, xw, xh); + width = GraphActivity.getWidth() - 100; + height = width; + center = width/2; + canvasBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + drawCanvas = new Canvas(canvasBitmap); + setupGrid(drawCanvas, width); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + // check for null inputs + if (min == null) { + min = Float.valueOf(0); + } + if (max == null) { + max = Float.valueOf(0); + } + if (coordinates == null) { + coordinates = new HashMap(); + coordinates.put(min, max); + } + + drawPath = new Path(); + drawPaint = new Paint(); + drawPaint.setAlpha(125); + drawPaint.setAntiAlias(true); + drawPaint.setStrokeWidth(5); + drawPaint.setStyle(Paint.Style.STROKE); + drawPaint.setStrokeJoin(Paint.Join.MITER); + drawPaint.setStrokeCap(Paint.Cap.BUTT); + canvasPaint = new Paint(Paint.DITHER_FLAG); + canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint); + + yMax = Collections.max(coordinates.values()); + yMin = Collections.min(coordinates.values()); + scaleX = width / (max - min); + scaleY = height / (yMax - yMin); + centerX = (max - min)/2; + centerY = (yMax - yMin)/2; + + // draw a graph of the equation + drawPaint.setColor(Color.BLACK); + for (float x = min; x < max; x++) { + float thisX = (centerX + x) * scaleX; + float thisY = height - (centerY + coordinates.get(x)) * scaleY; + float nextX = (centerX + (x + 1)) * scaleX; + float nextY = height - (centerY + coordinates.get(x + 1)) * scaleY; + drawPath.moveTo(thisX, thisY); + drawPath.lineTo(nextX, nextY); + canvas.drawPath(drawPath, drawPaint); + } + + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + float touchX = event.getX(); + float touchY = event.getY(); + float thisx = (touchX - center) / scaleX; + float thisy = 0 - ((touchY - center) / scaleY); + + String pos = "X = " + String.format("%.1f", thisx) + ", Y = " + String.format("%.1f", thisy); + + float textStart = center - (pos.length() * 12); + float textEnd = center + (pos.length() * 12); + textPath.moveTo(textStart, height - 30); + textPath.lineTo(textEnd, height - 30); + + Rect rect = new Rect((int)textStart - 30, height - 100, (int)textEnd + 30, height); + RectF rectF = new RectF(rect); + + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + drawCanvas.drawRoundRect(rectF, 15, 15, boxPaint); + drawCanvas.drawTextOnPath(pos, textPath, 0, 0, textPaint); + break; + case MotionEvent.ACTION_MOVE: + drawCanvas.drawRoundRect(rectF, 15, 15, boxPaint); + drawCanvas.drawTextOnPath(pos, textPath, 0, 0, textPaint); + break; + case MotionEvent.ACTION_UP: + break; + default: + return false; + } + invalidate(); + return true; + } +} diff --git a/app/src/main/java/nyc/c4q/ramonaharrison/scientificcalculator/MainActivity.java b/app/src/main/java/nyc/c4q/ramonaharrison/scientificcalculator/MainActivity.java new file mode 100644 index 0000000..d5e8dda --- /dev/null +++ b/app/src/main/java/nyc/c4q/ramonaharrison/scientificcalculator/MainActivity.java @@ -0,0 +1,592 @@ +package nyc.c4q.ramonaharrison.scientificcalculator; + +import android.content.Intent; +import android.content.res.Configuration; +import android.graphics.Color; +import android.os.Bundle; +import android.support.v7.app.ActionBar; +import android.support.v7.app.ActionBarActivity; +import android.text.SpannableString; +import android.text.style.ForegroundColorSpan; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; + +import java.util.Random; + + +public class MainActivity extends ActionBarActivity { + private TextView calculatorBar; + private TextView cacheBar; + private Button sin; + private Button cos; + private Button tan; + private Button ln; + private Button log; + private Button sqrt; + private Button ansb; + private Button rad; + private Button deg; + private Button ceac; + private Random random; + + + private boolean isDeg; + private boolean isInv; + private String equation; + private String cache; + private String result; + private String display; + private String ans; + private String closeParens; + private int ce; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + random = new Random(); + calculatorBar = (TextView) findViewById(R.id.calculator_bar); + cacheBar = (TextView) findViewById(R.id.cache); + sin = (Button) findViewById(R.id.sin); + cos = (Button) findViewById(R.id.cos); + tan = (Button) findViewById(R.id.tan); + ln = (Button) findViewById(R.id.ln); + log = (Button) findViewById(R.id.log); + sqrt = (Button) findViewById(R.id.sqrt); + ansb = (Button) findViewById(R.id.ans); + ceac = (Button) findViewById(R.id.ce); + ce = 0; + + if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) + { + // code to do for Portrait Mode + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayShowTitleEnabled(false); + actionBar.show(); + } + } else { + // code to do for Landscape Mode + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.hide(); + } + } + + + + if (savedInstanceState == null) { + setDeg(false); + setInv(false); + setEquation(""); + setCache(""); + setResult(""); + setDisplay("0"); + setAns("0"); + setCloseParens(""); + } else { + setDeg(savedInstanceState.getBoolean("isDeg")); + setInv(savedInstanceState.getBoolean("isInv")); + setEquation(savedInstanceState.getString("equation")); + setCache(savedInstanceState.getString("cache")); + setResult(savedInstanceState.getString("result")); + setDisplay(savedInstanceState.getString("display")); + setAns(savedInstanceState.getString("ans")); + setCloseParens(savedInstanceState.getString("closeParens")); + } + + setRadDegMode(); + displayText(); + cacheBar.setText(cache); + + } + + @Override + public void onSaveInstanceState(Bundle savedInstanceState) { + super.onSaveInstanceState(savedInstanceState); + savedInstanceState.putBoolean("isDeg", isDeg); + savedInstanceState.putBoolean("isInv", isInv); + savedInstanceState.putString("equation", equation); + savedInstanceState.putString("cache", cache); + savedInstanceState.putString("result", result); + savedInstanceState.putString("display", display); + savedInstanceState.putString("ans", ans); + savedInstanceState.putString("closeParens", closeParens); + } + + public void setRadDegMode() { + rad = (Button) findViewById(R.id.rad); + deg = (Button) findViewById(R.id.deg); + if (rad != null && deg != null) { + if (isDeg) { + deg.setBackgroundColor(Color.CYAN); + deg.setTextColor(Color.WHITE); + rad.setBackgroundColor(Color.LTGRAY); + rad.setTextColor(Color.GRAY); + } else { + deg.setBackgroundColor(Color.LTGRAY); + deg.setTextColor(Color.GRAY); + rad.setBackgroundColor(Color.CYAN); + rad.setTextColor(Color.WHITE); + } + } + } + + public void type(View view) { + // input button pressed + Button button = (Button) view; + digitInsertMultiply(); + equation += button.getText().toString(); + setDisplay(pad(equation)); + displayText(); + } + + public void typeSpecial(String special) { + // input button pressed + equation += special; + setDisplay(pad(equation)); + displayText(); + } + + public void ac(View view) { + // AC button pressed + setEquation(""); + setCache(""); + setResult(""); + setDisplay("0"); + setAns("0"); + setCloseParens(""); + + displayText(); + cacheBar.setText(cache); + } + + public void ce(View view) { + ce += 1; + if (ce == 4) { + ceac.setText("AC"); + } + if (equation.length() == 0 || ce == 5) { + setEquation(""); + setCache(""); + setResult(""); + setDisplay("0"); + setAns("0"); + setCloseParens(""); + ceac.setText("CE"); + ce = 0; + } else { + if (equation.charAt(equation.length() - 1) == '(') { + if (closeParens.length() > 0) { + closeParens = closeParens.substring(1); + } + } else if (equation.charAt(equation.length() - 1) == ')') { + closeParens += ')'; + } + setEquation(equation.substring(0, equation.length() - 1)); + setDisplay(pad(equation)); + } + + displayText(); + cacheBar.setText(cache); + } + + public void displayText() { + SpannableString displayText = new SpannableString(display + closeParens); + displayText.setSpan(new ForegroundColorSpan(Color.GRAY), displayText.length() - closeParens.length(), displayText.length(), 0); + calculatorBar.setText(displayText, TextView.BufferType.SPANNABLE); + } + + public String pad(String equation) { + String paddedEquation = ""; + for (int i = 0; i < equation.length(); i++) { + char c = equation.charAt(i); + if (c == '+' || c == '-') { + paddedEquation += " " + c + " "; + } else if (c == '*') { + paddedEquation += " × "; + } else if (c == '/') { + paddedEquation += " ÷ "; + } else { + paddedEquation += "" + c; + } + } + + return paddedEquation; + } + + public void equals(View view) { + + addCloseParens(); + insertZero(); + ce = 0; + cache = display + " = "; + cacheBar.setText(cache); + + if (isDeg) { + System.out.println("Degrees mode"); + String equationToRad = parseTrigonometicExpressions(equation); + System.out.println(equationToRad); + result = Calculate.calculate(equationToRad, isDeg); + } else { + System.out.println("Radians mode"); + result = Calculate.calculate(equation, isDeg); + } + + if (isNumeric(result)) { + ans = result; + display = result; + equation = result; + } else { + display = "Error"; + Toast.makeText(getApplicationContext(), result, Toast.LENGTH_SHORT).show(); + } + + displayText(); + + } + + public static String parseTrigonometicExpressions(String equation) { + String[] trigExpressions = {"sin(", "cos(", "tan("}; + for (int i = 0; i < trigExpressions.length; i++) { + int index = -1; + do { + index = equation.indexOf(trigExpressions[i], index + 1); + if (index != -1) { + String trigValue = equation.substring(index, equation.indexOf(')', index) + 1); + String newValue = trigExpressions[i] + toRadians(extractNumber(trigValue)) + ")"; + equation = equation.replace(trigValue, newValue); + } + } while (index != -1); + } + return equation; + } + + public static double extractNumber(String expression) { + + return Double.valueOf(expression.replaceAll("[^0-9.E-]", "")); + + } + + public static double toRadians(double degrees) { + return degrees * (Math.PI/180); + } + + public boolean isNumeric(String result) { + for (int i = 0; i < result.length(); i++) { + char c = result.charAt(i); + if ((c < 45 || c > 57) && c != 69) { + return false; + } + } + return true; + } + + public void addCloseParens() { + equation += closeParens; + display += closeParens; + closeParens = ""; + } + + + + + // This section contains onClick functions for the calculator buttons + + public void openParen(View view) { + closeParens += ")"; + insertMultiply(); + typeSpecial("("); + } + + public void closeParen(View view) { + if (equation.contains("(")) { + if (closeParens.length() > 0) { + closeParens = closeParens.substring(1); + } + insertZero(); + typeSpecial(")"); + } + } + + public void add(View view) { + insertZero(); + typeSpecial("+"); + } + + public void subtract(View view) { + typeSpecial("-"); + } + + public void divide(View view) { + insertZero(); + typeSpecial("/"); + } + + public void multiply(View view) { + insertZero(); + typeSpecial("*"); + } + + public void point(View view) { + insertZero(); + if (equation.charAt(equation.length() - 1) != '.') { + typeSpecial("."); + } + } + + public void insertMultiply() { + if (0 < equation.length()) { + char last = equation.charAt(equation.length() - 1); + if ((47 < last && last < 58) || last == ')' || last == 's' || last == 'π' || last == 'e' || last == '%') { // assume multiplication if the last item in the equation is a digit, close paren, or 'Ans' + typeSpecial("*"); + } + } + } + + public void digitInsertMultiply() { + if (0 < equation.length()) { + char last = equation.charAt(equation.length() - 1); + if (last == ')' || last == 's' || last == 'π' || last == 'e' || last == '%') { // assume multiplication if the last item in the equation is a digit, close paren, or 'Ans' + typeSpecial("*"); + } + } + } + + public void insertZero() { + if (equation.length() == 0) { + typeSpecial("0"); + } else { + char last = equation.charAt(equation.length() - 1); + if (last == '+' || last == '-' || last == '*' || last == '/' || last == '(') { + typeSpecial("0"); + } + } + } + + public void rad(View view) { + setDeg(false); + setRadDegMode(); + } + + public void deg(View view) { + setDeg(true); + setRadDegMode(); + } + + public void factorial(View view) { + insertZero(); + typeSpecial("!"); + } + + public void inv(View view) { + if (!isInv) { + isInv = true; + sin.setText("asin"); + cos.setText("acos"); + tan.setText("atan"); + ln.setText("eⁿ"); + log.setText("10ⁿ"); + sqrt.setText("x²"); + ansb.setText("Rnd"); + } else { + isInv = false; + sin.setText("sin"); + cos.setText("cos"); + tan.setText("tan"); + ln.setText("ln"); + log.setText("log"); + sqrt.setText("√"); + ansb.setText("Ans"); + } + } + + public void sin(View view) { + closeParens += ")"; + insertMultiply(); + if (!isInv) { + typeSpecial("sin("); + } else { + typeSpecial("asin("); + } + } + + public void ln(View view) { + closeParens += ")"; + insertMultiply(); + if (!isInv) { + typeSpecial("ln("); + } else { + typeSpecial("e^("); + } + } + + public void pi(View view) { + insertMultiply(); + typeSpecial("π"); + } + + public void cos(View view) { + insertMultiply(); + closeParens += ")"; + if (!isInv) { + typeSpecial("cos("); + } else { + typeSpecial("acos("); + } + } + + public void log(View view) { + insertMultiply(); + closeParens += ")"; + if (!isInv) { + typeSpecial("log("); + } else { + typeSpecial("10^("); + } + } + + public void e(View view) { + insertMultiply(); + typeSpecial("e"); + } + + public void tan(View view) { + insertMultiply(); + closeParens += ")"; + if (!isInv) { + typeSpecial("tan("); + } else { + typeSpecial("atan("); + } + } + + public void sqrt(View view) { + if (!isInv) { + insertMultiply(); + closeParens += ")"; + typeSpecial("√("); + } else { + insertZero(); + closeParens += ")"; + typeSpecial("^(2"); + } + } + + public void percent(View view) { + insertZero(); + typeSpecial("%"); + } + + public void ans(View view) { + insertMultiply(); + if (!isInv) { + typeSpecial(ans); + } else { + typeSpecial("" + String.format("%.2f", random.nextFloat() * 100.0f)); + } + } + + public void exp(View view) { + typeSpecial("E"); + } + + public void toThe(View view) { + closeParens += ")"; + insertZero(); + typeSpecial("^("); + } + + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.menu_main, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle action bar item clicks here. The action bar will + // automatically handle clicks on the Home/Up button, so long + // as you specify a parent activity in AndroidManifest.xml. + + // Handle presses on the action bar items + switch (item.getItemId()) { + case R.id.action_calculator: + return true; + case R.id.action_graph: + Intent graphIntent = new Intent(this, GraphActivity.class); + this.startActivity(graphIntent); + return true; + default: + return super.onOptionsItemSelected(item); + } + + } + + public void setDeg(boolean deg) { + this.isDeg = deg; + } + + public String getEquation() { + return equation; + } + + public void setEquation(String equation) { + this.equation = equation; + } + + public String getCache() { + return cache; + } + + public void setCache(String cache) { + this.cache = cache; + } + + public String getResult() { + return result; + } + + public void setResult(String result) { + this.result = result; + } + + public String getDisplay() { + return display; + } + + public void setDisplay(String display) { + this.display = display; + } + + public String getAns() { + return ans; + } + + public void setAns(String ans) { + this.ans = ans; + } + + + public boolean getInv() { + return isInv; + } + + public void setInv(boolean inv) { + this.isInv = inv; + } + + public String getCloseParens() { + return closeParens; + } + + public void setCloseParens(String closeParens) { + this.closeParens = closeParens; + } +} diff --git a/app/src/main/res/drawable/calculator_bar.xml b/app/src/main/res/drawable/calculator_bar.xml new file mode 100644 index 0000000..58d8226 --- /dev/null +++ b/app/src/main/res/drawable/calculator_bar.xml @@ -0,0 +1,17 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout-land/activity_main.xml b/app/src/main/res/layout-land/activity_main.xml new file mode 100644 index 0000000..e0ba4db --- /dev/null +++ b/app/src/main/res/layout-land/activity_main.xml @@ -0,0 +1,447 @@ + + + + + + + + + + + + + + + +