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

feature/top10
Razmig Sarkissian 7 years ago
commit dd20a75060
  1. 5
      app/build.gradle
  2. 80
      app/src/main/java/net/pokeranalytics/android/api/CurrencyConverterApi.kt
  3. 21
      app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt
  4. 3
      app/src/main/java/net/pokeranalytics/android/model/LiveData.kt
  5. 24
      app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt
  6. 11
      app/src/main/java/net/pokeranalytics/android/model/retrofit/ConvertResult.kt
  7. 65
      app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollDataFragment.kt
  8. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/EditableDataFragment.kt
  9. 5
      app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt
  10. 7
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetFragment.kt
  11. 15
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetMultiSelectionFragment.kt
  12. 6
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetSumFragment.kt
  13. 5
      app/src/main/java/net/pokeranalytics/android/ui/view/SessionRowView.kt
  14. 4
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SettingRow.kt
  15. 35
      app/src/main/java/net/pokeranalytics/android/util/CurrencyUtils.kt
  16. 20
      app/src/main/java/net/pokeranalytics/android/util/FormatUtils.kt
  17. 4
      app/src/main/java/net/pokeranalytics/android/util/URL.kt
  18. 16
      app/src/main/java/net/pokeranalytics/android/util/extensions/NumbersExtension.kt
  19. 1
      app/src/main/res/values/secrets.xml

@ -57,6 +57,11 @@ dependencies {
implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
implementation 'androidx.browser:browser:1.0.0' implementation 'androidx.browser:browser:1.0.0'
// Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.9.1'
implementation 'com.google.code.gson:gson:2.8.5'
// Places // Places
implementation 'com.google.android.libraries.places:places:1.0.0' implementation 'com.google.android.libraries.places:places:1.0.0'

@ -0,0 +1,80 @@
package net.pokeranalytics.android.api
import android.content.Context
import net.pokeranalytics.android.BuildConfig
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.retrofit.CurrencyConverterValue
import net.pokeranalytics.android.util.URL
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Call
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET
import retrofit2.http.Query
import java.util.concurrent.TimeUnit
/**
* Currency Converter API
*/
interface CurrencyConverterApi {
companion object {
private var currencyConverterApi: CurrencyConverterApi? = null
fun getApi(context: Context): CurrencyConverterApi? {
if (currencyConverterApi == null) {
var serviceEndpoint = URL.API_CURRENCY_CONVERTER
val httpClient = OkHttpClient.Builder()
// Logging interceptor
if (BuildConfig.DEBUG) {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BASIC
httpClient.addInterceptor(interceptor)
}
// Add headers
val interceptor = Interceptor { chain ->
val original = chain.request()
val originalHttpUrl = original.url()
val url = originalHttpUrl.newBuilder()
.addQueryParameter("apiKey", context.getString(R.string.currency_converter_api))
.build()
val requestBuilder = original.newBuilder()
.url(url)
chain.proceed(requestBuilder.build())
}
httpClient.addInterceptor(interceptor)
val client = httpClient
.readTimeout(60, TimeUnit.SECONDS)
.connectTimeout(60, TimeUnit.SECONDS)
.build()
val retrofit = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(serviceEndpoint.value)
.client(client)
.build()
currencyConverterApi = retrofit.create(CurrencyConverterApi::class.java)
}
return currencyConverterApi
}
}
@GET("convert")
fun convert(@Query("q") currencies: String, @Query("compact") compact: String = "y"): Call<Map<String, CurrencyConverterValue>>
}

@ -5,10 +5,11 @@ import net.pokeranalytics.android.R
import net.pokeranalytics.android.exceptions.FormattingException import net.pokeranalytics.android.exceptions.FormattingException
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.util.FormatUtils import net.pokeranalytics.android.util.CurrencyUtils
import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.extensions.formatted import net.pokeranalytics.android.util.extensions.formatted
import net.pokeranalytics.android.util.extensions.formattedHourlyDuration import net.pokeranalytics.android.util.extensions.formattedHourlyDuration
import java.util.*
/** /**
* An enum representing all the types of Session statistics * An enum representing all the types of Session statistics
@ -99,7 +100,7 @@ enum class Stat : RowRepresentable {
/** /**
* ComputedStat contains a [stat] and their associated [value] * ComputedStat contains a [stat] and their associated [value]
*/ */
class ComputedStat(stat: Stat, value: Double) { class ComputedStat(var stat: Stat, var value: Double, var currency: Currency? = null) {
constructor(stat: Stat, value: Double, previousValue: Double?) : this(stat, value) { constructor(stat: Stat, value: Double, previousValue: Double?) : this(stat, value) {
if (previousValue != null) { if (previousValue != null) {
@ -107,16 +108,6 @@ class ComputedStat(stat: Stat, value: Double) {
} }
} }
/**
* The statistic type
*/
var stat: Stat = stat
/**
* The stat value
*/
var value: Double = value
/** /**
* The variation of the stat * The variation of the stat
*/ */
@ -135,7 +126,7 @@ class ComputedStat(stat: Stat, value: Double) {
// Amounts + red/green // Amounts + red/green
Stat.NETRESULT, Stat.HOURLY_RATE, Stat.AVERAGE, Stat.NET_BB_PER_100_HANDS, Stat.HOURLY_RATE_BB, Stat.NETRESULT, Stat.HOURLY_RATE, Stat.AVERAGE, Stat.NET_BB_PER_100_HANDS, Stat.HOURLY_RATE_BB,
Stat.AVERAGE_NET_BB -> { Stat.AVERAGE_NET_BB -> {
val numberFormat= FormatUtils.getCurrencyFormatter(context) val numberFormat= CurrencyUtils.getCurrencyFormatter(context, currency)
val color = if (this.value >= this.stat.threshold) R.color.green else R.color.red val color = if (this.value >= this.stat.threshold) R.color.green else R.color.red
return TextFormat(numberFormat.format(this.value), color) return TextFormat(numberFormat.format(this.value), color)
} // white integers } // white integers
@ -148,10 +139,10 @@ class ComputedStat(stat: Stat, value: Double) {
Stat.WIN_RATIO, Stat.ROI -> { Stat.WIN_RATIO, Stat.ROI -> {
val color = if (value * 100 >= this.stat.threshold) R.color.green else R.color.red val color = if (value * 100 >= this.stat.threshold) R.color.green else R.color.red
return TextFormat("${(value * 100).formatted()}%", color) return TextFormat("${(value * 100).formatted()}%", color)
} // white amounts } // white amountsr
Stat.AVERAGE_BUYIN, Stat.STANDARD_DEVIATION, Stat.STANDARD_DEVIATION_HOURLY, Stat.AVERAGE_BUYIN, Stat.STANDARD_DEVIATION, Stat.STANDARD_DEVIATION_HOURLY,
Stat.STANDARD_DEVIATION_BB_PER_100_HANDS -> { Stat.STANDARD_DEVIATION_BB_PER_100_HANDS -> {
val numberFormat= FormatUtils.getCurrencyFormatter(context) val numberFormat= CurrencyUtils.getCurrencyFormatter(context, currency)
return TextFormat(numberFormat.format(this.value)) return TextFormat(numberFormat.format(this.value))
} }
else -> throw FormattingException("Stat formatting of ${this.stat.name} not handled") else -> throw FormattingException("Stat formatting of ${this.stat.name} not handled")

@ -145,6 +145,9 @@ enum class LiveData : Localizable {
} }
} }
/**
* Return the new entity title
*/
fun newEntityLocalizedTitle(context: Context): String { fun newEntityLocalizedTitle(context: Context): String {
return "${context.getString(R.string.new_entity)} ${this.localizedTitle(context)}" return "${context.getString(R.string.new_entity)} ${this.localizedTitle(context)}"
} }

@ -28,6 +28,7 @@ import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.SeparatorRowRepresentable import net.pokeranalytics.android.ui.view.rowrepresentable.SeparatorRowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.SessionRow import net.pokeranalytics.android.ui.view.rowrepresentable.SessionRow
import net.pokeranalytics.android.util.CurrencyUtils
import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.extensions.* import net.pokeranalytics.android.util.extensions.*
import java.util.* import java.util.*
@ -484,7 +485,7 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource
CustomizableRowRepresentable( CustomizableRowRepresentable(
RowViewType.HEADER_TITLE_AMOUNT_BIG, RowViewType.HEADER_TITLE_AMOUNT_BIG,
title = getFormattedDuration(), title = getFormattedDuration(),
computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0) computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0, CurrencyUtils.getCurrency(bankroll))
) )
) )
rows.add(SeparatorRowRepresentable()) rows.add(SeparatorRowRepresentable())
@ -494,7 +495,7 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource
CustomizableRowRepresentable( CustomizableRowRepresentable(
RowViewType.HEADER_TITLE_AMOUNT_BIG, RowViewType.HEADER_TITLE_AMOUNT_BIG,
resId = R.string.pause, resId = R.string.pause,
computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0) computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0, CurrencyUtils.getCurrency(bankroll))
) )
) )
rows.add(SeparatorRowRepresentable()) rows.add(SeparatorRowRepresentable())
@ -504,14 +505,14 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource
CustomizableRowRepresentable( CustomizableRowRepresentable(
RowViewType.HEADER_TITLE_AMOUNT_BIG, RowViewType.HEADER_TITLE_AMOUNT_BIG,
title = getFormattedDuration(), title = getFormattedDuration(),
computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0) computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0, CurrencyUtils.getCurrency(bankroll))
) )
) )
rows.add( rows.add(
CustomizableRowRepresentable( CustomizableRowRepresentable(
RowViewType.HEADER_TITLE_AMOUNT, RowViewType.HEADER_TITLE_AMOUNT,
resId = R.string.hour_rate_without_pauses, resId = R.string.hour_rate_without_pauses,
computedStat = ComputedStat(Stat.HOURLY_RATE, this.hourlyRate) computedStat = ComputedStat(Stat.HOURLY_RATE, this.hourlyRate, CurrencyUtils.getCurrency(bankroll))
) )
) )
@ -520,7 +521,7 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource
CustomizableRowRepresentable( CustomizableRowRepresentable(
RowViewType.HEADER_TITLE_VALUE, RowViewType.HEADER_TITLE_VALUE,
resId = R.string.bankroll_variation, resId = R.string.bankroll_variation,
computedStat = ComputedStat(Stat.HOURLY_RATE, 0.0) computedStat = ComputedStat(Stat.HOURLY_RATE, 0.0, CurrencyUtils.getCurrency(bankroll))
) )
) )
} }
@ -553,18 +554,18 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource
SessionRow.BANKROLL -> bankroll?.name ?: NULL_TEXT SessionRow.BANKROLL -> bankroll?.name ?: NULL_TEXT
SessionRow.BLINDS -> getBlinds() SessionRow.BLINDS -> getBlinds()
SessionRow.BREAK_TIME -> if (this.breakDuration > 0.0) this.breakDuration.toMinutes() else NULL_TEXT SessionRow.BREAK_TIME -> if (this.breakDuration > 0.0) this.breakDuration.toMinutes() else NULL_TEXT
SessionRow.BUY_IN -> this.result?.buyin?.toCurrency() ?: NULL_TEXT SessionRow.BUY_IN -> this.result?.buyin?.toCurrency(CurrencyUtils.getCurrency(bankroll)) ?: NULL_TEXT
SessionRow.CASHED_OUT, SessionRow.PRIZE, SessionRow.NET_RESULT -> this.result?.cashout?.toCurrency() ?: NULL_TEXT SessionRow.CASHED_OUT, SessionRow.PRIZE, SessionRow.NET_RESULT -> this.result?.cashout?.toCurrency(CurrencyUtils.getCurrency(bankroll)) ?: NULL_TEXT
SessionRow.COMMENT -> if (this.comment.isNotEmpty()) this.comment else NULL_TEXT SessionRow.COMMENT -> if (this.comment.isNotEmpty()) this.comment else NULL_TEXT
SessionRow.END_DATE -> this.endDate?.shortDateTime() ?: NULL_TEXT SessionRow.END_DATE -> this.endDate?.shortDateTime() ?: NULL_TEXT
SessionRow.GAME -> getGameTitle() SessionRow.GAME -> getGameTitle()
SessionRow.INITIAL_BUY_IN -> tournamentEntryFee?.toCurrency() ?: NULL_TEXT SessionRow.INITIAL_BUY_IN -> tournamentEntryFee?.toCurrency(CurrencyUtils.getCurrency(bankroll)) ?: NULL_TEXT
SessionRow.LOCATION -> location?.name ?: NULL_TEXT SessionRow.LOCATION -> location?.name ?: NULL_TEXT
SessionRow.PLAYERS -> tournamentNumberOfPlayers?.toString() ?: NULL_TEXT SessionRow.PLAYERS -> tournamentNumberOfPlayers?.toString() ?: NULL_TEXT
SessionRow.POSITION -> result?.tournamentFinalPosition?.toString() ?: NULL_TEXT SessionRow.POSITION -> result?.tournamentFinalPosition?.toString() ?: NULL_TEXT
SessionRow.START_DATE -> this.startDate?.shortDateTime() ?: NULL_TEXT SessionRow.START_DATE -> this.startDate?.shortDateTime() ?: NULL_TEXT
SessionRow.TABLE_SIZE -> this.tableSize?.let { TableSize(it).localizedTitle(context) } ?: NULL_TEXT SessionRow.TABLE_SIZE -> this.tableSize?.let { TableSize(it).localizedTitle(context) } ?: NULL_TEXT
SessionRow.TIPS -> result?.tips?.toCurrency() ?: NULL_TEXT SessionRow.TIPS -> result?.tips?.toCurrency(CurrencyUtils.getCurrency(bankroll)) ?: NULL_TEXT
SessionRow.TOURNAMENT_TYPE -> this.tournamentType?.let { SessionRow.TOURNAMENT_TYPE -> this.tournamentType?.let {
TournamentType.values()[it].localizedTitle(context) TournamentType.values()[it].localizedTitle(context)
} ?: run { } ?: run {
@ -575,10 +576,12 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource
"${tournamentFeatures.subList(0,2).joinToString { "${tournamentFeatures.subList(0,2).joinToString {
it.name it.name
}}, ..." }}, ..."
} else { } else if (tournamentFeatures.size > 0) {
tournamentFeatures.joinToString { tournamentFeatures.joinToString {
it.name it.name
} }
} else {
NULL_TEXT
} }
} }
SessionRow.TOURNAMENT_NAME -> tournamentName?.name ?: NULL_TEXT SessionRow.TOURNAMENT_NAME -> tournamentName?.name ?: NULL_TEXT
@ -681,6 +684,7 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource
val localResult = if (result != null) result as Result else realm.createObject(Result::class.java) val localResult = if (result != null) result as Result else realm.createObject(Result::class.java)
localResult.buyin = value as Double? localResult.buyin = value as Double?
result = localResult result = localResult
this.updateRowRepresentation()
} }
SessionRow.CASHED_OUT, SessionRow.PRIZE, SessionRow.NET_RESULT -> { SessionRow.CASHED_OUT, SessionRow.PRIZE, SessionRow.NET_RESULT -> {
val localResult = if (result != null) result as Result else realm.createObject(Result::class.java) val localResult = if (result != null) result as Result else realm.createObject(Result::class.java)

@ -0,0 +1,11 @@
package net.pokeranalytics.android.model.retrofit
import com.google.gson.annotations.SerializedName
/**
* Currency Converter mapping class
*/
class CurrencyConverterValue {
@SerializedName("val")
var value: Double? = 0.0
}

@ -4,12 +4,10 @@ import android.app.Activity.RESULT_OK
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.api.CurrencyConverterApi
import net.pokeranalytics.android.model.realm.Bankroll import net.pokeranalytics.android.model.realm.Bankroll
import net.pokeranalytics.android.model.retrofit.CurrencyConverterValue
import net.pokeranalytics.android.ui.activity.CurrenciesActivity import net.pokeranalytics.android.ui.activity.CurrenciesActivity
import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
@ -22,6 +20,8 @@ import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.Preferences import net.pokeranalytics.android.util.Preferences
import net.pokeranalytics.android.util.extensions.round import net.pokeranalytics.android.util.extensions.round
import retrofit2.Call
import retrofit2.Response
import java.util.* import java.util.*
/** /**
@ -42,6 +42,7 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
private lateinit var defaultCurrency: Currency private lateinit var defaultCurrency: Currency
private val rows = ArrayList<RowRepresentable>() private val rows = ArrayList<RowRepresentable>()
private var isRefreshingRate = false private var isRefreshingRate = false
private var lastRefreshRateCall = 0L
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
@ -111,25 +112,20 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) { override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
when (row) { when (row) {
BankrollRow.CURRENCY -> CurrenciesActivity.newInstanceForResult(this@BankrollDataFragment, BankrollDataFragment.REQUEST_CODE_CURRENCY) BankrollRow.CURRENCY -> CurrenciesActivity.newInstanceForResult(this@BankrollDataFragment, BankrollDataFragment.REQUEST_CODE_CURRENCY)
BankrollRow.REFRESH_RATE -> { BankrollRow.REFRESH_RATE -> refreshRate()
isRefreshingRate = true
//TODO: Call web-service to get the currency rate
GlobalScope.launch(Dispatchers.Main) {
delay(1500)
isRefreshingRate = false
rowRepresentableAdapter.refreshRow(BankrollRow.REFRESH_RATE)
}
rowRepresentableAdapter.refreshRow(BankrollRow.REFRESH_RATE)
}
else -> super.onRowSelected(position, row, fromAction) else -> super.onRowSelected(position, row, fromAction)
} }
} }
override fun onRowValueChanged(value: Any?, row: RowRepresentable) { override fun onRowValueChanged(value: Any?, row: RowRepresentable) {
super.onRowValueChanged(value, row) super.onRowValueChanged(value, row)
updateAdapterUI()
// Clear the value when the currency has been updated
if (row == BankrollRow.CURRENCY) {
lastRefreshRateCall = 0
}
updateAdapterUI()
} }
/** /**
@ -157,8 +153,6 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.currency)) rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.currency))
rows.add(BankrollRow.CURRENCY) rows.add(BankrollRow.CURRENCY)
val defaultCurrency = Currency.getInstance(Preferences.getCurrencyLocale(this.parentActivity))
var differentCurrency = false var differentCurrency = false
bankroll.currency?.let { bankrollCurrency -> bankroll.currency?.let { bankrollCurrency ->
differentCurrency = bankrollCurrency.code != defaultCurrency.currencyCode differentCurrency = bankrollCurrency.code != defaultCurrency.currencyCode
@ -186,5 +180,40 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
} }
} }
/**
* Refresh the rate with the Currency Converter API
*/
private fun refreshRate() {
// Check if the last call was older than 10 seconds
if (System.currentTimeMillis() - lastRefreshRateCall < 10 * 1000 || isRefreshingRate) {
return
}
lastRefreshRateCall = System.currentTimeMillis()
val currenciesConverterValue = "${defaultCurrency.currencyCode}_${bankroll?.currency?.code}"
val call = CurrencyConverterApi.getApi(requireContext())?.convert(currenciesConverterValue)
call?.enqueue(object : retrofit2.Callback<Map<String, CurrencyConverterValue>> {
override fun onResponse(call: Call<Map<String, CurrencyConverterValue>>, response: Response<Map<String, CurrencyConverterValue>>) {
response.body()?.let {
it[currenciesConverterValue]?.value?.let {rate ->
onRowValueChanged(rate.toString(), BankrollRow.RATE)
}
}
isRefreshingRate = false
rowRepresentableAdapter.refreshRow(BankrollRow.REFRESH_RATE)
}
override fun onFailure(call: Call<Map<String, CurrencyConverterValue>>, t: Throwable) {
isRefreshingRate = false
rowRepresentableAdapter.refreshRow(BankrollRow.REFRESH_RATE)
}
})
isRefreshingRate = true
rowRepresentableAdapter.refreshRow(BankrollRow.REFRESH_RATE)
}
} }

@ -111,7 +111,7 @@ open class EditableDataFragment : PokerAnalyticsFragment(), RowRepresentableDele
isUpdating = true isUpdating = true
} ?: run { } ?: run {
//TODO: Localize //TODO: Localize
this.appBar.toolbar.title = "New ${this.liveDataType.localizedTitle(this.parentActivity).toLowerCase().capitalize()}" this.appBar.toolbar.title = this.liveDataType.newEntityLocalizedTitle(requireContext())
} }
this.item = this.liveDataType.updateOrCreate(this.getRealm(), primaryKey) this.item = this.liveDataType.updateOrCreate(this.getRealm(), primaryKey)

@ -26,6 +26,7 @@ import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableDiffCallback import net.pokeranalytics.android.ui.view.RowRepresentableDiffCallback
import net.pokeranalytics.android.ui.view.SmoothScrollLinearLayoutManager import net.pokeranalytics.android.ui.view.SmoothScrollLinearLayoutManager
import net.pokeranalytics.android.ui.view.rowrepresentable.SessionRow import net.pokeranalytics.android.ui.view.rowrepresentable.SessionRow
import net.pokeranalytics.android.util.CurrencyUtils
import java.util.* import java.util.*
@ -99,9 +100,9 @@ class SessionFragment : PokerAnalyticsFragment(), RowRepresentableDelegate {
currentSession.startDate currentSession.startDate
) )
SessionRow.BANKROLL -> { SessionRow.BANKROLL -> {
BottomSheetFragment.create(fragmentManager, row, this, data, false) BottomSheetFragment.create(fragmentManager, row, this, data, false, CurrencyUtils.getCurrency(currentSession.bankroll))
} }
else -> BottomSheetFragment.create(fragmentManager, row, this, data) else -> BottomSheetFragment.create(fragmentManager, row, this, data, currentCurrency = CurrencyUtils.getCurrency(currentSession.bankroll))
} }
} }

@ -22,11 +22,13 @@ import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.rowrepresentable.SessionRow import net.pokeranalytics.android.ui.view.rowrepresentable.SessionRow
import net.pokeranalytics.android.ui.view.rowrepresentable.TransactionRow import net.pokeranalytics.android.ui.view.rowrepresentable.TransactionRow
import java.util.*
open class BottomSheetFragment : BottomSheetDialogFragment() { open class BottomSheetFragment : BottomSheetDialogFragment() {
lateinit var row: RowRepresentable lateinit var row: RowRepresentable
lateinit var delegate: RowRepresentableDelegate lateinit var delegate: RowRepresentableDelegate
var currentCurrency: Currency? = null
private var isClearable: Boolean = true private var isClearable: Boolean = true
private var rowRepresentableEditDescriptors: ArrayList<RowRepresentableEditDescriptor>? = null private var rowRepresentableEditDescriptors: ArrayList<RowRepresentableEditDescriptor>? = null
@ -40,7 +42,8 @@ open class BottomSheetFragment : BottomSheetDialogFragment() {
row: RowRepresentable, row: RowRepresentable,
delegate: RowRepresentableDelegate, delegate: RowRepresentableDelegate,
rowRepresentableEditDescriptors: ArrayList<RowRepresentableEditDescriptor>?, rowRepresentableEditDescriptors: ArrayList<RowRepresentableEditDescriptor>?,
isClearable: Boolean? = true isClearable: Boolean? = true,
currentCurrency: Currency? = null
): BottomSheetFragment { ): BottomSheetFragment {
val bottomSheetFragment = row.bottomSheetType.newInstance() val bottomSheetFragment = row.bottomSheetType.newInstance()
bottomSheetFragment.show(fragmentManager, "bottomSheet") bottomSheetFragment.show(fragmentManager, "bottomSheet")
@ -48,7 +51,7 @@ open class BottomSheetFragment : BottomSheetDialogFragment() {
bottomSheetFragment.delegate = delegate bottomSheetFragment.delegate = delegate
bottomSheetFragment.rowRepresentableEditDescriptors = rowRepresentableEditDescriptors bottomSheetFragment.rowRepresentableEditDescriptors = rowRepresentableEditDescriptors
bottomSheetFragment.isClearable = isClearable ?: true bottomSheetFragment.isClearable = isClearable ?: true
bottomSheetFragment.currentCurrency = currentCurrency
return bottomSheetFragment return bottomSheetFragment
} }
} }

@ -2,18 +2,14 @@ package net.pokeranalytics.android.ui.fragment.components.bottomsheet
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.os.Bundle
import android.view.View
import io.realm.RealmList import io.realm.RealmList
import io.realm.RealmObject import io.realm.RealmObject
import io.realm.RealmResults
import net.pokeranalytics.android.exceptions.RowRepresentableEditDescriptorException import net.pokeranalytics.android.exceptions.RowRepresentableEditDescriptorException
import net.pokeranalytics.android.model.LiveData import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.ui.activity.EditableDataActivity import net.pokeranalytics.android.ui.activity.EditableDataActivity
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.RowViewType
import timber.log.Timber
/** /**
* Manage multiple items selection in a bottom sheet list * Manage multiple items selection in a bottom sheet list
@ -38,7 +34,6 @@ open class BottomSheetMultiSelectionFragment : BottomSheetListFragment() {
} }
} }
//TODO: Set the correct values
override fun getValue(): Any? { override fun getValue(): Any? {
return selectedRows return selectedRows
} }
@ -50,16 +45,6 @@ open class BottomSheetMultiSelectionFragment : BottomSheetListFragment() {
selectedRows.add(row) selectedRows.add(row)
} }
dataAdapter.refreshRow(row) dataAdapter.refreshRow(row)
/*
realmData?.let {
val selectedData = it[position]
selectedData?.let {data ->
this.delegate.onRowValueChanged(data, this.row)
dismiss()
}
}
*/
} }
override fun isSelected(row: RowRepresentable): Boolean { override fun isSelected(row: RowRepresentable): Boolean {

@ -63,7 +63,7 @@ class BottomSheetSumFragment : BottomSheetFragment() {
0.0 0.0
} }
currentValue.text = currentDefaultValue.toCurrency() currentValue.text = currentDefaultValue.toCurrency(currentCurrency)
// First value // First value
val defaultValue1 = try { val defaultValue1 = try {
@ -72,7 +72,7 @@ class BottomSheetSumFragment : BottomSheetFragment() {
0.0 0.0
} }
button1.text = "+ ${defaultValue1.toCurrency()}" button1.text = "+ ${defaultValue1.toCurrency(currentCurrency)}"
button1.visibility = if (defaultValue1 > 0) View.VISIBLE else View.GONE button1.visibility = if (defaultValue1 > 0) View.VISIBLE else View.GONE
button1.setOnClickListener { button1.setOnClickListener {
this.delegate.onRowValueChanged(currentDefaultValue + defaultValue1, row) this.delegate.onRowValueChanged(currentDefaultValue + defaultValue1, row)
@ -86,7 +86,7 @@ class BottomSheetSumFragment : BottomSheetFragment() {
0.0 0.0
} }
button2.text = "+ ${defaultValue2.toCurrency()}" button2.text = "+ ${defaultValue2.toCurrency(currentCurrency)}"
button2.visibility = if (defaultValue2 > 0) View.VISIBLE else View.GONE button2.visibility = if (defaultValue2 > 0) View.VISIBLE else View.GONE
button2.setOnClickListener { button2.setOnClickListener {
this.delegate.onRowValueChanged(currentDefaultValue + defaultValue2, row) this.delegate.onRowValueChanged(currentDefaultValue + defaultValue2, row)

@ -14,6 +14,7 @@ import net.pokeranalytics.android.model.TableSize
import net.pokeranalytics.android.model.extensions.SessionState import net.pokeranalytics.android.model.extensions.SessionState
import net.pokeranalytics.android.model.extensions.getState import net.pokeranalytics.android.model.extensions.getState
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.util.CurrencyUtils
import net.pokeranalytics.android.util.extensions.getDayNumber import net.pokeranalytics.android.util.extensions.getDayNumber
import net.pokeranalytics.android.util.extensions.getShortDayName import net.pokeranalytics.android.util.extensions.getShortDayName
import net.pokeranalytics.android.util.extensions.shortTime import net.pokeranalytics.android.util.extensions.shortTime
@ -65,7 +66,7 @@ class SessionRowView : FrameLayout {
var title = "" var title = ""
if (session.isTournament()) { if (session.isTournament()) {
if (session.tournamentEntryFee != null) { if (session.tournamentEntryFee != null) {
title += session.tournamentEntryFee?.toCurrency() title += session.tournamentEntryFee?.toCurrency(CurrencyUtils.getCurrency(session.bankroll))
} }
session.game?.let { session.game?.let {
title += (if (title.isNotEmpty()) " " else "") + session.getGameTitle() title += (if (title.isNotEmpty()) " " else "") + session.getGameTitle()
@ -140,7 +141,7 @@ class SessionRowView : FrameLayout {
rowHistorySession.infoTitle.isVisible = false rowHistorySession.infoTitle.isVisible = false
val result = session.result?.net ?: 0.0 val result = session.result?.net ?: 0.0
val formattedStat = ComputedStat(Stat.NETRESULT, result).format(context) val formattedStat = ComputedStat(Stat.NETRESULT, result, currency = CurrencyUtils.getCurrency(session.bankroll)).format(context)
rowHistorySession.gameResult.setTextColor(formattedStat.getColor(context)) rowHistorySession.gameResult.setTextColor(formattedStat.getColor(context))
rowHistorySession.gameResult.text = formattedStat.text rowHistorySession.gameResult.text = formattedStat.text
} }

@ -27,6 +27,7 @@ enum class SettingRow : RowRepresentable {
TOURNAMENT_NAME, TOURNAMENT_NAME,
TOURNAMENT_FEATURE, TOURNAMENT_FEATURE,
TRANSACTION, TRANSACTION,
TRANSACTION_TYPE,
// Terms // Terms
PRIVACY_POLICY, PRIVACY_POLICY,
@ -56,7 +57,7 @@ enum class SettingRow : RowRepresentable {
resId = R.string.data_management resId = R.string.data_management
) )
) )
rows.addAll(arrayListOf(BANKROLL, GAME, LOCATION, TOURNAMENT_NAME, TOURNAMENT_FEATURE, TRANSACTION)) rows.addAll(arrayListOf(BANKROLL, GAME, LOCATION, TOURNAMENT_NAME, TOURNAMENT_FEATURE, TRANSACTION, TRANSACTION_TYPE))
rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.terms)) rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.terms))
rows.addAll(arrayListOf(PRIVACY_POLICY, TERMS_OF_USE, GDPR)) rows.addAll(arrayListOf(PRIVACY_POLICY, TERMS_OF_USE, GDPR))
@ -106,6 +107,7 @@ enum class SettingRow : RowRepresentable {
TOURNAMENT_NAME -> LiveData.TOURNAMENT_NAME TOURNAMENT_NAME -> LiveData.TOURNAMENT_NAME
TOURNAMENT_FEATURE -> LiveData.TOURNAMENT_FEATURE TOURNAMENT_FEATURE -> LiveData.TOURNAMENT_FEATURE
TRANSACTION -> LiveData.TRANSACTION TRANSACTION -> LiveData.TRANSACTION
TRANSACTION_TYPE -> LiveData.TRANSACTION_TYPE
else -> null else -> null
} }
} }

@ -0,0 +1,35 @@
package net.pokeranalytics.android.util
import android.content.Context
import net.pokeranalytics.android.model.realm.Bankroll
import java.text.NumberFormat
import java.util.*
class CurrencyUtils {
companion object {
/**
* return the currency associated with this bankroll
*/
fun getCurrency(bankroll: Bankroll? = null) : Currency {
val currencyCode = bankroll?.currency?.code ?: Currency.getInstance(Locale.getDefault()).currencyCode
return Currency.getInstance(currencyCode)
}
/**
* Get a currency formatter
*/
fun getCurrencyFormatter(context: Context, currency: Currency? = null) : NumberFormat {
val currencyFormatter = NumberFormat.getCurrencyInstance(Preferences.getCurrencyLocale(context))
currency?.let {
currencyFormatter.currency = it
}
currencyFormatter.minimumFractionDigits = 0
currencyFormatter.maximumFractionDigits = 2
return currencyFormatter
}
}
}

@ -1,20 +0,0 @@
package net.pokeranalytics.android.util
import android.content.Context
import java.text.NumberFormat
import java.util.*
class FormatUtils {
companion object {
fun getCurrencyFormatter(context: Context) : NumberFormat {
val formatter = NumberFormat.getCurrencyInstance(Preferences.getCurrencyLocale(context))
formatter.minimumFractionDigits = 0
formatter.maximumFractionDigits = 2
return formatter
}
}
}

@ -16,8 +16,10 @@ enum class URL(var value: String) {
FACEBOOK("https://www.facebook.com/171053452998758"), FACEBOOK("https://www.facebook.com/171053452998758"),
// Support // Support
SUPPORT_EMAIL("support@pokeranalytics.net") SUPPORT_EMAIL("support@pokeranalytics.net"),
// Currency Converter API
API_CURRENCY_CONVERTER("https://free.currencyconverterapi.com/api/v5/")
} }

@ -2,6 +2,7 @@ package net.pokeranalytics.android.util.extensions
import java.text.DecimalFormat import java.text.DecimalFormat
import java.text.NumberFormat import java.text.NumberFormat
import java.util.*
// Double // Double
@ -18,11 +19,16 @@ fun Double.formatted(): String {
return format.format(this) return format.format(this)
} }
fun Double.toCurrency(): String { fun Double.toCurrency(currency: Currency? = null): String {
val format = NumberFormat.getCurrencyInstance()
format.maximumFractionDigits = 2 val currencyFormatter = NumberFormat.getCurrencyInstance()
format.minimumFractionDigits = 0 currency?.let {
return format.format(this) currencyFormatter.currency = currency
}
currencyFormatter.maximumFractionDigits = 2
currencyFormatter.minimumFractionDigits = 0
return currencyFormatter.format(this)
} }
fun Double.formattedHourlyDuration() : String { fun Double.formattedHourlyDuration() : String {

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="google_places_api" translatable="false">AIzaSyCg-vgW4YnFsQ_s1iWjgzSq2vT0te3R1Hw</string> <string name="google_places_api" translatable="false">AIzaSyCg-vgW4YnFsQ_s1iWjgzSq2vT0te3R1Hw</string>
<string name="currency_converter_api" translatable="false">5ba8d38995282fe8b1c8</string>
</resources> </resources>
Loading…
Cancel
Save