Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,5 @@ dependencies {
implementation 'com.intuit.ssp:ssp-android:1.1.0'

implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
}
16 changes: 16 additions & 0 deletions app/src/main/java/com/fintamath/calculator/Approximator.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.fintamath.calculator

class Approximator {

external fun approximate(exprStr: String, varStr: String, valStr: String): String

external fun getVariableCount(exprStr: String): Int

external fun getLastVariable(exprStr: String): String

companion object {
init {
System.loadLibrary("fintamath_android")
}
}
}
6 changes: 6 additions & 0 deletions app/src/main/java/com/fintamath/calculator/Calculator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ internal class Calculator(

external fun setPrecision(int: Int)

external fun approximate(exprStr: String, varStr: String, valStr: String): String

external fun getVariableCount(exprStr: String): Int

external fun getLastVariable(exprStr: String): String

private fun onCalculated(str: String) {
calculatedCallback.invoke(listOf(*str.split("\n").toTypedArray()))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ class CalculatorProcessor(

fun setPrecision(precision: Int) = calculator.setPrecision(precision)

fun approximate(exprStr: String, varStr: String, valStr: String): String =
calculator.approximate(exprStr, varStr, valStr)

fun getVariableCount(exprStr: String): Int = calculator.getVariableCount(exprStr)

fun getLastVariable(exprStr: String): String = calculator.getLastVariable(exprStr)

private fun onCalculated(result: List<String>) {
callbacksThread {
isCalculating.set(false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,27 @@ package com.fintamath.fragment.calculator

import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.navigation.findNavController
import com.fintamath.R
import com.fintamath.calculator.CalculatorProcessor
import com.fintamath.databinding.FragmentCalculatorBinding
import com.fintamath.storage.HistoryStorage
import com.fintamath.storage.CalculatorInputStorage
import com.fintamath.storage.CalculatorStorage
import com.fintamath.storage.MathTextData
import com.fintamath.storage.SettingsStorage
import com.fintamath.widget.keyboard.Keyboard
import com.fintamath.widget.keyboard.KeyboardView
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.yield
import java.math.BigDecimal
import java.util.Timer
import java.util.TimerTask
import java.util.concurrent.atomic.AtomicBoolean
Expand All @@ -41,6 +47,8 @@ class CalculatorFragment : Fragment() {

private var wereSettingsUpdated = AtomicBoolean(false)

private var drawGraphJob: Job? = null

private val maxSolutionLength = 2000

private val inTextViewPreloadString = "abc * 123 Pi E I Inf ComplexInf () sqrt() abs() floor() ceil() derivative(x,x)"
Expand Down Expand Up @@ -78,8 +86,8 @@ class CalculatorFragment : Fragment() {
updateSettings()

if (inTextViewState.get() == InTextViewState.Ready.value) {
if (viewBinding.inTextView.text != CalculatorInputStorage.mathTextData.text) {
viewBinding.inTextView.text = CalculatorInputStorage.mathTextData.text
if (viewBinding.inTextView.text != CalculatorStorage.inputMathTextData.text) {
viewBinding.inTextView.text = CalculatorStorage.inputMathTextData.text
}

if (viewBinding.outSolutionView.isShowingLoading() || wereSettingsUpdated.get()) {
Expand All @@ -103,7 +111,7 @@ class CalculatorFragment : Fragment() {
private fun initMathTexts() {
viewBinding.inTextLayout.setOnTouchListener { _, event -> touchInText(event) }

viewBinding.inTextView.text = CalculatorInputStorage.mathTextData.text
viewBinding.inTextView.text = CalculatorStorage.inputMathTextData.text
viewBinding.inTextView.setOnTextChangedListener { _, text -> onInTextChange(text) }
viewBinding.inTextView.setOnFocusChangeListener { _, state -> onInTextFocusChange(state) }
}
Expand Down Expand Up @@ -174,10 +182,11 @@ class CalculatorFragment : Fragment() {
}

private fun initBarButtons() {
// viewBinding.cameraButton.setOnClickListener { showCameraFragment() } // TODO: uncomment when camera is implemented
// viewBinding.cameraButton.setOnClickListener { showCameraFragment() } // TODO: uncomment when camera is implemented
viewBinding.historyButton.setOnClickListener { showHistoryFragment() }
viewBinding.settingsButton.setOnClickListener { showSettingsFragment() }
viewBinding.aboutButton.setOnClickListener { showAboutFragment() }
viewBinding.graphButton.setOnClickListener { showGraphFragment() }
}

private fun updateSettings() {
Expand Down Expand Up @@ -206,7 +215,7 @@ class CalculatorFragment : Fragment() {
}
}

CalculatorInputStorage.mathTextData = MathTextData(text)
CalculatorStorage.inputMathTextData = MathTextData(text)
cancelSaveToHistoryTask()

viewBinding.inTextViewHint.visibility = if (viewBinding.inTextView.text.isNotEmpty())
Expand Down Expand Up @@ -245,6 +254,8 @@ class CalculatorFragment : Fragment() {
viewBinding.outSolutionView.showFailedToSolve()
} else {
val cutSolutionTexts = cutSolutionTexts(texts)
val firstSolutionText = cutSolutionTexts.first()
CalculatorStorage.outputMathTextData.text = firstSolutionText

if (countTextsLength(cutSolutionTexts) > maxSolutionLength) {
viewBinding.outSolutionView.showCharacterLimitExceeded()
Expand Down Expand Up @@ -314,6 +325,10 @@ class CalculatorFragment : Fragment() {
showFragment(R.id.action_calculatorFragment_to_settingsFragment)
}

private fun showGraphFragment() {
showFragment(R.id.action_calculatorFragment_to_graphFragment)
}

private fun showFragment(navigationId: Int) {
runSaveToHistoryTask()
viewBinding.inTextView.clearFocusInWeb()
Expand Down
161 changes: 161 additions & 0 deletions app/src/main/java/com/fintamath/fragment/graph/GraphFragment.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
package com.fintamath.fragment.graph

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.navigation.findNavController
import com.fintamath.R
import com.fintamath.calculator.Approximator
import com.fintamath.databinding.FragmentGraphBinding
import com.fintamath.storage.CalculatorStorage
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.yield
import java.math.BigDecimal

class GraphFragment : Fragment() {

private lateinit var viewBinding: FragmentGraphBinding
private lateinit var approximator: Approximator

private var currentMathText = CalculatorStorage.outputMathTextData.text

private val drawGraphScope = CoroutineScope(Job() + Dispatchers.Main)
private var drawGraphJob: Job? = null

private val initialMinX = BigDecimal(-10)
private val initialMaxX = BigDecimal(10)
private val graphPointNum = 200

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
viewBinding = FragmentGraphBinding.inflate(inflater, container, false)

initBarButtons()
initApproximator()

viewBinding.graphView.setOnScrollOrScale {
if (currentMathText != CalculatorStorage.outputMathTextData.text) {
currentMathText = CalculatorStorage.outputMathTextData.text
viewBinding.graphView.clearGraph()
}

drawGraph(viewBinding.graphView.getMinX(), viewBinding.graphView.getMaxX())
}

drawGraph(initialMinX, initialMaxX)

return viewBinding.root
}

private fun initBarButtons() {
viewBinding.calculatorButton.setOnClickListener { showCalculatorFragment() }
viewBinding.historyButton.setOnClickListener { showHistoryFragment() }
// viewBinding.cameraButton.setOnClickListener { showCameraFragment() } // TODO: uncomment when camera is implemented{
viewBinding.settingsButton.setOnClickListener { showSettingsFragment() }
viewBinding.aboutButton.setOnClickListener { showAboutFragment() }
}

private fun initApproximator() {
approximator = Approximator()
}

private fun drawGraph(minX: BigDecimal, maxX: BigDecimal) {
drawGraph(CalculatorStorage.outputMathTextData.text, minX, maxX)
}

private fun drawGraph(firstSolutionText: String, min: BigDecimal, max: BigDecimal) {
drawGraphJob?.cancel()

drawGraphJob = drawGraphScope.launch {
if (approximator.getVariableCount(firstSolutionText) != 1) {
return@launch
}

val varName = approximator.getLastVariable(firstSolutionText)
val mid = (min + max).divide(BigDecimal(2))

drawGraphPoint(firstSolutionText, varName, mid)

val delta = (max - min).divide(BigDecimal(graphPointNum))
var bottom = mid - delta
var top = mid + delta

while (bottom >= min) {
yield()

drawGraphPoint(firstSolutionText, varName, bottom)
drawGraphPoint(firstSolutionText, varName, top)

bottom -= delta
top += delta
}
}
}

private fun drawGraphPoint(
firstSolutionText: String,
varName: String,
varValue: BigDecimal
) {
if (viewBinding.graphView.hasPoint(varValue)) {
return
}

val approxValueStr = approximator.approximate(
firstSolutionText,
varName,
toFintamathReal(varValue)
)

if (approxValueStr.isEmpty()) {
return
}

viewBinding.graphView.addPoint(varValue, toBigDecimal(approxValueStr))
}

private fun toFintamathReal(bigDecimal: BigDecimal): String {
return bigDecimal.toString().replace("E", "*10^")
}

private fun toBigDecimal(fintamathReal: String): BigDecimal {
return BigDecimal(fintamathReal.replace("*10^", "E"))
}

private fun showCalculatorFragment() {
executeBack()
}

private fun showHistoryFragment() {
executeBack()
showFragment(R.id.action_calculatorFragment_to_historyFragment)
}

private fun showCameraFragment() {
executeBack()
showFragment(R.id.action_calculatorFragment_to_cameraFragment)
}

private fun showAboutFragment() {
showFragment(R.id.action_graphFragment_to_aboutFragment)
}

private fun showSettingsFragment() {
showFragment(R.id.action_graphFragment_to_settingsFragment)
}

private fun showFragment(navigationId: Int) {
viewBinding.root.findNavController().navigate(navigationId)
}

private fun executeBack() {
viewBinding.root.findNavController().navigateUp()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@ import com.fintamath.R
import com.fintamath.databinding.FragmentHistoryBinding
import com.fintamath.storage.HistoryStorage
import com.fintamath.storage.MathTextData
import com.fintamath.storage.CalculatorInputStorage
import java.util.Timer
import java.util.TimerTask
import kotlin.concurrent.schedule
import com.fintamath.storage.CalculatorStorage

class HistoryFragment : Fragment() {

Expand Down Expand Up @@ -52,7 +49,8 @@ class HistoryFragment : Fragment() {

private fun initBarButtons() {
viewBinding.calculatorButton.setOnClickListener { showCalculatorFragment() }
// viewBinding.cameraButton.setOnClickListener { showCameraFragment() } // TODO: uncomment when camera is implemented
viewBinding.graphButton.setOnClickListener { showGraphFragment() }
// viewBinding.cameraButton.setOnClickListener { showCameraFragment() } // TODO: uncomment when camera is implemented{
viewBinding.settingsButton.setOnClickListener { showSettingsFragment() }
viewBinding.aboutButton.setOnClickListener { showAboutFragment() }
}
Expand All @@ -73,14 +71,19 @@ class HistoryFragment : Fragment() {
}

private fun onCalculate(text: String) {
CalculatorInputStorage.mathTextData = MathTextData(text)
CalculatorStorage.inputMathTextData = MathTextData(text)
showCalculatorFragment()
}

private fun showCalculatorFragment() {
executeBack()
}

private fun showGraphFragment() {
executeBack()
showFragment(R.id.action_calculatorFragment_to_graphFragment)
}

private fun showCameraFragment() {
executeBack()
showFragment(R.id.action_calculatorFragment_to_cameraFragment)
Expand Down

This file was deleted.

6 changes: 6 additions & 0 deletions app/src/main/java/com/fintamath/storage/CalculatorStorage.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.fintamath.storage

object CalculatorStorage {
var inputMathTextData: MathTextData = MathTextData("")
var outputMathTextData: MathTextData = MathTextData("")
}
Loading