From 88d5ad52007adae9b2c01cecb3c826ed433b9bb4 Mon Sep 17 00:00:00 2001 From: Aurelien Hubert Date: Mon, 18 Mar 2019 10:54:05 +0100 Subject: [PATCH 01/24] Add Retrofit --- app/build.gradle | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/build.gradle b/app/build.gradle index 06b06296..d7300416 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -57,6 +57,11 @@ dependencies { implementation 'androidx.lifecycle:lifecycle-extensions:2.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 implementation 'com.google.android.libraries.places:places:1.0.0' From 26c63cb658396fe0ed33712e3aaf196f77ae5ecf Mon Sep 17 00:00:00 2001 From: Aurelien Hubert Date: Mon, 18 Mar 2019 10:54:56 +0100 Subject: [PATCH 02/24] Add Currency Converter management --- .../android/api/CurrencyConverterApi.kt | 80 +++++++++++++++++++ .../android/model/retrofit/ConvertResult.kt | 11 +++ .../net/pokeranalytics/android/util/URL.kt | 4 +- app/src/main/res/values/secrets.xml | 1 + 4 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/net/pokeranalytics/android/api/CurrencyConverterApi.kt create mode 100644 app/src/main/java/net/pokeranalytics/android/model/retrofit/ConvertResult.kt diff --git a/app/src/main/java/net/pokeranalytics/android/api/CurrencyConverterApi.kt b/app/src/main/java/net/pokeranalytics/android/api/CurrencyConverterApi.kt new file mode 100644 index 00000000..8d84d753 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/api/CurrencyConverterApi.kt @@ -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> + +} diff --git a/app/src/main/java/net/pokeranalytics/android/model/retrofit/ConvertResult.kt b/app/src/main/java/net/pokeranalytics/android/model/retrofit/ConvertResult.kt new file mode 100644 index 00000000..1520c711 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/model/retrofit/ConvertResult.kt @@ -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 +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/util/URL.kt b/app/src/main/java/net/pokeranalytics/android/util/URL.kt index 9e46339c..53bb173a 100644 --- a/app/src/main/java/net/pokeranalytics/android/util/URL.kt +++ b/app/src/main/java/net/pokeranalytics/android/util/URL.kt @@ -16,8 +16,10 @@ enum class URL(var value: String) { FACEBOOK("https://www.facebook.com/171053452998758"), // Support - SUPPORT_EMAIL("support@pokeranalytics.net") + SUPPORT_EMAIL("support@pokeranalytics.net"), + // Currency Converter API + API_CURRENCY_CONVERTER("https://free.currencyconverterapi.com/api/v5/") } diff --git a/app/src/main/res/values/secrets.xml b/app/src/main/res/values/secrets.xml index 77732c57..9510e5b7 100644 --- a/app/src/main/res/values/secrets.xml +++ b/app/src/main/res/values/secrets.xml @@ -1,4 +1,5 @@ AIzaSyCg-vgW4YnFsQ_s1iWjgzSq2vT0te3R1Hw + 5ba8d38995282fe8b1c8 \ No newline at end of file From 08a12e4d79f306203595d4b99cfc05ff5da7ef96 Mon Sep 17 00:00:00 2001 From: Aurelien Hubert Date: Mon, 18 Mar 2019 10:55:01 +0100 Subject: [PATCH 03/24] Add comment --- app/src/main/java/net/pokeranalytics/android/model/LiveData.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/net/pokeranalytics/android/model/LiveData.kt b/app/src/main/java/net/pokeranalytics/android/model/LiveData.kt index c89da1bc..5fdd89aa 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/LiveData.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/LiveData.kt @@ -145,6 +145,9 @@ enum class LiveData : Localizable { } } + /** + * Return the new entity title + */ fun newEntityLocalizedTitle(context: Context): String { return "${context.getString(R.string.new_entity)} ${this.localizedTitle(context)}" } From 3866ab21626e6e984f137bf169d830bf43af7cf3 Mon Sep 17 00:00:00 2001 From: Aurelien Hubert Date: Mon, 18 Mar 2019 10:55:10 +0100 Subject: [PATCH 04/24] Add transaction types --- .../android/ui/view/rowrepresentable/SettingRow.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SettingRow.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SettingRow.kt index 34be219d..8dd14fd9 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SettingRow.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SettingRow.kt @@ -27,6 +27,7 @@ enum class SettingRow : RowRepresentable { TOURNAMENT_NAME, TOURNAMENT_FEATURE, TRANSACTION, + TRANSACTION_TYPE, // Terms PRIVACY_POLICY, @@ -56,7 +57,7 @@ enum class SettingRow : RowRepresentable { 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.addAll(arrayListOf(PRIVACY_POLICY, TERMS_OF_USE, GDPR)) @@ -106,6 +107,7 @@ enum class SettingRow : RowRepresentable { TOURNAMENT_NAME -> LiveData.TOURNAMENT_NAME TOURNAMENT_FEATURE -> LiveData.TOURNAMENT_FEATURE TRANSACTION -> LiveData.TRANSACTION + TRANSACTION_TYPE -> LiveData.TRANSACTION_TYPE else -> null } } From ad2c5e1e5cc81ffaf7c2ad59786cd60f2b6c9cd9 Mon Sep 17 00:00:00 2001 From: Aurelien Hubert Date: Mon, 18 Mar 2019 10:55:27 +0100 Subject: [PATCH 05/24] Update title management --- .../pokeranalytics/android/ui/fragment/EditableDataFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/EditableDataFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/EditableDataFragment.kt index ce7cdcbd..ed1dd71f 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/EditableDataFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/EditableDataFragment.kt @@ -111,7 +111,7 @@ open class EditableDataFragment : PokerAnalyticsFragment(), RowRepresentableDele isUpdating = true } ?: run { //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) From 2be0bcf32951aeefed3d2e7f68be7548f50c6f30 Mon Sep 17 00:00:00 2001 From: Aurelien Hubert Date: Mon, 18 Mar 2019 10:55:40 +0100 Subject: [PATCH 06/24] Add Currency Converter API for bankroll rate --- .../ui/fragment/BankrollDataFragment.kt | 65 ++++++++++++++----- 1 file changed, 47 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollDataFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollDataFragment.kt index 616fbfb3..446039ed 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollDataFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollDataFragment.kt @@ -4,12 +4,10 @@ import android.app.Activity.RESULT_OK import android.content.Intent import android.os.Bundle 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.api.CurrencyConverterApi 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.adapter.RowRepresentableDataSource 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.Preferences import net.pokeranalytics.android.util.extensions.round +import retrofit2.Call +import retrofit2.Response import java.util.* /** @@ -42,6 +42,7 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS private lateinit var defaultCurrency: Currency private val rows = ArrayList() private var isRefreshingRate = false + private var lastRefreshRateCall = 0L override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -111,25 +112,20 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) { when (row) { BankrollRow.CURRENCY -> CurrenciesActivity.newInstanceForResult(this@BankrollDataFragment, BankrollDataFragment.REQUEST_CODE_CURRENCY) - BankrollRow.REFRESH_RATE -> { - 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) - } + BankrollRow.REFRESH_RATE -> refreshRate() else -> super.onRowSelected(position, row, fromAction) } } override fun onRowValueChanged(value: Any?, row: RowRepresentable) { 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(BankrollRow.CURRENCY) - val defaultCurrency = Currency.getInstance(Preferences.getCurrencyLocale(this.parentActivity)) - var differentCurrency = false bankroll.currency?.let { bankrollCurrency -> 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> { + + override fun onResponse(call: Call>, response: Response>) { + 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>, t: Throwable) { + isRefreshingRate = false + rowRepresentableAdapter.refreshRow(BankrollRow.REFRESH_RATE) + } + }) + + isRefreshingRate = true + rowRepresentableAdapter.refreshRow(BankrollRow.REFRESH_RATE) + } } \ No newline at end of file From 09966e1c26cef2eb7b48ab7bfafd22afef2b440b Mon Sep 17 00:00:00 2001 From: Aurelien Hubert Date: Mon, 18 Mar 2019 15:19:20 +0100 Subject: [PATCH 07/24] Add Currency Utils --- .../android/util/CurrencyUtils.kt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 app/src/main/java/net/pokeranalytics/android/util/CurrencyUtils.kt diff --git a/app/src/main/java/net/pokeranalytics/android/util/CurrencyUtils.kt b/app/src/main/java/net/pokeranalytics/android/util/CurrencyUtils.kt new file mode 100644 index 00000000..4f5ccb48 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/util/CurrencyUtils.kt @@ -0,0 +1,19 @@ +package net.pokeranalytics.android.util + +import net.pokeranalytics.android.model.realm.Bankroll +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) + } + + } + +} \ No newline at end of file From 8902c995905df35e3750fa405bca5ee90085cc16 Mon Sep 17 00:00:00 2001 From: Aurelien Hubert Date: Mon, 18 Mar 2019 15:21:18 +0100 Subject: [PATCH 08/24] Refactor FormatUtils in CurrencyUtils --- .../android/util/CurrencyUtils.kt | 16 +++++++++++++++ .../android/util/FormatUtils.kt | 20 ------------------- 2 files changed, 16 insertions(+), 20 deletions(-) delete mode 100644 app/src/main/java/net/pokeranalytics/android/util/FormatUtils.kt diff --git a/app/src/main/java/net/pokeranalytics/android/util/CurrencyUtils.kt b/app/src/main/java/net/pokeranalytics/android/util/CurrencyUtils.kt index 4f5ccb48..eaba67bd 100644 --- a/app/src/main/java/net/pokeranalytics/android/util/CurrencyUtils.kt +++ b/app/src/main/java/net/pokeranalytics/android/util/CurrencyUtils.kt @@ -1,11 +1,14 @@ 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 */ @@ -14,6 +17,19 @@ class CurrencyUtils { 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 + } + } } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/util/FormatUtils.kt b/app/src/main/java/net/pokeranalytics/android/util/FormatUtils.kt deleted file mode 100644 index 29fbb799..00000000 --- a/app/src/main/java/net/pokeranalytics/android/util/FormatUtils.kt +++ /dev/null @@ -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 - } - - } - -} \ No newline at end of file From 9e18a22d7fe7fa52df8bfa78102bdc64eb759e39 Mon Sep 17 00:00:00 2001 From: Aurelien Hubert Date: Mon, 18 Mar 2019 15:21:36 +0100 Subject: [PATCH 09/24] Add currency management --- .../android/util/extensions/NumbersExtension.kt | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/net/pokeranalytics/android/util/extensions/NumbersExtension.kt b/app/src/main/java/net/pokeranalytics/android/util/extensions/NumbersExtension.kt index d9a7c87a..d98df6b0 100644 --- a/app/src/main/java/net/pokeranalytics/android/util/extensions/NumbersExtension.kt +++ b/app/src/main/java/net/pokeranalytics/android/util/extensions/NumbersExtension.kt @@ -2,6 +2,7 @@ package net.pokeranalytics.android.util.extensions import java.text.DecimalFormat import java.text.NumberFormat +import java.util.* // Double @@ -18,11 +19,16 @@ fun Double.formatted(): String { return format.format(this) } -fun Double.toCurrency(): String { - val format = NumberFormat.getCurrencyInstance() - format.maximumFractionDigits = 2 - format.minimumFractionDigits = 0 - return format.format(this) +fun Double.toCurrency(currency: Currency? = null): String { + + val currencyFormatter = NumberFormat.getCurrencyInstance() + currency?.let { + currencyFormatter.currency = currency + } + + currencyFormatter.maximumFractionDigits = 2 + currencyFormatter.minimumFractionDigits = 0 + return currencyFormatter.format(this) } fun Double.formattedHourlyDuration() : String { From 004093a170347c49359d791a0de87c1e9045d21d Mon Sep 17 00:00:00 2001 From: Aurelien Hubert Date: Mon, 18 Mar 2019 15:21:52 +0100 Subject: [PATCH 10/24] Improve currency mamangement for sessions and stats --- .../pokeranalytics/android/calculus/Stat.kt | 21 +++++----------- .../android/model/realm/Session.kt | 24 +++++++++++-------- .../android/ui/fragment/SessionFragment.kt | 5 ++-- .../bottomsheet/BottomSheetFragment.kt | 7 ++++-- .../BottomSheetMultiSelectionFragment.kt | 15 ------------ .../bottomsheet/BottomSheetSumFragment.kt | 6 ++--- .../android/ui/view/SessionRowView.kt | 5 ++-- 7 files changed, 34 insertions(+), 49 deletions(-) diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt b/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt index 31b94ec1..7765025e 100644 --- a/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt +++ b/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt @@ -5,10 +5,11 @@ import net.pokeranalytics.android.R import net.pokeranalytics.android.exceptions.FormattingException import net.pokeranalytics.android.ui.view.RowRepresentable 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.extensions.formatted import net.pokeranalytics.android.util.extensions.formattedHourlyDuration +import java.util.* /** * 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] */ -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) { 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 */ @@ -135,7 +126,7 @@ class ComputedStat(stat: Stat, value: Double) { // Amounts + red/green Stat.NETRESULT, Stat.HOURLY_RATE, Stat.AVERAGE, Stat.NET_BB_PER_100_HANDS, Stat.HOURLY_RATE_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 return TextFormat(numberFormat.format(this.value), color) } // white integers @@ -148,10 +139,10 @@ class ComputedStat(stat: Stat, value: Double) { Stat.WIN_RATIO, Stat.ROI -> { val color = if (value * 100 >= this.stat.threshold) R.color.green else R.color.red return TextFormat("${(value * 100).formatted()}%", color) - } // white amounts + } // white amountsr Stat.AVERAGE_BUYIN, Stat.STANDARD_DEVIATION, Stat.STANDARD_DEVIATION_HOURLY, Stat.STANDARD_DEVIATION_BB_PER_100_HANDS -> { - val numberFormat= FormatUtils.getCurrencyFormatter(context) + val numberFormat= CurrencyUtils.getCurrencyFormatter(context, currency) return TextFormat(numberFormat.format(this.value)) } else -> throw FormattingException("Stat formatting of ${this.stat.name} not handled") diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt index 2f19b5bf..71a7b45a 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt @@ -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.SeparatorRowRepresentable 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.extensions.* import java.util.* @@ -484,7 +485,7 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource CustomizableRowRepresentable( RowViewType.HEADER_TITLE_AMOUNT_BIG, title = getFormattedDuration(), - computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0) + computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0, CurrencyUtils.getCurrency(bankroll)) ) ) rows.add(SeparatorRowRepresentable()) @@ -494,7 +495,7 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource CustomizableRowRepresentable( RowViewType.HEADER_TITLE_AMOUNT_BIG, 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()) @@ -504,14 +505,14 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource CustomizableRowRepresentable( RowViewType.HEADER_TITLE_AMOUNT_BIG, title = getFormattedDuration(), - computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0) + computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0, CurrencyUtils.getCurrency(bankroll)) ) ) rows.add( CustomizableRowRepresentable( RowViewType.HEADER_TITLE_AMOUNT, 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( RowViewType.HEADER_TITLE_VALUE, 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.BLINDS -> getBlinds() SessionRow.BREAK_TIME -> if (this.breakDuration > 0.0) this.breakDuration.toMinutes() else NULL_TEXT - SessionRow.BUY_IN -> this.result?.buyin?.toCurrency() ?: NULL_TEXT - SessionRow.CASHED_OUT, SessionRow.PRIZE, SessionRow.NET_RESULT -> this.result?.cashout?.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(CurrencyUtils.getCurrency(bankroll)) ?: NULL_TEXT SessionRow.COMMENT -> if (this.comment.isNotEmpty()) this.comment else NULL_TEXT SessionRow.END_DATE -> this.endDate?.shortDateTime() ?: NULL_TEXT 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.PLAYERS -> tournamentNumberOfPlayers?.toString() ?: NULL_TEXT SessionRow.POSITION -> result?.tournamentFinalPosition?.toString() ?: NULL_TEXT SessionRow.START_DATE -> this.startDate?.shortDateTime() ?: 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 { TournamentType.values()[it].localizedTitle(context) } ?: run { @@ -575,10 +576,12 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource "${tournamentFeatures.subList(0,2).joinToString { it.name }}, ..." - } else { + } else if (tournamentFeatures.size > 0) { tournamentFeatures.joinToString { it.name } + } else { + 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) localResult.buyin = value as Double? result = localResult + this.updateRowRepresentation() } SessionRow.CASHED_OUT, SessionRow.PRIZE, SessionRow.NET_RESULT -> { val localResult = if (result != null) result as Result else realm.createObject(Result::class.java) diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt index 60e39b00..a067ea5c 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt @@ -26,6 +26,7 @@ import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentableDiffCallback import net.pokeranalytics.android.ui.view.SmoothScrollLinearLayoutManager import net.pokeranalytics.android.ui.view.rowrepresentable.SessionRow +import net.pokeranalytics.android.util.CurrencyUtils import java.util.* @@ -99,9 +100,9 @@ class SessionFragment : PokerAnalyticsFragment(), RowRepresentableDelegate { currentSession.startDate ) 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)) } } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetFragment.kt index d177f966..82d5060e 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetFragment.kt @@ -22,11 +22,13 @@ import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor import net.pokeranalytics.android.ui.view.rowrepresentable.SessionRow import net.pokeranalytics.android.ui.view.rowrepresentable.TransactionRow +import java.util.* open class BottomSheetFragment : BottomSheetDialogFragment() { lateinit var row: RowRepresentable lateinit var delegate: RowRepresentableDelegate + var currentCurrency: Currency? = null private var isClearable: Boolean = true private var rowRepresentableEditDescriptors: ArrayList? = null @@ -40,7 +42,8 @@ open class BottomSheetFragment : BottomSheetDialogFragment() { row: RowRepresentable, delegate: RowRepresentableDelegate, rowRepresentableEditDescriptors: ArrayList?, - isClearable: Boolean? = true + isClearable: Boolean? = true, + currentCurrency: Currency? = null ): BottomSheetFragment { val bottomSheetFragment = row.bottomSheetType.newInstance() bottomSheetFragment.show(fragmentManager, "bottomSheet") @@ -48,7 +51,7 @@ open class BottomSheetFragment : BottomSheetDialogFragment() { bottomSheetFragment.delegate = delegate bottomSheetFragment.rowRepresentableEditDescriptors = rowRepresentableEditDescriptors bottomSheetFragment.isClearable = isClearable ?: true - + bottomSheetFragment.currentCurrency = currentCurrency return bottomSheetFragment } } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetMultiSelectionFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetMultiSelectionFragment.kt index 413d8f82..42872569 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetMultiSelectionFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetMultiSelectionFragment.kt @@ -2,18 +2,14 @@ package net.pokeranalytics.android.ui.fragment.components.bottomsheet import android.app.Activity import android.content.Intent -import android.os.Bundle -import android.view.View import io.realm.RealmList import io.realm.RealmObject -import io.realm.RealmResults import net.pokeranalytics.android.exceptions.RowRepresentableEditDescriptorException import net.pokeranalytics.android.model.LiveData import net.pokeranalytics.android.ui.activity.EditableDataActivity import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowViewType -import timber.log.Timber /** * 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? { return selectedRows } @@ -50,16 +45,6 @@ open class BottomSheetMultiSelectionFragment : BottomSheetListFragment() { selectedRows.add(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 { diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetSumFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetSumFragment.kt index 8153eb8f..58f1ff3e 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetSumFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetSumFragment.kt @@ -63,7 +63,7 @@ class BottomSheetSumFragment : BottomSheetFragment() { 0.0 } - currentValue.text = currentDefaultValue.toCurrency() + currentValue.text = currentDefaultValue.toCurrency(currentCurrency) // First value val defaultValue1 = try { @@ -72,7 +72,7 @@ class BottomSheetSumFragment : BottomSheetFragment() { 0.0 } - button1.text = "+ ${defaultValue1.toCurrency()}" + button1.text = "+ ${defaultValue1.toCurrency(currentCurrency)}" button1.visibility = if (defaultValue1 > 0) View.VISIBLE else View.GONE button1.setOnClickListener { this.delegate.onRowValueChanged(currentDefaultValue + defaultValue1, row) @@ -86,7 +86,7 @@ class BottomSheetSumFragment : BottomSheetFragment() { 0.0 } - button2.text = "+ ${defaultValue2.toCurrency()}" + button2.text = "+ ${defaultValue2.toCurrency(currentCurrency)}" button2.visibility = if (defaultValue2 > 0) View.VISIBLE else View.GONE button2.setOnClickListener { this.delegate.onRowValueChanged(currentDefaultValue + defaultValue2, row) diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/SessionRowView.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/SessionRowView.kt index 90b3df10..8e79ca03 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/SessionRowView.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/SessionRowView.kt @@ -14,6 +14,7 @@ import net.pokeranalytics.android.model.TableSize import net.pokeranalytics.android.model.extensions.SessionState import net.pokeranalytics.android.model.extensions.getState 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.getShortDayName import net.pokeranalytics.android.util.extensions.shortTime @@ -65,7 +66,7 @@ class SessionRowView : FrameLayout { var title = "" if (session.isTournament()) { if (session.tournamentEntryFee != null) { - title += session.tournamentEntryFee?.toCurrency() + title += session.tournamentEntryFee?.toCurrency(CurrencyUtils.getCurrency(session.bankroll)) } session.game?.let { title += (if (title.isNotEmpty()) " " else "") + session.getGameTitle() @@ -140,7 +141,7 @@ class SessionRowView : FrameLayout { rowHistorySession.infoTitle.isVisible = false 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.text = formattedStat.text } From 2a2a5aba4768958ad03d5e79e12c4385ce8c6487 Mon Sep 17 00:00:00 2001 From: Razmig Sarkissian Date: Mon, 18 Mar 2019 15:46:33 +0100 Subject: [PATCH 11/24] filter update --- .../android/FilterInstrumentedUnitTest.kt | 43 ++++++++++++++++- .../android/exceptions/Exceptions.kt | 4 ++ .../android/model/filter/FilterComponent.kt | 46 +++++++++++++++++-- 3 files changed, 86 insertions(+), 7 deletions(-) diff --git a/app/src/androidTest/java/net/pokeranalytics/android/FilterInstrumentedUnitTest.kt b/app/src/androidTest/java/net/pokeranalytics/android/FilterInstrumentedUnitTest.kt index 57e961e6..92add0ef 100644 --- a/app/src/androidTest/java/net/pokeranalytics/android/FilterInstrumentedUnitTest.kt +++ b/app/src/androidTest/java/net/pokeranalytics/android/FilterInstrumentedUnitTest.kt @@ -2,16 +2,15 @@ package net.pokeranalytics.android import androidx.test.ext.junit.runners.AndroidJUnit4 import io.realm.RealmResults +import net.pokeranalytics.android.exceptions.FilterValueMapException import net.pokeranalytics.android.model.filter.FilterManager import net.pokeranalytics.android.model.filter.SessionFilterable import net.pokeranalytics.android.model.realm.Bankroll -import net.pokeranalytics.android.model.realm.Result import net.pokeranalytics.android.model.realm.Session import org.junit.Assert import org.junit.Test import org.junit.runner.RunWith import java.util.* -import java.util.prefs.Preferences @RunWith(AndroidJUnit4::class) class FilterInstrumentedUnitTest : RealmInstrumentedUnitTest() { @@ -28,6 +27,46 @@ class FilterInstrumentedUnitTest : RealmInstrumentedUnitTest() { return session } + @Test(expected = FilterValueMapException::class) + fun testFilterException() { + val realm = this.mockRealm + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(SessionFilterable.BLINDS) + ) as RealmResults + } + + @Test(expected = FilterValueMapException::class) + fun testValueKeyFilterException() { + var filter = SessionFilterable.STARTED_FROM_DATE + filter.valueMap = mapOf("bob" to Date()) + + val realm = this.mockRealm + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) as RealmResults + } + + @Test(expected = FilterValueMapException::class) + fun testSubValueKeyFilterException() { + var filter = SessionFilterable.BLINDS + filter.valueMap = mapOf("map" to arrayOf(mapOf( + "bob" to 0.5, + "bb" to 1.0, + "code" to null + ))) + + val realm = this.mockRealm + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) as RealmResults + } + @Test fun testCashFilter() { diff --git a/app/src/main/java/net/pokeranalytics/android/exceptions/Exceptions.kt b/app/src/main/java/net/pokeranalytics/android/exceptions/Exceptions.kt index ac0e2564..deefbc3c 100644 --- a/app/src/main/java/net/pokeranalytics/android/exceptions/Exceptions.kt +++ b/app/src/main/java/net/pokeranalytics/android/exceptions/Exceptions.kt @@ -10,4 +10,8 @@ class FormattingException(message: String) : Exception(message) { class RowRepresentableEditDescriptorException(message: String) : Exception(message) { +} + +class FilterValueMapException(message: String) : Exception(message) { + } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/FilterComponent.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/FilterComponent.kt index 6a399360..1dd53f6a 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/filter/FilterComponent.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/FilterComponent.kt @@ -2,6 +2,7 @@ package net.pokeranalytics.android.model.filter import io.realm.RealmObject import io.realm.RealmQuery +import net.pokeranalytics.android.exceptions.FilterValueMapException import net.pokeranalytics.android.model.realm.Session import java.util.* @@ -47,7 +48,37 @@ enum class SessionFilterable(var fieldName:String? = null) : Filterable { SMALL_BLIND("cgSmallBlind"); } - var valueMap : Map? = null + private var _valueMap: Map? = null + var valueMap : Map? + get() { + this.valueMapExceptedKeys?.let { valueMapExceptedKeys -> + _valueMap?.let { map -> + println("valueMapExceptedKeys $valueMapExceptedKeys") + println("map.keys $map.keys") + var missingKeys = map.keys.filter { !valueMapExceptedKeys.contains(it) } + println("missingKeys $missingKeys") + if (map.keys.size == valueMapExceptedKeys.size && missingKeys.isNotEmpty()) { + throw FilterValueMapException("valueMap does not contain ${missingKeys}") + } + } ?: run { + throw FilterValueMapException("valueMap null not expected") + } + } + return _valueMap + } + set(value) { + _valueMap = value + } + + private val valueMapExceptedKeys : Array? + get() { + return when (this) { + BANKROLL -> arrayOf("ids") + STARTED_FROM_DATE, STARTED_TO_DATE, ENDED_FROM_DATE, ENDED_TO_DATE -> arrayOf("date") + BLINDS -> arrayOf("map") + else -> null + } + } override fun filter(realmQuery: RealmQuery<*>): RealmQuery { return when (this) { @@ -79,11 +110,16 @@ enum class SessionFilterable(var fieldName:String? = null) : Filterable { BLINDS -> { val map : Array> by valueMap var finalQuery = realmQuery - map.forEachIndexed { index, it -> + val expectedSubKeys = arrayOf("sb", "bb", "code") as Array + map.forEachIndexed { index, subMap -> + var missingKeys = subMap.keys.filter { !expectedSubKeys.contains(it) } + if (subMap.keys.size == expectedSubKeys.size && missingKeys.isNotEmpty()) { + throw FilterValueMapException("subValueMap does not contain ${missingKeys}") + } - val sb : Double? by it - val bb : Double? by it - val code : String? by it + val sb : Double? by subMap + val bb : Double? by subMap + val code : String? by subMap finalQuery .beginGroup() From 4292c6f7947462253c3e436faa925aaa13027fd5 Mon Sep 17 00:00:00 2001 From: Aurelien Hubert Date: Tue, 19 Mar 2019 09:06:14 +0100 Subject: [PATCH 12/24] Improve stability and fix crashes --- .../android/ui/fragment/StatsFragment.kt | 48 ++++++++++++------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatsFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatsFragment.kt index 0d68efc2..3a00f7ae 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatsFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatsFragment.kt @@ -29,6 +29,9 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc get() = Dispatchers.Main private var rowRepresentables: ArrayList = ArrayList() + private var stringAll = "" + private var stringCashGame = "" + private var stringTournament = "" private lateinit var statsAdapter: RowRepresentableAdapter @@ -54,6 +57,8 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) initData() + initUI() + launchStatComputation() } // Row Representable DS @@ -103,10 +108,28 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc */ private fun initData() { + this.stringAll = getString(R.string.all) + this.stringCashGame = getString(R.string.cash_game) + this.stringTournament = getString(R.string.tournament) + this.statsAdapter = RowRepresentableAdapter(this) - this.launchStatComputation() } + /** + * Init UI + */ + private fun initUI() { + + val viewManager = LinearLayoutManager(requireContext()) + + recyclerView.apply { + setHasFixedSize(true) + layoutManager = viewManager + adapter = statsAdapter + } + } + + private fun launchStatComputation() { // Thread() { @@ -144,7 +167,10 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc } test.await() - showResults(results) + + if (!isDetached) { + showResults(results) + } } } @@ -175,13 +201,11 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc } val allStats: List = listOf(Stat.NETRESULT, Stat.HOURLY_RATE, Stat.AVERAGE, Stat.NUMBER_OF_SETS, Stat.AVERAGE_DURATION, Stat.DURATION) - val allSessionGroup = SessionGroup(getString(R.string.all), sessionsList, allStats) + val allSessionGroup = SessionGroup(stringAll, sessionsList, allStats) val cgStats: List = listOf(Stat.NETRESULT, Stat.HOURLY_RATE, Stat.NET_BB_PER_100_HANDS, Stat.HOURLY_RATE_BB, Stat.AVERAGE, Stat.STANDARD_DEVIATION_HOURLY, Stat.WIN_RATIO, Stat.NUMBER_OF_GAMES, Stat.AVERAGE_BUYIN) - val cgSessionGroup = SessionGroup(getString(R.string.cash_game), cgSessions, cgStats) + val cgSessionGroup = SessionGroup(stringCashGame, cgSessions, cgStats) val tStats: List = listOf(Stat.NETRESULT, Stat.HOURLY_RATE, Stat.ROI, Stat.WIN_RATIO, Stat.NUMBER_OF_GAMES, Stat.AVERAGE_BUYIN) - val tSessionGroup = SessionGroup(getString(R.string.tournament), tSessions, tStats) - - + val tSessionGroup = SessionGroup(stringTournament, tSessions, tStats) Timber.d(">>>>> Start computations...") @@ -190,16 +214,8 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc } private fun showResults(results: List) { - this.rowRepresentables = this.convertResultsIntoRepresentables(results) - - val viewManager = LinearLayoutManager(requireContext()) - - recyclerView.apply { - setHasFixedSize(true) - layoutManager = viewManager - adapter = statsAdapter - } + statsAdapter.notifyDataSetChanged() } private fun convertResultsIntoRepresentables(results: List) : ArrayList { From 0adf9c744904171888c24ce5b3c9e73a257d90d0 Mon Sep 17 00:00:00 2001 From: Razmig Sarkissian Date: Tue, 19 Mar 2019 09:20:56 +0100 Subject: [PATCH 13/24] add new filters --- .../filter/BaseFilterInstrumentedUnitTest.kt | 27 ++ .../filter/DateFilterInstrumentedUnitTest.kt | 268 ++++++++++++++++++ .../filter/ExceptionFilterInstrumentedTest.kt | 56 ++++ .../SessionFilterInstrumentedUnitTest.kt} | 176 +----------- .../android/model/filter/FilterComponent.kt | 140 +++++---- .../android/model/filter/Filterable.kt | 28 +- .../android/model/interfaces/Timed.kt | 1 - .../android/model/realm/Session.kt | 9 +- 8 files changed, 480 insertions(+), 225 deletions(-) create mode 100644 app/src/androidTest/java/net/pokeranalytics/android/filter/BaseFilterInstrumentedUnitTest.kt create mode 100644 app/src/androidTest/java/net/pokeranalytics/android/filter/DateFilterInstrumentedUnitTest.kt create mode 100644 app/src/androidTest/java/net/pokeranalytics/android/filter/ExceptionFilterInstrumentedTest.kt rename app/src/androidTest/java/net/pokeranalytics/android/{FilterInstrumentedUnitTest.kt => filter/SessionFilterInstrumentedUnitTest.kt} (61%) diff --git a/app/src/androidTest/java/net/pokeranalytics/android/filter/BaseFilterInstrumentedUnitTest.kt b/app/src/androidTest/java/net/pokeranalytics/android/filter/BaseFilterInstrumentedUnitTest.kt new file mode 100644 index 00000000..1611beb9 --- /dev/null +++ b/app/src/androidTest/java/net/pokeranalytics/android/filter/BaseFilterInstrumentedUnitTest.kt @@ -0,0 +1,27 @@ +package net.pokeranalytics.android.filter + +import net.pokeranalytics.android.RealmInstrumentedUnitTest +import net.pokeranalytics.android.model.realm.Bankroll +import net.pokeranalytics.android.model.realm.Session +import java.util.* + +open class BaseFilterInstrumentedUnitTest : RealmInstrumentedUnitTest() { + + // convenience extension + fun Session.Companion.testInstance( + netResult: Double, + isTournament: Boolean, + startDate: Date, + endDate: Int = 1, + bankroll: Bankroll? = null + ): Session { + val session: Session = Session.newInstance(super.mockRealm, isTournament, bankroll) + session.result?.netResult = netResult + session.startDate = startDate + val cal = Calendar.getInstance() // creates calendar + cal.time = startDate // sets calendar time/date + cal.add(Calendar.HOUR_OF_DAY, endDate) // adds one hour + session.endDate = cal.time // returns new date object, one hour in the future + return session + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/net/pokeranalytics/android/filter/DateFilterInstrumentedUnitTest.kt b/app/src/androidTest/java/net/pokeranalytics/android/filter/DateFilterInstrumentedUnitTest.kt new file mode 100644 index 00000000..b8ef64cb --- /dev/null +++ b/app/src/androidTest/java/net/pokeranalytics/android/filter/DateFilterInstrumentedUnitTest.kt @@ -0,0 +1,268 @@ +package net.pokeranalytics.android.filter + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import io.realm.RealmResults +import net.pokeranalytics.android.model.filter.DateFilterable +import net.pokeranalytics.android.model.filter.FilterManager +import net.pokeranalytics.android.model.realm.Session +import org.junit.Assert +import org.junit.Test +import org.junit.runner.RunWith +import java.util.* + +@RunWith(AndroidJUnit4::class) +class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { + + @Test + fun testDayOfWeekFilter() { + + val realm = this.mockRealm + realm.beginTransaction() + + val cal = Calendar.getInstance() // creates calendar + cal.time = Date() // sets calendar time/date + val s1 = Session.testInstance(100.0, false, cal.time) + cal.add(Calendar.DAY_OF_MONTH, 1) // adds one hour + val s2 = Session.testInstance(100.0, true, cal.time) + realm.commitTransaction() + + var filter = DateFilterable.DAY_OF_WEEK + cal.time = s1.startDate + filter.valueMap = mapOf("dayOfWeek" to cal.get(Calendar.DAY_OF_WEEK)) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) as RealmResults + + Assert.assertEquals(1, sessions.size) + sessions[0]?.run { + Assert.assertEquals(s1.id, this.id) + } + } + + @Test + fun testMonthFilter() { + + val realm = this.mockRealm + realm.beginTransaction() + val cal = Calendar.getInstance() + cal.time = Date() + val s1 = Session.testInstance(100.0, false, cal.time) + cal.add(Calendar.MONTH, 1) + val s2 = Session.testInstance(100.0, true, cal.time) + realm.commitTransaction() + + var filter = DateFilterable.MONTH + cal.time = s1.startDate + filter.valueMap = mapOf("month" to cal.get(Calendar.MONTH)) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) as RealmResults + + Assert.assertEquals(1, sessions.size) + sessions[0]?.run { + Assert.assertEquals(s1.id, this.id) + } + } + + @Test + fun testYearFilter() { + + val realm = this.mockRealm + realm.beginTransaction() + val cal = Calendar.getInstance() + cal.time = Date() + val s1 = Session.testInstance(100.0, false, cal.time) + cal.add(Calendar.YEAR, 1) + val s2 = Session.testInstance(100.0, true, cal.time) + realm.commitTransaction() + + var filter = DateFilterable.YEAR + cal.time = s1.startDate + filter.valueMap = mapOf("year" to cal.get(Calendar.YEAR)) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) as RealmResults + + Assert.assertEquals(1, sessions.size) + sessions[0]?.run { + Assert.assertEquals(s1.id, this.id) + } + } + + + @Test + fun testWeekEndFilter() { + + val realm = this.mockRealm + realm.beginTransaction() + val cal = Calendar.getInstance() + cal.time = Date() + cal.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY) + val s1 = Session.testInstance(100.0, false, cal.time) + cal.set(Calendar.DAY_OF_WEEK, Calendar.TUESDAY) + val s2 = Session.testInstance(100.0, true, cal.time) + realm.commitTransaction() + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(DateFilterable.WEEK_END) + ) as RealmResults + + Assert.assertEquals(1, sessions.size) + sessions[0]?.run { + Assert.assertEquals(s1.id, this.id) + } + } + + @Test + fun testWeekDayFilter() { + + val realm = this.mockRealm + realm.beginTransaction() + val cal = Calendar.getInstance() + cal.time = Date() + cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY) + val s1 = Session.testInstance(100.0, false, cal.time) + cal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY) + val s2 = Session.testInstance(100.0, true, cal.time) + realm.commitTransaction() + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(DateFilterable.WEEK_DAY) + ) as RealmResults + + Assert.assertEquals(1, sessions.size) + sessions[0]?.run { + Assert.assertEquals(s1.id, this.id) + } + } + + @Test + fun testStartedFomDateFilter() { + + val realm = this.mockRealm + realm.beginTransaction() + + val cal = Calendar.getInstance() // creates calendar + cal.time = Date() // sets calendar time/date + val s1 = Session.testInstance(100.0, false, cal.time, 1) + + cal.add(Calendar.HOUR_OF_DAY, 2) // adds one hour + val s2 = Session.testInstance(100.0, true, cal.time, 1) + realm.commitTransaction() + + var filter = DateFilterable.STARTED_FROM_DATE + filter.valueMap = mapOf("date" to s2.startDate) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) as RealmResults + + Assert.assertEquals(1, sessions.size) + sessions[0]?.run { + Assert.assertEquals(s2.id, this.id) + } + } + + @Test + fun testStartedToDateFilter() { + + val realm = this.mockRealm + realm.beginTransaction() + + val cal = Calendar.getInstance() // creates calendar + cal.time = Date() // sets calendar time/date + val s1 = Session.testInstance(100.0, false, cal.time, 1) + + cal.add(Calendar.HOUR_OF_DAY, 2) // adds one hour + val s2 = Session.testInstance(100.0, true, cal.time, 1) + + realm.commitTransaction() + + var filter = DateFilterable.STARTED_TO_DATE + filter.valueMap = mapOf("date" to s1.startDate) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) as RealmResults + + Assert.assertEquals(1, sessions.size) + sessions[0]?.run { + Assert.assertEquals(s1.id, this.id) + } + } + + @Test + fun testEndedFomDateFilter() { + + val realm = this.mockRealm + realm.beginTransaction() + + val cal = Calendar.getInstance() // creates calendar + cal.time = Date() // sets calendar time/date + val s1 = Session.testInstance(100.0, false, cal.time, 1) + + cal.add(Calendar.HOUR_OF_DAY, 2) // adds one hour + val s2 = Session.testInstance(100.0, true, cal.time, 1) + + realm.commitTransaction() + + var filter = DateFilterable.ENDED_FROM_DATE + filter.valueMap = mapOf("date" to s2.endDate) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) as RealmResults + + Assert.assertEquals(1, sessions.size) + sessions[0]?.run { + Assert.assertEquals(s2.id, this.id) + } + } + + @Test + fun testEndedToDateFilter() { + + val realm = this.mockRealm + realm.beginTransaction() + + val cal = Calendar.getInstance() // creates calendar + cal.time = Date() // sets calendar time/date + val s1 = Session.testInstance(100.0, false, cal.time, 1) + + cal.add(Calendar.HOUR_OF_DAY, 2) // adds one hour + val s2 = Session.testInstance(100.0, true, cal.time, 1) + realm.commitTransaction() + + + var filter = DateFilterable.ENDED_TO_DATE + filter.valueMap = mapOf("date" to s1.endDate) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) as RealmResults + + Assert.assertEquals(1, sessions.size) + sessions[0]?.run { + Assert.assertEquals(s1.id, this.id) + } + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/net/pokeranalytics/android/filter/ExceptionFilterInstrumentedTest.kt b/app/src/androidTest/java/net/pokeranalytics/android/filter/ExceptionFilterInstrumentedTest.kt new file mode 100644 index 00000000..84bc396c --- /dev/null +++ b/app/src/androidTest/java/net/pokeranalytics/android/filter/ExceptionFilterInstrumentedTest.kt @@ -0,0 +1,56 @@ +package net.pokeranalytics.android.filter + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import io.realm.RealmResults +import net.pokeranalytics.android.exceptions.FilterValueMapException +import net.pokeranalytics.android.model.filter.DateFilterable +import net.pokeranalytics.android.model.filter.FilterManager +import net.pokeranalytics.android.model.filter.SessionFilterable +import net.pokeranalytics.android.model.realm.Session +import org.junit.Test +import org.junit.runner.RunWith +import java.util.* + +@RunWith(AndroidJUnit4::class) +class ExceptionFilterInstrumentedTest: BaseFilterInstrumentedUnitTest() { + + @Test(expected = FilterValueMapException::class) + fun testFilterException() { + val realm = this.mockRealm + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(SessionFilterable.BLINDS) + ) as RealmResults + } + + @Test(expected = FilterValueMapException::class) + fun testValueKeyFilterException() { + var filter = DateFilterable.STARTED_FROM_DATE + filter.valueMap = mapOf("bob" to Date()) + + val realm = this.mockRealm + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) as RealmResults + } + + @Test(expected = FilterValueMapException::class) + fun testSubValueKeyFilterException() { + var filter = SessionFilterable.BLINDS + filter.valueMap = mapOf("map" to arrayOf(mapOf( + "bob" to 0.5, + "bb" to 1.0, + "code" to null + ))) + + val realm = this.mockRealm + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) as RealmResults + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/net/pokeranalytics/android/FilterInstrumentedUnitTest.kt b/app/src/androidTest/java/net/pokeranalytics/android/filter/SessionFilterInstrumentedUnitTest.kt similarity index 61% rename from app/src/androidTest/java/net/pokeranalytics/android/FilterInstrumentedUnitTest.kt rename to app/src/androidTest/java/net/pokeranalytics/android/filter/SessionFilterInstrumentedUnitTest.kt index 92add0ef..eb478b82 100644 --- a/app/src/androidTest/java/net/pokeranalytics/android/FilterInstrumentedUnitTest.kt +++ b/app/src/androidTest/java/net/pokeranalytics/android/filter/SessionFilterInstrumentedUnitTest.kt @@ -1,8 +1,7 @@ -package net.pokeranalytics.android +package net.pokeranalytics.android.filter import androidx.test.ext.junit.runners.AndroidJUnit4 import io.realm.RealmResults -import net.pokeranalytics.android.exceptions.FilterValueMapException import net.pokeranalytics.android.model.filter.FilterManager import net.pokeranalytics.android.model.filter.SessionFilterable import net.pokeranalytics.android.model.realm.Bankroll @@ -13,59 +12,7 @@ import org.junit.runner.RunWith import java.util.* @RunWith(AndroidJUnit4::class) -class FilterInstrumentedUnitTest : RealmInstrumentedUnitTest() { - - // convenience extension - fun Session.Companion.testInstance(netResult: Double, isTournament: Boolean, startDate: Date, endDate: Int, bankroll:Bankroll? = null): Session { - val session: Session = Session.newInstance(super.mockRealm, isTournament, bankroll) - session.result?.netResult = netResult - session.startDate = startDate - val cal = Calendar.getInstance() // creates calendar - cal.time = startDate // sets calendar time/date - cal.add(Calendar.HOUR_OF_DAY, endDate) // adds one hour - session.endDate = cal.time // returns new date object, one hour in the future - return session - } - - @Test(expected = FilterValueMapException::class) - fun testFilterException() { - val realm = this.mockRealm - val sessions = FilterManager().filter( - realm, - Session::class.java, - arrayListOf(SessionFilterable.BLINDS) - ) as RealmResults - } - - @Test(expected = FilterValueMapException::class) - fun testValueKeyFilterException() { - var filter = SessionFilterable.STARTED_FROM_DATE - filter.valueMap = mapOf("bob" to Date()) - - val realm = this.mockRealm - val sessions = FilterManager().filter( - realm, - Session::class.java, - arrayListOf(filter) - ) as RealmResults - } - - @Test(expected = FilterValueMapException::class) - fun testSubValueKeyFilterException() { - var filter = SessionFilterable.BLINDS - filter.valueMap = mapOf("map" to arrayOf(mapOf( - "bob" to 0.5, - "bb" to 1.0, - "code" to null - ))) - - val realm = this.mockRealm - val sessions = FilterManager().filter( - realm, - Session::class.java, - arrayListOf(filter) - ) as RealmResults - } +class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { @Test fun testCashFilter() { @@ -164,125 +111,6 @@ class FilterInstrumentedUnitTest : RealmInstrumentedUnitTest() { } } - @Test - fun testStartedFomDateFilter() { - - val realm = this.mockRealm - realm.beginTransaction() - - val cal = Calendar.getInstance() // creates calendar - cal.time = Date() // sets calendar time/date - val s1 = Session.testInstance(100.0, false, cal.time, 1) - - cal.add(Calendar.HOUR_OF_DAY, 2) // adds one hour - val s2 = Session.testInstance(100.0, true, cal.time, 1) - realm.commitTransaction() - - var filter = SessionFilterable.STARTED_FROM_DATE - filter.valueMap = mapOf("date" to s2.startDate) - - val sessions = FilterManager().filter( - realm, - Session::class.java, - arrayListOf(filter) - ) as RealmResults - - Assert.assertEquals(1, sessions.size) - sessions[0]?.run { - Assert.assertEquals(s2.id, this.id) - } - } - - @Test - fun testStartedToDateFilter() { - - val realm = this.mockRealm - realm.beginTransaction() - - val cal = Calendar.getInstance() // creates calendar - cal.time = Date() // sets calendar time/date - val s1 = Session.testInstance(100.0, false, cal.time, 1) - - cal.add(Calendar.HOUR_OF_DAY, 2) // adds one hour - val s2 = Session.testInstance(100.0, true, cal.time, 1) - - realm.commitTransaction() - - var filter = SessionFilterable.STARTED_TO_DATE - filter.valueMap = mapOf("date" to s1.startDate) - - val sessions = FilterManager().filter( - realm, - Session::class.java, - arrayListOf(filter) - ) as RealmResults - - Assert.assertEquals(1, sessions.size) - sessions[0]?.run { - Assert.assertEquals(s1.id, this.id) - } - } - - @Test - fun testEndedFomDateFilter() { - - val realm = this.mockRealm - realm.beginTransaction() - - val cal = Calendar.getInstance() // creates calendar - cal.time = Date() // sets calendar time/date - val s1 = Session.testInstance(100.0, false, cal.time, 1) - - cal.add(Calendar.HOUR_OF_DAY, 2) // adds one hour - val s2 = Session.testInstance(100.0, true, cal.time, 1) - - realm.commitTransaction() - - var filter = SessionFilterable.ENDED_FROM_DATE - filter.valueMap = mapOf("date" to s2.endDate) - - val sessions = FilterManager().filter( - realm, - Session::class.java, - arrayListOf(filter) - ) as RealmResults - - Assert.assertEquals(1, sessions.size) - sessions[0]?.run { - Assert.assertEquals(s2.id, this.id) - } - } - - @Test - fun testEndedToDateFilter() { - - val realm = this.mockRealm - realm.beginTransaction() - - val cal = Calendar.getInstance() // creates calendar - cal.time = Date() // sets calendar time/date - val s1 = Session.testInstance(100.0, false, cal.time, 1) - - cal.add(Calendar.HOUR_OF_DAY, 2) // adds one hour - val s2 = Session.testInstance(100.0, true, cal.time, 1) - realm.commitTransaction() - - - var filter = SessionFilterable.ENDED_TO_DATE - filter.valueMap = mapOf("date" to s1.endDate) - - val sessions = FilterManager().filter( - realm, - Session::class.java, - arrayListOf(filter) - ) as RealmResults - - Assert.assertEquals(1, sessions.size) - sessions[0]?.run { - Assert.assertEquals(s1.id, this.id) - } - } - @Test fun testSingleBlindNoCurrencyFilter() { diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/FilterComponent.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/FilterComponent.kt index 1dd53f6a..3afd5c87 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/filter/FilterComponent.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/FilterComponent.kt @@ -4,6 +4,7 @@ import io.realm.RealmObject import io.realm.RealmQuery import net.pokeranalytics.android.exceptions.FilterValueMapException import net.pokeranalytics.android.model.realm.Session +import java.time.DayOfWeek import java.util.* @@ -11,6 +12,91 @@ enum class FilterComponent { } +interface TimeFilterable { + + var dayOfWeek : Int? + var month : Int? + var year : Int? + + fun updateTimeParameter(startDate:Date?) { + startDate?.let { + val cal = Calendar.getInstance() + cal.time = it + dayOfWeek = cal.get(Calendar.DAY_OF_WEEK) + month = cal.get(Calendar.MONTH) + year = cal.get(Calendar.YEAR) + } + } +} + +enum class DateFilterable(var fieldName:String? = null) : Filterable { + STARTED_FROM_DATE, + STARTED_TO_DATE, + ENDED_FROM_DATE, + ENDED_TO_DATE, + DAY_OF_WEEK("dayOfWeek"), + MONTH("month"), + YEAR("year"), + WEEK_DAY, + WEEK_END, + ; + + private enum class Field(var fieldName:String) { + START_DATE("startDate"), + END_DATE("endDate"), + } + + override var valueMap : Map? = null + + override val filterValuesExceptedKeys : Array? + get() { + return when (this) { + STARTED_FROM_DATE, STARTED_TO_DATE, ENDED_FROM_DATE, ENDED_TO_DATE -> arrayOf("date") + DAY_OF_WEEK -> arrayOf("dayOfWeek") + MONTH -> arrayOf("month") + YEAR -> arrayOf("year") + else -> null + } + } + + override fun filter(realmQuery: RealmQuery<*>): RealmQuery { + return when (this) { + STARTED_FROM_DATE -> { + val date : Date by filterValues + realmQuery.greaterThanOrEqualTo(Field.START_DATE.fieldName, date) + } + STARTED_TO_DATE -> { + val date : Date by filterValues + realmQuery.lessThanOrEqualTo(Field.START_DATE.fieldName, date) + } + ENDED_FROM_DATE -> { + val date : Date by filterValues + realmQuery.greaterThanOrEqualTo(Field.END_DATE.fieldName, date) + } + ENDED_TO_DATE -> { + val date : Date by filterValues + realmQuery.lessThanOrEqualTo(Field.END_DATE.fieldName, date) + } + DAY_OF_WEEK -> { + val dayOfWeek : Int by filterValues + realmQuery.equalTo(this.fieldName, dayOfWeek) + } + MONTH -> { + val month: Int by filterValues + realmQuery.equalTo(this.fieldName, month) + } + YEAR -> { + val year: Int by filterValues + realmQuery.equalTo(this.fieldName, year) + } + WEEK_END -> { + realmQuery.equalTo(DAY_OF_WEEK.fieldName, Calendar.SATURDAY).or().equalTo(DAY_OF_WEEK.fieldName, Calendar.SUNDAY) + } + WEEK_DAY -> WEEK_END.filter(realmQuery.not()) + } as RealmQuery + } +} + enum class SessionFilterable(var fieldName:String? = null) : Filterable { LIVE("bankroll.live"), CASH("type"), @@ -21,21 +107,17 @@ enum class SessionFilterable(var fieldName:String? = null) : Filterable { LIMIT("limit"), TABLE_SIZE("tableSize"), LOCATION("location.id"), - NUMBEROFTABLE("numberOfTable"), + NUMBER_OF_TABLE("numberOfTable"), COMMENT("comment"), TOURNAMENT_TYPE("tournamentType"), TOURNAMENT_NAME("tournamentName.id"), TOURNAMENT_FEATURES("tournamentFeature.id"), TOURNAMENT_NUMBER_OF_PLAYER("tournamentNumberOfPlayers"), TOURNAMENT_ENTRY_FEE("tournamentEntryFee"), - RESULT_BUYIN("result.buyin"), + RESULT_BUY_IN("result.buyin"), RESULT_CASHED_OUT("result.cashout"), RESULT_NET("result.ratedNet"), RESULT_TIPS("result.tips"), - STARTED_FROM_DATE, - STARTED_TO_DATE, - ENDED_FROM_DATE, - ENDED_TO_DATE, BLINDS, ; @@ -48,33 +130,12 @@ enum class SessionFilterable(var fieldName:String? = null) : Filterable { SMALL_BLIND("cgSmallBlind"); } - private var _valueMap: Map? = null - var valueMap : Map? - get() { - this.valueMapExceptedKeys?.let { valueMapExceptedKeys -> - _valueMap?.let { map -> - println("valueMapExceptedKeys $valueMapExceptedKeys") - println("map.keys $map.keys") - var missingKeys = map.keys.filter { !valueMapExceptedKeys.contains(it) } - println("missingKeys $missingKeys") - if (map.keys.size == valueMapExceptedKeys.size && missingKeys.isNotEmpty()) { - throw FilterValueMapException("valueMap does not contain ${missingKeys}") - } - } ?: run { - throw FilterValueMapException("valueMap null not expected") - } - } - return _valueMap - } - set(value) { - _valueMap = value - } + override var valueMap : Map? = null - private val valueMapExceptedKeys : Array? + override val filterValuesExceptedKeys : Array? get() { return when (this) { BANKROLL -> arrayOf("ids") - STARTED_FROM_DATE, STARTED_TO_DATE, ENDED_FROM_DATE, ENDED_TO_DATE -> arrayOf("date") BLINDS -> arrayOf("map") else -> null } @@ -87,28 +148,11 @@ enum class SessionFilterable(var fieldName:String? = null) : Filterable { ONLINE -> LIVE.filter(realmQuery.not()) TOURNAMENT -> CASH.filter(realmQuery.not()) BANKROLL -> { - val ids : Array by valueMap + val ids : Array by filterValues realmQuery.`in`(this.fieldName, ids) } - STARTED_FROM_DATE -> { - val date : Date by valueMap - realmQuery.greaterThanOrEqualTo(Field.START_DATE.fieldName, date) - } - STARTED_TO_DATE -> { - val date : Date by valueMap - realmQuery.lessThanOrEqualTo(Field.START_DATE.fieldName, date) - } - ENDED_FROM_DATE -> { - val date : Date by valueMap - realmQuery.greaterThanOrEqualTo(Field.END_DATE.fieldName, date) - } - ENDED_TO_DATE -> { - val date : Date by valueMap - realmQuery.lessThanOrEqualTo(Field.END_DATE.fieldName, date) - } - BLINDS -> { - val map : Array> by valueMap + val map : Array> by filterValues var finalQuery = realmQuery val expectedSubKeys = arrayOf("sb", "bb", "code") as Array map.forEachIndexed { index, subMap -> diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/Filterable.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/Filterable.kt index 05ab4baf..ae445f9d 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/filter/Filterable.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/Filterable.kt @@ -4,6 +4,7 @@ import io.realm.Realm import io.realm.RealmObject import io.realm.RealmQuery import io.realm.RealmResults +import net.pokeranalytics.android.exceptions.FilterValueMapException import net.pokeranalytics.android.model.LiveData import net.pokeranalytics.android.model.realm.* @@ -33,10 +34,35 @@ import net.pokeranalytics.android.model.realm.* * */ -interface Filterable { +interface Filterable : ValueFilterable { fun filter(realmQuery: RealmQuery<*>): RealmQuery } +interface ValueFilterable { + + var valueMap: Map? + + var filterValues : Map? + get() { + this.filterValuesExceptedKeys?.let { valueMapExceptedKeys -> + valueMap?.let { map -> + var missingKeys = map.keys.filter { !valueMapExceptedKeys.contains(it) } + if (map.keys.size == valueMapExceptedKeys.size && missingKeys.isNotEmpty()) { + throw FilterValueMapException("valueMap does not contain ${missingKeys}") + } + } ?: run { + throw FilterValueMapException("valueMap null not expected") + } + } + return this.valueMap + } + set(value) { + valueMap = value + } + + val filterValuesExceptedKeys : Array? +} + class FilterManager { fun test(realmResults: RealmResults) { diff --git a/app/src/main/java/net/pokeranalytics/android/model/interfaces/Timed.kt b/app/src/main/java/net/pokeranalytics/android/model/interfaces/Timed.kt index 08316cda..0bb7fc80 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/interfaces/Timed.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/interfaces/Timed.kt @@ -14,7 +14,6 @@ interface Timed { var netDuration: Long - /** * Computes the net netDuration of the session */ diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt index 71a7b45a..ec11040d 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt @@ -17,6 +17,7 @@ import net.pokeranalytics.android.model.TableSize import net.pokeranalytics.android.model.TournamentType import net.pokeranalytics.android.model.extensions.SessionState import net.pokeranalytics.android.model.extensions.getState +import net.pokeranalytics.android.model.filter.TimeFilterable import net.pokeranalytics.android.model.interfaces.Manageable import net.pokeranalytics.android.model.interfaces.Timed import net.pokeranalytics.android.model.utils.SessionSetManager @@ -35,7 +36,7 @@ import java.util.* import java.util.Currency import kotlin.collections.ArrayList -open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource, RowRepresentable, Timed { +open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource, RowRepresentable, Timed, TimeFilterable { enum class Type { CASH_GAME, @@ -69,12 +70,18 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource // Timed interface + override var dayOfWeek : Int? = null + override var month: Int? = null + override var year: Int? = null + /** * The start date of the session */ var startDate: Date? = null set(value) { field = value + + this.updateTimeParameter(field) this.computeNetDuration() this.computeStats() // nullifies endate when setting the start date after the end date From 032c2aa7aecfc0f85ac430e7f738f7611404b20f Mon Sep 17 00:00:00 2001 From: Razmig Sarkissian Date: Tue, 19 Mar 2019 10:23:29 +0100 Subject: [PATCH 14/24] remove warning and clean up files --- .../filter/DateFilterInstrumentedUnitTest.kt | 76 +++---- .../filter/ExceptionFilterInstrumentedTest.kt | 17 +- .../SessionFilterInstrumentedUnitTest.kt | 57 +++--- .../android/model/filter/DateFilterable.kt | 76 +++++++ .../android/model/filter/FilterComponent.kt | 193 ------------------ .../android/model/filter/Filterable.kt | 40 +--- .../android/model/filter/SessionFilterable.kt | 108 ++++++++++ .../model/filter/interfaces/Filterable.kt | 7 + .../model/filter/interfaces/TimeFilterable.kt | 20 ++ .../filter/interfaces/ValueFilterable.kt | 28 +++ .../android/model/realm/Session.kt | 5 +- .../android/ui/fragment/HistoryFragment.kt | 19 -- 12 files changed, 321 insertions(+), 325 deletions(-) create mode 100644 app/src/main/java/net/pokeranalytics/android/model/filter/DateFilterable.kt create mode 100644 app/src/main/java/net/pokeranalytics/android/model/filter/SessionFilterable.kt create mode 100644 app/src/main/java/net/pokeranalytics/android/model/filter/interfaces/Filterable.kt create mode 100644 app/src/main/java/net/pokeranalytics/android/model/filter/interfaces/TimeFilterable.kt create mode 100644 app/src/main/java/net/pokeranalytics/android/model/filter/interfaces/ValueFilterable.kt diff --git a/app/src/androidTest/java/net/pokeranalytics/android/filter/DateFilterInstrumentedUnitTest.kt b/app/src/androidTest/java/net/pokeranalytics/android/filter/DateFilterInstrumentedUnitTest.kt index b8ef64cb..700856ab 100644 --- a/app/src/androidTest/java/net/pokeranalytics/android/filter/DateFilterInstrumentedUnitTest.kt +++ b/app/src/androidTest/java/net/pokeranalytics/android/filter/DateFilterInstrumentedUnitTest.kt @@ -1,7 +1,6 @@ package net.pokeranalytics.android.filter import androidx.test.ext.junit.runners.AndroidJUnit4 -import io.realm.RealmResults import net.pokeranalytics.android.model.filter.DateFilterable import net.pokeranalytics.android.model.filter.FilterManager import net.pokeranalytics.android.model.realm.Session @@ -23,10 +22,10 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { cal.time = Date() // sets calendar time/date val s1 = Session.testInstance(100.0, false, cal.time) cal.add(Calendar.DAY_OF_MONTH, 1) // adds one hour - val s2 = Session.testInstance(100.0, true, cal.time) + Session.testInstance(100.0, true, cal.time) realm.commitTransaction() - var filter = DateFilterable.DAY_OF_WEEK + val filter = DateFilterable.DAY_OF_WEEK cal.time = s1.startDate filter.valueMap = mapOf("dayOfWeek" to cal.get(Calendar.DAY_OF_WEEK)) @@ -34,11 +33,11 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { realm, Session::class.java, arrayListOf(filter) - ) as RealmResults + ) Assert.assertEquals(1, sessions.size) sessions[0]?.run { - Assert.assertEquals(s1.id, this.id) + Assert.assertEquals(s1.id, (this as Session).id) } } @@ -51,10 +50,11 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { cal.time = Date() val s1 = Session.testInstance(100.0, false, cal.time) cal.add(Calendar.MONTH, 1) - val s2 = Session.testInstance(100.0, true, cal.time) + + Session.testInstance(100.0, true, cal.time) realm.commitTransaction() - var filter = DateFilterable.MONTH + val filter = DateFilterable.MONTH cal.time = s1.startDate filter.valueMap = mapOf("month" to cal.get(Calendar.MONTH)) @@ -62,11 +62,11 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { realm, Session::class.java, arrayListOf(filter) - ) as RealmResults + ) Assert.assertEquals(1, sessions.size) sessions[0]?.run { - Assert.assertEquals(s1.id, this.id) + Assert.assertEquals(s1.id, (this as Session).id) } } @@ -79,10 +79,11 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { cal.time = Date() val s1 = Session.testInstance(100.0, false, cal.time) cal.add(Calendar.YEAR, 1) - val s2 = Session.testInstance(100.0, true, cal.time) + + Session.testInstance(100.0, true, cal.time) realm.commitTransaction() - var filter = DateFilterable.YEAR + val filter = DateFilterable.YEAR cal.time = s1.startDate filter.valueMap = mapOf("year" to cal.get(Calendar.YEAR)) @@ -90,11 +91,11 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { realm, Session::class.java, arrayListOf(filter) - ) as RealmResults + ) Assert.assertEquals(1, sessions.size) sessions[0]?.run { - Assert.assertEquals(s1.id, this.id) + Assert.assertEquals(s1.id, (this as Session).id) } } @@ -109,17 +110,18 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { cal.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY) val s1 = Session.testInstance(100.0, false, cal.time) cal.set(Calendar.DAY_OF_WEEK, Calendar.TUESDAY) - val s2 = Session.testInstance(100.0, true, cal.time) + + Session.testInstance(100.0, true, cal.time) realm.commitTransaction() val sessions = FilterManager().filter( realm, Session::class.java, arrayListOf(DateFilterable.WEEK_END) - ) as RealmResults + ) Assert.assertEquals(1, sessions.size) sessions[0]?.run { - Assert.assertEquals(s1.id, this.id) + Assert.assertEquals(s1.id, (this as Session).id) } } @@ -133,17 +135,18 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY) val s1 = Session.testInstance(100.0, false, cal.time) cal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY) - val s2 = Session.testInstance(100.0, true, cal.time) + + Session.testInstance(100.0, true, cal.time) realm.commitTransaction() val sessions = FilterManager().filter( realm, Session::class.java, arrayListOf(DateFilterable.WEEK_DAY) - ) as RealmResults + ) Assert.assertEquals(1, sessions.size) sessions[0]?.run { - Assert.assertEquals(s1.id, this.id) + Assert.assertEquals(s1.id, (this as Session).id) } } @@ -155,24 +158,25 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { val cal = Calendar.getInstance() // creates calendar cal.time = Date() // sets calendar time/date - val s1 = Session.testInstance(100.0, false, cal.time, 1) + + Session.testInstance(100.0, false, cal.time, 1) cal.add(Calendar.HOUR_OF_DAY, 2) // adds one hour val s2 = Session.testInstance(100.0, true, cal.time, 1) realm.commitTransaction() - var filter = DateFilterable.STARTED_FROM_DATE + val filter = DateFilterable.STARTED_FROM_DATE filter.valueMap = mapOf("date" to s2.startDate) val sessions = FilterManager().filter( realm, Session::class.java, arrayListOf(filter) - ) as RealmResults + ) Assert.assertEquals(1, sessions.size) sessions[0]?.run { - Assert.assertEquals(s2.id, this.id) + Assert.assertEquals(s2.id, (this as Session).id) } } @@ -187,22 +191,22 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { val s1 = Session.testInstance(100.0, false, cal.time, 1) cal.add(Calendar.HOUR_OF_DAY, 2) // adds one hour - val s2 = Session.testInstance(100.0, true, cal.time, 1) + Session.testInstance(100.0, true, cal.time, 1) realm.commitTransaction() - var filter = DateFilterable.STARTED_TO_DATE + val filter = DateFilterable.STARTED_TO_DATE filter.valueMap = mapOf("date" to s1.startDate) val sessions = FilterManager().filter( realm, Session::class.java, arrayListOf(filter) - ) as RealmResults + ) Assert.assertEquals(1, sessions.size) sessions[0]?.run { - Assert.assertEquals(s1.id, this.id) + Assert.assertEquals(s1.id, (this as Session).id) } } @@ -214,25 +218,26 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { val cal = Calendar.getInstance() // creates calendar cal.time = Date() // sets calendar time/date - val s1 = Session.testInstance(100.0, false, cal.time, 1) + + Session.testInstance(100.0, false, cal.time, 1) cal.add(Calendar.HOUR_OF_DAY, 2) // adds one hour val s2 = Session.testInstance(100.0, true, cal.time, 1) realm.commitTransaction() - var filter = DateFilterable.ENDED_FROM_DATE + val filter = DateFilterable.ENDED_FROM_DATE filter.valueMap = mapOf("date" to s2.endDate) val sessions = FilterManager().filter( realm, Session::class.java, arrayListOf(filter) - ) as RealmResults + ) Assert.assertEquals(1, sessions.size) sessions[0]?.run { - Assert.assertEquals(s2.id, this.id) + Assert.assertEquals(s2.id, (this as Session).id) } } @@ -247,22 +252,23 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { val s1 = Session.testInstance(100.0, false, cal.time, 1) cal.add(Calendar.HOUR_OF_DAY, 2) // adds one hour - val s2 = Session.testInstance(100.0, true, cal.time, 1) + + Session.testInstance(100.0, true, cal.time, 1) realm.commitTransaction() - var filter = DateFilterable.ENDED_TO_DATE + val filter = DateFilterable.ENDED_TO_DATE filter.valueMap = mapOf("date" to s1.endDate) val sessions = FilterManager().filter( realm, Session::class.java, arrayListOf(filter) - ) as RealmResults + ) Assert.assertEquals(1, sessions.size) sessions[0]?.run { - Assert.assertEquals(s1.id, this.id) + Assert.assertEquals(s1.id, (this as Session).id) } } } \ No newline at end of file diff --git a/app/src/androidTest/java/net/pokeranalytics/android/filter/ExceptionFilterInstrumentedTest.kt b/app/src/androidTest/java/net/pokeranalytics/android/filter/ExceptionFilterInstrumentedTest.kt index 84bc396c..bc453c26 100644 --- a/app/src/androidTest/java/net/pokeranalytics/android/filter/ExceptionFilterInstrumentedTest.kt +++ b/app/src/androidTest/java/net/pokeranalytics/android/filter/ExceptionFilterInstrumentedTest.kt @@ -1,7 +1,6 @@ package net.pokeranalytics.android.filter import androidx.test.ext.junit.runners.AndroidJUnit4 -import io.realm.RealmResults import net.pokeranalytics.android.exceptions.FilterValueMapException import net.pokeranalytics.android.model.filter.DateFilterable import net.pokeranalytics.android.model.filter.FilterManager @@ -17,29 +16,29 @@ class ExceptionFilterInstrumentedTest: BaseFilterInstrumentedUnitTest() { @Test(expected = FilterValueMapException::class) fun testFilterException() { val realm = this.mockRealm - val sessions = FilterManager().filter( + FilterManager().filter( realm, Session::class.java, arrayListOf(SessionFilterable.BLINDS) - ) as RealmResults + ) } @Test(expected = FilterValueMapException::class) fun testValueKeyFilterException() { - var filter = DateFilterable.STARTED_FROM_DATE + val filter = DateFilterable.STARTED_FROM_DATE filter.valueMap = mapOf("bob" to Date()) val realm = this.mockRealm - val sessions = FilterManager().filter( + FilterManager().filter( realm, Session::class.java, arrayListOf(filter) - ) as RealmResults + ) } @Test(expected = FilterValueMapException::class) fun testSubValueKeyFilterException() { - var filter = SessionFilterable.BLINDS + val filter = SessionFilterable.BLINDS filter.valueMap = mapOf("map" to arrayOf(mapOf( "bob" to 0.5, "bb" to 1.0, @@ -47,10 +46,10 @@ class ExceptionFilterInstrumentedTest: BaseFilterInstrumentedUnitTest() { ))) val realm = this.mockRealm - val sessions = FilterManager().filter( + FilterManager().filter( realm, Session::class.java, arrayListOf(filter) - ) as RealmResults + ) } } \ No newline at end of file diff --git a/app/src/androidTest/java/net/pokeranalytics/android/filter/SessionFilterInstrumentedUnitTest.kt b/app/src/androidTest/java/net/pokeranalytics/android/filter/SessionFilterInstrumentedUnitTest.kt index eb478b82..fe8263b1 100644 --- a/app/src/androidTest/java/net/pokeranalytics/android/filter/SessionFilterInstrumentedUnitTest.kt +++ b/app/src/androidTest/java/net/pokeranalytics/android/filter/SessionFilterInstrumentedUnitTest.kt @@ -1,7 +1,6 @@ package net.pokeranalytics.android.filter import androidx.test.ext.junit.runners.AndroidJUnit4 -import io.realm.RealmResults import net.pokeranalytics.android.model.filter.FilterManager import net.pokeranalytics.android.model.filter.SessionFilterable import net.pokeranalytics.android.model.realm.Bankroll @@ -20,19 +19,19 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { val realm = this.mockRealm realm.beginTransaction() - val s1 = Session.testInstance(100.0, false, Date(), 1) - val s2 = Session.testInstance(100.0, true, Date(), 1) + Session.testInstance(100.0, false, Date(), 1) + Session.testInstance(100.0, true, Date(), 1) realm.commitTransaction() val sessions = FilterManager().filter( realm, Session::class.java, arrayListOf(SessionFilterable.CASH) - ) as RealmResults + ) Assert.assertEquals(1, sessions.size) sessions[0]?.run { - Assert.assertEquals(Session.Type.CASH_GAME.ordinal, this.type) + Assert.assertEquals(Session.Type.CASH_GAME.ordinal, (this as Session).type) } } @@ -42,19 +41,19 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { val realm = this.mockRealm realm.beginTransaction() - val s1 = Session.testInstance(100.0, false, Date(), 1) - val s2 = Session.testInstance(100.0, true, Date(), 1) + Session.testInstance(100.0, false, Date(), 1) + Session.testInstance(100.0, true, Date(), 1) realm.commitTransaction() val sessions = FilterManager().filter( realm, Session::class.java, arrayListOf(SessionFilterable.TOURNAMENT) - ) as RealmResults + ) Assert.assertEquals(1, sessions.size) sessions[0]?.run { - Assert.assertEquals(Session.Type.TOURNAMENT.ordinal, this.type) + Assert.assertEquals(Session.Type.TOURNAMENT.ordinal, (this as Session).type) } } @@ -69,18 +68,18 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { b1.live = true b2.live = false - val s1 = Session.testInstance(100.0, false, Date(), 1, b1) - val s2 = Session.testInstance(100.0, true, Date(), 1, b2) + Session.testInstance(100.0, false, Date(), 1, b1) + Session.testInstance(100.0, true, Date(), 1, b2) realm.commitTransaction() val sessions = FilterManager().filter( realm, Session::class.java, arrayListOf(SessionFilterable.LIVE) - ) as RealmResults + ) Assert.assertEquals(1, sessions.size) - sessions[0]?.bankroll?.run { + (sessions[0] as Session).bankroll?.run { Assert.assertEquals(true, this.live) } } @@ -95,18 +94,18 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { b1.live = false b2.live = true - val s1 = Session.testInstance(100.0, false, Date(), 1, b1) - val s2 = Session.testInstance(100.0, true, Date(), 1, b2) + Session.testInstance(100.0, false, Date(), 1, b1) + Session.testInstance(100.0, true, Date(), 1, b2) realm.commitTransaction() val sessions = FilterManager().filter( realm, Session::class.java, arrayListOf(SessionFilterable.ONLINE) - ) as RealmResults + ) Assert.assertEquals(1, sessions.size) - sessions[0]?.bankroll?.run { + (sessions[0] as Session).bankroll?.run { Assert.assertEquals(false, this.live) } } @@ -139,7 +138,7 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { realm.commitTransaction() - var filter = SessionFilterable.BLINDS + val filter = SessionFilterable.BLINDS filter.valueMap = mapOf("map" to arrayOf(mapOf( "sb" to 0.5, "bb" to 1.0, @@ -150,11 +149,11 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { realm, Session::class.java, arrayListOf(filter) - ) as RealmResults + ) Assert.assertEquals(2, sessions.size) sessions.map { - Assert.assertTrue(arrayListOf(s1.id, s2.id).contains(it.id)) + Assert.assertTrue(arrayListOf(s1.id, s2.id).contains((it as Session).id)) } } @@ -186,7 +185,7 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { realm.commitTransaction() - var filter = SessionFilterable.BLINDS + val filter = SessionFilterable.BLINDS filter.valueMap = mapOf("map" to arrayOf(mapOf( "sb" to null, "bb" to 1.0, @@ -197,11 +196,11 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { realm, Session::class.java, arrayListOf(filter) - ) as RealmResults + ) Assert.assertEquals(2, sessions.size) sessions.map { - Assert.assertTrue(arrayListOf(s1.id, s2.id).contains(it.id)) + Assert.assertTrue(arrayListOf(s1.id, s2.id).contains((it as Session).id)) } } @@ -233,7 +232,7 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { realm.commitTransaction() - var filter = SessionFilterable.BLINDS + val filter = SessionFilterable.BLINDS filter.valueMap = mapOf("map" to arrayOf(mapOf( "sb" to 1.0, "bb" to 2.0, @@ -244,11 +243,11 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { realm, Session::class.java, arrayListOf(filter) - ) as RealmResults + ) Assert.assertEquals(1, sessions.size) sessions.map { - Assert.assertEquals(s3.id, it.id) + Assert.assertEquals(s3.id, (it as Session).id) } } @@ -280,7 +279,7 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { realm.commitTransaction() - var filter = SessionFilterable.BLINDS + val filter = SessionFilterable.BLINDS filter.valueMap = mapOf("map" to arrayOf( mapOf( "sb" to 1.0, @@ -297,11 +296,11 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { realm, Session::class.java, arrayListOf(filter) - ) as RealmResults + ) Assert.assertEquals(2, sessions.size) sessions.map { - Assert.assertTrue(arrayListOf(s1.id, s2.id).contains(it.id)) + Assert.assertTrue(arrayListOf(s1.id, s2.id).contains((it as Session).id)) } } } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/DateFilterable.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/DateFilterable.kt new file mode 100644 index 00000000..8d11541f --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/DateFilterable.kt @@ -0,0 +1,76 @@ +package net.pokeranalytics.android.model.filter + +import io.realm.RealmQuery +import net.pokeranalytics.android.model.filter.interfaces.Filterable +import java.util.* + +enum class DateFilterable : Filterable { + STARTED_FROM_DATE, + STARTED_TO_DATE, + ENDED_FROM_DATE, + ENDED_TO_DATE, + DAY_OF_WEEK, + MONTH, + YEAR, + WEEK_DAY, + WEEK_END, + ; + + private enum class Field(var fieldName:String) { + START_DATE("startDate"), + END_DATE("endDate"), + DAY("dayOfWeek"), + MONTH("month"), + YEAR("year"), + } + + override var valueMap : Map? = null + + override val filterValuesExceptedKeys : Array? + get() { + return when (this) { + STARTED_FROM_DATE, STARTED_TO_DATE, ENDED_FROM_DATE, ENDED_TO_DATE -> arrayOf("date") + DAY_OF_WEEK -> arrayOf("dayOfWeek") + MONTH -> arrayOf("month") + YEAR -> arrayOf("year") + else -> null + } + } + + override fun filter(realmQuery: RealmQuery<*>): RealmQuery<*> { + return when (this) { + STARTED_FROM_DATE -> { + val date : Date by filterValues + realmQuery.greaterThanOrEqualTo(Field.START_DATE.fieldName, date) + } + STARTED_TO_DATE -> { + val date : Date by filterValues + realmQuery.lessThanOrEqualTo(Field.START_DATE.fieldName, date) + } + ENDED_FROM_DATE -> { + val date : Date by filterValues + realmQuery.greaterThanOrEqualTo(Field.END_DATE.fieldName, date) + } + ENDED_TO_DATE -> { + val date : Date by filterValues + realmQuery.lessThanOrEqualTo(Field.END_DATE.fieldName, date) + } + DAY_OF_WEEK -> { + val dayOfWeek : Int by filterValues + realmQuery.equalTo(Field.DAY.fieldName, dayOfWeek) + } + MONTH -> { + val month: Int by filterValues + realmQuery.equalTo(Field.MONTH.fieldName, month) + } + YEAR -> { + val year: Int by filterValues + realmQuery.equalTo(Field.YEAR.fieldName, year) + } + WEEK_END -> { + realmQuery.`in`(Field.DAY.fieldName, arrayOf(Calendar.SATURDAY,Calendar.SUNDAY)) + } + WEEK_DAY -> WEEK_END.filter(realmQuery.not()) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/FilterComponent.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/FilterComponent.kt index 3afd5c87..094521d0 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/filter/FilterComponent.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/FilterComponent.kt @@ -1,198 +1,5 @@ package net.pokeranalytics.android.model.filter -import io.realm.RealmObject -import io.realm.RealmQuery -import net.pokeranalytics.android.exceptions.FilterValueMapException -import net.pokeranalytics.android.model.realm.Session -import java.time.DayOfWeek -import java.util.* - - enum class FilterComponent { -} - -interface TimeFilterable { - - var dayOfWeek : Int? - var month : Int? - var year : Int? - - fun updateTimeParameter(startDate:Date?) { - startDate?.let { - val cal = Calendar.getInstance() - cal.time = it - dayOfWeek = cal.get(Calendar.DAY_OF_WEEK) - month = cal.get(Calendar.MONTH) - year = cal.get(Calendar.YEAR) - } - } -} - -enum class DateFilterable(var fieldName:String? = null) : Filterable { - STARTED_FROM_DATE, - STARTED_TO_DATE, - ENDED_FROM_DATE, - ENDED_TO_DATE, - DAY_OF_WEEK("dayOfWeek"), - MONTH("month"), - YEAR("year"), - WEEK_DAY, - WEEK_END, - ; - - private enum class Field(var fieldName:String) { - START_DATE("startDate"), - END_DATE("endDate"), - } - - override var valueMap : Map? = null - - override val filterValuesExceptedKeys : Array? - get() { - return when (this) { - STARTED_FROM_DATE, STARTED_TO_DATE, ENDED_FROM_DATE, ENDED_TO_DATE -> arrayOf("date") - DAY_OF_WEEK -> arrayOf("dayOfWeek") - MONTH -> arrayOf("month") - YEAR -> arrayOf("year") - else -> null - } - } - - override fun filter(realmQuery: RealmQuery<*>): RealmQuery { - return when (this) { - STARTED_FROM_DATE -> { - val date : Date by filterValues - realmQuery.greaterThanOrEqualTo(Field.START_DATE.fieldName, date) - } - STARTED_TO_DATE -> { - val date : Date by filterValues - realmQuery.lessThanOrEqualTo(Field.START_DATE.fieldName, date) - } - ENDED_FROM_DATE -> { - val date : Date by filterValues - realmQuery.greaterThanOrEqualTo(Field.END_DATE.fieldName, date) - } - ENDED_TO_DATE -> { - val date : Date by filterValues - realmQuery.lessThanOrEqualTo(Field.END_DATE.fieldName, date) - } - DAY_OF_WEEK -> { - val dayOfWeek : Int by filterValues - realmQuery.equalTo(this.fieldName, dayOfWeek) - } - MONTH -> { - val month: Int by filterValues - realmQuery.equalTo(this.fieldName, month) - } - YEAR -> { - val year: Int by filterValues - realmQuery.equalTo(this.fieldName, year) - } - WEEK_END -> { - realmQuery.equalTo(DAY_OF_WEEK.fieldName, Calendar.SATURDAY).or().equalTo(DAY_OF_WEEK.fieldName, Calendar.SUNDAY) - } - WEEK_DAY -> WEEK_END.filter(realmQuery.not()) - } as RealmQuery - } -} - -enum class SessionFilterable(var fieldName:String? = null) : Filterable { - LIVE("bankroll.live"), - CASH("type"), - ONLINE, - TOURNAMENT, - BANKROLL("bankroll.id"), - GAME("game.id"), - LIMIT("limit"), - TABLE_SIZE("tableSize"), - LOCATION("location.id"), - NUMBER_OF_TABLE("numberOfTable"), - COMMENT("comment"), - TOURNAMENT_TYPE("tournamentType"), - TOURNAMENT_NAME("tournamentName.id"), - TOURNAMENT_FEATURES("tournamentFeature.id"), - TOURNAMENT_NUMBER_OF_PLAYER("tournamentNumberOfPlayers"), - TOURNAMENT_ENTRY_FEE("tournamentEntryFee"), - RESULT_BUY_IN("result.buyin"), - RESULT_CASHED_OUT("result.cashout"), - RESULT_NET("result.ratedNet"), - RESULT_TIPS("result.tips"), - BLINDS, - ; - - private enum class Field(var fieldName:String) { - START_DATE("startDate"), - END_DATE("endDate"), - CURRENCY("bankroll.currency"), - CURRENCY_CODE("bankroll.currency.code"), - BIG_BLIND("cgBigBlind"), - SMALL_BLIND("cgSmallBlind"); - } - - override var valueMap : Map? = null - - override val filterValuesExceptedKeys : Array? - get() { - return when (this) { - BANKROLL -> arrayOf("ids") - BLINDS -> arrayOf("map") - else -> null - } - } - - override fun filter(realmQuery: RealmQuery<*>): RealmQuery { - return when (this) { - LIVE -> realmQuery.equalTo(this.fieldName, true) - CASH -> realmQuery.equalTo(this.fieldName, Session.Type.CASH_GAME.ordinal) - ONLINE -> LIVE.filter(realmQuery.not()) - TOURNAMENT -> CASH.filter(realmQuery.not()) - BANKROLL -> { - val ids : Array by filterValues - realmQuery.`in`(this.fieldName, ids) - } - BLINDS -> { - val map : Array> by filterValues - var finalQuery = realmQuery - val expectedSubKeys = arrayOf("sb", "bb", "code") as Array - map.forEachIndexed { index, subMap -> - var missingKeys = subMap.keys.filter { !expectedSubKeys.contains(it) } - if (subMap.keys.size == expectedSubKeys.size && missingKeys.isNotEmpty()) { - throw FilterValueMapException("subValueMap does not contain ${missingKeys}") - } - - val sb : Double? by subMap - val bb : Double? by subMap - val code : String? by subMap - - finalQuery - .beginGroup() - - sb?.let { - finalQuery - .equalTo(Field.SMALL_BLIND.fieldName, sb) - .and() - } - - finalQuery - .equalTo(Field.BIG_BLIND.fieldName, bb) - .and() - - code?.let { - finalQuery.equalTo(Field.CURRENCY_CODE.fieldName, code) - } ?: run { - finalQuery.isNull(Field.CURRENCY_CODE.fieldName) - } - - finalQuery.endGroup() - - if (index < map.size - 1) { - finalQuery.or() - } - } - finalQuery - } - else -> realmQuery - } as RealmQuery - } } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/Filterable.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/Filterable.kt index ae445f9d..36cf67bd 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/filter/Filterable.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/Filterable.kt @@ -4,9 +4,7 @@ import io.realm.Realm import io.realm.RealmObject import io.realm.RealmQuery import io.realm.RealmResults -import net.pokeranalytics.android.exceptions.FilterValueMapException -import net.pokeranalytics.android.model.LiveData -import net.pokeranalytics.android.model.realm.* +import net.pokeranalytics.android.model.filter.interfaces.Filterable /** * We want to be able to store filters in the database: @@ -34,45 +32,11 @@ import net.pokeranalytics.android.model.realm.* * */ -interface Filterable : ValueFilterable { - fun filter(realmQuery: RealmQuery<*>): RealmQuery -} - -interface ValueFilterable { - - var valueMap: Map? - - var filterValues : Map? - get() { - this.filterValuesExceptedKeys?.let { valueMapExceptedKeys -> - valueMap?.let { map -> - var missingKeys = map.keys.filter { !valueMapExceptedKeys.contains(it) } - if (map.keys.size == valueMapExceptedKeys.size && missingKeys.isNotEmpty()) { - throw FilterValueMapException("valueMap does not contain ${missingKeys}") - } - } ?: run { - throw FilterValueMapException("valueMap null not expected") - } - } - return this.valueMap - } - set(value) { - valueMap = value - } - - val filterValuesExceptedKeys : Array? -} - class FilterManager { - - fun test(realmResults: RealmResults) { - realmResults.where().greaterThan("test", 5).findAll() - } - fun filter(realm:Realm, relatedEntity: Class, queries:List): RealmResults<*> { var realmQuery = realm.where(relatedEntity) queries.forEach { - realmQuery = it.filter(realmQuery).and() + realmQuery = (it.filter(realmQuery) as RealmQuery).and() } return realmQuery.findAll() } diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/SessionFilterable.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/SessionFilterable.kt new file mode 100644 index 00000000..bc4e452a --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/SessionFilterable.kt @@ -0,0 +1,108 @@ +package net.pokeranalytics.android.model.filter + +import io.realm.RealmQuery +import net.pokeranalytics.android.exceptions.FilterValueMapException +import net.pokeranalytics.android.model.filter.interfaces.Filterable +import net.pokeranalytics.android.model.realm.Session + +enum class SessionFilterable: Filterable { + LIVE, + CASH, + ONLINE, + TOURNAMENT, + BANKROLL, + BLINDS, + ; + + private enum class Field(var fieldName:String) { + LIVE("bankroll.live"), + CASH("type"), + BANKROLL("bankroll.id"), + START_DATE("startDate"), + END_DATE("endDate"), + CURRENCY("bankroll.currency"), + CURRENCY_CODE("bankroll.currency.code"), + BIG_BLIND("cgBigBlind"), + SMALL_BLIND("cgSmallBlind"), + GAME("game.id"), + LIMIT("limit"), + TABLE_SIZE("tableSize"), + LOCATION("location.id"), + NUMBER_OF_TABLE("numberOfTable"), + COMMENT("comment"), + TOURNAMENT_TYPE("tournamentType"), + TOURNAMENT_NAME("tournamentName.id"), + TOURNAMENT_FEATURES("tournamentFeature.id"), + TOURNAMENT_NUMBER_OF_PLAYER("tournamentNumberOfPlayers"), + TOURNAMENT_ENTRY_FEE("tournamentEntryFee"), + RESULT_BUY_IN("result.buyin"), + RESULT_CASHED_OUT("result.cashout"), + RESULT_NET("result.ratedNet"), + RESULT_TIPS("result.tips"), + ; + } + + override var valueMap : Map? = null + + override val filterValuesExceptedKeys : Array? + get() { + return when (this) { + BANKROLL -> arrayOf("ids") + BLINDS -> arrayOf("map") + else -> null + } + } + + override fun filter(realmQuery: RealmQuery<*>): RealmQuery<*> { + return when (this) { + LIVE -> realmQuery.equalTo(Field.LIVE.fieldName, true) + CASH -> realmQuery.equalTo(Field.CASH.fieldName, Session.Type.CASH_GAME.ordinal) + ONLINE -> LIVE.filter(realmQuery.not()) + TOURNAMENT -> CASH.filter(realmQuery.not()) + BANKROLL -> { + val ids : Array by filterValues + realmQuery.`in`(Field.BANKROLL.fieldName, ids) + } + BLINDS -> { + val map : Array> by filterValues + val expectedSubKeys = arrayOf("sb", "bb", "code") + map.forEachIndexed { index, subMap -> + val missingKeys = subMap.keys.filter { !expectedSubKeys.contains(it) } + if (subMap.keys.size == expectedSubKeys.size && missingKeys.isNotEmpty()) { + throw FilterValueMapException("subValueMap does not contain $missingKeys") + } + + val sb : Double? by subMap + val bb : Double? by subMap + val code : String? by subMap + + realmQuery + .beginGroup() + + sb?.let { + realmQuery + .equalTo(Field.SMALL_BLIND.fieldName, sb) + .and() + } + + realmQuery + .equalTo(Field.BIG_BLIND.fieldName, bb) + .and() + + code?.let { + realmQuery.equalTo(Field.CURRENCY_CODE.fieldName, code) + } ?: run { + realmQuery.isNull(Field.CURRENCY_CODE.fieldName) + } + + realmQuery.endGroup() + + if (index < map.size - 1) { + realmQuery.or() + } + } + realmQuery + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/interfaces/Filterable.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/interfaces/Filterable.kt new file mode 100644 index 00000000..ca5ed70c --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/interfaces/Filterable.kt @@ -0,0 +1,7 @@ +package net.pokeranalytics.android.model.filter.interfaces + +import io.realm.RealmQuery + +interface Filterable : ValueFilterable { + fun filter(realmQuery: RealmQuery<*>): RealmQuery<*> +} diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/interfaces/TimeFilterable.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/interfaces/TimeFilterable.kt new file mode 100644 index 00000000..f900d86d --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/interfaces/TimeFilterable.kt @@ -0,0 +1,20 @@ +package net.pokeranalytics.android.model.filter.interfaces + +import java.util.* + +interface TimeFilterable { + + var dayOfWeek : Int? + var month : Int? + var year : Int? + + fun updateTimeParameter(startDate: Date?) { + startDate?.let { + val cal = Calendar.getInstance() + cal.time = it + dayOfWeek = cal.get(Calendar.DAY_OF_WEEK) + month = cal.get(Calendar.MONTH) + year = cal.get(Calendar.YEAR) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/interfaces/ValueFilterable.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/interfaces/ValueFilterable.kt new file mode 100644 index 00000000..451b2c30 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/interfaces/ValueFilterable.kt @@ -0,0 +1,28 @@ +package net.pokeranalytics.android.model.filter.interfaces + +import net.pokeranalytics.android.exceptions.FilterValueMapException + +interface ValueFilterable { + + var valueMap: Map? + + var filterValues : Map? + get() { + this.filterValuesExceptedKeys?.let { valueMapExceptedKeys -> + valueMap?.let { map -> + var missingKeys = map.keys.filter { !valueMapExceptedKeys.contains(it) } + if (map.keys.size == valueMapExceptedKeys.size && missingKeys.isNotEmpty()) { + throw FilterValueMapException("valueMap does not contain ${missingKeys}") + } + } ?: run { + throw FilterValueMapException("valueMap null not expected") + } + } + return this.valueMap + } + set(value) { + valueMap = value + } + + val filterValuesExceptedKeys : Array? +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt index ec11040d..56880bed 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt @@ -17,7 +17,7 @@ import net.pokeranalytics.android.model.TableSize import net.pokeranalytics.android.model.TournamentType import net.pokeranalytics.android.model.extensions.SessionState import net.pokeranalytics.android.model.extensions.getState -import net.pokeranalytics.android.model.filter.TimeFilterable +import net.pokeranalytics.android.model.filter.interfaces.TimeFilterable import net.pokeranalytics.android.model.interfaces.Manageable import net.pokeranalytics.android.model.interfaces.Timed import net.pokeranalytics.android.model.utils.SessionSetManager @@ -36,7 +36,8 @@ import java.util.* import java.util.Currency import kotlin.collections.ArrayList -open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource, RowRepresentable, Timed, TimeFilterable { +open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource, RowRepresentable, Timed, + TimeFilterable { enum class Type { CASH_GAME, diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/HistoryFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/HistoryFragment.kt index 0bcedc4f..175adfc9 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/HistoryFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/HistoryFragment.kt @@ -5,7 +5,6 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.core.view.isVisible -import androidx.lifecycle.LiveData import androidx.recyclerview.widget.DiffUtil import io.realm.RealmResults import io.realm.Sort @@ -14,11 +13,7 @@ import kotlinx.android.synthetic.main.fragment_history.* import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import net.pokeranalytics.android.R -import net.pokeranalytics.android.model.filter.FilterManager -import net.pokeranalytics.android.model.filter.Filterable -import net.pokeranalytics.android.model.filter.SessionFilterable import net.pokeranalytics.android.model.interfaces.Manageable -import net.pokeranalytics.android.model.realm.Bankroll import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.ui.activity.SessionActivity import net.pokeranalytics.android.ui.adapter.LiveRowRepresentableDataSource @@ -97,20 +92,6 @@ class HistoryFragment : PokerAnalyticsFragment(), LiveRowRepresentableDataSource * Init data */ private fun initData() { - -/* - var brs = (net.pokeranalytics.android.model.LiveData.BANKROLL.items(getRealm()) as RealmResults).toArray().map{ - (it as Bankroll).id - } - - var br = SessionFilterable.BANKROLL - br.valueMap = mapOf("ids" to arrayOf(brs.last())) - - realmSessions = FilterManager().filter(getRealm(), Session::class.java, arrayListOf(br)) - .sort("creationDate", Sort.DESCENDING) as RealmResults - -// realmSessions = FilterManager().filter(getRealm(), Session::class.java, arrayListOf(SessionFilterable.ONLINE, SessionFilterable.CASH)).sort("creationDate", Sort.DESCENDING) as RealmResults -*/ realmSessions = getRealm().where().findAll().sort("creationDate", Sort.DESCENDING) val viewManager = SmoothScrollLinearLayoutManager(requireContext()) From 41de2d537023834b164bdf2f99d3ff514520d3eb Mon Sep 17 00:00:00 2001 From: Razmig Sarkissian Date: Tue, 19 Mar 2019 10:31:33 +0100 Subject: [PATCH 15/24] update filter interface signature --- .../net/pokeranalytics/android/model/filter/DateFilterable.kt | 3 ++- .../net/pokeranalytics/android/model/filter/Filterable.kt | 4 ++-- .../pokeranalytics/android/model/filter/SessionFilterable.kt | 3 ++- .../android/model/filter/interfaces/Filterable.kt | 3 ++- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/DateFilterable.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/DateFilterable.kt index 8d11541f..b2cad68a 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/filter/DateFilterable.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/DateFilterable.kt @@ -1,5 +1,6 @@ package net.pokeranalytics.android.model.filter +import io.realm.RealmObject import io.realm.RealmQuery import net.pokeranalytics.android.model.filter.interfaces.Filterable import java.util.* @@ -37,7 +38,7 @@ enum class DateFilterable : Filterable { } } - override fun filter(realmQuery: RealmQuery<*>): RealmQuery<*> { + override fun filter(realmQuery: RealmQuery): RealmQuery { return when (this) { STARTED_FROM_DATE -> { val date : Date by filterValues diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/Filterable.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/Filterable.kt index 36cf67bd..bfac5991 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/filter/Filterable.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/Filterable.kt @@ -34,9 +34,9 @@ import net.pokeranalytics.android.model.filter.interfaces.Filterable class FilterManager { fun filter(realm:Realm, relatedEntity: Class, queries:List): RealmResults<*> { - var realmQuery = realm.where(relatedEntity) + var realmQuery : RealmQuery = realm.where(relatedEntity) queries.forEach { - realmQuery = (it.filter(realmQuery) as RealmQuery).and() + realmQuery = (it.filter(realmQuery)).and() } return realmQuery.findAll() } diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/SessionFilterable.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/SessionFilterable.kt index bc4e452a..332a8c0c 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/filter/SessionFilterable.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/SessionFilterable.kt @@ -1,5 +1,6 @@ package net.pokeranalytics.android.model.filter +import io.realm.RealmObject import io.realm.RealmQuery import net.pokeranalytics.android.exceptions.FilterValueMapException import net.pokeranalytics.android.model.filter.interfaces.Filterable @@ -53,7 +54,7 @@ enum class SessionFilterable: Filterable { } } - override fun filter(realmQuery: RealmQuery<*>): RealmQuery<*> { + override fun filter(realmQuery: RealmQuery): RealmQuery { return when (this) { LIVE -> realmQuery.equalTo(Field.LIVE.fieldName, true) CASH -> realmQuery.equalTo(Field.CASH.fieldName, Session.Type.CASH_GAME.ordinal) diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/interfaces/Filterable.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/interfaces/Filterable.kt index ca5ed70c..509ee118 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/filter/interfaces/Filterable.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/interfaces/Filterable.kt @@ -1,7 +1,8 @@ package net.pokeranalytics.android.model.filter.interfaces +import io.realm.RealmObject import io.realm.RealmQuery interface Filterable : ValueFilterable { - fun filter(realmQuery: RealmQuery<*>): RealmQuery<*> + fun filter(realmQuery: RealmQuery): RealmQuery } From c2216ddf628d966a7bbe86f4519cc7e55fb05d6c Mon Sep 17 00:00:00 2001 From: Aurelien Hubert Date: Tue, 19 Mar 2019 10:56:44 +0100 Subject: [PATCH 16/24] Clean code --- .../android/ui/view/rowrepresentable/SessionRow.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SessionRow.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SessionRow.kt index 094f9bd6..c3aca78c 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SessionRow.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SessionRow.kt @@ -6,7 +6,6 @@ import net.pokeranalytics.android.R import net.pokeranalytics.android.model.TournamentType import net.pokeranalytics.android.model.extensions.SessionState import net.pokeranalytics.android.model.extensions.getState -import net.pokeranalytics.android.model.realm.Game import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType import net.pokeranalytics.android.ui.view.RowRepresentable @@ -277,8 +276,6 @@ enum class SessionRow : RowRepresentable { } else -> null } - - - } + } \ No newline at end of file From 68c855e8253672eb8625d1bc79865eda817b3682 Mon Sep 17 00:00:00 2001 From: Aurelien Hubert Date: Tue, 19 Mar 2019 10:57:03 +0100 Subject: [PATCH 17/24] Improve style --- app/src/main/res/values/styles.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 8a13e62f..b9faf4be 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -185,7 +185,7 @@ From be4c4bd306a6fd1490446b8c1f9282ce0f3d5402 Mon Sep 17 00:00:00 2001 From: Aurelien Hubert Date: Tue, 19 Mar 2019 10:57:15 +0100 Subject: [PATCH 18/24] Add filter (work in progress) --- app/src/main/AndroidManifest.xml | 5 +- .../android/ui/activity/FilterActivity.kt | 59 +++++ .../android/ui/activity/HomeActivity.kt | 82 ++++++- .../android/ui/fragment/FilterDataFragment.kt | 210 ++++++++++++++++++ .../ui/view/rowrepresentable/FilterRow.kt | 50 +++++ app/src/main/res/layout/activity_filter.xml | 7 + app/src/main/res/layout/fragment_filter.xml | 61 +++++ app/src/main/res/menu/home_menu.xml | 11 + 8 files changed, 477 insertions(+), 8 deletions(-) create mode 100644 app/src/main/java/net/pokeranalytics/android/ui/activity/FilterActivity.kt create mode 100644 app/src/main/java/net/pokeranalytics/android/ui/fragment/FilterDataFragment.kt create mode 100644 app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterRow.kt create mode 100644 app/src/main/res/layout/activity_filter.xml create mode 100644 app/src/main/res/layout/fragment_filter.xml create mode 100644 app/src/main/res/menu/home_menu.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a7bce528..e581fdd5 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -42,9 +42,12 @@ android:launchMode="singleTop" /> + when (item.itemId) { net.pokeranalytics.android.R.id.navigation_history -> { @@ -48,10 +53,26 @@ class HomeActivity : PokerAnalyticsActivity() { checkFirstLaunch() } + override fun onCreateOptionsMenu(menu: Menu?): Boolean { + menuInflater.inflate(R.menu.home_menu, menu) + this.homeMenu = menu + return super.onCreateOptionsMenu(menu) + } + + override fun onOptionsItemSelected(item: MenuItem?): Boolean { + when (item?.itemId) { + R.id.filter -> manageFilters() + } + return super.onOptionsItemSelected(item) + } + /** * Init UI */ private fun initUI() { + + setSupportActionBar(toolbar) + navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener) navigation.selectedItemId = net.pokeranalytics.android.R.id.navigation_history @@ -80,16 +101,63 @@ class HomeActivity : PokerAnalyticsActivity() { * Display a new fragment */ private fun displayFragment(index: Int) { + viewPager.setCurrentItem(index, false) + updateToolbar(index) + } - toolbar.title = when (index) { - 0 -> getString(R.string.title_history) - 1 -> getString(R.string.title_stats) - 2 -> getString(R.string.title_settings) - else -> "" + /** + * Update toolbar + */ + private fun updateToolbar(index: Int) { + when (index) { + 0 -> { + toolbar.title = getString(R.string.title_history) + homeMenu?.findItem(R.id.filter)?.isVisible = true + } + 1 -> { + toolbar.title = getString(R.string.title_stats) + homeMenu?.findItem(R.id.filter)?.isVisible = false + } + 2 -> { + toolbar.title = getString(R.string.title_settings) + homeMenu?.findItem(R.id.filter)?.isVisible = false + } } - - viewPager.setCurrentItem(index, false) } + /** + * Manage filters + */ + private fun manageFilters() { + + val filterSelected = false + + val choices = ArrayList() + choices.add(getString(R.string.new_str)) + + if (filterSelected) { + choices.add(getString(R.string.modify_current_filter)) + choices.add(getString(R.string.load_from_db)) + choices.add(getString(R.string.remove_filter)) + } + + val builder = AlertDialog.Builder(this) + builder.setTitle(R.string.filter_selection) + .setCancelable(true) + .setItems(choices.toTypedArray()) { _, which -> + Timber.d("Click on $which") + + when(which) { + 0 -> FilterActivity.newInstance(this@HomeActivity) + } + + } + .setNegativeButton(R.string.cancel) {dialog, which -> + Timber.d("Click on cancel") + } + + builder.show() + + } } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/FilterDataFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/FilterDataFragment.kt new file mode 100644 index 00000000..cc530abe --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/FilterDataFragment.kt @@ -0,0 +1,210 @@ +package net.pokeranalytics.android.ui.fragment + +import android.os.Bundle +import android.view.* +import androidx.recyclerview.widget.LinearLayoutManager +import io.realm.RealmObject +import kotlinx.android.synthetic.main.fragment_editable_data.* +import kotlinx.android.synthetic.main.fragment_filter.view.* +import net.pokeranalytics.android.R +import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity +import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter +import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate +import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource +import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment +import net.pokeranalytics.android.ui.view.RowRepresentable +import net.pokeranalytics.android.ui.view.rowrepresentable.FilterRow + + +open class FilterDataFragment : PokerAnalyticsFragment(), StaticRowRepresentableDataSource, RowRepresentableDelegate { + + lateinit var parentActivity: PokerAnalyticsActivity + lateinit var item: RealmObject + lateinit var rowRepresentableAdapter: RowRepresentableAdapter + + + private var rows: ArrayList = ArrayList() + private var filterMenu: Menu? = null + private var dataType: Int? = null + private var primaryKey: String? = null + + var isUpdating = false + var shouldOpenKeyboard = true + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.fragment_filter, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + initUI() + initData() + } + + override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { + /* + inflater?.inflate(R.menu.editable_data, menu) + this.filterMenu = menu + */ + updateMenuUI() + super.onCreateOptionsMenu(menu, inflater) + } + + + override fun onOptionsItemSelected(item: MenuItem?): Boolean { + when (item!!.itemId) { + R.id.save -> saveData() + R.id.delete -> deleteData() + } + return true + } + + override fun adapterRows(): List? { + return rows + } + + override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) { + super.onRowSelected(position, row, fromAction) + } + + override fun onRowValueChanged(value: Any?, row: RowRepresentable) { + super.onRowValueChanged(value, row) + } + + /** + * Init UI + */ + private fun initUI() { + parentActivity = activity as PokerAnalyticsActivity + parentActivity.setSupportActionBar(toolbar) + parentActivity.supportActionBar?.setDisplayHomeAsUpEnabled(true) + setHasOptionsMenu(true) + + val viewManager = LinearLayoutManager(requireContext()) + + recyclerView.apply { + setHasFixedSize(true) + layoutManager = viewManager + } + } + + /** + * Init data + */ + private fun initData() { + + this.appBar.toolbar.title = getString(R.string.filter) + + rows.addAll(FilterRow.values()) + + this.rowRepresentableAdapter = RowRepresentableAdapter(this, this) + this.recyclerView.adapter = rowRepresentableAdapter + + /* + if (this.dataType != null) { + val proxyItem: RealmObject? = this.liveDataType.getData(this.getRealm(), primaryKey) + proxyItem?.let { + //TODO: Localize + this.appBar.toolbar.title = "Update ${this.liveDataType.localizedTitle(this.parentActivity).toLowerCase().capitalize()}" + isUpdating = true + } ?: run { + //TODO: Localize + this.appBar.toolbar.title = this.liveDataType.newEntityLocalizedTitle(requireContext()) + } + this.item = this.liveDataType.updateOrCreate(this.getRealm(), primaryKey) + + val dataSource = getDataSource() + this.rowRepresentableAdapter = RowRepresentableAdapter(getDataSource(), this) + this.recyclerView.adapter = rowRepresentableAdapter + + // When creating an object, open automatically the keyboard for the first row + if (!isUpdating && shouldOpenKeyboard) { + val row = dataSource.adapterRows()?.firstOrNull() + row?.let { + onRowSelected(0, it) + } + } + } + */ + } + + /** + * Update menu UI + */ + private fun updateMenuUI() { + /* + editableMenu?.findItem(R.id.delete)?.isVisible = isUpdating + editableMenu?.findItem(R.id.save)?.isVisible = true + */ + } + + /** + * Save data + */ + fun saveData() { + /* + if ((this.item as Savable).isValidForSave()) { + this.getRealm().executeTransaction { + val item = it.copyToRealmOrUpdate(this.item) + + val uniqueIdentifier = if (item is Identifiable) { + item.id + } else "" + + finishActivityWithResult(uniqueIdentifier) + } + } else { + val message = (this.item as Savable).getFailedSaveMessage() + val builder = AlertDialog.Builder(requireContext()) + .setMessage(message) + .setNegativeButton(R.string.ok, null) + builder.show() + } + */ + } + + /** + * Delete data + */ + private fun deleteData() { + /* + val builder = AlertDialog.Builder(requireContext()) + builder.setTitle(R.string.warning) + .setMessage(R.string.are_you_sure_you_want_to_do_that_) + .setNegativeButton(R.string.no, null) + .setPositiveButton(R.string.yes) { _, _ -> + //TODO: Maybe update this code, does the object need to be managed? + this.getRealm().executeTransaction { + this.liveDataType.deleteData(it, (this.item as Manageable)) + } + this.activity?.finish() + } + builder.show() + */ + } + + /** + * Finish the activity with a result + */ + private fun finishActivityWithResult(uniqueIdentifier: String) { + /* + val intent = Intent() + intent.putExtra(EditableDataActivity.IntentKey.DATA_TYPE.keyName, dataType) + intent.putExtra(EditableDataActivity.IntentKey.PRIMARY_KEY.keyName, uniqueIdentifier) + activity?.setResult(RESULT_OK, intent) + */ + activity?.finish() + } + + /** + * Set fragment data + */ + fun setData(dataType: Int, primaryKey: String?) { + /* + this.dataType = dataType + this.liveDataType = LiveData.values()[dataType] + this.primaryKey = primaryKey + */ + } + +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterRow.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterRow.kt new file mode 100644 index 00000000..0b5f2b7a --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterRow.kt @@ -0,0 +1,50 @@ +package net.pokeranalytics.android.ui.view.rowrepresentable + +import net.pokeranalytics.android.R +import net.pokeranalytics.android.ui.view.RowRepresentable +import net.pokeranalytics.android.ui.view.RowViewType + +enum class FilterRow : RowRepresentable { + + GENERAL, + DATE, + DURATION, + SESSION, + CASH, + TOURNAMENT, + ONLINE, + RESULT, + TRANSACTION_TYPES, + + // Title Custom fields + LOCATION, + BANKROLL, + PLAYERS; + + override val resId: Int? + get() { + return when (this) { + GENERAL -> R.string.general + DATE -> R.string.date + DURATION -> R.string.duration + SESSION -> R.string.session + CASH -> R.string.cash + TOURNAMENT -> R.string.tournament + ONLINE -> R.string.online + RESULT -> R.string.result + TRANSACTION_TYPES -> R.string.operation_types + LOCATION -> R.string.location + BANKROLL -> R.string.bankroll + PLAYERS -> R.string.players + } + } + + override val viewType: Int + get() { + return when (this) { + GENERAL, DATE, DURATION, SESSION, CASH, TOURNAMENT, ONLINE, RESULT, TRANSACTION_TYPES, + LOCATION, BANKROLL, PLAYERS -> RowViewType.TITLE_VALUE_ARROW.ordinal + } + } + +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_filter.xml b/app/src/main/res/layout/activity_filter.xml new file mode 100644 index 00000000..70454fb9 --- /dev/null +++ b/app/src/main/res/layout/activity_filter.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_filter.xml b/app/src/main/res/layout/fragment_filter.xml new file mode 100644 index 00000000..bab049a9 --- /dev/null +++ b/app/src/main/res/layout/fragment_filter.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/home_menu.xml b/app/src/main/res/menu/home_menu.xml new file mode 100644 index 00000000..38cbd892 --- /dev/null +++ b/app/src/main/res/menu/home_menu.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file From aa92dcf6e5a52b84153df4c935c0beff8411c724 Mon Sep 17 00:00:00 2001 From: Razmig Sarkissian Date: Tue, 19 Mar 2019 11:24:08 +0100 Subject: [PATCH 19/24] add new filter --- .../filter/BaseFilterInstrumentedUnitTest.kt | 28 +- .../filter/BlindFilterInstrumentedTest.kt | 205 +++++++++++++ .../SessionFilterInstrumentedUnitTest.kt | 279 +++++++++++------- .../android/model/filter/SessionFilterable.kt | 62 +++- 4 files changed, 437 insertions(+), 137 deletions(-) create mode 100644 app/src/androidTest/java/net/pokeranalytics/android/filter/BlindFilterInstrumentedTest.kt diff --git a/app/src/androidTest/java/net/pokeranalytics/android/filter/BaseFilterInstrumentedUnitTest.kt b/app/src/androidTest/java/net/pokeranalytics/android/filter/BaseFilterInstrumentedUnitTest.kt index 1611beb9..3b80c3c2 100644 --- a/app/src/androidTest/java/net/pokeranalytics/android/filter/BaseFilterInstrumentedUnitTest.kt +++ b/app/src/androidTest/java/net/pokeranalytics/android/filter/BaseFilterInstrumentedUnitTest.kt @@ -1,21 +1,35 @@ package net.pokeranalytics.android.filter +import io.realm.RealmList import net.pokeranalytics.android.RealmInstrumentedUnitTest -import net.pokeranalytics.android.model.realm.Bankroll -import net.pokeranalytics.android.model.realm.Session +import net.pokeranalytics.android.model.realm.* import java.util.* open class BaseFilterInstrumentedUnitTest : RealmInstrumentedUnitTest() { // convenience extension fun Session.Companion.testInstance( - netResult: Double, - isTournament: Boolean, - startDate: Date, + netResult: Double = 0.0, + isTournament: Boolean = false, + startDate: Date = Date(), endDate: Int = 1, - bankroll: Bankroll? = null - ): Session { + bankroll: Bankroll? = null, + game: Game? = null, + location : Location? = null, + tournamentName: TournamentName? = null, + tournamentFeatures: RealmList = RealmList(), + numberOfTable: Int = 1, + limit: Int? = null, + tableSize: Int? = null + ): Session { val session: Session = Session.newInstance(super.mockRealm, isTournament, bankroll) + session.game = game + session.location = location + session.tournamentFeatures = tournamentFeatures + session.tournamentName = tournamentName + session.limit = limit + session.numberOfTables = numberOfTable + session.tableSize = tableSize session.result?.netResult = netResult session.startDate = startDate val cal = Calendar.getInstance() // creates calendar diff --git a/app/src/androidTest/java/net/pokeranalytics/android/filter/BlindFilterInstrumentedTest.kt b/app/src/androidTest/java/net/pokeranalytics/android/filter/BlindFilterInstrumentedTest.kt new file mode 100644 index 00000000..a3ffd4a9 --- /dev/null +++ b/app/src/androidTest/java/net/pokeranalytics/android/filter/BlindFilterInstrumentedTest.kt @@ -0,0 +1,205 @@ +package net.pokeranalytics.android.filter + +import net.pokeranalytics.android.model.filter.FilterManager +import net.pokeranalytics.android.model.filter.SessionFilterable +import net.pokeranalytics.android.model.realm.Bankroll +import net.pokeranalytics.android.model.realm.Session +import org.junit.Assert +import org.junit.Test +import java.util.* + +class BlindFilterInstrumentedTest : BaseFilterInstrumentedUnitTest() { + @Test + fun testSingleBlindNoCurrencyFilter() { + + val realm = this.mockRealm + realm.beginTransaction() + + val currency = realm.createObject(net.pokeranalytics.android.model.realm.Currency::class.java, "1") + currency.code = "AUD" + + val b1 = realm.createObject(Bankroll::class.java, "1") + val b2 = realm.createObject(Bankroll::class.java, "2") + b2.currency = currency + + val s1 = Session.testInstance(100.0, false, Date(), 1, b1) + s1.cgBigBlind = 1.0 + s1.cgSmallBlind = 0.5 + + val s2 = Session.testInstance(100.0, false, Date(), 1, b1) + s2.cgBigBlind = 1.0 + s2.cgSmallBlind = 0.5 + + val s3 = Session.testInstance(100.0, false, Date(), 1, b1) + s3.cgBigBlind = 2.0 + s3.cgSmallBlind = 1.0 + + realm.commitTransaction() + + + val filter = SessionFilterable.BLINDS + filter.valueMap = mapOf("map" to arrayOf(mapOf( + "sb" to 0.5, + "bb" to 1.0, + "code" to null + ))) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(2, sessions.size) + sessions.map { + Assert.assertTrue(arrayListOf(s1.id, s2.id).contains((it as Session).id)) + } + } + + @Test + fun testSingleBlindNoSmallBlindNoCurrencyFilter() { + + val realm = this.mockRealm + realm.beginTransaction() + + val currency = realm.createObject(net.pokeranalytics.android.model.realm.Currency::class.java, "1") + currency.code = "AUD" + + val b1 = realm.createObject(Bankroll::class.java, "1") + val b2 = realm.createObject(Bankroll::class.java, "2") + b2.currency = currency + + val s1 = Session.testInstance(100.0, false, Date(), 1, b1) + s1.cgBigBlind = 1.0 + s1.cgSmallBlind = 0.5 + + val s2 = Session.testInstance(100.0, false, Date(), 1, b1) + s2.cgBigBlind = 1.0 + s2.cgSmallBlind = 0.5 + + val s3 = Session.testInstance(100.0, false, Date(), 1, b1) + s3.cgBigBlind = 2.0 + s3.cgSmallBlind = 1.0 + + realm.commitTransaction() + + + val filter = SessionFilterable.BLINDS + filter.valueMap = mapOf("map" to arrayOf(mapOf( + "sb" to null, + "bb" to 1.0, + "code" to null + ))) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(2, sessions.size) + sessions.map { + Assert.assertTrue(arrayListOf(s1.id, s2.id).contains((it as Session).id)) + } + } + + @Test + fun testSingleBlindCurrencyFilter() { + + val realm = this.mockRealm + realm.beginTransaction() + + val currency = realm.createObject(net.pokeranalytics.android.model.realm.Currency::class.java, "1") + currency.code = "AUD" + + val b1 = realm.createObject(Bankroll::class.java, "1") + val b2 = realm.createObject(Bankroll::class.java, "2") + b2.currency = currency + + val s1 = Session.testInstance(100.0, false, Date(), 1, b1) + s1.cgBigBlind = 1.0 + s1.cgSmallBlind = 0.5 + + val s2 = Session.testInstance(100.0, false, Date(), 1, b1) + s2.cgBigBlind = 1.0 + s2.cgSmallBlind = 0.5 + + val s3 = Session.testInstance(100.0, false, Date(), 1, b2) + s3.cgBigBlind = 2.0 + s3.cgSmallBlind = 1.0 + + realm.commitTransaction() + + + val filter = SessionFilterable.BLINDS + filter.valueMap = mapOf("map" to arrayOf(mapOf( + "sb" to 1.0, + "bb" to 2.0, + "code" to "AUD" + ))) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(1, sessions.size) + sessions.map { + Assert.assertEquals(s3.id, (it as Session).id) + } + } + + @Test + fun testMultiBlindNoCurrencyFilter() { + + val realm = this.mockRealm + realm.beginTransaction() + + val currency = realm.createObject(net.pokeranalytics.android.model.realm.Currency::class.java, "1") + currency.code = "AUD" + + val b1 = realm.createObject(Bankroll::class.java, "1") + val b2 = realm.createObject(Bankroll::class.java, "2") + b2.currency = currency + + val s1 = Session.testInstance(100.0, false, Date(), 1, b1) + s1.cgBigBlind = 1.0 + s1.cgSmallBlind = 0.5 + + val s2 = Session.testInstance(100.0, false, Date(), 1, b1) + s2.cgBigBlind = 2.0 + s2.cgSmallBlind = 1.0 + + val s3 = Session.testInstance(100.0, false, Date(), 1, b2) + s3.cgBigBlind = 2.0 + s3.cgSmallBlind = 1.0 + + realm.commitTransaction() + + + val filter = SessionFilterable.BLINDS + filter.valueMap = mapOf("map" to arrayOf( + mapOf( + "sb" to 1.0, + "bb" to 2.0, + "code" to null + ), + mapOf( + "sb" to 0.5, + "bb" to 1.0, + "code" to null + ))) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(2, sessions.size) + sessions.map { + Assert.assertTrue(arrayListOf(s1.id, s2.id).contains((it as Session).id)) + } + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/net/pokeranalytics/android/filter/SessionFilterInstrumentedUnitTest.kt b/app/src/androidTest/java/net/pokeranalytics/android/filter/SessionFilterInstrumentedUnitTest.kt index fe8263b1..35c6b3c7 100644 --- a/app/src/androidTest/java/net/pokeranalytics/android/filter/SessionFilterInstrumentedUnitTest.kt +++ b/app/src/androidTest/java/net/pokeranalytics/android/filter/SessionFilterInstrumentedUnitTest.kt @@ -3,8 +3,7 @@ package net.pokeranalytics.android.filter import androidx.test.ext.junit.runners.AndroidJUnit4 import net.pokeranalytics.android.model.filter.FilterManager import net.pokeranalytics.android.model.filter.SessionFilterable -import net.pokeranalytics.android.model.realm.Bankroll -import net.pokeranalytics.android.model.realm.Session +import net.pokeranalytics.android.model.realm.* import org.junit.Assert import org.junit.Test import org.junit.runner.RunWith @@ -111,39 +110,19 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { } @Test - fun testSingleBlindNoCurrencyFilter() { - + fun testBankrollFilter() { val realm = this.mockRealm realm.beginTransaction() - - val currency = realm.createObject(net.pokeranalytics.android.model.realm.Currency::class.java, "1") - currency.code = "AUD" - val b1 = realm.createObject(Bankroll::class.java, "1") val b2 = realm.createObject(Bankroll::class.java, "2") - b2.currency = currency - - val s1 = Session.testInstance(100.0, false, Date(), 1, b1) - s1.cgBigBlind = 1.0 - s1.cgSmallBlind = 0.5 - - val s2 = Session.testInstance(100.0, false, Date(), 1, b1) - s2.cgBigBlind = 1.0 - s2.cgSmallBlind = 0.5 - - val s3 = Session.testInstance(100.0, false, Date(), 1, b1) - s3.cgBigBlind = 2.0 - s3.cgSmallBlind = 1.0 - + b1.live = false + b2.live = true + Session.testInstance(bankroll = b1) + Session.testInstance(bankroll = b2) realm.commitTransaction() - - val filter = SessionFilterable.BLINDS - filter.valueMap = mapOf("map" to arrayOf(mapOf( - "sb" to 0.5, - "bb" to 1.0, - "code" to null - ))) + val filter = SessionFilterable.BANKROLL + filter.valueMap = mapOf("ids" to arrayOf(b1.id)) val sessions = FilterManager().filter( realm, @@ -151,46 +130,60 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { arrayListOf(filter) ) - Assert.assertEquals(2, sessions.size) - sessions.map { - Assert.assertTrue(arrayListOf(s1.id, s2.id).contains((it as Session).id)) + Assert.assertEquals(1, sessions.size) + (sessions[0] as Session).bankroll?.run { + Assert.assertEquals(b1.id, this.id) } } @Test - fun testSingleBlindNoSmallBlindNoCurrencyFilter() { - + fun testMultipleBankrollFilter() { val realm = this.mockRealm realm.beginTransaction() - - val currency = realm.createObject(net.pokeranalytics.android.model.realm.Currency::class.java, "1") - currency.code = "AUD" - val b1 = realm.createObject(Bankroll::class.java, "1") val b2 = realm.createObject(Bankroll::class.java, "2") - b2.currency = currency + val b3 = realm.createObject(Bankroll::class.java, "3") + Session.testInstance(bankroll = b1) + Session.testInstance(bankroll = b2) + Session.testInstance(bankroll = b3) + Session.testInstance(bankroll = b1) + Session.testInstance(bankroll = b2) + Session.testInstance(bankroll = b3) + Session.testInstance(bankroll = b1) + Session.testInstance(bankroll = b2) + Session.testInstance(bankroll = b3) + realm.commitTransaction() + + val filter = SessionFilterable.BANKROLL + filter.valueMap = mapOf("ids" to arrayOf(b1.id, b2.id)) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) - val s1 = Session.testInstance(100.0, false, Date(), 1, b1) - s1.cgBigBlind = 1.0 - s1.cgSmallBlind = 0.5 + Assert.assertEquals(6, sessions.size) - val s2 = Session.testInstance(100.0, false, Date(), 1, b1) - s2.cgBigBlind = 1.0 - s2.cgSmallBlind = 0.5 + val result = arrayListOf(b1.id, b2.id) - val s3 = Session.testInstance(100.0, false, Date(), 1, b1) - s3.cgBigBlind = 2.0 - s3.cgSmallBlind = 1.0 + sessions.forEach { + Assert.assertTrue(result.contains((it as Session).bankroll?.id)) + } + } + @Test + fun testGameFilter() { + val realm = this.mockRealm + realm.beginTransaction() + val g1 = realm.createObject(Game::class.java, "1") + val g2 = realm.createObject(Game::class.java, "2") + Session.testInstance(game = g1) + Session.testInstance(game = g2) realm.commitTransaction() - - val filter = SessionFilterable.BLINDS - filter.valueMap = mapOf("map" to arrayOf(mapOf( - "sb" to null, - "bb" to 1.0, - "code" to null - ))) + val filter = SessionFilterable.GAME + filter.valueMap = mapOf("ids" to arrayOf(g2.id)) val sessions = FilterManager().filter( realm, @@ -198,46 +191,60 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { arrayListOf(filter) ) - Assert.assertEquals(2, sessions.size) - sessions.map { - Assert.assertTrue(arrayListOf(s1.id, s2.id).contains((it as Session).id)) + Assert.assertEquals(1, sessions.size) + (sessions[0] as Session).game?.run { + Assert.assertEquals(g2.id, this.id) } } @Test - fun testSingleBlindCurrencyFilter() { - + fun testMultipleGameFilter() { val realm = this.mockRealm realm.beginTransaction() + val g1 = realm.createObject(Game::class.java, "1") + val g2 = realm.createObject(Game::class.java, "2") + val g3 = realm.createObject(Game::class.java, "3") + Session.testInstance(game = g1) + Session.testInstance(game = g2) + Session.testInstance(game = g3) + Session.testInstance(game = g1) + Session.testInstance(game = g2) + Session.testInstance(game = g3) + Session.testInstance(game = g1) + Session.testInstance(game = g2) + Session.testInstance(game = g3) + realm.commitTransaction() - val currency = realm.createObject(net.pokeranalytics.android.model.realm.Currency::class.java, "1") - currency.code = "AUD" + val filter = SessionFilterable.GAME + filter.valueMap = mapOf("ids" to arrayOf(g2.id, g3.id)) - val b1 = realm.createObject(Bankroll::class.java, "1") - val b2 = realm.createObject(Bankroll::class.java, "2") - b2.currency = currency + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) - val s1 = Session.testInstance(100.0, false, Date(), 1, b1) - s1.cgBigBlind = 1.0 - s1.cgSmallBlind = 0.5 + Assert.assertEquals(6, sessions.size) - val s2 = Session.testInstance(100.0, false, Date(), 1, b1) - s2.cgBigBlind = 1.0 - s2.cgSmallBlind = 0.5 + val result = arrayListOf(g2.id, g3.id) - val s3 = Session.testInstance(100.0, false, Date(), 1, b2) - s3.cgBigBlind = 2.0 - s3.cgSmallBlind = 1.0 + sessions.forEach { + Assert.assertTrue(result.contains((it as Session).game?.id)) + } + } + @Test + fun testLocationFilter() { + val realm = this.mockRealm + realm.beginTransaction() + val l1 = realm.createObject(Location::class.java, "1") + val l2 = realm.createObject(Location::class.java, "2") + Session.testInstance(location = l1) + Session.testInstance(location = l2) realm.commitTransaction() - - val filter = SessionFilterable.BLINDS - filter.valueMap = mapOf("map" to arrayOf(mapOf( - "sb" to 1.0, - "bb" to 2.0, - "code" to "AUD" - ))) + val filter = SessionFilterable.LOCATION + filter.valueMap = mapOf("ids" to arrayOf(l1.id)) val sessions = FilterManager().filter( realm, @@ -246,51 +253,92 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { ) Assert.assertEquals(1, sessions.size) - sessions.map { - Assert.assertEquals(s3.id, (it as Session).id) + (sessions[0] as Session).location?.run { + Assert.assertEquals(l1.id, this.id) } } @Test - fun testMultiBlindNoCurrencyFilter() { - + fun testMultipleLocationFilter() { val realm = this.mockRealm realm.beginTransaction() + val l1 = realm.createObject(Location::class.java, "1") + val l2 = realm.createObject(Location::class.java, "2") + val l3 = realm.createObject(Location::class.java, "3") + Session.testInstance(location = l1) + Session.testInstance(location = l2) + Session.testInstance(location = l3) + Session.testInstance(location = l1) + Session.testInstance(location = l2) + Session.testInstance(location = l3) + Session.testInstance(location = l1) + Session.testInstance(location = l2) + Session.testInstance(location = l3) + realm.commitTransaction() - val currency = realm.createObject(net.pokeranalytics.android.model.realm.Currency::class.java, "1") - currency.code = "AUD" + val filter = SessionFilterable.LOCATION + filter.valueMap = mapOf("ids" to arrayOf(l1.id, l3.id)) - val b1 = realm.createObject(Bankroll::class.java, "1") - val b2 = realm.createObject(Bankroll::class.java, "2") - b2.currency = currency + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) - val s1 = Session.testInstance(100.0, false, Date(), 1, b1) - s1.cgBigBlind = 1.0 - s1.cgSmallBlind = 0.5 + Assert.assertEquals(6, sessions.size) - val s2 = Session.testInstance(100.0, false, Date(), 1, b1) - s2.cgBigBlind = 2.0 - s2.cgSmallBlind = 1.0 + val result = arrayListOf(l2.id, l3.id) - val s3 = Session.testInstance(100.0, false, Date(), 1, b2) - s3.cgBigBlind = 2.0 - s3.cgSmallBlind = 1.0 + sessions.forEach { + Assert.assertTrue(result.contains((it as Session).location?.id)) + } + } + @Test + fun testTournamentNameFilter() { + val realm = this.mockRealm + realm.beginTransaction() + val t1 = realm.createObject(TournamentName::class.java, "1") + val t2 = realm.createObject(TournamentName::class.java, "2") + Session.testInstance(tournamentName = t1) + Session.testInstance(tournamentName = t2) realm.commitTransaction() + val filter = SessionFilterable.TOURNAMENT_NAME + filter.valueMap = mapOf("ids" to arrayOf(t1.id)) - val filter = SessionFilterable.BLINDS - filter.valueMap = mapOf("map" to arrayOf( - mapOf( - "sb" to 1.0, - "bb" to 2.0, - "code" to null - ), - mapOf( - "sb" to 0.5, - "bb" to 1.0, - "code" to null - ))) + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(1, sessions.size) + (sessions[0] as Session).tournamentName?.run { + Assert.assertEquals(t1.id, this.id) + } + } + + @Test + fun testMultipleTournamentNameFilter() { + val realm = this.mockRealm + realm.beginTransaction() + val t1 = realm.createObject(TournamentName::class.java, "1") + val t2 = realm.createObject(TournamentName::class.java, "2") + val t3 = realm.createObject(TournamentName::class.java, "3") + Session.testInstance(tournamentName = t1) + Session.testInstance(tournamentName = t2) + Session.testInstance(tournamentName = t3) + Session.testInstance(tournamentName = t1) + Session.testInstance(tournamentName = t2) + Session.testInstance(tournamentName = t3) + Session.testInstance(tournamentName = t1) + Session.testInstance(tournamentName = t2) + Session.testInstance(tournamentName = t3) + realm.commitTransaction() + + val filter = SessionFilterable.TOURNAMENT_NAME + filter.valueMap = mapOf("ids" to arrayOf(t1.id, t2.id)) val sessions = FilterManager().filter( realm, @@ -298,9 +346,12 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { arrayListOf(filter) ) - Assert.assertEquals(2, sessions.size) - sessions.map { - Assert.assertTrue(arrayListOf(s1.id, s2.id).contains((it as Session).id)) + Assert.assertEquals(6, sessions.size) + + val result = arrayListOf(t1.id, t2.id) + + sessions.forEach { + Assert.assertTrue(result.contains((it as Session).tournamentName?.id)) } } } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/SessionFilterable.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/SessionFilterable.kt index 332a8c0c..96deb0a0 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/filter/SessionFilterable.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/SessionFilterable.kt @@ -6,34 +6,32 @@ import net.pokeranalytics.android.exceptions.FilterValueMapException import net.pokeranalytics.android.model.filter.interfaces.Filterable import net.pokeranalytics.android.model.realm.Session -enum class SessionFilterable: Filterable { +enum class SessionFilterable(private var fieldName:String? = null): Filterable { LIVE, CASH, ONLINE, TOURNAMENT, - BANKROLL, + BANKROLL("bankroll.id"), + GAME("game.id"), + TOURNAMENT_NAME("tournamentName.id"), + ANY_TOURNAMENT_FEATURES("tournamentFeature.id"), + ALL_TOURNAMENT_FEATURES("tournamentFeature.id"), + LOCATION("location.id"), + LIMIT("limit"), + TABLE_SIZE("tableSize"), + NUMBER_OF_TABLE("numberOfTable"), + TOURNAMENT_TYPE("tournamentType"), BLINDS, ; private enum class Field(var fieldName:String) { LIVE("bankroll.live"), CASH("type"), - BANKROLL("bankroll.id"), - START_DATE("startDate"), - END_DATE("endDate"), CURRENCY("bankroll.currency"), CURRENCY_CODE("bankroll.currency.code"), BIG_BLIND("cgBigBlind"), SMALL_BLIND("cgSmallBlind"), - GAME("game.id"), - LIMIT("limit"), - TABLE_SIZE("tableSize"), - LOCATION("location.id"), - NUMBER_OF_TABLE("numberOfTable"), COMMENT("comment"), - TOURNAMENT_TYPE("tournamentType"), - TOURNAMENT_NAME("tournamentName.id"), - TOURNAMENT_FEATURES("tournamentFeature.id"), TOURNAMENT_NUMBER_OF_PLAYER("tournamentNumberOfPlayers"), TOURNAMENT_ENTRY_FEE("tournamentEntryFee"), RESULT_BUY_IN("result.buyin"), @@ -48,7 +46,8 @@ enum class SessionFilterable: Filterable { override val filterValuesExceptedKeys : Array? get() { return when (this) { - BANKROLL -> arrayOf("ids") + BANKROLL, GAME, LOCATION, ANY_TOURNAMENT_FEATURES, ALL_TOURNAMENT_FEATURES -> arrayOf("ids") + LIMIT, TOURNAMENT_TYPE, TABLE_SIZE, NUMBER_OF_TABLE -> arrayOf("values") BLINDS -> arrayOf("map") else -> null } @@ -60,9 +59,40 @@ enum class SessionFilterable: Filterable { CASH -> realmQuery.equalTo(Field.CASH.fieldName, Session.Type.CASH_GAME.ordinal) ONLINE -> LIVE.filter(realmQuery.not()) TOURNAMENT -> CASH.filter(realmQuery.not()) - BANKROLL -> { + ALL_TOURNAMENT_FEATURES -> { val ids : Array by filterValues - realmQuery.`in`(Field.BANKROLL.fieldName, ids) + this.fieldName?.let {fieldName -> + ids.forEachIndexed { index, id -> + if (index == 0) { + realmQuery.beginGroup() + } + realmQuery.`in`(fieldName, arrayOf(id)) + if (index == ids.size - 1) { + realmQuery.endGroup() + } else { + realmQuery.and() + } + } + realmQuery + } ?: run { + throw FilterValueMapException("fieldName is missing") + } + } + BANKROLL, GAME, LOCATION, ANY_TOURNAMENT_FEATURES, TOURNAMENT_NAME -> { + val ids : Array by filterValues + this.fieldName?.let { + realmQuery.`in`(it, ids) + } ?: run { + throw FilterValueMapException("fieldName is missing") + } + } + LIMIT, TOURNAMENT_TYPE, TABLE_SIZE, NUMBER_OF_TABLE -> { + val values : Array? by filterValues + this.fieldName?.let { + realmQuery.`in`(it, values) + } ?: run { + throw FilterValueMapException("fieldName is missing") + } } BLINDS -> { val map : Array> by filterValues From 79b93693db4e57723eda29b94a9f5bb353d6c817 Mon Sep 17 00:00:00 2001 From: Razmig Sarkissian Date: Tue, 19 Mar 2019 12:07:47 +0100 Subject: [PATCH 20/24] add any/all features filter --- .../SessionFilterInstrumentedUnitTest.kt | 100 ++++++++++++++++++ .../android/model/filter/SessionFilterable.kt | 29 ++--- 2 files changed, 111 insertions(+), 18 deletions(-) diff --git a/app/src/androidTest/java/net/pokeranalytics/android/filter/SessionFilterInstrumentedUnitTest.kt b/app/src/androidTest/java/net/pokeranalytics/android/filter/SessionFilterInstrumentedUnitTest.kt index 35c6b3c7..d2ba8a39 100644 --- a/app/src/androidTest/java/net/pokeranalytics/android/filter/SessionFilterInstrumentedUnitTest.kt +++ b/app/src/androidTest/java/net/pokeranalytics/android/filter/SessionFilterInstrumentedUnitTest.kt @@ -1,6 +1,7 @@ package net.pokeranalytics.android.filter import androidx.test.ext.junit.runners.AndroidJUnit4 +import io.realm.RealmList import net.pokeranalytics.android.model.filter.FilterManager import net.pokeranalytics.android.model.filter.SessionFilterable import net.pokeranalytics.android.model.realm.* @@ -354,4 +355,103 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { Assert.assertTrue(result.contains((it as Session).tournamentName?.id)) } } + + @Test + fun testAllTournamentFeatureFilter() { + val realm = this.mockRealm + realm.beginTransaction() + val t1 = realm.createObject(TournamentFeature::class.java, "1") + val t2 = realm.createObject(TournamentFeature::class.java, "2") + val t3 = realm.createObject(TournamentFeature::class.java, "3") + val t4 = realm.createObject(TournamentFeature::class.java, "4") + Session.testInstance(tournamentFeatures = RealmList(t1,t2)) + Session.testInstance(tournamentFeatures = RealmList(t2,t3)) + Session.testInstance(tournamentFeatures = RealmList(t3,t4)) + val s = Session.testInstance(tournamentFeatures = RealmList(t1,t2,t3,t4)) + Session.testInstance(tournamentFeatures = RealmList(t1,t4)) + Session.testInstance(tournamentFeatures = RealmList(t1,t3)) + Session.testInstance(tournamentFeatures = RealmList(t2,t4, t3)) + Session.testInstance(tournamentFeatures = RealmList(t1)) + realm.commitTransaction() + + val filter = SessionFilterable.ALL_TOURNAMENT_FEATURES + filter.valueMap = mapOf("ids" to arrayOf(t1.id, t2.id, t3.id, t4.id)) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(1, sessions.size) + (sessions[0] as Session)?.run { + Assert.assertEquals(s.id, this.id) + } + } + + @Test + fun testAnyTournamentFeatureFilter() { + val realm = this.mockRealm + realm.beginTransaction() + val t1 = realm.createObject(TournamentFeature::class.java, "1") + val t2 = realm.createObject(TournamentFeature::class.java, "2") + val t3 = realm.createObject(TournamentFeature::class.java, "3") + val t4 = realm.createObject(TournamentFeature::class.java, "4") + Session.testInstance(tournamentFeatures = RealmList(t1,t2)) + Session.testInstance(tournamentFeatures = RealmList(t2,t3)) + Session.testInstance(tournamentFeatures = RealmList(t3,t4)) + Session.testInstance(tournamentFeatures = RealmList(t1,t2,t3,t4)) + Session.testInstance(tournamentFeatures = RealmList(t1,t4)) + Session.testInstance(tournamentFeatures = RealmList(t1,t3)) + Session.testInstance(tournamentFeatures = RealmList(t2,t4, t3)) + Session.testInstance(tournamentFeatures = RealmList(t1)) + realm.commitTransaction() + + val filter = SessionFilterable.ANY_TOURNAMENT_FEATURES + filter.valueMap = mapOf("ids" to arrayOf(t1.id, t2.id, t3.id, t4.id)) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(8, sessions.size) + } + + @Test + fun testSingleAnyTournamentFeatureFilter() { + val realm = this.mockRealm + realm.beginTransaction() + val t1 = realm.createObject(TournamentFeature::class.java, "1") + val t2 = realm.createObject(TournamentFeature::class.java, "2") + val t3 = realm.createObject(TournamentFeature::class.java, "3") + val t4 = realm.createObject(TournamentFeature::class.java, "4") + val s1 = Session.testInstance(tournamentFeatures = RealmList(t1,t2)) + val s2 = Session.testInstance(tournamentFeatures = RealmList(t2,t3)) + Session.testInstance(tournamentFeatures = RealmList(t3,t4)) + val s3 = Session.testInstance(tournamentFeatures = RealmList(t1,t2,t3,t4)) + Session.testInstance(tournamentFeatures = RealmList(t1,t4)) + Session.testInstance(tournamentFeatures = RealmList(t1,t3)) + val s4 = Session.testInstance(tournamentFeatures = RealmList(t2,t4, t3)) + Session.testInstance(tournamentFeatures = RealmList(t1)) + realm.commitTransaction() + + val filter = SessionFilterable.ANY_TOURNAMENT_FEATURES + filter.valueMap = mapOf("ids" to arrayOf(t2.id)) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + val result = arrayListOf(s1.id, s2.id, s3.id, s4.id) + + Assert.assertEquals(4, sessions.size) + sessions.forEach { + Assert.assertTrue(result.contains((it as Session).id)) + } + + } } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/SessionFilterable.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/SessionFilterable.kt index 96deb0a0..37886323 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/filter/SessionFilterable.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/SessionFilterable.kt @@ -14,8 +14,8 @@ enum class SessionFilterable(private var fieldName:String? = null): Filterable { BANKROLL("bankroll.id"), GAME("game.id"), TOURNAMENT_NAME("tournamentName.id"), - ANY_TOURNAMENT_FEATURES("tournamentFeature.id"), - ALL_TOURNAMENT_FEATURES("tournamentFeature.id"), + ANY_TOURNAMENT_FEATURES, + ALL_TOURNAMENT_FEATURES, LOCATION("location.id"), LIMIT("limit"), TABLE_SIZE("tableSize"), @@ -32,6 +32,7 @@ enum class SessionFilterable(private var fieldName:String? = null): Filterable { BIG_BLIND("cgBigBlind"), SMALL_BLIND("cgSmallBlind"), COMMENT("comment"), + TOURNAMENT_FEATURES("tournamentFeatures.id"), TOURNAMENT_NUMBER_OF_PLAYER("tournamentNumberOfPlayers"), TOURNAMENT_ENTRY_FEE("tournamentEntryFee"), RESULT_BUY_IN("result.buyin"), @@ -61,24 +62,16 @@ enum class SessionFilterable(private var fieldName:String? = null): Filterable { TOURNAMENT -> CASH.filter(realmQuery.not()) ALL_TOURNAMENT_FEATURES -> { val ids : Array by filterValues - this.fieldName?.let {fieldName -> - ids.forEachIndexed { index, id -> - if (index == 0) { - realmQuery.beginGroup() - } - realmQuery.`in`(fieldName, arrayOf(id)) - if (index == ids.size - 1) { - realmQuery.endGroup() - } else { - realmQuery.and() - } - } - realmQuery - } ?: run { - throw FilterValueMapException("fieldName is missing") + ids.forEach { + realmQuery.equalTo(Field.TOURNAMENT_FEATURES.fieldName, it) } + realmQuery + } + ANY_TOURNAMENT_FEATURES -> { + val ids : Array by filterValues + realmQuery.`in`(Field.TOURNAMENT_FEATURES.fieldName, ids) } - BANKROLL, GAME, LOCATION, ANY_TOURNAMENT_FEATURES, TOURNAMENT_NAME -> { + BANKROLL, GAME, LOCATION, TOURNAMENT_NAME -> { val ids : Array by filterValues this.fieldName?.let { realmQuery.`in`(it, ids) From 2358e662ccfd1a1bd79bb01afdadb1281518c500 Mon Sep 17 00:00:00 2001 From: Aurelien Hubert Date: Tue, 19 Mar 2019 13:58:09 +0100 Subject: [PATCH 21/24] Improve Filter management / wip --- app/src/main/AndroidManifest.xml | 6 +- .../ui/activity/FilterDetailsActivity.kt | 60 ++++++ .../{FilterActivity.kt => FiltersActivity.kt} | 12 +- .../android/ui/activity/HomeActivity.kt | 2 +- ...taFragment.kt => FilterDetailsFragment.kt} | 37 +++- .../android/ui/fragment/FiltersFragment.kt | 191 ++++++++++++++++++ .../android/ui/view/RowViewType.kt | 3 +- .../rowrepresentable/FilterCategoryRow.kt | 91 +++++++++ .../ui/view/rowrepresentable/FilterRow.kt | 50 ----- .../rowrepresentable/FilterSubcategoryRow.kt | 113 +++++++++++ ...filter.xml => activity_filter_details.xml} | 0 app/src/main/res/layout/activity_filters.xml | 7 + ...filter.xml => fragment_filter_details.xml} | 0 app/src/main/res/layout/fragment_filters.xml | 61 ++++++ 14 files changed, 563 insertions(+), 70 deletions(-) create mode 100644 app/src/main/java/net/pokeranalytics/android/ui/activity/FilterDetailsActivity.kt rename app/src/main/java/net/pokeranalytics/android/ui/activity/{FilterActivity.kt => FiltersActivity.kt} (76%) rename app/src/main/java/net/pokeranalytics/android/ui/fragment/{FilterDataFragment.kt => FilterDetailsFragment.kt} (83%) create mode 100644 app/src/main/java/net/pokeranalytics/android/ui/fragment/FiltersFragment.kt create mode 100644 app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterCategoryRow.kt delete mode 100644 app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterRow.kt create mode 100644 app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterSubcategoryRow.kt rename app/src/main/res/layout/{activity_filter.xml => activity_filter_details.xml} (100%) create mode 100644 app/src/main/res/layout/activity_filters.xml rename app/src/main/res/layout/{fragment_filter.xml => fragment_filter_details.xml} (100%) create mode 100644 app/src/main/res/layout/fragment_filters.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e581fdd5..f3d02022 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -42,7 +42,11 @@ android:launchMode="singleTop" /> + + FilterActivity.newInstance(this@HomeActivity) + 0 -> FiltersActivity.newInstance(this@HomeActivity) } } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/FilterDataFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/FilterDetailsFragment.kt similarity index 83% rename from app/src/main/java/net/pokeranalytics/android/ui/fragment/FilterDataFragment.kt rename to app/src/main/java/net/pokeranalytics/android/ui/fragment/FilterDetailsFragment.kt index cc530abe..95349e78 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/FilterDataFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/FilterDetailsFragment.kt @@ -4,8 +4,8 @@ import android.os.Bundle import android.view.* import androidx.recyclerview.widget.LinearLayoutManager import io.realm.RealmObject -import kotlinx.android.synthetic.main.fragment_editable_data.* -import kotlinx.android.synthetic.main.fragment_filter.view.* +import kotlinx.android.synthetic.main.fragment_filter_details.* +import kotlinx.android.synthetic.main.fragment_filter_details.view.* import net.pokeranalytics.android.R import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter @@ -13,10 +13,11 @@ import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment import net.pokeranalytics.android.ui.view.RowRepresentable -import net.pokeranalytics.android.ui.view.rowrepresentable.FilterRow +import net.pokeranalytics.android.ui.view.rowrepresentable.FilterCategoryRow +import timber.log.Timber -open class FilterDataFragment : PokerAnalyticsFragment(), StaticRowRepresentableDataSource, RowRepresentableDelegate { +open class FilterDetailsFragment : PokerAnalyticsFragment(), StaticRowRepresentableDataSource, RowRepresentableDelegate { lateinit var parentActivity: PokerAnalyticsActivity lateinit var item: RealmObject @@ -25,14 +26,13 @@ open class FilterDataFragment : PokerAnalyticsFragment(), StaticRowRepresentable private var rows: ArrayList = ArrayList() private var filterMenu: Menu? = null - private var dataType: Int? = null - private var primaryKey: String? = null + private var filterCategory: FilterCategoryRow? = null var isUpdating = false var shouldOpenKeyboard = true override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater.inflate(R.layout.fragment_filter, container, false) + return inflater.inflate(R.layout.fragment_filter_details, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -93,12 +93,22 @@ open class FilterDataFragment : PokerAnalyticsFragment(), StaticRowRepresentable */ private fun initData() { + Timber.d("initData") + this.appBar.toolbar.title = getString(R.string.filter) - rows.addAll(FilterRow.values()) + filterCategory?.let { + + this.appBar.toolbar.title = it.localizedTitle(requireContext()) + + this.rows.clear() + this.rows.addAll(it.getSubcategories()) + Timber.d("initData: ${this.rows.size}") + + this.rowRepresentableAdapter = RowRepresentableAdapter(this, this) + this.recyclerView.adapter = rowRepresentableAdapter - this.rowRepresentableAdapter = RowRepresentableAdapter(this, this) - this.recyclerView.adapter = rowRepresentableAdapter + } /* if (this.dataType != null) { @@ -199,7 +209,12 @@ open class FilterDataFragment : PokerAnalyticsFragment(), StaticRowRepresentable /** * Set fragment data */ - fun setData(dataType: Int, primaryKey: String?) { + fun setData(filterCategory: Int) { + + Timber.d("Filter Category: ${FilterCategoryRow.values()[filterCategory]}") + Timber.d("Filter Subcategories: ${FilterCategoryRow.values()[filterCategory].getSubcategories()}") + this.filterCategory = FilterCategoryRow.values()[filterCategory] + /* this.dataType = dataType this.liveDataType = LiveData.values()[dataType] diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/FiltersFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/FiltersFragment.kt new file mode 100644 index 00000000..ed9186d9 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/FiltersFragment.kt @@ -0,0 +1,191 @@ +package net.pokeranalytics.android.ui.fragment + +import android.os.Bundle +import android.view.* +import androidx.recyclerview.widget.LinearLayoutManager +import io.realm.RealmObject +import kotlinx.android.synthetic.main.fragment_editable_data.* +import kotlinx.android.synthetic.main.fragment_filters.view.* +import net.pokeranalytics.android.R +import net.pokeranalytics.android.ui.activity.FilterDetailsActivity +import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity +import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter +import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate +import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource +import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment +import net.pokeranalytics.android.ui.view.RowRepresentable +import net.pokeranalytics.android.ui.view.rowrepresentable.FilterCategoryRow +import timber.log.Timber + + +open class FiltersFragment : PokerAnalyticsFragment(), StaticRowRepresentableDataSource, RowRepresentableDelegate { + + lateinit var parentActivity: PokerAnalyticsActivity + lateinit var item: RealmObject + lateinit var rowRepresentableAdapter: RowRepresentableAdapter + + private var rows: ArrayList = ArrayList() + private var filterMenu: Menu? = null + private var dataType: Int? = null + private var primaryKey: String? = null + + var isUpdating = false + var shouldOpenKeyboard = true + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.fragment_filters, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + initUI() + initData() + } + + override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { + /* + inflater?.inflate(R.menu.editable_data, menu) + this.filterMenu = menu + */ + updateMenuUI() + super.onCreateOptionsMenu(menu, inflater) + } + + + override fun onOptionsItemSelected(item: MenuItem?): Boolean { + when (item!!.itemId) { + R.id.save -> saveData() + R.id.delete -> deleteData() + } + return true + } + + override fun adapterRows(): List? { + return rows + } + + override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) { + super.onRowSelected(position, row, fromAction) + + if (row is FilterCategoryRow) { + Timber.d("Subcategories: ${row.getSubcategories()}") + FilterDetailsActivity.newInstanceForResult(this, row.ordinal, 1000) + } + + } + + override fun onRowValueChanged(value: Any?, row: RowRepresentable) { + super.onRowValueChanged(value, row) + } + + /** + * Init UI + */ + private fun initUI() { + parentActivity = activity as PokerAnalyticsActivity + parentActivity.setSupportActionBar(toolbar) + parentActivity.supportActionBar?.setDisplayHomeAsUpEnabled(true) + setHasOptionsMenu(true) + + val viewManager = LinearLayoutManager(requireContext()) + + recyclerView.apply { + setHasFixedSize(true) + layoutManager = viewManager + } + } + + /** + * Init data + */ + private fun initData() { + + this.appBar.toolbar.title = getString(R.string.filter) + + rows.addAll(FilterCategoryRow.values()) + + this.rowRepresentableAdapter = RowRepresentableAdapter(this, this) + this.recyclerView.adapter = rowRepresentableAdapter + + } + + /** + * Update menu UI + */ + private fun updateMenuUI() { + /* + editableMenu?.findItem(R.id.delete)?.isVisible = isUpdating + editableMenu?.findItem(R.id.save)?.isVisible = true + */ + } + + /** + * Save data + */ + fun saveData() { + /* + if ((this.item as Savable).isValidForSave()) { + this.getRealm().executeTransaction { + val item = it.copyToRealmOrUpdate(this.item) + + val uniqueIdentifier = if (item is Identifiable) { + item.id + } else "" + + finishActivityWithResult(uniqueIdentifier) + } + } else { + val message = (this.item as Savable).getFailedSaveMessage() + val builder = AlertDialog.Builder(requireContext()) + .setMessage(message) + .setNegativeButton(R.string.ok, null) + builder.show() + } + */ + } + + /** + * Delete data + */ + private fun deleteData() { + /* + val builder = AlertDialog.Builder(requireContext()) + builder.setTitle(R.string.warning) + .setMessage(R.string.are_you_sure_you_want_to_do_that_) + .setNegativeButton(R.string.no, null) + .setPositiveButton(R.string.yes) { _, _ -> + //TODO: Maybe update this code, does the object need to be managed? + this.getRealm().executeTransaction { + this.liveDataType.deleteData(it, (this.item as Manageable)) + } + this.activity?.finish() + } + builder.show() + */ + } + + /** + * Finish the activity with a result + */ + private fun finishActivityWithResult(uniqueIdentifier: String) { + /* + val intent = Intent() + intent.putExtra(EditableDataActivity.IntentKey.DATA_TYPE.keyName, dataType) + intent.putExtra(EditableDataActivity.IntentKey.PRIMARY_KEY.keyName, uniqueIdentifier) + activity?.setResult(RESULT_OK, intent) + */ + activity?.finish() + } + + /** + * Set fragment data + */ + fun setData(dataType: Int, primaryKey: String?) { + /* + this.dataType = dataType + this.liveDataType = LiveData.values()[dataType] + this.primaryKey = primaryKey + */ + } + +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt index 2a82aee7..b828c444 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt @@ -41,6 +41,7 @@ enum class RowViewType(private var layoutRes: Int) { INFO(R.layout.row_info), // Row + CLASSIC_HEADER_TITLE(R.layout.row_header_title), TITLE(R.layout.row_title), TITLE_ARROW(R.layout.row_title_arrow), TITLE_VALUE(R.layout.row_title_value), @@ -75,7 +76,7 @@ enum class RowViewType(private var layoutRes: Int) { HEADER_TITLE, HEADER_TITLE_VALUE, HEADER_TITLE_AMOUNT, HEADER_TITLE_AMOUNT_BIG, LOCATION_TITLE, INFO -> CustomizableRowViewHolder(layout) // Row View Holder - TITLE, TITLE_ARROW, TITLE_VALUE, TITLE_VALUE_ARROW, TITLE_GRID, TITLE_SWITCH, TITLE_CHECK, DATA, BOTTOM_SHEET_DATA, LOADER -> RowViewHolder( + CLASSIC_HEADER_TITLE, TITLE, TITLE_ARROW, TITLE_VALUE, TITLE_VALUE_ARROW, TITLE_GRID, TITLE_SWITCH, TITLE_CHECK, DATA, BOTTOM_SHEET_DATA, LOADER -> RowViewHolder( layout ) diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterCategoryRow.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterCategoryRow.kt new file mode 100644 index 00000000..af5d5f88 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterCategoryRow.kt @@ -0,0 +1,91 @@ +package net.pokeranalytics.android.ui.view.rowrepresentable + +import net.pokeranalytics.android.R +import net.pokeranalytics.android.ui.view.RowRepresentable +import net.pokeranalytics.android.ui.view.RowViewType + +enum class FilterCategoryRow : RowRepresentable { + + GENERAL, + DATE, + DURATION, + SESSION, + CASH, + TOURNAMENT, + ONLINE, + RESULT, + TRANSACTION_TYPES, + + // Title Custom fields + LOCATION, + BANKROLL, + PLAYERS; + + override val resId: Int? + get() { + return when (this) { + GENERAL -> R.string.general + DATE -> R.string.date + DURATION -> R.string.duration + SESSION -> R.string.session + CASH -> R.string.cash + TOURNAMENT -> R.string.tournament + ONLINE -> R.string.online + RESULT -> R.string.result + TRANSACTION_TYPES -> R.string.operation_types + LOCATION -> R.string.location + BANKROLL -> R.string.bankroll + PLAYERS -> R.string.players + } + } + + override val viewType: Int + get() { + return when (this) { + GENERAL, DATE, DURATION, SESSION, CASH, TOURNAMENT, ONLINE, RESULT, TRANSACTION_TYPES, + LOCATION, BANKROLL, PLAYERS -> RowViewType.TITLE_VALUE_ARROW.ordinal + } + } + + /** + * Get subcategories of filters + */ + fun getSubcategories(): ArrayList { + val subcategories = ArrayList() + + when (this) { + GENERAL -> subcategories.addAll( + arrayListOf( + FilterSubcategoryRow.CASH_TOURNAMENT, FilterSubcategoryRow.LIVE_ONLINE, FilterSubcategoryRow.GAME, + FilterSubcategoryRow.LIMIT_TYPE, FilterSubcategoryRow.TABLE_SIZE + ) + ) + DATE -> subcategories.addAll( + arrayListOf( + FilterSubcategoryRow.DYNAMIC_DATE, FilterSubcategoryRow.FIXED_DATE, FilterSubcategoryRow.DURATION, FilterSubcategoryRow.YEAR, + FilterSubcategoryRow.WEEKDAYS_OR_WEEKEND, FilterSubcategoryRow.DAY_OF_WEEK, FilterSubcategoryRow.MONTH_OF_YEAR + ) + ) + DURATION -> subcategories.addAll(arrayListOf(FilterSubcategoryRow.SESSION_DURATION, FilterSubcategoryRow.RANGE)) + SESSION -> subcategories.addAll(arrayListOf()) + CASH -> subcategories.addAll(arrayListOf(FilterSubcategoryRow.BLINDS, FilterSubcategoryRow.CASH_RE_BUY_COUNT)) + TOURNAMENT -> subcategories.addAll( + arrayListOf( + FilterSubcategoryRow.TOURNAMENT_TYPE, FilterSubcategoryRow.COMPLETION_PERCENTAGE, FilterSubcategoryRow.PLACE, + FilterSubcategoryRow.PLAYERS_COUNT, FilterSubcategoryRow.TOURNAMENT_RE_BUY_COUNT, FilterSubcategoryRow.BUY_IN + ) + ) + ONLINE -> subcategories.addAll(arrayListOf(FilterSubcategoryRow.MULTI_TABLING)) + RESULT -> subcategories.addAll(arrayListOf(FilterSubcategoryRow.VALUE)) + TRANSACTION_TYPES -> subcategories.addAll(arrayListOf()) + LOCATION -> subcategories.addAll(arrayListOf(FilterSubcategoryRow.LOCATION)) + BANKROLL -> subcategories.addAll(arrayListOf(FilterSubcategoryRow.BANKROLL)) + PLAYERS -> subcategories.addAll(arrayListOf(FilterSubcategoryRow.NUMBER_OF_PLAYERS, FilterSubcategoryRow.MULTI_PLAYER)) + + } + + return subcategories + } + + +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterRow.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterRow.kt deleted file mode 100644 index 0b5f2b7a..00000000 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterRow.kt +++ /dev/null @@ -1,50 +0,0 @@ -package net.pokeranalytics.android.ui.view.rowrepresentable - -import net.pokeranalytics.android.R -import net.pokeranalytics.android.ui.view.RowRepresentable -import net.pokeranalytics.android.ui.view.RowViewType - -enum class FilterRow : RowRepresentable { - - GENERAL, - DATE, - DURATION, - SESSION, - CASH, - TOURNAMENT, - ONLINE, - RESULT, - TRANSACTION_TYPES, - - // Title Custom fields - LOCATION, - BANKROLL, - PLAYERS; - - override val resId: Int? - get() { - return when (this) { - GENERAL -> R.string.general - DATE -> R.string.date - DURATION -> R.string.duration - SESSION -> R.string.session - CASH -> R.string.cash - TOURNAMENT -> R.string.tournament - ONLINE -> R.string.online - RESULT -> R.string.result - TRANSACTION_TYPES -> R.string.operation_types - LOCATION -> R.string.location - BANKROLL -> R.string.bankroll - PLAYERS -> R.string.players - } - } - - override val viewType: Int - get() { - return when (this) { - GENERAL, DATE, DURATION, SESSION, CASH, TOURNAMENT, ONLINE, RESULT, TRANSACTION_TYPES, - LOCATION, BANKROLL, PLAYERS -> RowViewType.TITLE_VALUE_ARROW.ordinal - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterSubcategoryRow.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterSubcategoryRow.kt new file mode 100644 index 00000000..bc4e4aa9 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterSubcategoryRow.kt @@ -0,0 +1,113 @@ +package net.pokeranalytics.android.ui.view.rowrepresentable + +import net.pokeranalytics.android.R +import net.pokeranalytics.android.ui.view.RowRepresentable +import net.pokeranalytics.android.ui.view.RowViewType + +enum class FilterSubcategoryRow : RowRepresentable { + + // General + CASH_TOURNAMENT, + LIVE_ONLINE, + GAME, + LIMIT_TYPE, + TABLE_SIZE, + + // Date + DYNAMIC_DATE, + FIXED_DATE, + DURATION, + YEAR, + WEEKDAYS_OR_WEEKEND, + DAY_OF_WEEK, + MONTH_OF_YEAR, + + // Duration + SESSION_DURATION, + RANGE, + + // Sessions + // - + + // Cash + BLINDS, + CASH_RE_BUY_COUNT, + + // Tournament + TOURNAMENT_TYPE, + COMPLETION_PERCENTAGE, + PLACE, + PLAYERS_COUNT, + TOURNAMENT_RE_BUY_COUNT, + BUY_IN, + + // Online + MULTI_TABLING, + + // Result + VALUE, + + // Transaction types + // - + + // Location + LOCATION, + + // Bankroll + BANKROLL, + + // Players + NUMBER_OF_PLAYERS, + MULTI_PLAYER; + + override val resId: Int? + get() { + return when(this) { + CASH_TOURNAMENT -> R.string.cash_or_tournament + LIVE_ONLINE -> R.string.live_or_online + GAME -> R.string.game + LIMIT_TYPE -> R.string.type_de_limite + TABLE_SIZE -> R.string.table_size + + DYNAMIC_DATE -> R.string.dynamic_date + FIXED_DATE -> R.string.fixed_date + DURATION -> R.string.duration + YEAR -> R.string.year + WEEKDAYS_OR_WEEKEND -> R.string.weekdays_or_weekend + DAY_OF_WEEK -> R.string.day_of_the_week + MONTH_OF_YEAR -> R.string.month_of_the_year + + SESSION_DURATION -> R.string.session_duration + RANGE -> R.string.hour_slot + + BLINDS -> R.string.blinds + CASH_RE_BUY_COUNT -> R.string.rebuy_count + + TOURNAMENT_TYPE -> R.string.tournament_type + COMPLETION_PERCENTAGE -> R.string.tournament_completion_percentage_interval + PLACE -> R.string.place + PLAYERS_COUNT -> R.string.players_count + TOURNAMENT_RE_BUY_COUNT -> R.string.rebuy_count + BUY_IN -> R.string.buyin + + MULTI_TABLING -> R.string.multi_tabling + + VALUE -> R.string.value + + LOCATION -> R.string.location + + BANKROLL -> R.string.bankroll + + NUMBER_OF_PLAYERS -> R.string.number_of_players + MULTI_PLAYER -> R.string.multiplayer + } + } + + override val viewType: Int = RowViewType.CLASSIC_HEADER_TITLE.ordinal + + fun getFilterRow() : ArrayList { + val rows = ArrayList() + return rows + } + +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_filter.xml b/app/src/main/res/layout/activity_filter_details.xml similarity index 100% rename from app/src/main/res/layout/activity_filter.xml rename to app/src/main/res/layout/activity_filter_details.xml diff --git a/app/src/main/res/layout/activity_filters.xml b/app/src/main/res/layout/activity_filters.xml new file mode 100644 index 00000000..70454fb9 --- /dev/null +++ b/app/src/main/res/layout/activity_filters.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_filter.xml b/app/src/main/res/layout/fragment_filter_details.xml similarity index 100% rename from app/src/main/res/layout/fragment_filter.xml rename to app/src/main/res/layout/fragment_filter_details.xml diff --git a/app/src/main/res/layout/fragment_filters.xml b/app/src/main/res/layout/fragment_filters.xml new file mode 100644 index 00000000..bab049a9 --- /dev/null +++ b/app/src/main/res/layout/fragment_filters.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 9a9bc2138630d44c7f4cacd5ac8ac11d07a7f071 Mon Sep 17 00:00:00 2001 From: Razmig Sarkissian Date: Tue, 19 Mar 2019 14:24:22 +0100 Subject: [PATCH 22/24] add new filters --- .../SessionFilterInstrumentedUnitTest.kt | 110 ++++++++++++++++++ .../android/model/filter/SessionFilterable.kt | 15 +++ 2 files changed, 125 insertions(+) diff --git a/app/src/androidTest/java/net/pokeranalytics/android/filter/SessionFilterInstrumentedUnitTest.kt b/app/src/androidTest/java/net/pokeranalytics/android/filter/SessionFilterInstrumentedUnitTest.kt index d2ba8a39..5b477aef 100644 --- a/app/src/androidTest/java/net/pokeranalytics/android/filter/SessionFilterInstrumentedUnitTest.kt +++ b/app/src/androidTest/java/net/pokeranalytics/android/filter/SessionFilterInstrumentedUnitTest.kt @@ -452,6 +452,116 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { sessions.forEach { Assert.assertTrue(result.contains((it as Session).id)) } + } + + @Test + fun testTableSizeFilter() { + val realm = this.mockRealm + realm.beginTransaction() + val s1 = Session.testInstance(tableSize = 2) + val s2 = Session.testInstance(tableSize = 4) + Session.testInstance(tableSize = 9) + Session.testInstance(tableSize = 10) + realm.commitTransaction() + + val filter = SessionFilterable.TABLE_SIZE + filter.valueMap = mapOf("values" to arrayOf(2,4)) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(2, sessions.size) + + val result = arrayListOf(s1.id, s2.id) + sessions.forEach { + Assert.assertTrue(result.contains((it as Session).id)) + } + } + + @Test + fun testMoreThanNetResultFilter() { + val realm = this.mockRealm + realm.beginTransaction() + Session.testInstance(netResult = 200.0) + val s1 = Session.testInstance(netResult = 500.0) + Session.testInstance(netResult = 50.0) + val s2 = Session.testInstance(netResult = 570.0) + realm.commitTransaction() + + val filter = SessionFilterable.MORE_THAN_NET_RESULT + filter.valueMap = mapOf("net" to 204.0) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(2, sessions.size) + + val result = arrayListOf(s1.id, s2.id) + sessions.forEach { + Assert.assertTrue(result.contains((it as Session).id)) + } + } + + @Test + fun testLessThanNetResultFilter() { + val realm = this.mockRealm + realm.beginTransaction() + val s1 = Session.testInstance(netResult = 200.0) + val s2 = Session.testInstance(netResult = 500.0) + val s3 = Session.testInstance(netResult = 50.0) + Session.testInstance(netResult = 570.0) + realm.commitTransaction() + + val filter = SessionFilterable.LESS_THAN_NET_RESULT + filter.valueMap = mapOf("net" to 540.0) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(3, sessions.size) + + val result = arrayListOf(s1.id, s2.id, s3.id) + sessions.forEach { + Assert.assertTrue(result.contains((it as Session).id)) + } + } + + @Test + fun tesNetResultFilter() { + val realm = this.mockRealm + realm.beginTransaction() + val s1 = Session.testInstance(netResult = 200.0) + val s2 = Session.testInstance(netResult = 500.0) + val s3 = Session.testInstance(netResult = 50.0) + Session.testInstance(netResult = 570.0) + realm.commitTransaction() + + val filterMore = SessionFilterable.MORE_THAN_NET_RESULT + filterMore.valueMap = mapOf("net" to 200.0) + + val filterLess = SessionFilterable.LESS_THAN_NET_RESULT + filterLess.valueMap = mapOf("net" to 400.0) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filterLess, filterMore) + ) + Assert.assertEquals(1, sessions.size) + + val result = arrayListOf(s1.id) + sessions.forEach { + Assert.assertTrue(result.contains((it as Session).id)) + } } } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/SessionFilterable.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/SessionFilterable.kt index 37886323..ee3eb862 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/filter/SessionFilterable.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/SessionFilterable.kt @@ -22,6 +22,8 @@ enum class SessionFilterable(private var fieldName:String? = null): Filterable { NUMBER_OF_TABLE("numberOfTable"), TOURNAMENT_TYPE("tournamentType"), BLINDS, + LESS_THAN_NET_RESULT, + MORE_THAN_NET_RESULT, ; private enum class Field(var fieldName:String) { @@ -50,10 +52,16 @@ enum class SessionFilterable(private var fieldName:String? = null): Filterable { BANKROLL, GAME, LOCATION, ANY_TOURNAMENT_FEATURES, ALL_TOURNAMENT_FEATURES -> arrayOf("ids") LIMIT, TOURNAMENT_TYPE, TABLE_SIZE, NUMBER_OF_TABLE -> arrayOf("values") BLINDS -> arrayOf("map") + MORE_THAN_NET_RESULT, LESS_THAN_NET_RESULT -> arrayOf("net") else -> null } } + var between: Boolean = false + var moreThan: Boolean = false + var lessThan: Boolean = false + var strict: Boolean = false + override fun filter(realmQuery: RealmQuery): RealmQuery { return when (this) { LIVE -> realmQuery.equalTo(Field.LIVE.fieldName, true) @@ -87,6 +95,13 @@ enum class SessionFilterable(private var fieldName:String? = null): Filterable { throw FilterValueMapException("fieldName is missing") } } + MORE_THAN_NET_RESULT, LESS_THAN_NET_RESULT -> { + val net : Double by filterValues + if (this == LESS_THAN_NET_RESULT) { + realmQuery.not() + } + realmQuery.greaterThanOrEqualTo(Field.RESULT_NET.fieldName, net) + } BLINDS -> { val map : Array> by filterValues val expectedSubKeys = arrayOf("sb", "bb", "code") From 940666adb909d059491f6dc96003c9a2c4d719f3 Mon Sep 17 00:00:00 2001 From: Aurelien Hubert Date: Tue, 19 Mar 2019 15:15:40 +0100 Subject: [PATCH 23/24] Improve filters / wip --- .../ui/fragment/FilterDetailsFragment.kt | 68 +++++++++---------- .../ui/view/rowrepresentable/FilterRow.kt | 27 ++++++++ .../rowrepresentable/FilterSubcategoryRow.kt | 35 +++++++++- 3 files changed, 92 insertions(+), 38 deletions(-) create mode 100644 app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterRow.kt diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/FilterDetailsFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/FilterDetailsFragment.kt index 95349e78..87688c66 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/FilterDetailsFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/FilterDetailsFragment.kt @@ -9,15 +9,16 @@ import kotlinx.android.synthetic.main.fragment_filter_details.view.* import net.pokeranalytics.android.R import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter +import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate -import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment import net.pokeranalytics.android.ui.view.RowRepresentable +import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.rowrepresentable.FilterCategoryRow import timber.log.Timber -open class FilterDetailsFragment : PokerAnalyticsFragment(), StaticRowRepresentableDataSource, RowRepresentableDelegate { +open class FilterDetailsFragment : PokerAnalyticsFragment(), RowRepresentableDataSource, RowRepresentableDelegate { lateinit var parentActivity: PokerAnalyticsActivity lateinit var item: RealmObject @@ -59,10 +60,7 @@ open class FilterDetailsFragment : PokerAnalyticsFragment(), StaticRowRepresenta return true } - override fun adapterRows(): List? { - return rows - } - + /* override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) { super.onRowSelected(position, row, fromAction) } @@ -70,6 +68,29 @@ open class FilterDetailsFragment : PokerAnalyticsFragment(), StaticRowRepresenta override fun onRowValueChanged(value: Any?, row: RowRepresentable) { super.onRowValueChanged(value, row) } + */ + + override fun adapterRows(): List? { + return rows + } + + override fun rowRepresentableForPosition(position: Int): RowRepresentable? { + return rows[position] + } + + override fun numberOfRows(): Int { + return rows.size + } + + override fun viewTypeForPosition(position: Int): Int { + val rowViewType = rowRepresentableForPosition(position)?.viewType ?: -1 + return if (rowViewType != -1) rowViewType else RowViewType.TITLE_CHECK.ordinal + } + + override fun indexForRow(row: RowRepresentable): Int { + return rows.indexOf(row) + } + /** * Init UI @@ -102,40 +123,15 @@ open class FilterDetailsFragment : PokerAnalyticsFragment(), StaticRowRepresenta this.appBar.toolbar.title = it.localizedTitle(requireContext()) this.rows.clear() - this.rows.addAll(it.getSubcategories()) - Timber.d("initData: ${this.rows.size}") + for (subcategory in it.getSubcategories()) { + this.rows.add(subcategory) + this.rows.addAll(subcategory.getFilterRows(getRealm())) + } this.rowRepresentableAdapter = RowRepresentableAdapter(this, this) this.recyclerView.adapter = rowRepresentableAdapter - } - /* - if (this.dataType != null) { - val proxyItem: RealmObject? = this.liveDataType.getData(this.getRealm(), primaryKey) - proxyItem?.let { - //TODO: Localize - this.appBar.toolbar.title = "Update ${this.liveDataType.localizedTitle(this.parentActivity).toLowerCase().capitalize()}" - isUpdating = true - } ?: run { - //TODO: Localize - this.appBar.toolbar.title = this.liveDataType.newEntityLocalizedTitle(requireContext()) - } - this.item = this.liveDataType.updateOrCreate(this.getRealm(), primaryKey) - - val dataSource = getDataSource() - this.rowRepresentableAdapter = RowRepresentableAdapter(getDataSource(), this) - this.recyclerView.adapter = rowRepresentableAdapter - - // When creating an object, open automatically the keyboard for the first row - if (!isUpdating && shouldOpenKeyboard) { - val row = dataSource.adapterRows()?.firstOrNull() - row?.let { - onRowSelected(0, it) - } - } - } - */ } /** @@ -211,8 +207,6 @@ open class FilterDetailsFragment : PokerAnalyticsFragment(), StaticRowRepresenta */ fun setData(filterCategory: Int) { - Timber.d("Filter Category: ${FilterCategoryRow.values()[filterCategory]}") - Timber.d("Filter Subcategories: ${FilterCategoryRow.values()[filterCategory].getSubcategories()}") this.filterCategory = FilterCategoryRow.values()[filterCategory] /* diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterRow.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterRow.kt new file mode 100644 index 00000000..67ee210f --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterRow.kt @@ -0,0 +1,27 @@ +package net.pokeranalytics.android.ui.view.rowrepresentable + +import net.pokeranalytics.android.R +import net.pokeranalytics.android.ui.view.RowRepresentable +import net.pokeranalytics.android.ui.view.RowViewType + +enum class FilterRow : RowRepresentable { + + // General + CASH_GAME, + TOURNAMENT, + LIVE, + ONLINE; + + override val resId: Int? + get() { + return when (this) { + CASH_GAME -> R.string.cash_game + TOURNAMENT -> R.string.tournament + LIVE -> R.string.live + ONLINE -> R.string.online + } + } + + override val viewType: Int = RowViewType.TITLE_CHECK.ordinal + +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterSubcategoryRow.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterSubcategoryRow.kt index bc4e4aa9..a9a30dbc 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterSubcategoryRow.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterSubcategoryRow.kt @@ -1,6 +1,11 @@ package net.pokeranalytics.android.ui.view.rowrepresentable +import io.realm.Realm +import io.realm.RealmResults import net.pokeranalytics.android.R +import net.pokeranalytics.android.model.Limit +import net.pokeranalytics.android.model.LiveData +import net.pokeranalytics.android.model.realm.Game import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowViewType @@ -60,6 +65,11 @@ enum class FilterSubcategoryRow : RowRepresentable { NUMBER_OF_PLAYERS, MULTI_PLAYER; + enum class Type { + SINGLE, + MULTIPLE, + } + override val resId: Int? get() { return when(this) { @@ -105,8 +115,31 @@ enum class FilterSubcategoryRow : RowRepresentable { override val viewType: Int = RowViewType.CLASSIC_HEADER_TITLE.ordinal - fun getFilterRow() : ArrayList { + /** + * Return the type of the selection + */ + fun getType() : Type { + return when(this) { + GAME -> Type.MULTIPLE + else -> Type.SINGLE + } + } + + /** + * Returns the filter rows + */ + fun getFilterRows(realm: Realm) : ArrayList { val rows = ArrayList() + when(this) { + CASH_TOURNAMENT -> rows.addAll(arrayListOf(FilterRow.CASH_GAME, FilterRow.TOURNAMENT)) + LIVE_ONLINE -> rows.addAll(arrayListOf(FilterRow.LIVE, FilterRow.ONLINE)) + GAME -> { + val games = realm.copyFromRealm(LiveData.GAME.items(realm) as RealmResults) + rows.addAll(games) + } + LIMIT_TYPE -> rows.addAll(Limit.values()) + else -> rows.addAll(arrayListOf()) + } return rows } From 47c76e18c1170d6fb1bfb38459c0879b03dfa18c Mon Sep 17 00:00:00 2001 From: Aurelien Hubert Date: Tue, 19 Mar 2019 15:34:47 +0100 Subject: [PATCH 24/24] Add single/multiple row selection --- .../ui/fragment/FilterDetailsFragment.kt | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/FilterDetailsFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/FilterDetailsFragment.kt index 87688c66..a6b90282 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/FilterDetailsFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/FilterDetailsFragment.kt @@ -15,6 +15,7 @@ import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.rowrepresentable.FilterCategoryRow +import net.pokeranalytics.android.ui.view.rowrepresentable.FilterSubcategoryRow import timber.log.Timber @@ -60,15 +61,40 @@ open class FilterDetailsFragment : PokerAnalyticsFragment(), RowRepresentableDat return true } - /* override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) { super.onRowSelected(position, row, fromAction) + + + filterCategory?.let { + for (subcategory in it.getSubcategories()) { + if (subcategory.getFilterRows(getRealm()).contains(row)) { + if (subcategory.getType() == FilterSubcategoryRow.Type.SINGLE) { + for (filterRow in subcategory.getFilterRows(getRealm())) { + selectedRows.remove(filterRow) + } + } + } + } + } + + if (selectedRows.contains(row)) { + selectedRows.remove(row) + } else { + selectedRows.add(row) + } + + rowRepresentableAdapter.notifyDataSetChanged() + } + + val selectedRows = ArrayList() + + override fun isSelected(row: RowRepresentable): Boolean { + return selectedRows.contains(row) } override fun onRowValueChanged(value: Any?, row: RowRepresentable) { super.onRowValueChanged(value, row) } - */ override fun adapterRows(): List? { return rows