From 853548225c4e2541841e7602d7fff2ed122ab455 Mon Sep 17 00:00:00 2001 From: "Alberto Duarte (PWC)" Date: Mon, 9 Oct 2023 16:54:46 +0100 Subject: Initial commit --- .../com/pwc/calculatorv2/data/dao/FunctionDao.kt | 51 ++++ .../data/datasources/FunctionListDataSource.kt | 70 +++++ .../pwc/calculatorv2/data/models/FunctionDTO.kt | 28 ++ .../data/repositories/FunctionListRepository.kt | 121 ++++++++ .../data/responses/FunctionListResponse.kt | 8 + .../data/viewmodels/CalculatorViewModel.kt | 316 +++++++++++++++++++++ 6 files changed, 594 insertions(+) create mode 100644 app/src/main/java/com/pwc/calculatorv2/data/dao/FunctionDao.kt create mode 100644 app/src/main/java/com/pwc/calculatorv2/data/datasources/FunctionListDataSource.kt create mode 100644 app/src/main/java/com/pwc/calculatorv2/data/models/FunctionDTO.kt create mode 100644 app/src/main/java/com/pwc/calculatorv2/data/repositories/FunctionListRepository.kt create mode 100644 app/src/main/java/com/pwc/calculatorv2/data/responses/FunctionListResponse.kt create mode 100644 app/src/main/java/com/pwc/calculatorv2/data/viewmodels/CalculatorViewModel.kt (limited to 'app/src/main/java/com/pwc/calculatorv2/data') diff --git a/app/src/main/java/com/pwc/calculatorv2/data/dao/FunctionDao.kt b/app/src/main/java/com/pwc/calculatorv2/data/dao/FunctionDao.kt new file mode 100644 index 0000000..341f961 --- /dev/null +++ b/app/src/main/java/com/pwc/calculatorv2/data/dao/FunctionDao.kt @@ -0,0 +1,51 @@ +package com.pwc.calculatorv2.data.dao + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.Query +import com.pwc.calculatorv2.data.models.Function + +@Dao +interface FunctionDao { + @Query("SELECT * FROM Function") + fun getAll(): List + + @Query("SELECT * FROM Function WHERE function LIKE '%+%'") + fun getPlus(): List + + @Query("SELECT * FROM Function WHERE function LIKE '%-%'") + fun getMinus(): List + + @Query("SELECT * FROM Function WHERE function LIKE '%*%'") + fun getPer(): List + + @Query("SELECT * FROM Function WHERE function LIKE '%/%'") + fun getDivide(): List + + @Insert + fun insertAll(functionList: List) + + @Insert + fun insert(function: Function) + + @Delete + fun delete(function: Function) + + @Query("DELETE FROM Function") + fun wipe() + + @Query("DELETE FROM Function WHERE function LIKE '%+%'") + fun wipePlus() + + @Query("DELETE FROM Function WHERE function LIKE '%-%'") + fun wipeMinus() + + @Query("DELETE FROM Function WHERE function LIKE '%*%'") + fun wipePer() + + @Query("DELETE FROM Function WHERE function LIKE '%/%'") + fun wipeDivided() + + +} \ No newline at end of file diff --git a/app/src/main/java/com/pwc/calculatorv2/data/datasources/FunctionListDataSource.kt b/app/src/main/java/com/pwc/calculatorv2/data/datasources/FunctionListDataSource.kt new file mode 100644 index 0000000..aaee7b3 --- /dev/null +++ b/app/src/main/java/com/pwc/calculatorv2/data/datasources/FunctionListDataSource.kt @@ -0,0 +1,70 @@ +package com.pwc.calculatorv2.data.datasources + +import android.content.Context +import androidx.room.Room +import com.pwc.calculatorv2.AppDatabase +import com.pwc.calculatorv2.data.models.Function + +class FunctionListDataSource (context: Context){ + private val db: AppDatabase = Room.databaseBuilder( + context.applicationContext, + AppDatabase::class.java, + "calculator" + ).build() + + fun getFunctionList(): List { + return db.functionDao().getAll() + } + + fun getPlusFunctionList(): List { + return db.functionDao().getPlus() + } + + fun getMinusFunctionList(): List { + return db.functionDao().getMinus() + } + + fun getPerFunctionList(): List { + return db.functionDao().getPer() + } + + fun getDividedFunctionList(): List { + return db.functionDao().getDivide() + } + + fun addFunction(function: Function): List { + db.functionDao().insert(function) + return db.functionDao().getAll() + } + + fun removeFunction(function: Function): List { + db.functionDao().delete(function) + return db.functionDao().getAll() + } + + fun wipeFunctionList(): List { + db.functionDao().wipe() + return db.functionDao().getAll() + } + + fun wipePlusFunctionList(): List { + db.functionDao().wipePlus() + return db.functionDao().getAll() + } + + fun wipeMinusFunctionList(): List { + db.functionDao().wipeMinus() + return db.functionDao().getAll() + } + + fun wipePerFunctionList(): List { + db.functionDao().wipePer() + return db.functionDao().getAll() + } + + fun wipeDividedFunctionList(): List { + db.functionDao().wipeDivided() + return db.functionDao().getAll() + } + +} diff --git a/app/src/main/java/com/pwc/calculatorv2/data/models/FunctionDTO.kt b/app/src/main/java/com/pwc/calculatorv2/data/models/FunctionDTO.kt new file mode 100644 index 0000000..b8b73a2 --- /dev/null +++ b/app/src/main/java/com/pwc/calculatorv2/data/models/FunctionDTO.kt @@ -0,0 +1,28 @@ +package com.pwc.calculatorv2.data.models + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import androidx.room.TypeConverter +import androidx.room.TypeConverters +import java.util.Date + +@Entity +@TypeConverters(DateConverter::class) +data class Function( + @PrimaryKey (autoGenerate = true) var id: Int = 0, + @ColumnInfo var function: String = "", + @ColumnInfo var date: Date = Date() +) + +class DateConverter { + @TypeConverter + fun fromDate(date: Date?): Long? { + return date?.time + } + + @TypeConverter + fun toDate(timestamp: Long?): Date? { + return timestamp?.let { Date(it) } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/pwc/calculatorv2/data/repositories/FunctionListRepository.kt b/app/src/main/java/com/pwc/calculatorv2/data/repositories/FunctionListRepository.kt new file mode 100644 index 0000000..d3b0682 --- /dev/null +++ b/app/src/main/java/com/pwc/calculatorv2/data/repositories/FunctionListRepository.kt @@ -0,0 +1,121 @@ +package com.pwc.calculatorv2.data.repositories + +import android.content.Context +import com.pwc.calculatorv2.data.datasources.FunctionListDataSource +import com.pwc.calculatorv2.data.responses.FunctionListResponse +import kotlinx.coroutines.flow.flow +import com.pwc.calculatorv2.data.models.Function +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.flowOn + +class FunctionListRepository (context: Context) { + private val dataSource = FunctionListDataSource(context) + + fun getFunctionList() = flow { + try { + val functionList = dataSource.getFunctionList() + emit(FunctionListResponse.Success( functionList )) + } catch (e: Exception) { + emit(FunctionListResponse.Error(e.message ?: "Error")) + } + }.flowOn(Dispatchers.IO) + + fun getPlusFunctionList() = flow { + try { + val functionList = dataSource.getPlusFunctionList() + emit(FunctionListResponse.Success( functionList )) + } catch (e: Exception) { + emit(FunctionListResponse.Error(e.message ?: "Error")) + } + }.flowOn(Dispatchers.IO) + + fun getMinusFunctionList() = flow { + try { + val functionList = dataSource.getMinusFunctionList() + emit(FunctionListResponse.Success( functionList )) + } catch (e: Exception) { + emit(FunctionListResponse.Error(e.message ?: "Error")) + } + }.flowOn(Dispatchers.IO) + + fun getPerFunctionList() = flow { + try { + val functionList = dataSource.getPerFunctionList() + emit(FunctionListResponse.Success( functionList )) + } catch (e: Exception) { + emit(FunctionListResponse.Error(e.message ?: "Error")) + } + }.flowOn(Dispatchers.IO) + + fun getDividedFunctionList() = flow { + try { + val functionList = dataSource.getDividedFunctionList() + emit(FunctionListResponse.Success( functionList )) + } catch (e: Exception) { + emit(FunctionListResponse.Error(e.message ?: "Error")) + } + }.flowOn(Dispatchers.IO) + + fun addFunction(function: Function) = flow { + try { + val functionList = dataSource.addFunction(function) + emit(FunctionListResponse.Success( functionList )) + } catch (e: Exception) { + emit(FunctionListResponse.Error(e.message ?: "Error")) + } + }.flowOn((Dispatchers.IO)) + + fun removeFunction(function: Function) = flow { + try { + val functionList = dataSource.removeFunction(function) + emit(FunctionListResponse.Success( functionList )) + } catch (e: Exception) { + emit(FunctionListResponse.Error(e.message ?: "Error")) + } + }.flowOn((Dispatchers.IO)) + + fun wipeFunctionList() = flow { + try { + val functionList = dataSource.wipeFunctionList() + emit(FunctionListResponse.Success( functionList )) + } catch (e: Exception) { + emit(FunctionListResponse.Error(e.message ?: "Error")) + } + }.flowOn((Dispatchers.IO)) + + fun wipePlusFunctionList() = flow { + try { + val functionList = dataSource.wipePlusFunctionList() + emit(FunctionListResponse.Success( functionList )) + } catch (e: Exception) { + emit(FunctionListResponse.Error(e.message ?: "Error")) + } + }.flowOn((Dispatchers.IO)) + + fun wipeMinusFunctionList() = flow { + try { + val functionList = dataSource.wipeMinusFunctionList() + emit(FunctionListResponse.Success( functionList )) + } catch (e: Exception) { + emit(FunctionListResponse.Error(e.message ?: "Error")) + } + }.flowOn((Dispatchers.IO)) + + fun wipePerFunctionList() = flow { + try { + val functionList = dataSource.wipePerFunctionList() + emit(FunctionListResponse.Success( functionList )) + } catch (e: Exception) { + emit(FunctionListResponse.Error(e.message ?: "Error")) + } + }.flowOn((Dispatchers.IO)) + + fun wipeDividedFunctionList() = flow { + try { + val functionList = dataSource.wipeDividedFunctionList() + emit(FunctionListResponse.Success( functionList )) + } catch (e: Exception) { + emit(FunctionListResponse.Error(e.message ?: "Error")) + } + }.flowOn((Dispatchers.IO)) +} \ No newline at end of file diff --git a/app/src/main/java/com/pwc/calculatorv2/data/responses/FunctionListResponse.kt b/app/src/main/java/com/pwc/calculatorv2/data/responses/FunctionListResponse.kt new file mode 100644 index 0000000..b2a75ca --- /dev/null +++ b/app/src/main/java/com/pwc/calculatorv2/data/responses/FunctionListResponse.kt @@ -0,0 +1,8 @@ +package com.pwc.calculatorv2.data.responses + +import com.pwc.calculatorv2.data.models.Function + +sealed class FunctionListResponse { + data class Success(val functionList: List) : FunctionListResponse() + data class Error(val error: String): FunctionListResponse() +} diff --git a/app/src/main/java/com/pwc/calculatorv2/data/viewmodels/CalculatorViewModel.kt b/app/src/main/java/com/pwc/calculatorv2/data/viewmodels/CalculatorViewModel.kt new file mode 100644 index 0000000..bbb270a --- /dev/null +++ b/app/src/main/java/com/pwc/calculatorv2/data/viewmodels/CalculatorViewModel.kt @@ -0,0 +1,316 @@ +package com.pwc.calculatorv2.data.viewmodels + +import android.content.Context +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.pwc.calculatorv2.data.repositories.FunctionListRepository +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import com.pwc.calculatorv2.data.models.Function +import com.pwc.calculatorv2.data.responses.FunctionListResponse +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach + +class CalculatorViewModel(context: Context, private val repository: FunctionListRepository = FunctionListRepository(context)) : ViewModel() { + private val mutableState = MutableStateFlow(CalculatorViewState()) + val calculatorViewState: StateFlow = mutableState + val index = mutableStateOf(-1) + + + fun getFunctionList() { + mutableState.value = mutableState.value.copy(isLoading = true) + repository.getFunctionList() + .onEach { response -> + when (response) { + is FunctionListResponse.Success -> + mutableState.value = + mutableState.value.copy(functionList = response.functionList) + is FunctionListResponse.Error -> + mutableState.value = + mutableState.value.copy(error = response.error) + } + index.value = mutableState.value.functionList?.lastIndex ?: -1 + } + .launchIn(viewModelScope) + } + + fun getPlusFunctionList() { + mutableState.value = mutableState.value.copy(isLoading = true) + repository.getPlusFunctionList() + .onEach { response -> + when (response) { + is FunctionListResponse.Success -> + mutableState.value = + mutableState.value.copy(functionList = response.functionList) + is FunctionListResponse.Error -> + mutableState.value = + mutableState.value.copy(error = response.error) + } + } + .launchIn(viewModelScope) + } + + fun getMinusFunctionList() { + mutableState.value = mutableState.value.copy(isLoading = true) + repository.getMinusFunctionList() + .onEach { response -> + when (response) { + is FunctionListResponse.Success -> + mutableState.value = + mutableState.value.copy(functionList = response.functionList) + is FunctionListResponse.Error -> + mutableState.value = + mutableState.value.copy(error = response.error) + } + } + .launchIn(viewModelScope) + } + + fun getPerFunctionList() { + mutableState.value = mutableState.value.copy(isLoading = true) + repository.getPerFunctionList() + .onEach { response -> + when (response) { + is FunctionListResponse.Success -> + mutableState.value = + mutableState.value.copy(functionList = response.functionList) + is FunctionListResponse.Error -> + mutableState.value = + mutableState.value.copy(error = response.error) + } + } + .launchIn(viewModelScope) + } + + fun getDivideFunctionList() { + mutableState.value = mutableState.value.copy(isLoading = true) + repository.getDividedFunctionList() + .onEach { response -> + when (response) { + is FunctionListResponse.Success -> + mutableState.value = + mutableState.value.copy(functionList = response.functionList) + is FunctionListResponse.Error -> + mutableState.value = + mutableState.value.copy(error = response.error) + } + } + .launchIn(viewModelScope) + } + + private fun addFunction(function: Function) { + repository.addFunction(function) + .onEach { response -> + when (response) { + is FunctionListResponse.Success -> + mutableState.value = + mutableState.value.copy(functionList = response.functionList) + is FunctionListResponse.Error -> + mutableState.value = + mutableState.value.copy(error = response.error) + } + index.value = mutableState.value.functionList?.lastIndex ?: -1 + } + .launchIn(viewModelScope) + } + + fun removeFunction(function: Function) { + repository.removeFunction(function) + .onEach { response -> + when (response) { + is FunctionListResponse.Success -> + mutableState.value = + mutableState.value.copy(functionList = response.functionList) + is FunctionListResponse.Error -> + mutableState.value = + mutableState.value.copy(error = response.error) + } + } + .launchIn(viewModelScope) + } + + fun wipeFunctionList() { + repository.wipeFunctionList() + .onEach { response -> + when (response) { + is FunctionListResponse.Success -> + mutableState.value = + mutableState.value.copy(functionList = response.functionList) + is FunctionListResponse.Error -> + mutableState.value = + mutableState.value.copy(error = response.error) + } + } + .launchIn(viewModelScope) + } + + fun wipePlusFunctionList() { + repository.wipePlusFunctionList() + .onEach { response -> + when (response) { + is FunctionListResponse.Success -> + mutableState.value = + mutableState.value.copy(functionList = response.functionList) + is FunctionListResponse.Error -> + mutableState.value = + mutableState.value.copy(error = response.error) + } + } + .launchIn(viewModelScope) + } + + fun wipeMinusFunctionList() { + repository.wipeMinusFunctionList() + .onEach { response -> + when (response) { + is FunctionListResponse.Success -> + mutableState.value = + mutableState.value.copy(functionList = response.functionList) + is FunctionListResponse.Error -> + mutableState.value = + mutableState.value.copy(error = response.error) + } + } + .launchIn(viewModelScope) + } + + fun wipePerFunctionList() { + repository.wipePerFunctionList() + .onEach { response -> + when (response) { + is FunctionListResponse.Success -> + mutableState.value = + mutableState.value.copy(functionList = response.functionList) + is FunctionListResponse.Error -> + mutableState.value = + mutableState.value.copy(error = response.error) + } + } + .launchIn(viewModelScope) + } + + fun wipeDividedFunctionList() { + repository.wipeDividedFunctionList() + .onEach { response -> + when (response) { + is FunctionListResponse.Success -> + mutableState.value = + mutableState.value.copy(functionList = response.functionList) + is FunctionListResponse.Error -> + mutableState.value = + mutableState.value.copy(error = response.error) + } + } + .launchIn(viewModelScope) + } + + fun showLast( + ):String { + var string = "" + val functionList = mutableState.value.functionList + if (!functionList.isNullOrEmpty()){ + if (index.value < 0 || index.value > functionList.lastIndex){ + index.value = functionList.lastIndex + } + string = functionList[index.value].function + index.value = index.value - 1 + return string + } + return string + } + + fun calculateResult( + expression: MutableState, + ) { + // Calculate the result of the expression + val expressionValue = expression.value + val result = try { + if(expressionValue != "" || expressionValue.contains(" ")){ + val numericResult = evaluateExpression(expressionValue) + numericResult.toString() + } else if(!expressionValue.contains(" ")){ + expressionValue + } + else + { + "" + } + } catch (e: Exception) { + "ErrorHello" + } + + addFunction(Function(function = expressionValue)) + expression.value = result + } + + private fun evaluateExpression(expression: String): Double { + var modifiedExpression = expression + + while (modifiedExpression.contains("(")) { + val openingIndex = modifiedExpression.lastIndexOf("(") + val closingIndex = modifiedExpression.indexOf(")", openingIndex) + val innerExpression = modifiedExpression.substring(openingIndex + 1, closingIndex) + val innerResult = evaluateExpression(innerExpression) + + // Replace the inner expression (within parentheses) with its result + modifiedExpression = + modifiedExpression.replace("($innerExpression)", innerResult.toString()) +// modifiedExpression = modifiedExpression.replaceRange( +// openingIndex -1, +// closingIndex, +// innerResult.toString() +// ) + + } + + val parts = modifiedExpression.split(" ").toMutableList() + var operator: String = "" + var result: Double = 0.0 + + + while (parts.contains("*")) { + multiply(parts) + } + while (parts.contains("/")) { + divide(parts) + } + + parts.forEachIndexed { _ , unit -> + if (unit.toDoubleOrNull() != null) { + val operand = unit.toDouble() + when (operator) { + "" -> result = operand + "+" -> result += operand + "-" -> result -= operand + } + } else { + operator = unit.trim() + } + } + + return result + } + + + private fun divide(parts: MutableList) { + val indexOfSymbol = parts.indexOf("/") + parts[indexOfSymbol] = (parts[indexOfSymbol - 1].toDouble() / parts[indexOfSymbol + 1].toDouble()).toString() + parts.removeAt(indexOfSymbol - 1) + parts.removeAt(indexOfSymbol) + } + + private fun multiply(parts: MutableList) { + val indexOfSymbol = parts.indexOf("*") + parts[indexOfSymbol] = (parts[indexOfSymbol - 1].toDouble() * parts[indexOfSymbol + 1].toDouble()).toString() + parts.removeAt(indexOfSymbol - 1) + parts.removeAt(indexOfSymbol) + } + +} +data class CalculatorViewState( + val functionList: List? = null, + val error: String? = null, + val isLoading: Boolean = false +) -- cgit v1.2.3-54-g00ecf