diff --git a/app/build.gradle b/app/build.gradle index b0bcd84f..3db7b2a0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,7 +6,9 @@ apply plugin: 'realm-android' // Crashlytics apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.firebase.crashlytics' -////////////// +// Serialization +apply plugin: "kotlinx-serialization" + repositories { 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-android:1.3.6" 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 implementation 'androidx.appcompat:appcompat:1.1.0' diff --git a/app/src/main/java/net/pokeranalytics/android/api/FreeConverterApi.kt b/app/src/main/java/net/pokeranalytics/android/api/FreeConverterApi.kt index 77a3f364..1a8217b5 100644 --- a/app/src/main/java/net/pokeranalytics/android/api/FreeConverterApi.kt +++ b/app/src/main/java/net/pokeranalytics/android/api/FreeConverterApi.kt @@ -1,42 +1,53 @@ package net.pokeranalytics.android.api import android.content.Context -import com.android.volley.Request +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 kotlinx.serialization.json.JsonConfiguration import timber.log.Timber +@Serializable +data class RateResponse(var info: RateInfo) +@Serializable +data class RateInfo(var rate: Double) + class FreeConverterApi { companion object { - fun currencyRate(pair: String, context: Context, callback: (Double) -> (Unit)) { + 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://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 } - 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 = $url") + val stringRequest = object : StringRequest( + Method.GET, url, + { response -> + val o = Json.decodeFromString(response) + callback(o.info.rate, null) }, { + callback(null, it) Timber.d("Api call failed: ${it.message}") - }) + }) { + + override fun getHeaders(): MutableMap { + val headers = HashMap() + headers["apikey"] = "XnfeyID3PMKd3k4zTPW0XmZAbcZlZgqH" + return headers + } + } queue.add(stringRequest) } diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/Query.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/Query.kt index 307c80ab..7c7c89bc 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/filter/Query.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/Query.kt @@ -119,6 +119,7 @@ class Query { is QueryCondition.QueryDataCondition<*> -> { c.objectId?.let { return it } } + else -> {} } } return null diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/QueryCondition.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/QueryCondition.kt index ec7318eb..e1d4b1b8 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/filter/QueryCondition.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/QueryCondition.kt @@ -848,6 +848,7 @@ sealed class QueryCondition : RowRepresentable { } return realmQuery } + else -> {} } if (this is CustomFieldRelated) { diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/FilterCondition.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/FilterCondition.kt index 3568edf1..b299ef32 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/FilterCondition.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/FilterCondition.kt @@ -29,6 +29,7 @@ open class FilterCondition() : RealmObject() { 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.ListOfString -> this.setValues(filterElementRows.flatMap { (it as QueryCondition.ListOfString).listOfValues }) + else -> {} } } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/activity/ImportActivity.kt b/app/src/main/java/net/pokeranalytics/android/ui/activity/ImportActivity.kt index feeab09d..9a739237 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/activity/ImportActivity.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/activity/ImportActivity.kt @@ -83,7 +83,7 @@ class ImportActivity : BaseActivity() { when (requestCode) { RequestCode.IMPORT.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() }) } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/extensions/UIExtensions.kt b/app/src/main/java/net/pokeranalytics/android/ui/extensions/UIExtensions.kt index 478bb7e6..0f1e9910 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/extensions/UIExtensions.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/extensions/UIExtensions.kt @@ -3,7 +3,6 @@ package net.pokeranalytics.android.ui.extensions import android.app.Activity import android.content.ActivityNotFoundException import android.content.Context -import android.content.DialogInterface import android.content.Intent import android.content.res.Resources import android.graphics.Bitmap @@ -147,9 +146,9 @@ fun Activity.showAlertDialog(title: Int? = null, message: Int? = null) { 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 { - showAlertDialog(it, title, message) + showAlertDialog(it, title, messageResId, message) } } @@ -157,16 +156,20 @@ fun Fragment.showAlertDialog(title: Int? = null, message: Int? = null) { * Create and show an alert dialog */ 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 ) { val builder = AlertDialog.Builder(context) title?.let { builder.setTitle(title) } + messageResId?.let { + builder.setMessage(messageResId) + } message?.let { - builder.setMessage(message) + builder.setMessage(it) } + builder.setPositiveButton(net.pokeranalytics.android.R.string.ok) { _, _ -> positiveAction?.invoke() } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/BaseFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/BaseFragment.kt index 608b1326..1608817f 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/BaseFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/BaseFragment.kt @@ -7,6 +7,7 @@ import android.os.Bundle import android.view.View import androidx.appcompat.widget.Toolbar import androidx.fragment.app.Fragment +import com.google.android.material.snackbar.Snackbar import net.pokeranalytics.android.PokerAnalyticsApplication import net.pokeranalytics.android.R 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.RowRepresentableEditDescriptor import net.pokeranalytics.android.util.CrashLogging +import timber.log.Timber import java.io.File import java.util.* @@ -183,4 +185,13 @@ abstract class BaseFragment : Fragment() { 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") + } + } + } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/calendar/CalendarDetailsFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/calendar/CalendarDetailsFragment.kt index 2e3a1dbb..210b26ba 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/calendar/CalendarDetailsFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/calendar/CalendarDetailsFragment.kt @@ -177,6 +177,7 @@ class CalendarDetailsFragment : BaseFragment(), StaticRowRepresentableDataSource when (model.sessionTypeCondition) { QueryCondition.IsCash -> query.add(QueryCondition.IsCash) QueryCondition.IsTournament -> query.add(QueryCondition.IsTournament) + else -> {} } val requiredStats: List = listOf(Stat.LOCATIONS_PLAYED, Stat.LONGEST_STREAKS, Stat.DAYS_PLAYED, Stat.STANDARD_DEVIATION_HOURLY) diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/calendar/CalendarFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/calendar/CalendarFragment.kt index 09eecc5e..02591d28 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/calendar/CalendarFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/calendar/CalendarFragment.kt @@ -431,6 +431,7 @@ class CalendarFragment : RealmFragment(), CoroutineScope, StaticRowRepresentable Calendar.MONTH, condition.listOfValues.first() ) + else -> {} } } @@ -478,6 +479,7 @@ class CalendarFragment : RealmFragment(), CoroutineScope, StaticRowRepresentable Calendar.YEAR, condition.listOfValues.first() ) + else -> {} } } yearlyReports[calendar.time] = computedResults diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/data/BankrollDataFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/data/BankrollDataFragment.kt index 996eac62..b9bea97b 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/data/BankrollDataFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/data/BankrollDataFragment.kt @@ -15,6 +15,7 @@ import net.pokeranalytics.android.ui.activity.CurrenciesActivity import net.pokeranalytics.android.ui.activity.components.RequestCode import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource 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.view.RowRepresentable 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 { return when (row) { - SimpleRow.NAME -> if (bankroll.name.isNotEmpty()) bankroll.name else NULL_TEXT + SimpleRow.NAME -> bankroll.name.ifEmpty { NULL_TEXT } BankrollPropertiesRow.CURRENCY -> { bankroll.currency?.code?.let { code -> Currency.getInstance(code).currencyCode @@ -263,12 +264,24 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS } this.lastRefreshRateCall = System.currentTimeMillis() - val currenciesConverterValue = "${bankroll.currency?.code}_${defaultCurrency.currencyCode}" +// val currenciesConverterValue = "${bankroll.currency?.code}_${defaultCurrency.currencyCode}" - FreeConverterApi.currencyRate(currenciesConverterValue, requireContext()) { rate -> - onRowValueChanged(rate, BankrollPropertiesRow.RATE) - isRefreshingRate = false - rowRepresentableAdapter.refreshRow(BankrollPropertiesRow.REFRESH_RATE) + bankroll.currency?.code?.let { from -> + val to = defaultCurrency.currencyCode + FreeConverterApi.currencyRate(from, to, requireContext()) { rate, error -> + + rate?.let { + onRowValueChanged(rate, BankrollPropertiesRow.RATE) + } + + error?.localizedMessage?.let { message -> + toast(message) + } + +// onRowValueChanged(rate, BankrollPropertiesRow.RATE) + isRefreshingRate = false + rowRepresentableAdapter.refreshRow(BankrollPropertiesRow.REFRESH_RATE) + } } this.isRefreshingRate = true @@ -280,7 +293,6 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS this.bankrollModel.selectedCaptureType.value?.let { Preferences.setResultCaptureType(this.bankroll, it, requireContext()) } - } } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/data/PlayerDataFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/data/PlayerDataFragment.kt index 5a5d2684..bd1c5fff 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/data/PlayerDataFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/data/PlayerDataFragment.kt @@ -172,7 +172,7 @@ class PlayerDataFragment : EditableDataFragment(), StaticRowRepresentableDataSou if (row.isValidForDelete(getRealm())) { GlobalScope.launch(Dispatchers.Main) { 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) rowRepresentableAdapter.notifyDataSetChanged() }) diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/rows/FilterSectionRow.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/rows/FilterSectionRow.kt index e09a04ad..4d62f22d 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/rows/FilterSectionRow.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/rows/FilterSectionRow.kt @@ -63,6 +63,7 @@ sealed class FilterSectionRow(override val resId: Int?) : RowRepresentable { is CustomField -> { return customField.name } + else -> {} } return name } diff --git a/build.gradle b/build.gradle index 6ce66563..c357114f 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.5.21' + ext.kotlin_version = '1.7.21' repositories { google() jcenter() @@ -15,6 +15,9 @@ buildscript { classpath 'com.google.gms:google-services:4.3.4' classpath 'com.google.firebase:firebase-crashlytics-gradle:2.4.1' + // serialization + classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" + } }