realmasync
Laurent 3 years ago
commit c0b022a553
  1. 7
      app/build.gradle
  2. 2
      app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt
  3. 61
      app/src/main/java/net/pokeranalytics/android/api/CurrencyConverterApi.kt
  4. 46
      app/src/main/java/net/pokeranalytics/android/api/FreeConverterApi.kt
  5. 1
      app/src/main/java/net/pokeranalytics/android/model/filter/Query.kt
  6. 1
      app/src/main/java/net/pokeranalytics/android/model/filter/QueryCondition.kt
  7. 15
      app/src/main/java/net/pokeranalytics/android/model/migrations/Patcher.kt
  8. 6
      app/src/main/java/net/pokeranalytics/android/model/migrations/PokerAnalyticsMigration.kt
  9. 1
      app/src/main/java/net/pokeranalytics/android/model/realm/FilterCondition.kt
  10. 8
      app/src/main/java/net/pokeranalytics/android/model/realm/Transaction.kt
  11. 2
      app/src/main/java/net/pokeranalytics/android/ui/activity/ImportActivity.kt
  12. 82
      app/src/main/java/net/pokeranalytics/android/ui/extensions/UIExtensions.kt
  13. 7
      app/src/main/java/net/pokeranalytics/android/ui/fragment/CurrenciesFragment.kt
  14. 55
      app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt
  15. 11
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/BaseFragment.kt
  16. 8
      app/src/main/java/net/pokeranalytics/android/ui/fragment/report/AbstractReportFragment.kt
  17. 1
      app/src/main/java/net/pokeranalytics/android/ui/modules/calendar/CalendarDetailsFragment.kt
  18. 2
      app/src/main/java/net/pokeranalytics/android/ui/modules/calendar/CalendarFragment.kt
  19. 22
      app/src/main/java/net/pokeranalytics/android/ui/modules/data/BankrollDataFragment.kt
  20. 2
      app/src/main/java/net/pokeranalytics/android/ui/modules/data/PlayerDataFragment.kt
  21. 1
      app/src/main/java/net/pokeranalytics/android/ui/view/rows/FilterSectionRow.kt
  22. 25
      app/src/main/java/net/pokeranalytics/android/util/Preferences.kt
  23. 2
      app/src/main/res/values-de/strings.xml
  24. 2
      app/src/main/res/values-es/strings.xml
  25. 2
      app/src/main/res/values-fr/strings.xml
  26. 2
      app/src/main/res/values-hi/strings.xml
  27. 2
      app/src/main/res/values-it/strings.xml
  28. 2
      app/src/main/res/values-ja/strings.xml
  29. 2
      app/src/main/res/values-pt/strings.xml
  30. 2
      app/src/main/res/values-ru/strings.xml
  31. 2
      app/src/main/res/values-zh/strings.xml
  32. 2
      app/src/main/res/values/strings.xml
  33. 5
      build.gradle

@ -6,7 +6,9 @@ apply plugin: 'realm-android'
// Crashlytics // Crashlytics
apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.google.firebase.crashlytics' apply plugin: 'com.google.firebase.crashlytics'
////////////// // Serialization
apply plugin: "kotlinx-serialization"
repositories { repositories {
maven { url 'https://jitpack.io' } // required for MPAndroidChart maven { url 'https://jitpack.io' } // required for MPAndroidChart
@ -99,7 +101,8 @@ dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.6' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.6'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.6" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.6"
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.20.0") // JVM dependency // implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.20.0") // JVM dependency
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1"
// Android // Android
implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.appcompat:appcompat:1.1.0'

@ -39,7 +39,9 @@ class PokerAnalyticsApplication : Application() {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
if (!BuildConfig.DEBUG) {
FirebaseApp.initializeApp(this) FirebaseApp.initializeApp(this)
}
UserDefaults.init(this) UserDefaults.init(this)

@ -0,0 +1,61 @@
package net.pokeranalytics.android.api
import android.content.Context
import com.android.volley.VolleyError
import com.android.volley.toolbox.StringRequest
import com.android.volley.toolbox.Volley
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import timber.log.Timber
@Serializable
data class RateResponse(var info: RateInfo)
@Serializable
data class RateInfo(var rate: Double)
class CurrencyConverterApi {
companion object {
val json = Json { ignoreUnknownKeys = true }
fun currencyRate(fromCurrency: String, toCurrency: String, context: Context, callback: (Double?, VolleyError?) -> (Unit)) {
val queue = Volley.newRequestQueue(context)
// val url = "https://free.currconv.com/api/v7/convert?q=${pair}&compact=ultra&apiKey=9b56e742a75392c8aeb7"
val url = "https://api.apilayer.com/exchangerates_data/convert?to=$toCurrency&from=$fromCurrency&amount=1"
// https://free.currconv.com/api/v7/convert?q=GBP_USD&compact=ultra&apiKey=5ba8d38995282fe8b1c8
// { "USD_PHP": 44.1105, "PHP_USD": 0.0227 }
Timber.d("Api call = $url")
val stringRequest = object : StringRequest(
Method.GET, url,
{ response ->
val o = json.decodeFromString<RateResponse>(response)
Timber.d("rate = ${o.info.rate}")
callback(o.info.rate, null)
},
{
Timber.d("Api call failed: ${it.message}")
callback(null, it)
}) {
override fun getHeaders(): MutableMap<String, String> {
val headers = HashMap<String, String>()
headers["apikey"] = "XnfeyID3PMKd3k4zTPW0XmZAbcZlZgqH"
return headers
}
}
queue.add(stringRequest)
}
}
}

@ -1,46 +0,0 @@
package net.pokeranalytics.android.api
import android.content.Context
import com.android.volley.Request
import com.android.volley.toolbox.StringRequest
import com.android.volley.toolbox.Volley
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonConfiguration
import timber.log.Timber
class FreeConverterApi {
companion object {
fun currencyRate(pair: String, context: Context, callback: (Double) -> (Unit)) {
val queue = Volley.newRequestQueue(context)
val url = "https://free.currconv.com/api/v7/convert?q=${pair}&compact=ultra&apiKey=9b56e742a75392c8aeb7"
// https://free.currconv.com/api/v7/convert?q=GBP_USD&compact=ultra&apiKey=5ba8d38995282fe8b1c8
// { "USD_PHP": 44.1105, "PHP_USD": 0.0227 }
val stringRequest = StringRequest(
Request.Method.GET, url,
{ response ->
val json = Json(JsonConfiguration.Stable)
val f = json.parseJson(response)
f.jsonObject[pair]?.primitive?.double?.let { rate ->
callback(rate)
} ?: run {
Timber.d("no rate: $response")
}
},
{
Timber.d("Api call failed: ${it.message}")
})
queue.add(stringRequest)
}
}
}

@ -119,6 +119,7 @@ class Query {
is QueryCondition.QueryDataCondition<*> -> { is QueryCondition.QueryDataCondition<*> -> {
c.objectId?.let { return it } c.objectId?.let { return it }
} }
else -> {}
} }
} }
return null return null

@ -848,6 +848,7 @@ sealed class QueryCondition : RowRepresentable {
} }
return realmQuery return realmQuery
} }
else -> {}
} }
if (this is CustomFieldRelated) { if (this is CustomFieldRelated) {

@ -57,6 +57,10 @@ class Patcher {
patchZeroTable() patchZeroTable()
} }
Preferences.executeOnce(Preferences.Keys.PATCH_RATED_AMOUNT, context) {
patchRatedAmounts()
}
patchPerformances(application) patchPerformances(application)
} }
@ -215,5 +219,16 @@ class Patcher {
realm.close() realm.close()
} }
private fun patchRatedAmounts() {
val realm = Realm.getDefaultInstance()
val transactions = realm.where<Transaction>().findAll()
realm.executeTransaction {
transactions.forEach { t ->
t.computeRatedAmount()
}
}
realm.close()
}
} }
} }

@ -326,6 +326,12 @@ class PokerAnalyticsMigration : RealmMigration {
ucs.addField("transactionTypeIds", String::class.java).setRequired("transactionTypeIds", true) ucs.addField("transactionTypeIds", String::class.java).setRequired("transactionTypeIds", true)
} ?: throw PAIllegalStateException("UserConfig schema not found") } ?: throw PAIllegalStateException("UserConfig schema not found")
schema.get("Performance")?.let { ps ->
if (!ps.isPrimaryKey("id")) {
ps.addPrimaryKey("id")
}
}
currentVersion++ currentVersion++
} }

@ -29,6 +29,7 @@ open class FilterCondition() : RealmObject() {
is QueryCondition.ListOfDouble -> this.setValues(filterElementRows.flatMap { (it as QueryCondition.ListOfDouble).listOfValues }) is QueryCondition.ListOfDouble -> this.setValues(filterElementRows.flatMap { (it as QueryCondition.ListOfDouble).listOfValues })
is QueryCondition.ListOfInt -> this.setValues(filterElementRows.flatMap { (it as QueryCondition.ListOfInt).listOfValues }) is QueryCondition.ListOfInt -> this.setValues(filterElementRows.flatMap { (it as QueryCondition.ListOfInt).listOfValues })
is QueryCondition.ListOfString -> this.setValues(filterElementRows.flatMap { (it as QueryCondition.ListOfString).listOfValues }) is QueryCondition.ListOfString -> this.setValues(filterElementRows.flatMap { (it as QueryCondition.ListOfString).listOfValues })
else -> {}
} }
} }

@ -75,8 +75,7 @@ open class Transaction : RealmObject(), RowRepresentable, RowUpdatable, Manageab
override var amount: Double = 0.0 override var amount: Double = 0.0
set(value) { set(value) {
field = value field = value
val rate = this.bankroll?.currency?.rate ?: 1.0 computeRatedAmount()
this.ratedAmount = rate * value
} }
// The amount of the transaction // The amount of the transaction
@ -114,6 +113,11 @@ open class Transaction : RealmObject(), RowRepresentable, RowUpdatable, Manageab
RATED_AMOUNT("ratedAmount") RATED_AMOUNT("ratedAmount")
} }
fun computeRatedAmount() {
val rate = this.bankroll?.currency?.rate ?: 1.0
this.ratedAmount = rate * this.amount
}
val displayAmount: Double val displayAmount: Double
get() { // for transfers we want to show a positive value (in the feed for instance) get() { // for transfers we want to show a positive value (in the feed for instance)
return if (this.destination == null) { this.amount } else { abs(this.amount) } return if (this.destination == null) { this.amount } else { abs(this.amount) }

@ -84,7 +84,7 @@ class ImportActivity : BaseActivity() {
when (requestCode) { when (requestCode) {
RequestCode.IMPORT.value -> { RequestCode.IMPORT.value -> {
if (resultCode == ResultCode.IMPORT_UNRECOGNIZED_FORMAT.value) { if (resultCode == ResultCode.IMPORT_UNRECOGNIZED_FORMAT.value) {
showAlertDialog(context = this, message = R.string.unknown_import_format_popup_message, positiveAction = { showAlertDialog(context = this, messageResId = R.string.unknown_import_format_popup_message, positiveAction = {
finish() finish()
}) })
} }

@ -3,20 +3,17 @@ package net.pokeranalytics.android.ui.extensions
import android.app.Activity import android.app.Activity
import android.content.ActivityNotFoundException import android.content.ActivityNotFoundException
import android.content.Context import android.content.Context
import android.content.DialogInterface
import android.content.Intent import android.content.Intent
import android.content.res.Resources import android.content.res.Resources
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.Canvas import android.graphics.Canvas
import android.graphics.Color import android.graphics.Color
import android.net.Uri import android.net.Uri
import android.text.SpannableStringBuilder
import android.util.TypedValue import android.util.TypedValue
import android.view.View import android.view.View
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import android.widget.ImageView import android.widget.*
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
@ -85,7 +82,11 @@ fun BaseActivity.openContactMail(subjectStringRes: Int, filePath: String? = null
filePath?.let { filePath?.let {
val databaseFile = File(it) val databaseFile = File(it)
val contentUri = FileProvider.getUriForFile(this, "net.pokeranalytics.android.fileprovider", databaseFile) val contentUri = FileProvider.getUriForFile(
this,
"net.pokeranalytics.android.fileprovider",
databaseFile
)
if (contentUri != null) { if (contentUri != null) {
emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
emailIntent.setDataAndType(contentUri, contentResolver.getType(contentUri)) emailIntent.setDataAndType(contentUri, contentResolver.getType(contentUri))
@ -108,7 +109,12 @@ fun Context.openUrl(url: String) {
} }
// Open custom tab // Open custom tab
fun Context.areYouSure(title: Int? = null, message: Int? = null, positiveTitle: Int? = null, proceed: () -> Unit) { fun Context.areYouSure(
title: Int? = null,
message: Int? = null,
positiveTitle: Int? = null,
proceed: () -> Unit
) {
val builder: android.app.AlertDialog.Builder = android.app.AlertDialog.Builder(this) val builder: android.app.AlertDialog.Builder = android.app.AlertDialog.Builder(this)
@ -124,22 +130,7 @@ fun Context.areYouSure(title: Int? = null, message: Int? = null, positiveTitle:
builder.setNegativeButton(R.string.cancel) { _, _ -> builder.setNegativeButton(R.string.cancel) { _, _ ->
// nothing // nothing
} }
// builder.setItems(
// arrayOf<CharSequence>(
// getString(R.string.yes),
// getString(R.string.cancel)
// )
// ) { _, index ->
// // The 'which' argument contains the index position
// // of the selected item
// when (index) {
// 0 -> proceed()
// 1 -> {} // nothing
// }
// }
builder.create().show() builder.create().show()
} }
// Display Alert Dialog // Display Alert Dialog
@ -147,26 +138,65 @@ fun Activity.showAlertDialog(title: Int? = null, message: Int? = null) {
showAlertDialog(this, title, message) showAlertDialog(this, title, message)
} }
fun Fragment.showAlertDialog(title: Int? = null, message: Int? = null) { fun Fragment.showAlertDialog(
title: Int? = null,
messageResId: Int? = null,
message: String? = null
) {
context?.let { context?.let {
showAlertDialog(it, title, message) showAlertDialog(it, title, messageResId, message)
}
}
fun showEditTextAlertDialog(
context: Context, inputType: Int, title: Int? = null, messageResId: Int? = null, message: String? = null,
editTextText: String? = null, positiveAction: ((String) -> Unit)? = null
) {
val builder = AlertDialog.Builder(context)
title?.let {
builder.setTitle(title)
}
messageResId?.let {
builder.setMessage(messageResId)
} }
message?.let {
builder.setMessage(it)
}
val editText = EditText(context)
editTextText?.let {
editText.text = SpannableStringBuilder(it)
}
editText.setTextColor(ContextCompat.getColor(context, R.color.white))
editText.inputType = inputType
builder.setView(editText)
builder.setPositiveButton(net.pokeranalytics.android.R.string.ok) { _, _ ->
positiveAction?.invoke(editText.text.toString())
}
builder.show()
} }
/** /**
* Create and show an alert dialog * Create and show an alert dialog
*/ */
fun showAlertDialog( fun showAlertDialog(
context: Context, title: Int? = null, message: Int? = null, cancelButtonTitle: Int? = null, showCancelButton: Boolean = false, context: Context, title: Int? = null, messageResId: Int? = null, message: String? = null,
cancelButtonTitle: Int? = null, showCancelButton: Boolean = false,
positiveAction: (() -> Unit)? = null, negativeAction: (() -> Unit)? = null positiveAction: (() -> Unit)? = null, negativeAction: (() -> Unit)? = null
) { ) {
val builder = AlertDialog.Builder(context) val builder = AlertDialog.Builder(context)
title?.let { title?.let {
builder.setTitle(title) builder.setTitle(title)
} }
messageResId?.let {
builder.setMessage(messageResId)
}
message?.let { message?.let {
builder.setMessage(message) builder.setMessage(it)
} }
builder.setPositiveButton(net.pokeranalytics.android.R.string.ok) { _, _ -> builder.setPositiveButton(net.pokeranalytics.android.R.string.ok) { _, _ ->
positiveAction?.invoke() positiveAction?.invoke()
} }

@ -65,8 +65,8 @@ class CurrenciesFragment : BaseFragment(), StaticRowRepresentableDataSource, Row
} }
var currencyCode: String = currency.currencyCode var currencyCode: String = currency.currencyCode
var currencySymbole: String = currency.getSymbol(Locale.getDefault()) var currencySymbol: String = currency.getSymbol(Locale.getDefault())
var currencyCodeAndSymbol: String = "${this.currencyCode} (${this.currencySymbole})" var currencyCodeAndSymbol: String = "${this.currencyCode} (${this.currencySymbol})"
override val viewType: Int = RowViewType.TITLE_VALUE.ordinal override val viewType: Int = RowViewType.TITLE_VALUE.ordinal
} }
@ -110,6 +110,9 @@ class CurrenciesFragment : BaseFragment(), StaticRowRepresentableDataSource, Row
// RowRepresentableDelegate // RowRepresentableDelegate
override fun onRowSelected(position: Int, row: RowRepresentable, tag: Int) { override fun onRowSelected(position: Int, row: RowRepresentable, tag: Int) {
val intent = Intent() val intent = Intent()
intent.putExtra(INTENT_CURRENCY_CODE, (row as CurrencyRow).currency.currencyCode) intent.putExtra(INTENT_CURRENCY_CODE, (row as CurrencyRow).currency.currencyCode)
this.activity?.setResult(Activity.RESULT_OK, intent) this.activity?.setResult(Activity.RESULT_OK, intent)

@ -6,6 +6,7 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.text.InputType
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -17,6 +18,7 @@ import com.google.android.play.core.review.ReviewManagerFactory
import io.realm.Realm import io.realm.Realm
import net.pokeranalytics.android.BuildConfig import net.pokeranalytics.android.BuildConfig
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.api.CurrencyConverterApi
import net.pokeranalytics.android.databinding.FragmentSettingsBinding import net.pokeranalytics.android.databinding.FragmentSettingsBinding
import net.pokeranalytics.android.exceptions.PAIllegalStateException import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.model.LiveData import net.pokeranalytics.android.model.LiveData
@ -33,6 +35,7 @@ import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.extensions.openContactMail import net.pokeranalytics.android.ui.extensions.openContactMail
import net.pokeranalytics.android.ui.extensions.openUrl import net.pokeranalytics.android.ui.extensions.openUrl
import net.pokeranalytics.android.ui.extensions.showEditTextAlertDialog
import net.pokeranalytics.android.ui.fragment.components.RealmFragment import net.pokeranalytics.android.ui.fragment.components.RealmFragment
import net.pokeranalytics.android.ui.modules.bankroll.BankrollActivity import net.pokeranalytics.android.ui.modules.bankroll.BankrollActivity
import net.pokeranalytics.android.ui.modules.datalist.DataListActivity import net.pokeranalytics.android.ui.modules.datalist.DataListActivity
@ -141,27 +144,59 @@ class SettingsFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRep
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {
data?.let { data?.let {
val currencyCode = data.getStringExtra(CurrenciesFragment.INTENT_CURRENCY_CODE) ?: throw PAIllegalStateException("Missing currency code") val currencyCode = data.getStringExtra(CurrenciesFragment.INTENT_CURRENCY_CODE) ?: throw PAIllegalStateException("Missing currency code")
updateMainCurrency(currencyCode)
}
}
}
RequestCode.SUBSCRIPTION.value -> {
settingsAdapterRow.refreshRow(SettingsRow.SUBSCRIPTION)
}
}
}
private fun updateMainCurrency(currencyCode: String) {
Preferences.getDefaultCurrency(requireContext())?.currencyCode?.let { mainCurrencyCode ->
if (mainCurrencyCode == currencyCode) {
return
}
showLoader(R.string.please_wait)
CurrencyConverterApi.currencyRate(mainCurrencyCode, currencyCode, requireContext()) { apiRate, _ ->
hideLoader()
val message = requireContext().getString(R.string.currency_rate_confirmation, mainCurrencyCode, currencyCode)
// val message = "Please enter the $mainCurrencyCode to $currencyCode rate to apply to all your bankrolls"
showEditTextAlertDialog(requireContext(), InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL,
message = message, editTextText = apiRate?.toString()) { value ->
value.toDoubleOrNull()?.let { rate ->
updateMainCurrency(currencyCode, rate)
}
}
}
}
}
private fun updateMainCurrency(currencyCode: String, rate: Double) {
Preferences.setCurrencyCode(currencyCode, requireContext()) Preferences.setCurrencyCode(currencyCode, requireContext())
val realm = Realm.getDefaultInstance() val realm = Realm.getDefaultInstance()
realm.executeTransaction { realm.executeTransaction {
realm.where(Currency::class.java).isNull("code").or().equalTo("code", UserDefaults.currency.currencyCode).findAll().forEach { currency -> realm.where(Currency::class.java).findAll().forEach { currency ->
currency.rate = Currency.DEFAULT_RATE currency.rate = (currency.rate ?: 1.0) * rate
} }
realm.where(Session::class.java).isNull("bankroll.currency.code").findAll().forEach { session -> realm.where(Session::class.java).findAll().forEach { session ->
session.bankrollHasBeenUpdated() session.bankrollHasBeenUpdated()
} }
} }
realm.close() realm.close()
settingsAdapterRow.refreshRow(SettingsRow.CURRENCY) settingsAdapterRow.refreshRow(SettingsRow.CURRENCY)
} }
}
}
RequestCode.SUBSCRIPTION.value -> {
settingsAdapterRow.refreshRow(SettingsRow.SUBSCRIPTION)
}
}
}
override fun adapterRows(): List<RowRepresentable> { override fun adapterRows(): List<RowRepresentable> {
return rowRepresentation return rowRepresentation

@ -7,6 +7,7 @@ import android.os.Bundle
import android.view.View import android.view.View
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.google.android.material.snackbar.Snackbar
import net.pokeranalytics.android.PokerAnalyticsApplication import net.pokeranalytics.android.PokerAnalyticsApplication
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.activity.components.BaseActivity import net.pokeranalytics.android.ui.activity.components.BaseActivity
@ -15,6 +16,7 @@ import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheet
import net.pokeranalytics.android.ui.view.RowRepresentable 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.util.CrashLogging import net.pokeranalytics.android.util.CrashLogging
import timber.log.Timber
import java.io.File import java.io.File
import java.util.* import java.util.*
@ -183,4 +185,13 @@ abstract class BaseFragment : Fragment() {
return capability?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) ?: false return capability?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) ?: false
} }
fun showSnackBar(message: String) {
this.view?.let { view ->
val snackBar = Snackbar.make(view, message, Snackbar.LENGTH_INDEFINITE)
snackBar.show()
} ?: run {
Timber.d("No parent view for snackbar")
}
}
} }

@ -68,9 +68,9 @@ abstract class AbstractReportFragment : DataManagerFragment() {
// Inflate and set the layout for the dialog // Inflate and set the layout for the dialog
// Pass null as the parent view because its going in the dialog layout // Pass null as the parent view because its going in the dialog layout
val view = inflater.inflate(net.pokeranalytics.android.R.layout.dialog_edit_text, null) val view = inflater.inflate(R.layout.dialog_edit_text, null)
val nameEditText = val nameEditText =
view.findViewById<EditText>(net.pokeranalytics.android.R.id.reportName) view.findViewById<EditText>(R.id.reportName)
nameEditText.inputType = InputType.TYPE_TEXT_FLAG_CAP_SENTENCES nameEditText.inputType = InputType.TYPE_TEXT_FLAG_CAP_SENTENCES
this.model.primaryKey?.let { id -> this.model.primaryKey?.let { id ->
@ -81,7 +81,7 @@ abstract class AbstractReportFragment : DataManagerFragment() {
builder.setView(view) builder.setView(view)
// Add action buttons // Add action buttons
.setPositiveButton(net.pokeranalytics.android.R.string.save) { dialog, _ -> .setPositiveButton(R.string.save) { dialog, _ ->
try { try {
saveReport(nameEditText.text.toString()) saveReport(nameEditText.text.toString())
dialog.dismiss() dialog.dismiss()
@ -89,7 +89,7 @@ abstract class AbstractReportFragment : DataManagerFragment() {
Toast.makeText(requireContext(), e.localizedMessage, Toast.LENGTH_SHORT).show() Toast.makeText(requireContext(), e.localizedMessage, Toast.LENGTH_SHORT).show()
} }
} }
.setNegativeButton(net.pokeranalytics.android.R.string.cancel) { dialog, _ -> .setNegativeButton(R.string.cancel) { dialog, _ ->
dialog.cancel() dialog.cancel()
} }

@ -177,6 +177,7 @@ class CalendarDetailsFragment : BaseFragment(), StaticRowRepresentableDataSource
when (model.sessionTypeCondition) { when (model.sessionTypeCondition) {
QueryCondition.IsCash -> query.add(QueryCondition.IsCash) QueryCondition.IsCash -> query.add(QueryCondition.IsCash)
QueryCondition.IsTournament -> query.add(QueryCondition.IsTournament) QueryCondition.IsTournament -> query.add(QueryCondition.IsTournament)
else -> {}
} }
val requiredStats: List<Stat> = listOf(Stat.LOCATIONS_PLAYED, Stat.LONGEST_STREAKS, Stat.DAYS_PLAYED, Stat.STANDARD_DEVIATION_HOURLY) val requiredStats: List<Stat> = listOf(Stat.LOCATIONS_PLAYED, Stat.LONGEST_STREAKS, Stat.DAYS_PLAYED, Stat.STANDARD_DEVIATION_HOURLY)

@ -431,6 +431,7 @@ class CalendarFragment : RealmFragment(), CoroutineScope, StaticRowRepresentable
Calendar.MONTH, Calendar.MONTH,
condition.listOfValues.first() condition.listOfValues.first()
) )
else -> {}
} }
} }
@ -478,6 +479,7 @@ class CalendarFragment : RealmFragment(), CoroutineScope, StaticRowRepresentable
Calendar.YEAR, Calendar.YEAR,
condition.listOfValues.first() condition.listOfValues.first()
) )
else -> {}
} }
} }
yearlyReports[calendar.time] = computedResults yearlyReports[calendar.time] = computedResults

@ -8,13 +8,14 @@ import android.view.View
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.api.FreeConverterApi 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.realm.ResultCaptureType import net.pokeranalytics.android.model.realm.ResultCaptureType
import net.pokeranalytics.android.ui.activity.CurrenciesActivity import net.pokeranalytics.android.ui.activity.CurrenciesActivity
import net.pokeranalytics.android.ui.activity.components.RequestCode import net.pokeranalytics.android.ui.activity.components.RequestCode
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
import net.pokeranalytics.android.ui.extensions.toast
import net.pokeranalytics.android.ui.fragment.CurrenciesFragment import net.pokeranalytics.android.ui.fragment.CurrenciesFragment
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
@ -137,7 +138,7 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
override fun charSequenceForRow(row: RowRepresentable, context: Context, tag: Int): CharSequence { override fun charSequenceForRow(row: RowRepresentable, context: Context, tag: Int): CharSequence {
return when (row) { return when (row) {
SimpleRow.NAME -> if (bankroll.name.isNotEmpty()) bankroll.name else NULL_TEXT SimpleRow.NAME -> bankroll.name.ifEmpty { NULL_TEXT }
BankrollPropertiesRow.CURRENCY -> { BankrollPropertiesRow.CURRENCY -> {
bankroll.currency?.code?.let { code -> bankroll.currency?.code?.let { code ->
Currency.getInstance(code).currencyCode Currency.getInstance(code).currencyCode
@ -263,13 +264,25 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
} }
this.lastRefreshRateCall = System.currentTimeMillis() this.lastRefreshRateCall = System.currentTimeMillis()
val currenciesConverterValue = "${bankroll.currency?.code}_${defaultCurrency.currencyCode}" // val currenciesConverterValue = "${bankroll.currency?.code}_${defaultCurrency.currencyCode}"
FreeConverterApi.currencyRate(currenciesConverterValue, requireContext()) { rate -> bankroll.currency?.code?.let { from ->
val to = defaultCurrency.currencyCode
CurrencyConverterApi.currencyRate(from, to, requireContext()) { rate, error ->
rate?.let {
onRowValueChanged(rate, BankrollPropertiesRow.RATE) onRowValueChanged(rate, BankrollPropertiesRow.RATE)
}
error?.localizedMessage?.let { message ->
toast(message)
}
// onRowValueChanged(rate, BankrollPropertiesRow.RATE)
isRefreshingRate = false isRefreshingRate = false
rowRepresentableAdapter.refreshRow(BankrollPropertiesRow.REFRESH_RATE) rowRepresentableAdapter.refreshRow(BankrollPropertiesRow.REFRESH_RATE)
} }
}
this.isRefreshingRate = true this.isRefreshingRate = true
this.rowRepresentableAdapter.refreshRow(BankrollPropertiesRow.REFRESH_RATE) this.rowRepresentableAdapter.refreshRow(BankrollPropertiesRow.REFRESH_RATE)
@ -280,7 +293,6 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
this.bankrollModel.selectedCaptureType.value?.let { this.bankrollModel.selectedCaptureType.value?.let {
Preferences.setResultCaptureType(this.bankroll, it, requireContext()) Preferences.setResultCaptureType(this.bankroll, it, requireContext())
} }
} }
} }

@ -172,7 +172,7 @@ class PlayerDataFragment : EditableDataFragment(), StaticRowRepresentableDataSou
if (row.isValidForDelete(getRealm())) { if (row.isValidForDelete(getRealm())) {
GlobalScope.launch(Dispatchers.Main) { GlobalScope.launch(Dispatchers.Main) {
delay(300) delay(300)
showAlertDialog(requireContext(), message = R.string.are_you_sure_you_want_to_delete, showCancelButton = true, positiveAction = { showAlertDialog(requireContext(), messageResId = R.string.are_you_sure_you_want_to_delete, showCancelButton = true, positiveAction = {
player.deleteComment(row) player.deleteComment(row)
rowRepresentableAdapter.notifyDataSetChanged() rowRepresentableAdapter.notifyDataSetChanged()
}) })

@ -63,6 +63,7 @@ sealed class FilterSectionRow(override val resId: Int?) : RowRepresentable {
is CustomField -> { is CustomField -> {
return customField.name return customField.name
} }
else -> {}
} }
return name return name
} }

@ -48,7 +48,8 @@ class Preferences {
PATCH_STAKES("patchStakes"), PATCH_STAKES("patchStakes"),
CLEAN_BLINDS_FILTERS("deleteBlindsFilters"), CLEAN_BLINDS_FILTERS("deleteBlindsFilters"),
SHOW_IN_APP_BADGES("showInAppBadges"), SHOW_IN_APP_BADGES("showInAppBadges"),
LAST_CALENDAR_BADGE_DATE("lastCalendarBadgeDate") LAST_CALENDAR_BADGE_DATE("lastCalendarBadgeDate"),
PATCH_RATED_AMOUNT("patchRatedAmount[new field]")
} }
enum class FeedMessage { enum class FeedMessage {
@ -101,17 +102,17 @@ class Preferences {
companion object { companion object {
fun setStringSet(key: PreferenceKey, value: MutableSet<String>, context: Context) { // fun setStringSet(key: PreferenceKey, value: MutableSet<String>, context: Context) {
val preferences = PreferenceManager.getDefaultSharedPreferences(context) // val preferences = PreferenceManager.getDefaultSharedPreferences(context)
val editor = preferences.edit() // val editor = preferences.edit()
editor.putStringSet(key.identifier, value) // editor.putStringSet(key.identifier, value)
editor.apply() // editor.apply()
} // }
//
fun getStringSet(key: Keys, context: Context): MutableSet<String>? { // fun getStringSet(key: Keys, context: Context): MutableSet<String>? {
val preferences = PreferenceManager.getDefaultSharedPreferences(context) // val preferences = PreferenceManager.getDefaultSharedPreferences(context)
return preferences.getStringSet(key.identifier, null) // return preferences.getStringSet(key.identifier, null)
} // }
fun setString(key: PreferenceKey, value: String, context: Context) { fun setString(key: PreferenceKey, value: String, context: Context) {
val preferences = PreferenceManager.getDefaultSharedPreferences(context) val preferences = PreferenceManager.getDefaultSharedPreferences(context)

@ -780,5 +780,7 @@
<string name="less_or_equal_sign"><![CDATA[≤]]></string> <string name="less_or_equal_sign"><![CDATA[≤]]></string>
<string name="less_sign"><![CDATA[<]]></string> <string name="less_sign"><![CDATA[<]]></string>
<string name="expense">expense</string> <string name="expense">expense</string>
<string name="please_wait">Please wait…</string>
<string name="currency_rate_confirmation">Please enter the %1$s to %2$s rate to apply to all your bankrolls</string>
</resources> </resources>

@ -784,6 +784,8 @@ La aplicación funciona con una suscripción anual para uso ilimitado, pero obti
<string name="less_or_equal_sign"><![CDATA[≤]]></string> <string name="less_or_equal_sign"><![CDATA[≤]]></string>
<string name="less_sign"><![CDATA[<]]></string> <string name="less_sign"><![CDATA[<]]></string>
<string name="expense">expense</string> <string name="expense">expense</string>
<string name="please_wait">Please wait…</string>
<string name="currency_rate_confirmation">Please enter the %1$s to %2$s rate to apply to all your bankrolls</string>
</resources> </resources>

@ -789,5 +789,7 @@
<string name="less_sign"><![CDATA[<]]></string> <string name="less_sign"><![CDATA[<]]></string>
<string name="transaction_filter">Filtre de transactions</string> <string name="transaction_filter">Filtre de transactions</string>
<string name="expense">frais</string> <string name="expense">frais</string>
<string name="please_wait">Veuillez patienter…</string>
<string name="currency_rate_confirmation">Veuillez entrer le taux de %1$s vers %2$s pour l\'appliquer à toutes vos bankrolls</string>
</resources> </resources>

@ -779,5 +779,7 @@
<string name="less_or_equal_sign"><![CDATA[≤]]></string> <string name="less_or_equal_sign"><![CDATA[≤]]></string>
<string name="less_sign"><![CDATA[<]]></string> <string name="less_sign"><![CDATA[<]]></string>
<string name="expense">expense</string> <string name="expense">expense</string>
<string name="please_wait">Please wait…</string>
<string name="currency_rate_confirmation">Please enter the %1$s to %2$s rate to apply to all your bankrolls</string>
</resources> </resources>

@ -779,5 +779,7 @@
<string name="less_or_equal_sign"><![CDATA[≤]]></string> <string name="less_or_equal_sign"><![CDATA[≤]]></string>
<string name="less_sign"><![CDATA[<]]></string> <string name="less_sign"><![CDATA[<]]></string>
<string name="expense">expense</string> <string name="expense">expense</string>
<string name="please_wait">Please wait…</string>
<string name="currency_rate_confirmation">Please enter the %1$s to %2$s rate to apply to all your bankrolls</string>
</resources> </resources>

@ -783,5 +783,7 @@
<string name="less_or_equal_sign"><![CDATA[≤]]></string> <string name="less_or_equal_sign"><![CDATA[≤]]></string>
<string name="less_sign"><![CDATA[<]]></string> <string name="less_sign"><![CDATA[<]]></string>
<string name="expense">expense</string> <string name="expense">expense</string>
<string name="please_wait">Please wait…...</string>
<string name="currency_rate_confirmation">Please enter the %1$s to %2$s rate to apply to all your bankrolls</string>
</resources> </resources>

@ -778,5 +778,7 @@
<string name="less_or_equal_sign"><![CDATA[≤]]></string> <string name="less_or_equal_sign"><![CDATA[≤]]></string>
<string name="less_sign"><![CDATA[<]]></string> <string name="less_sign"><![CDATA[<]]></string>
<string name="expense">expense</string> <string name="expense">expense</string>
<string name="please_wait">Please wait…</string>
<string name="currency_rate_confirmation">Please enter the %1$s to %2$s rate to apply to all your bankrolls</string>
</resources> </resources>

@ -780,5 +780,7 @@
<string name="less_or_equal_sign"><![CDATA[≤]]></string> <string name="less_or_equal_sign"><![CDATA[≤]]></string>
<string name="less_sign"><![CDATA[<]]></string> <string name="less_sign"><![CDATA[<]]></string>
<string name="expense">expense</string> <string name="expense">expense</string>
<string name="please_wait">Please wait…</string>
<string name="currency_rate_confirmation">Please enter the %1$s to %2$s rate to apply to all your bankrolls</string>
</resources> </resources>

@ -773,5 +773,7 @@
<string name="less_or_equal_sign"><![CDATA[≤]]></string> <string name="less_or_equal_sign"><![CDATA[≤]]></string>
<string name="less_sign"><![CDATA[<]]></string> <string name="less_sign"><![CDATA[<]]></string>
<string name="expense">expense</string> <string name="expense">expense</string>
<string name="please_wait">Please wait…</string>
<string name="currency_rate_confirmation">Please enter the %1$s to %2$s rate to apply to all your bankrolls</string>
</resources> </resources>

@ -833,5 +833,7 @@
<string name="empty_reports_screen">This screen will show where you perform the best when you\'ll have more data. You also can create custom reports using the top right button.</string> <string name="empty_reports_screen">This screen will show where you perform the best when you\'ll have more data. You also can create custom reports using the top right button.</string>
<string name="transaction_filter">Transaction Filter</string> <string name="transaction_filter">Transaction Filter</string>
<string name="expense">expense</string> <string name="expense">expense</string>
<string name="please_wait">Please wait…</string>
<string name="currency_rate_confirmation">Please enter the %1$s to %2$s rate to apply to all your bankrolls</string>
</resources> </resources>

@ -1,7 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
ext.kotlin_version = '1.5.21' ext.kotlin_version = '1.7.21'
repositories { repositories {
google() google()
jcenter() jcenter()
@ -15,6 +15,9 @@ buildscript {
classpath 'com.google.gms:google-services:4.3.4' classpath 'com.google.gms:google-services:4.3.4'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.4.1' classpath 'com.google.firebase:firebase-crashlytics-gradle:2.4.1'
// serialization
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
} }
} }

Loading…
Cancel
Save