Merge branch 'dev' of gitlab.com:stax-river/poker-analytics into dev

# Conflicts:
#	app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt
dev
Aurelien Hubert 7 years ago
commit e8341277d9
  1. 7
      app/src/main/java/net/pokeranalytics/android/model/filter/Query.kt
  2. 149
      app/src/main/java/net/pokeranalytics/android/model/filter/QueryCondition.kt
  3. 3
      app/src/main/java/net/pokeranalytics/android/model/migrations/PokerAnalyticsMigration.kt
  4. 14
      app/src/main/java/net/pokeranalytics/android/model/realm/Filter.kt
  5. 12
      app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt
  6. 6
      app/src/main/java/net/pokeranalytics/android/model/realm/Transaction.kt
  7. 36
      app/src/main/java/net/pokeranalytics/android/ui/fragment/FeedFragment.kt
  8. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/FiltersFragment.kt
  9. 4
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterCategoryRow.kt
  10. 6
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterSectionRow.kt
  11. 4
      app/src/main/java/net/pokeranalytics/android/util/extensions/NumbersExtension.kt

@ -2,6 +2,7 @@ package net.pokeranalytics.android.model.filter
import android.content.Context
import io.realm.RealmQuery
import io.realm.kotlin.where
import net.pokeranalytics.android.R
fun List<Query>.mapFirstCondition() : List<QueryCondition> {
@ -67,6 +68,12 @@ class Query {
}
}
val queryLast = this.conditions.filter {
it is QueryCondition.Last
}.firstOrNull()
queryLast?.let {
return realmQuery.limit((it as QueryCondition.Last).singleValue.toLong())
}
return realmQuery
}

@ -20,10 +20,7 @@ import net.pokeranalytics.android.ui.view.rowrepresentable.FilterElementRow
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterSectionRow
import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.UserDefaults
import net.pokeranalytics.android.util.extensions.endOfDay
import net.pokeranalytics.android.util.extensions.hourMinute
import net.pokeranalytics.android.util.extensions.startOfDay
import net.pokeranalytics.android.util.extensions.toCurrency
import net.pokeranalytics.android.util.extensions.*
import java.text.DateFormatSymbols
import java.util.*
import kotlin.collections.ArrayList
@ -80,9 +77,7 @@ sealed class QueryCondition : FilterElementRow {
MORE,
LESS,
EQUALS,
BETWEEN,
BETWEEN_RIGHT_EXCLUSIVE,
BETWEEN_LEFT_EXCLUSIVE,
TRUE,
;
}
@ -111,7 +106,7 @@ sealed class QueryCondition : FilterElementRow {
}
}
open var operator: Operator = Operator.ANY
abstract var operator: Operator
abstract class ListOfValues<T>: QueryCondition(), Comparable<ListOfValues<T>> where T:Comparable<T> {
@ -138,29 +133,37 @@ sealed class QueryCondition : FilterElementRow {
abstract class ListOfDouble: ListOfValues<Double>() {
open var sign: Int = 1
override var operator: Operator = Operator.ANY
override var listOfValues = arrayListOf(0.0)
override fun updateValueBy(filterCondition: FilterCondition) {
super.updateValueBy(filterCondition)
listOfValues = filterCondition.getValues()
}
override fun labelForValue(value: Double, context: Context): String {
return value.toCurrency(UserDefaults.currency)
val prefix = this.resId?.let {
context.getString(it)+" "
} ?: ""
return prefix+value.toCurrency(UserDefaults.currency)
}
}
abstract class ListOfInt: ListOfValues<Int>() {
override var operator: Operator = Operator.ANY
override var listOfValues = arrayListOf(0)
override fun updateValueBy(filterCondition: FilterCondition) {
super.updateValueBy(filterCondition)
listOfValues = filterCondition.getValues()
}
override fun labelForValue(value: Int, context: Context): String {
return value.toString()
val prefix = this.resId?.let {
context.getString(it)+" "
} ?: ""
return prefix+value.toString()
}
}
abstract class ListOfString: ListOfValues<String>() {
override var operator: Operator = Operator.ANY
override var listOfValues = ArrayList<String>()
override fun labelForValue(value: String, context: Context): String { return value }
override fun updateValueBy(filterCondition: FilterCondition) {
@ -171,8 +174,12 @@ sealed class QueryCondition : FilterElementRow {
abstract class SingleDate: SingleValue<Date>() {
override fun labelForValue(value: Date, context: Context): String {
return value.toString()
val prefix = this.resId?.let {
context.getString(it)+" "
} ?: ""
return prefix+value.shortDate()
}
override var listOfValues = ArrayList<Date>()
override var singleValue: Date
@ -190,8 +197,12 @@ sealed class QueryCondition : FilterElementRow {
abstract class SingleInt: SingleValue<Int>() {
override fun labelForValue(value: Int, context: Context): String {
return value.toString()
val prefix = this.resId?.let {
context.getString(it)+" "
} ?: ""
return prefix+value.toString()
}
override var singleValue: Int
get() { return listOfValues.firstOrNull() ?: 0 }
set(value) {
@ -205,7 +216,12 @@ sealed class QueryCondition : FilterElementRow {
}
}
override fun getDisplayName(context: Context): String { return baseId }
override fun getDisplayName(context: Context): String {
this.resId?.let {
return context.getString(it)
}
return baseId
}
override var filterSectionRow: FilterSectionRow = FilterSectionRow.CASH_TOURNAMENT
@ -250,21 +266,17 @@ sealed class QueryCondition : FilterElementRow {
override val showTime: Boolean = true
}
object IsLive : QueryCondition() {
override fun getDisplayName(context: Context): String { return "Live" }
abstract class TrueQueryCondition: QueryCondition() {
override var operator: Operator = Operator.TRUE
}
object IsCash : QueryCondition() {
override fun getDisplayName(context: Context): String { return "Cash" }
}
object IsLive : TrueQueryCondition()
object IsOnline : QueryCondition() {
override fun getDisplayName(context: Context): String { return "Online" }
}
object IsCash : TrueQueryCondition()
object IsTournament : QueryCondition() {
override fun getDisplayName(context: Context): String { return "Tournament" }
}
object IsOnline : TrueQueryCondition()
object IsTournament : TrueQueryCondition()
class AnyBankroll(): QueryDataCondition<Bankroll>() {
override var entity: Class<Bankroll> = Bankroll::class.java
@ -336,30 +348,64 @@ sealed class QueryCondition : FilterElementRow {
class AnyBlind: ListOfString()
class LastGame: SingleInt()
class LastSession: SingleInt()
object Last: SingleInt() {
override var operator = Operator.EQUALS
override fun getDisplayName(context: Context): String {
//TODO update string "last %i"
return "${context.getString(R.string.last_i_records)} $singleValue"
}
}
class NumberOfTable: ListOfInt()
class NumberOfTable: ListOfInt() {
override fun labelForValue(value: Int, context: Context): String {
val prefix = this.resId?.let {
context.getString(it) + " "
} ?: ""
return prefix + value.toString() + " " + context.getString(R.string.tables)
}
}
class NumberOfRebuy(): ListOfDouble() {
constructor(operator: Operator, numberOfRebuy: Double) : this() {
this.operator = operator
this.listOfValues = arrayListOf(numberOfRebuy)
}
override fun labelForValue(value: Double, context: Context): String {
val prefix = this.resId?.let {
context.getString(it) + " "
} ?: ""
return prefix + value.toString()
}
}
open class TournamentFinalPosition(): ListOfInt() {
class TournamentFinalPosition(): ListOfInt() {
constructor(operator: Operator, finalPosition: Int) : this() {
this.operator = operator
this.listOfValues = arrayListOf(finalPosition)
}
override fun labelForValue(value: Int, context: Context): String {
val prefix = this.resId?.let {
context.getString(it) + " "
} ?: ""
return prefix + value.toString()
}
}
open class NetAmount: ListOfDouble()
class NetAmountWon: NetAmount()
class NetAmountLost: NetAmount() { override var sign: Int = -1 }
class TournamentNumberOfPlayer: ListOfInt()
class TournamentNumberOfPlayer: ListOfInt() {
override fun labelForValue(value: Int, context: Context): String {
val prefix = this.resId?.let {
context.getString(it) + " "
} ?: ""
return prefix + value.toString() + context.getString(R.string.number_of_players)
}
}
class StartedFromDate: DateQuery() { override var operator = Operator.MORE }
class StartedToDate: DateQuery() { override var operator = Operator.LESS }
@ -392,26 +438,38 @@ sealed class QueryCondition : FilterElementRow {
}
}
object IsWeekDay: QueryCondition()
object IsWeekEnd: QueryCondition()
object IsToday: QueryCondition()
object WasYesterday: QueryCondition()
object WasTodayAndYesterday: QueryCondition()
object DuringThisWeek: QueryCondition()
object DuringThisMonth: QueryCondition()
object DuringThisYear: QueryCondition()
object IsWeekDay: TrueQueryCondition()
object IsWeekEnd: TrueQueryCondition()
object IsToday: TrueQueryCondition()
object WasYesterday: TrueQueryCondition()
object WasTodayAndYesterday: TrueQueryCondition()
object DuringThisWeek: TrueQueryCondition()
object DuringThisMonth: TrueQueryCondition()
object DuringThisYear: TrueQueryCondition()
class TournamentFee: ListOfDouble() {
override fun labelForValue(value: Double, context: Context): String {
return value.toCurrency(UserDefaults.currency)
val prefix = this.resId?.let {
context.getString(it)+" "
} ?: ""
return prefix+value.toCurrency(UserDefaults.currency)
}
}
class PastDay: SingleInt() {
override var operator = Operator.EQUALS
override val viewType: Int = RowViewType.TITLE_VALUE_CHECK.ordinal
override fun labelForValue(value: Int, context: Context): String {
val suffix = this.resId?.let {
" "+context.getString(it)
} ?: ""
return value.toString() + suffix
}
}
class Duration: SingleInt() {
override var operator = Operator.EQUALS
var minutes:Int
get() { return singleValue }
set(value) { listOfValues = arrayListOf(value) }
@ -473,6 +531,13 @@ sealed class QueryCondition : FilterElementRow {
calendar.add(Calendar.HOUR_OF_DAY, -24)
return realmQuery.greaterThanOrEqualTo(fieldName, calendar.time.startOfDay()).and().lessThanOrEqualTo(fieldName, calendar.time.endOfDay())
}
is PastDay -> {
val startDate = Date()
val calendar = Calendar.getInstance()
calendar.time = startDate
calendar.add(Calendar.DAY_OF_YEAR, -singleValue)
return realmQuery.greaterThanOrEqualTo(fieldName, calendar.time.startOfDay()).and().lessThanOrEqualTo(fieldName, startDate.endOfDay())
}
is DuringThisWeek -> {
val startDate = Date()
val calendar = Calendar.getInstance()
@ -584,8 +649,6 @@ sealed class QueryCondition : FilterElementRow {
get() {
return when (this) {
is PastDay -> RowViewType.TITLE_VALUE_CHECK.ordinal
is LastGame -> RowViewType.TITLE_VALUE_CHECK.ordinal
is LastSession -> RowViewType.TITLE_VALUE_CHECK.ordinal
else -> {
when (this.operator) {
Operator.MORE -> RowViewType.TITLE_VALUE_CHECK.ordinal
@ -600,8 +663,6 @@ sealed class QueryCondition : FilterElementRow {
get() {
return when (this) {
is PastDay -> BottomSheetType.EDIT_TEXT
is LastGame -> BottomSheetType.EDIT_TEXT
is LastSession -> BottomSheetType.EDIT_TEXT
else -> {
when (this.operator) {
Operator.MORE -> BottomSheetType.EDIT_TEXT
@ -630,8 +691,6 @@ sealed class QueryCondition : FilterElementRow {
is IsWeekDay -> R.string.week_days
is IsWeekEnd -> R.string.weekend
is PastDay -> R.string.period_in_days
is LastGame -> R.string.last_records
is LastSession -> R.string.last_sessions
is NetAmountWon -> {
when (this.operator) {
Operator.MORE -> R.string.won_amount_more_than

@ -128,6 +128,9 @@ class PokerAnalyticsMigration : RealmMigration {
it.addField("endDateHourMinuteComponent", Double::class.java).setNullable("endDateHourMinuteComponent", true)
it.addRealmListField("customFieldEntries", CustomFieldEntry::class.java)
}
schema.get("Filter")?.addField("filterableTypeOrdinal", Integer::class.java)
currentVersion++
}
}

@ -7,6 +7,7 @@ import io.realm.kotlin.where
import net.pokeranalytics.android.model.filter.Filterable
import net.pokeranalytics.android.model.filter.Query
import net.pokeranalytics.android.model.filter.QueryCondition
import net.pokeranalytics.android.ui.interfaces.FilterableType
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterCategoryRow
import java.util.*
@ -21,8 +22,9 @@ open class Filter : RealmObject(), RowRepresentable {
companion object {
// Create a new instance
fun newInstance(realm: Realm): Filter {
fun newInstance(realm: Realm, filterableType:Int): Filter {
val filter = Filter()
filter.filterableTypeOrdinal = filterableType
return realm.copyToRealm(filter)
}
@ -59,6 +61,16 @@ open class Filter : RealmObject(), RowRepresentable {
var filterConditions: RealmList<FilterCondition> = RealmList()
private set
private var filterableTypeOrdinal: Int? = null
val filterableType: FilterableType
get() {
this.filterableTypeOrdinal?.let {
return FilterableType.values()[it]
}
return FilterableType.ALL
}
fun createOrUpdateFilterConditions(filterConditionRows: ArrayList<QueryCondition>) {
println("list of querys saving: ${filterConditionRows.map { it.id }}")
println("list of querys previous: ${this.filterConditions.map { it.queryCondition.id }}")

@ -39,7 +39,6 @@ import net.pokeranalytics.android.ui.view.rowrepresentable.SessionRow
import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.UserDefaults
import net.pokeranalytics.android.util.extensions.*
import timber.log.Timber
import java.text.DateFormat
import java.util.*
import java.util.Currency
@ -68,7 +67,7 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat
return realm.copyToRealm(session)
}
fun fieldNameForQueryType(queryCondition: Class<out QueryCondition>): String? {
fun fieldNameForQueryType(queryCondition: Class < out QueryCondition >): String? {
return when (queryCondition) {
IsLive::class.java, IsOnline::class.java -> "bankroll.live"
IsCash::class.java, IsTournament::class.java -> "type"
@ -81,7 +80,7 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat
AnyTableSize::class.java -> "tableSize"
AnyTournamentType::class.java -> "tournamentType"
AnyBlind::class.java -> "blinds"
NumberOfTable::class.java -> "numberOfTable"
NumberOfTable::class.java -> "numberOfTables"
NetAmountWon::class.java, NetAmountLost::class.java -> "computableResults.ratedNet"
NumberOfRebuy::class.java -> "result.numberOfRebuy"
TournamentNumberOfPlayer::class.java -> "result.tournamentNumberOfPlayers"
@ -92,7 +91,7 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat
AnyDayOfWeek::class.java, IsWeekEnd::class.java, IsWeekDay::class.java -> "dayOfWeek"
AnyMonthOfYear::class.java -> "month"
AnyYear::class.java -> "year"
IsToday::class.java, WasYesterday::class.java, WasTodayAndYesterday::class.java, DuringThisYear::class.java, DuringThisMonth::class.java, DuringThisWeek::class.java -> "startDate"
PastDay::class.java, IsToday::class.java, WasYesterday::class.java, WasTodayAndYesterday::class.java, DuringThisYear::class.java, DuringThisMonth::class.java, DuringThisWeek::class.java -> "startDate"
StartedFromTime::class.java -> "startDateHourMinuteComponent"
EndedToTime::class.java -> "endDateHourMinuteComponent"
Duration::class.java -> "netDuration"
@ -1008,17 +1007,12 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat
when (row.type) {
CustomField.Type.AMOUNT.uniqueIdentifier,
CustomField.Type.NUMBER.uniqueIdentifier -> {
Timber.d("AMOUNT or NUMBER: ${value}")
if (value != null) {
val customFieldEntry = CustomFieldEntry()
customFieldEntry.customField = row
customFieldEntry.value = value.toString()
Timber.d("customFieldEntry: ${customFieldEntry.id}")
Timber.d("customFieldEntry: ${customFieldEntry.customField}")
Timber.d("customFieldEntry: ${customFieldEntry.value}")
customFieldEntries.add(customFieldEntry)
}
Timber.d("customFieldEntries: ${customFieldEntries.size}")
}
CustomField.Type.LIST.uniqueIdentifier -> {
if (value != null && value is CustomFieldEntry) {

@ -37,8 +37,12 @@ open class Transaction : RealmObject(), Manageable, StaticRowRepresentableDataSo
return when (queryCondition) {
QueryCondition.AnyBankroll::class.java -> "bankroll.id"
QueryCondition.AnyTransactionType::class.java -> "type"
QueryCondition.AnyTransactionType::class.java -> "type.id"
QueryCondition.StartedFromDate::class.java, QueryCondition.StartedToDate::class.java -> "date"
QueryCondition.AnyDayOfWeek::class.java, QueryCondition.IsWeekEnd::class.java, QueryCondition.IsWeekDay::class.java -> "dayOfWeek"
QueryCondition.AnyMonthOfYear::class.java -> "month"
QueryCondition.AnyYear::class.java -> "year"
QueryCondition.PastDay::class.java, QueryCondition.IsToday::class.java, QueryCondition.WasYesterday::class.java, QueryCondition.WasTodayAndYesterday::class.java, QueryCondition.DuringThisYear::class.java, QueryCondition.DuringThisMonth::class.java, QueryCondition.DuringThisWeek::class.java -> "date"
else -> null
}
}

@ -18,7 +18,6 @@ import io.realm.kotlin.where
import kotlinx.android.synthetic.main.fragment_feed.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.model.filter.Query
import net.pokeranalytics.android.model.interfaces.Editable
import net.pokeranalytics.android.model.realm.Filter
import net.pokeranalytics.android.model.realm.Session
@ -138,8 +137,14 @@ class FeedFragment : RealmFragment(), RowRepresentableDelegate, FilterHandler {
tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab) {
when (tab.position) {
0 -> recyclerView.adapter = feedSessionAdapter
1 -> recyclerView.adapter = feedTransactionAdapter
0 -> {
currentFilterable = FilterableType.SESSION
recyclerView.adapter = feedSessionAdapter
}
1 -> {
currentFilterable = FilterableType.TRANSACTION
recyclerView.adapter = feedTransactionAdapter
}
}
}
@ -162,27 +167,42 @@ class FeedFragment : RealmFragment(), RowRepresentableDelegate, FilterHandler {
betaLimitDate = sdf.parse("17/7/2019 10:00")
val filter : Filter? = this.currentFilter(this.requireContext(), getRealm())
val sessionFilter: Filter? = filter?.let {
if (it.filterableType == FilterableType.SESSION) {
it
} else {
null
}
}
val transactionFilter: Filter? = filter?.let {
if (it.filterableType == FilterableType.TRANSACTION) {
it
} else {
null
}
}
// Sessions
this.realmSessions = filter?.results() ?: run { getRealm().where<Session>().findAll() }.sort("startDate", Sort.DESCENDING)
this.realmSessions = sessionFilter?.results() ?: run { getRealm().where<Session>().findAll() }.sort("startDate", Sort.DESCENDING)
this.realmSessions.addChangeListener { _, _ ->
this.feedSessionAdapter.refreshData()
this.feedSessionAdapter.notifyDataSetChanged()
}
val pendingSessions = filter?.let { getRealm().where<Session>().alwaysFalse().findAll() } ?: run { getRealm().where<Session>().isNull("year").isNull("month").findAll().sort("startDate", Sort.DESCENDING) }
val distinctDateSessions = filter?.results("year", "month") ?: run { getRealm().where<Session>().distinct("year", "month").findAll() }.sort("startDate", Sort.DESCENDING)
val pendingSessions = sessionFilter?.let { getRealm().where<Session>().alwaysFalse().findAll() } ?: run { getRealm().where<Session>().isNull("year").isNull("month").findAll().sort("startDate", Sort.DESCENDING) }
val distinctDateSessions = sessionFilter?.results("year", "month") ?: run { getRealm().where<Session>().distinct("year", "month").findAll() }.sort("startDate", Sort.DESCENDING)
this.feedSessionAdapter = FeedSessionRowRepresentableAdapter(this, realmSessions, pendingSessions, distinctDateSessions)
// Transactions
this.realmTransactions = getRealm().where<Transaction>().findAll().sort("date", Sort.DESCENDING)
this.realmTransactions = transactionFilter?.results() ?: run { getRealm().where<Transaction>().findAll()}.sort("date", Sort.DESCENDING)
this.realmTransactions.addChangeListener { _, _ ->
this.feedTransactionAdapter.refreshData()
this.feedTransactionAdapter.notifyDataSetChanged()
}
val distinctDateTransactions = getRealm().where<Transaction>().distinct("year", "month").findAll().sort("date", Sort.DESCENDING)
val distinctDateTransactions = transactionFilter?.results("year", "month") ?: run { getRealm().where<Transaction>().distinct("year", "month").findAll() }.sort("date", Sort.DESCENDING)
this.feedTransactionAdapter = FeedTransactionRowRepresentableAdapter(this, realmTransactions, distinctDateTransactions)
val viewManager = SmoothScrollLinearLayoutManager(requireContext())

@ -158,7 +158,7 @@ open class FiltersFragment : RealmFragment(), StaticRowRepresentableDataSource,
isUpdating = true
} ?: run {
realm.beginTransaction()
currentFilter = Filter.newInstance(realm)
currentFilter = Filter.newInstance(realm, this.filterableType.ordinal)
realm.commitTransaction()
}

@ -16,7 +16,7 @@ enum class FilterCategoryRow(override val resId: Int?, override val viewType: In
GENERAL(R.string.general),
DATE(R.string.date),
TIME_FRAME(R.string.duration),
SESSIONS(R.string.sessions),
//SESSIONS(R.string.sessions),
CASH(R.string.cash),
TOURNAMENT(R.string.tournament),
ONLINE(R.string.online),
@ -92,7 +92,7 @@ enum class FilterCategoryRow(override val resId: Int?, override val viewType: In
SESSION_DURATION,
TIME_FRAME_RANGE
)
SESSIONS -> arrayListOf(FilterSectionRow.SESSIONS)
//SESSIONS -> arrayListOf(FilterSectionRow.SESSIONS)
BANKROLLS -> arrayListOf(
BANKROLL
)

@ -87,7 +87,7 @@ enum class FilterSectionRow(override val resId: Int?) : RowRepresentable {
TIME_FRAME_RANGE -> arrayListOf(QueryCondition.StartedFromTime(), QueryCondition.EndedToTime())
// Sessions
SESSIONS -> arrayListOf(QueryCondition.LastGame(), QueryCondition.LastSession())
//SESSIONS -> arrayListOf(QueryCondition.LastGame(), QueryCondition.LastSession())
// Cash
BLIND -> Criteria.Blinds.queryConditions.mapFirstCondition()
@ -113,9 +113,7 @@ enum class FilterSectionRow(override val resId: Int?) : RowRepresentable {
addAll(QueryCondition.moreOrLess<QueryCondition.NetAmountWon>())
addAll(QueryCondition.moreOrLess<QueryCondition.NetAmountLost>())
}
TRANSACTION_TYPES -> arrayListOf<QueryCondition>().apply {
}
TRANSACTION_TYPES -> Criteria.TransactionTypes.queryConditions.mapFirstCondition()
else -> arrayListOf()
}.apply {
this.forEach {

@ -38,9 +38,7 @@ fun Double.round(): String {
}
fun Double.roundOffDecimal(): Double {
val df = DecimalFormat("#.##")
df.roundingMode = RoundingMode.CEILING
return df.format(this).toDouble()
return this.toBigDecimal().setScale(2, RoundingMode.CEILING).toDouble()
}
fun Double.formatted(): String {

Loading…
Cancel
Save