diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5776f99f..714f4e26 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -176,6 +176,11 @@ android:launchMode="singleTop" android:screenOrientation="portrait" /> + + = listOf() ) { constructor( @@ -252,8 +251,16 @@ class Calculator { // Timber.d("$$$ buyin = ${it.ratedBuyin} $$$ net result = ${it.ratedNet}") // } - val sum = computables.sum(ComputableResult.Field.RATED_NET.identifier).toDouble() - results.addStat(NET_RESULT, sum) + var ratedNet = computables.sum(ComputableResult.Field.RATED_NET.identifier).toDouble() + if (options.includedTransactions.isNotEmpty()) { + for (transactionType in options.includedTransactions) { + val transactions = computableGroup.transactions(realm, transactionType, options.shouldSortValues) + val transactionRatedAmount = transactions.sum(Transaction.Field.RATED_AMOUNT.identifier).toDouble() + ratedNet += transactionRatedAmount + } + } + + results.addStat(NET_RESULT, ratedNet) val totalHands = computables.sum(ComputableResult.Field.ESTIMATED_HANDS.identifier).toDouble() results.addStat(HANDS_PLAYED, totalHands) @@ -288,7 +295,7 @@ class Calculator { Stat.netBBPer100Hands(bbSum, totalHands)?.let { netBB100 -> results.addStat(NET_BB_PER_100_HANDS, netBB100) } - Stat.returnOnInvestment(sum, totalBuyin)?.let { roi -> + Stat.returnOnInvestment(ratedNet, totalBuyin)?.let { roi -> results.addStat(ROI, roi) } @@ -305,7 +312,7 @@ class Calculator { var average = 0.0 // also used for standard deviation later if (computables.size > 0) { - average = sum / computables.size.toDouble() + average = ratedNet / computables.size.toDouble() val winRatio = winningSessionCount.toDouble() / computables.size.toDouble() val itmRatio = winningSessionCount.toDouble() / computables.size.toDouble() val avgBuyin = totalBuyin / computables.size.toDouble() @@ -425,9 +432,9 @@ class Calculator { } } - val shouldIterateOverSets = computableGroup.conditions.isNotEmpty() || - options.progressValues != Options.ProgressValues.NONE || - options.computeDaysPlayed + val shouldIterateOverSets = computableGroup.conditions.isNotEmpty() + || options.progressValues != Options.ProgressValues.NONE + || options.computeDaysPlayed // Session Set if (shouldIterateOverSets) { @@ -525,7 +532,7 @@ class Calculator { var hourlyRate = 0.0 if (gHourlyDuration != null) { - hourlyRate = sum / gHourlyDuration + hourlyRate = ratedNet / gHourlyDuration if (sessionSets.size > 0) { val avgDuration = gHourlyDuration / sessionSets.size results.addStat(HOURLY_RATE, hourlyRate) diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/ComputableGroup.kt b/app/src/main/java/net/pokeranalytics/android/calculus/ComputableGroup.kt index 5cd8937d..d0ce49c6 100644 --- a/app/src/main/java/net/pokeranalytics/android/calculus/ComputableGroup.kt +++ b/app/src/main/java/net/pokeranalytics/android/calculus/ComputableGroup.kt @@ -4,15 +4,14 @@ import io.realm.Realm import io.realm.RealmResults import net.pokeranalytics.android.model.filter.Query import net.pokeranalytics.android.model.filter.QueryCondition -import net.pokeranalytics.android.model.realm.ComputableResult -import net.pokeranalytics.android.model.realm.Filter -import net.pokeranalytics.android.model.realm.SessionSet +import net.pokeranalytics.android.model.realm.* +import timber.log.Timber /** * A sessionGroup of computable items identified by a name */ -class ComputableGroup(var query: Query, var displayedStats: List? = null) { +class ComputableGroup(val query: Query, var displayedStats: List? = null) { /** * A subgroup used to compute stat variation @@ -85,6 +84,17 @@ class ComputableGroup(var query: Query, var displayedStats: List? = null) return sets } + /** + * Retrieves the transactions on the relative [realm] filtered with the provided [conditions] + */ + fun transactions(realm: Realm, transactionType: TransactionType, sorted: Boolean = false): RealmResults { + val query = this.query.copy() + query.add(QueryCondition.AnyTransactionType(transactionType)) + val sortedField = if (sorted) "date" else null + Timber.d("query = ${query.defaultName}") + return Filter.queryOn(realm, query, sortedField) + } + /** * Nullifies used Realm results */ 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 c86980ed..e0c7a276 100644 --- a/app/src/main/java/net/pokeranalytics/android/exceptions/Exceptions.kt +++ b/app/src/main/java/net/pokeranalytics/android/exceptions/Exceptions.kt @@ -17,7 +17,7 @@ sealed class PokerAnalyticsException(message: String) : Exception(message) { // object FilterElementUnknownSectionName: PokerAnalyticsException(message = "No filterElement section name was found to identify the queryCondition") // object FilterMissingEntity: PokerAnalyticsException(message = "This queryWith has no entity initialized") // object FilterUnhandledEntity : PokerAnalyticsException(message = "This entity is not filterable") - object QueryValueMapUnknown: PokerAnalyticsException(message = "fieldName is missing") +class QueryValueMapUnknown(message: String = "fieldName is missing"): PokerAnalyticsException(message) class QueryTypeUnhandled(clazz: String) : PokerAnalyticsException(message = "queryWith type not handled: $clazz") class ComparisonCriteriaUnhandled(criteria: Criteria) : diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/Query.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/Query.kt index 8a8b583f..307c80ab 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/filter/Query.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/Query.kt @@ -11,6 +11,10 @@ fun List.mapFirstCondition() : List { class Query { + constructor(query: Query) { + this._conditions.addAll(query.conditions) + } + constructor(vararg elements: QueryCondition?) { if (elements.isNotEmpty()) { this.add(elements.filterNotNull()) @@ -100,6 +104,11 @@ class Query { return this } + fun copy(): Query { + return Query(this) + } + + /* Returns the first object Id of any QueryCondition */ diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/QueryCondition.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/QueryCondition.kt index 8354a29c..ec7318eb 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/filter/QueryCondition.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/QueryCondition.kt @@ -23,6 +23,7 @@ import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.UserDefaults import net.pokeranalytics.android.util.extensions.* +import timber.log.Timber import java.text.DateFormatSymbols import java.text.NumberFormat import java.util.* @@ -747,9 +748,16 @@ sealed class QueryCondition : RowRepresentable { ): RealmQuery { val fieldName = FilterHelper.fieldNameForQueryType(this::class.java) - if (BuildConfig.DEBUG) { - fieldName ?: throw PokerAnalyticsException.QueryValueMapUnknown +// if (BuildConfig.DEBUG) { +// val className = T::class.java +// fieldName ?: throw PokerAnalyticsException.QueryValueMapUnknown("fieldName missing for $this, class = $className") +// } + + if (fieldName == null) { + val className = T::class.java + Timber.w("Possible missing filter configuration for $this in class $className") } + fieldName ?: return realmQuery when (this) { diff --git a/app/src/main/java/net/pokeranalytics/android/model/migrations/PokerAnalyticsMigration.kt b/app/src/main/java/net/pokeranalytics/android/model/migrations/PokerAnalyticsMigration.kt index 8ca95a3e..91d61f5e 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/migrations/PokerAnalyticsMigration.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/migrations/PokerAnalyticsMigration.kt @@ -292,11 +292,11 @@ class PokerAnalyticsMigration : RealmMigration { // Migrate to version 13 if (currentVersion == 12) { Timber.d("*** Running migration ${currentVersion + 1}") - schema.get("Transaction")?.let { tts -> - tts.addField("transferRate", Double::class.java) + schema.get("Transaction")?.let { ts -> + ts.addField("transferRate", Double::class.java) .setNullable("transferRate", true) schema.get("Bankroll")?.let { bs -> - tts.addRealmObjectField("destination", bs) + ts.addRealmObjectField("destination", bs) } ?: throw PAIllegalStateException("Bankroll schema not found") } @@ -314,6 +314,21 @@ class PokerAnalyticsMigration : RealmMigration { currentVersion++ } + // Migrate to version 14 + if (currentVersion == 13) { + Timber.d("*** Running migration ${currentVersion + 1}") + schema.get("Transaction")?.let { ts -> + ts.addField("ratedAmount", Double::class.java) + } ?: throw PAIllegalStateException("Transaction schema not found") + + //transactionTypeIds + schema.get("UserConfig")?.let { ucs -> + ucs.addField("transactionTypeIds", String::class.java).setRequired("transactionTypeIds", true) + } ?: throw PAIllegalStateException("UserConfig schema not found") + + currentVersion++ + } + } override fun equals(other: Any?): Boolean { diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/Transaction.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/Transaction.kt index 6f8362a5..094dca1d 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/Transaction.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/Transaction.kt @@ -73,6 +73,14 @@ open class Transaction : RealmObject(), RowRepresentable, RowUpdatable, Manageab // The amount of the transaction override var amount: Double = 0.0 + set(value) { + field = value + val rate = this.bankroll?.currency?.rate ?: 1.0 + this.ratedAmount = rate * value + } + + // The amount of the transaction + var ratedAmount: Double = 0.0 // The date of the transaction override var date: Date = Date() @@ -102,6 +110,10 @@ open class Transaction : RealmObject(), RowRepresentable, RowUpdatable, Manageab @Ignore override val viewType: Int = RowViewType.ROW_TRANSACTION.ordinal + enum class Field(val identifier: String) { + RATED_AMOUNT("ratedAmount") + } + val displayAmount: Double get() { // for transfers we want to show a positive value (in the feed for instance) return if (this.destination == null) { this.amount } else { abs(this.amount) } diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/UserConfig.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/UserConfig.kt index 5b95e626..96094c1f 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/UserConfig.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/UserConfig.kt @@ -3,6 +3,8 @@ package net.pokeranalytics.android.model.realm import io.realm.Realm import io.realm.RealmObject import io.realm.annotations.PrimaryKey +import net.pokeranalytics.android.util.UUID_SEPARATOR +import net.pokeranalytics.android.util.extensions.findById import java.util.* open class UserConfig : RealmObject() { @@ -25,4 +27,15 @@ open class UserConfig : RealmObject() { var onlineDealtHandsPerHour: Int = 500 + var transactionTypeIds: String = "" + + fun setTransactionTypeIds(transactionTypes: Set) { + this.transactionTypeIds = transactionTypes.joinToString(UUID_SEPARATOR) { it.id } + } + + fun transactionTypes(realm: Realm): List { + val ids = this.transactionTypeIds.split(UUID_SEPARATOR) + return ids.mapNotNull { realm.findById(it) } + } + } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatisticsFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatisticsFragment.kt index 6b8d81f9..c2c48e5f 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatisticsFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatisticsFragment.kt @@ -2,11 +2,13 @@ package net.pokeranalytics.android.ui.fragment import android.app.Activity import android.content.Intent +import android.content.res.ColorStateList +import android.os.Build import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup +import android.view.* +import androidx.appcompat.widget.Toolbar import io.realm.Realm +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.async import kotlinx.coroutines.launch @@ -19,16 +21,14 @@ import net.pokeranalytics.android.databinding.FragmentStatsBinding import net.pokeranalytics.android.exceptions.PAIllegalStateException import net.pokeranalytics.android.model.filter.Query import net.pokeranalytics.android.model.filter.QueryCondition -import net.pokeranalytics.android.model.realm.ComputableResult -import net.pokeranalytics.android.model.realm.Filter -import net.pokeranalytics.android.model.realm.Result -import net.pokeranalytics.android.model.realm.UserConfig +import net.pokeranalytics.android.model.realm.* import net.pokeranalytics.android.ui.fragment.components.FilterableFragment import net.pokeranalytics.android.ui.fragment.components.RealmAsyncListener import net.pokeranalytics.android.ui.fragment.report.ComposableTableReportFragment import net.pokeranalytics.android.ui.modules.filter.FilterActivityRequestCode import net.pokeranalytics.android.ui.modules.filter.FilterableType import net.pokeranalytics.android.ui.modules.filter.FiltersActivity +import net.pokeranalytics.android.ui.modules.settings.TransactionFilterActivity import timber.log.Timber import java.util.* @@ -36,6 +36,8 @@ class StatisticsFragment : FilterableFragment(), RealmAsyncListener { private lateinit var tableReportFragment: ComposableTableReportFragment + private var transactionFilterMenuItem: MenuItem? = null + companion object { /** @@ -73,6 +75,7 @@ class StatisticsFragment : FilterableFragment(), RealmAsyncListener { addRealmChangeListener(this, UserConfig::class.java) addRealmChangeListener(this, ComputableResult::class.java) + addRealmChangeListener(this, Transaction::class.java) } private fun initUI() { @@ -83,27 +86,41 @@ class StatisticsFragment : FilterableFragment(), RealmAsyncListener { this.tableReportFragment = fragment } -// override val observedEntities: List> = listOf(ComputableResult::class.java) - -// override fun entitiesChanged(clazz: Class, results: RealmResults) { -// Timber.d("Entities changes, launch stats computation, size = ${results.size}") -// val cr = results as RealmResults -// cr.forEach { -// Timber.d("### buyin = ${it.ratedBuyin} ### net result = ${it.ratedNet}") -// } -// this.launchStatComputation() -// } - -// override fun convertReportIntoRepresentables(report: Report): ArrayList { -// val rows: ArrayList = ArrayList() -// report.results.forEach { result -> -// rows.add(CustomizableRowRepresentable(title = result.group.name)) -// result.group.stats?.forEach { stat -> -// rows.add(StatRow(stat, result.computedStat(stat), result.group.name)) -// } -// } -// return rows -// } + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + super.onCreateOptionsMenu(menu, inflater) + view?.findViewById(R.id.toolbar)?.let { toolbar -> + toolbar.menu.removeItem(R.id.menu_item_transaction_filter) + transactionFilterMenuItem = toolbar.menu?.add(0, R.id.menu_item_transaction_filter, 1, R.string.filter) + transactionFilterMenuItem?.setIcon(R.drawable.baseline_payment_24) + transactionFilterMenuItem?.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM) + setTransactionFilterItemColor() + } + } + + private fun setTransactionFilterItemColor() { + context?.let { + val userConfig = UserConfig.getConfiguration(getRealm()) + val color = if (userConfig.transactionTypeIds.isNotEmpty()) R.color.red else R.color.white + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + this.transactionFilterMenuItem?.iconTintList = ColorStateList.valueOf(it.getColor(color)) + } + } + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.menu_item_transaction_filter -> { + showTransactionFilter() + } + } + return super.onOptionsItemSelected(item) + } + + private fun showTransactionFilter() { + context?.let { + TransactionFilterActivity.newInstance(it) + } + } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) @@ -130,18 +147,11 @@ class StatisticsFragment : FilterableFragment(), RealmAsyncListener { // Business override fun asyncListenedEntityChange(realm: Realm) { - if (isAdded) { // Fixes: java.lang.IllegalStateException Fragment StatisticsFragment{9d3e5ec} not attached to a context. launchStatComputation() } -// val report = createSessionGroupsAndStartCompute(realm) -// tableReportFragment.report = report -// -// GlobalScope.launch(Dispatchers.Main) { -// tableReportFragment.showResults() -// } - + setTransactionFilterItemColor() } /** @@ -149,7 +159,7 @@ class StatisticsFragment : FilterableFragment(), RealmAsyncListener { */ private fun launchStatComputation() { - GlobalScope.launch(coroutineContext) { + CoroutineScope(coroutineContext).launch { val async = GlobalScope.async { val s = Date() @@ -238,6 +248,8 @@ class StatisticsFragment : FilterableFragment(), RealmAsyncListener { computedStats.addAll(tStats) options.stats = computedStats + options.includedTransactions = UserConfig.getConfiguration(realm).transactionTypes(realm) + return Calculator.computeGroups(realm, listOf(allSessionGroup, cgSessionGroup, tSessionGroup), options) } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/FilterableFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/FilterableFragment.kt index 81fab871..ccfcd16c 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/FilterableFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/FilterableFragment.kt @@ -27,8 +27,7 @@ import net.pokeranalytics.android.util.Preferences * - Listen for INTENT_FILTER_UPDATE_FILTER_UI * - */ -open class FilterableFragment : RealmFragment(), - FilterHandler { +open class FilterableFragment : RealmFragment(), FilterHandler { override var currentFilterable: FilterableType = FilterableType.ALL set(value) { @@ -83,7 +82,7 @@ open class FilterableFragment : RealmFragment(), super.onCreateOptionsMenu(menu, inflater) view?.findViewById(R.id.toolbar)?.let { toolbar -> toolbar.menu.removeItem(R.id.menu_item_filter) - filterMenuItem = toolbar.menu?.add(0, R.id.menu_item_filter, 0, R.string.filter) + filterMenuItem = toolbar.menu?.add(0, R.id.menu_item_filter, 10, R.string.filter) filterMenuItem?.setIcon(R.drawable.ic_outline_filter_list) filterMenuItem?.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM) } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/RealmFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/RealmFragment.kt index a9de0bbb..a61491e3 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/RealmFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/RealmFragment.kt @@ -76,18 +76,6 @@ open class RealmFragment : BaseFragment() { this.observedRealmResults.add(results) } -// fun listenRealmChanges(listener: RealmAsyncListener, clazz: Class) { -// -// this.changeListener = listener -// -// this.realmResults = this.realm.where(clazz).findAllAsync() -// this.realmResults?.addChangeListener { t, _ -> -// Timber.d("Realm changes: ${realmResults?.size}, $this") -// this.changeListener?.asyncListenedEntityChange(t.realm) -// } -// -// } - override fun onDestroyView() { super.onDestroyView() diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/settings/DealtHandsPerHourFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/settings/DealtHandsPerHourFragment.kt index 2a874ad9..060bef31 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/settings/DealtHandsPerHourFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/settings/DealtHandsPerHourFragment.kt @@ -34,7 +34,7 @@ class DealtHandsPerHourFragment : RealmFragment() { override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { menu.clear() - inflater.inflate(R.menu.toolbar_dealt_hands_per_hour, menu) + inflater.inflate(R.menu.toolbar_save, menu) super.onCreateOptionsMenu(menu, inflater) } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/settings/TransactionFilterActivity.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/settings/TransactionFilterActivity.kt new file mode 100644 index 00000000..8de5539f --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/settings/TransactionFilterActivity.kt @@ -0,0 +1,25 @@ +package net.pokeranalytics.android.ui.modules.settings + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import net.pokeranalytics.android.R +import net.pokeranalytics.android.ui.activity.components.BaseActivity + +class TransactionFilterActivity : BaseActivity() { + + companion object { + + fun newInstance(context: Context) { + val intent = Intent(context, TransactionFilterActivity::class.java) + context.startActivity(intent) + } + + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_transaction_filter) + } + +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/settings/TransactionFilterFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/settings/TransactionFilterFragment.kt new file mode 100644 index 00000000..85f82ac2 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/settings/TransactionFilterFragment.kt @@ -0,0 +1,132 @@ +package net.pokeranalytics.android.ui.modules.settings + +import android.content.Context +import android.os.Bundle +import android.view.* +import androidx.lifecycle.ViewModelProvider +import androidx.recyclerview.widget.LinearLayoutManager +import io.realm.kotlin.where +import net.pokeranalytics.android.R +import net.pokeranalytics.android.databinding.FragmentTransactionFilterBinding +import net.pokeranalytics.android.model.realm.TransactionType +import net.pokeranalytics.android.model.realm.UserConfig +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.RealmFragment +import net.pokeranalytics.android.ui.view.RowRepresentable +import net.pokeranalytics.android.ui.view.RowViewType + +class TransactionFilterFragment : RealmFragment(), StaticRowRepresentableDataSource, + RowRepresentableDelegate { + + private var _binding: FragmentTransactionFilterBinding? = null + private val binding get() = _binding!! + + private lateinit var model: TransactionFilterViewModel + + private lateinit var rowRepresentableAdapter: RowRepresentableAdapter + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + this.model = activity?.run { + ViewModelProvider(this).get(TransactionFilterViewModel::class.java) + } ?: throw Exception("Invalid Activity") + + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + super.onCreateView(inflater, container, savedInstanceState) + _binding = FragmentTransactionFilterBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + initUI() + initData() + } + + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + menu.clear() + inflater.inflate(R.menu.toolbar_save, menu) + super.onCreateOptionsMenu(menu, inflater) + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.save -> save() + } + return true + } + + private fun initUI() { + setDisplayHomeAsUpEnabled(true) + + val viewManager = LinearLayoutManager(requireContext()) + this.binding.recyclerView.apply { + setHasFixedSize(true) + layoutManager = viewManager + } + + this.rowRepresentableAdapter = RowRepresentableAdapter(this, this) + this.binding.recyclerView.adapter = rowRepresentableAdapter + + } + + private fun initData() { + val transactionTypes = getRealm().where() + .notEqualTo("kind", TransactionType.Value.DEPOSIT.uniqueIdentifier) + .notEqualTo("kind", TransactionType.Value.WITHDRAWAL.uniqueIdentifier) + .notEqualTo("kind", TransactionType.Value.TRANSFER.uniqueIdentifier) + .notEqualTo("kind", TransactionType.Value.STACKING_INCOMING.uniqueIdentifier) + .notEqualTo("kind", TransactionType.Value.STACKING_OUTGOING.uniqueIdentifier) + .sort("name") + .findAll() + this.model.transactionTypes = transactionTypes + + val userConfig = UserConfig.getConfiguration(this.getRealm()) + this.model.selectedTransactionTypes = userConfig.transactionTypes(getRealm()).toMutableSet() + + } + + private fun save() { + getRealm().executeTransaction { realm -> + val userConfig = UserConfig.getConfiguration(realm) + userConfig.setTransactionTypeIds(this.model.selectedTransactionTypes) + realm.copyToRealmOrUpdate(userConfig) + } + this.activity?.finish() + } + + override fun adapterRows(): List { + return this.model.transactionTypes.map { TransactionTypeSwitchRow(it) } + } + + override fun boolForRow(row: RowRepresentable): Boolean { + val transactionTypeRow = row as TransactionTypeSwitchRow + return this.model.selectedTransactionTypes.contains(transactionTypeRow.transactionType) + } + + override fun onRowValueChanged(value: Any?, row: RowRepresentable) { + val isChecked = value as Boolean + val transactionTypeRow = row as TransactionTypeSwitchRow + this.model.selectTransactionType(transactionTypeRow.transactionType, isChecked) + } + +} + +class TransactionTypeSwitchRow(val transactionType: TransactionType) : RowRepresentable { + + override fun getDisplayName(context: Context): String { + return transactionType.name + } + + override val viewType: Int = RowViewType.TITLE_SWITCH.identifier + +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/settings/TransactionFilterViewModel.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/settings/TransactionFilterViewModel.kt new file mode 100644 index 00000000..864d7f93 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/settings/TransactionFilterViewModel.kt @@ -0,0 +1,19 @@ +package net.pokeranalytics.android.ui.modules.settings + +import androidx.lifecycle.ViewModel +import net.pokeranalytics.android.model.realm.TransactionType + +class TransactionFilterViewModel : ViewModel() { + + lateinit var transactionTypes: List + + var selectedTransactionTypes: MutableSet = mutableSetOf() + + fun selectTransactionType(transactionType: TransactionType, selected: Boolean) { + when(selected) { + true -> this.selectedTransactionTypes.add(transactionType) + false -> this.selectedTransactionTypes.remove(transactionType) + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/util/Global.kt b/app/src/main/java/net/pokeranalytics/android/util/Global.kt index 85ffc3b2..400362d5 100644 --- a/app/src/main/java/net/pokeranalytics/android/util/Global.kt +++ b/app/src/main/java/net/pokeranalytics/android/util/Global.kt @@ -4,3 +4,4 @@ const val NULL_TEXT: String = "--" const val RANDOM_PLAYER: String = "☺︎" const val FFMPEG_DESCRIPTOR_FILE = "descriptor.txt" const val BLIND_SEPARATOR: String = "/" +const val UUID_SEPARATOR: String = "," diff --git a/app/src/main/java/net/pokeranalytics/android/util/Preferences.kt b/app/src/main/java/net/pokeranalytics/android/util/Preferences.kt index 4fe2ac29..853ffa13 100644 --- a/app/src/main/java/net/pokeranalytics/android/util/Preferences.kt +++ b/app/src/main/java/net/pokeranalytics/android/util/Preferences.kt @@ -47,7 +47,7 @@ class Preferences { PATCH_NEGATIVE_LIMITS("negativeLimits"), PATCH_STAKES("patchStakes"), CLEAN_BLINDS_FILTERS("deleteBlindsFilters"), - SHOW_INAPP_BADGES("showInAppBadges"), + SHOW_IN_APP_BADGES("showInAppBadges"), LAST_CALENDAR_BADGE_DATE("lastCalendarBadgeDate") } @@ -101,6 +101,18 @@ class Preferences { companion object { + fun setStringSet(key: PreferenceKey, value: MutableSet, context: Context) { + val preferences = PreferenceManager.getDefaultSharedPreferences(context) + val editor = preferences.edit() + editor.putStringSet(key.identifier, value) + editor.apply() + } + + fun getStringSet(key: Keys, context: Context): MutableSet? { + val preferences = PreferenceManager.getDefaultSharedPreferences(context) + return preferences.getStringSet(key.identifier, null) + } + fun setString(key: PreferenceKey, value: String, context: Context) { val preferences = PreferenceManager.getDefaultSharedPreferences(context) val editor = preferences.edit() @@ -232,14 +244,6 @@ class Preferences { } } -// fun executeOnceInThread(key: Keys, context: Context, executable: () -> Unit) { -// -// if (!getBoolean(key, context)) { -// Thread { executable.invoke() } -// setBoolean(key, true, context) -// } -// } - fun setResultCaptureType(bankroll: Bankroll, type: ResultCaptureType, context: Context) { val key = "${Keys.BANKROLL_RESULT_CAPTURE_TYPE}${bankroll.id}" val preferences = PreferenceManager.getDefaultSharedPreferences(context) @@ -307,11 +311,11 @@ class Preferences { } fun showInAppBadges(context: Context): Boolean { - return getBoolean(Keys.SHOW_INAPP_BADGES, context, true) + return getBoolean(Keys.SHOW_IN_APP_BADGES, context, true) } fun setShowInAppBadges(context: Context, show: Boolean) { - setBoolean(Keys.SHOW_INAPP_BADGES, show, context) + setBoolean(Keys.SHOW_IN_APP_BADGES, show, context) } fun lastCalendarBadgeDate(context: Context): Long { diff --git a/app/src/main/res/drawable-xxhdpi/baseline_payment_24.xml b/app/src/main/res/drawable-xxhdpi/baseline_payment_24.xml new file mode 100644 index 00000000..9c0fb1f1 --- /dev/null +++ b/app/src/main/res/drawable-xxhdpi/baseline_payment_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/activity_transaction_filter.xml b/app/src/main/res/layout/activity_transaction_filter.xml new file mode 100644 index 00000000..207e1b65 --- /dev/null +++ b/app/src/main/res/layout/activity_transaction_filter.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml index e1d3e396..dce49f7f 100644 --- a/app/src/main/res/layout/fragment_settings.xml +++ b/app/src/main/res/layout/fragment_settings.xml @@ -1,7 +1,6 @@ @@ -25,33 +24,4 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_transaction_filter.xml b/app/src/main/res/layout/fragment_transaction_filter.xml new file mode 100644 index 00000000..9e8cb033 --- /dev/null +++ b/app/src/main/res/layout/fragment_transaction_filter.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/toolbar_dealt_hands_per_hour.xml b/app/src/main/res/menu/toolbar_save.xml similarity index 100% rename from app/src/main/res/menu/toolbar_dealt_hands_per_hour.xml rename to app/src/main/res/menu/toolbar_save.xml diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 382fc861..6771e517 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -787,5 +787,6 @@ ]]> + Filtre de transactions diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml index 6e5acd9b..38d38849 100644 --- a/app/src/main/res/values/ids.xml +++ b/app/src/main/res/values/ids.xml @@ -1,4 +1,5 @@ + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index cbc792c5..e71cbbd6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -831,5 +831,6 @@ This screen will show where you perform the best when you\'ll have more data. You also can create custom reports using the top right button. + Transaction Filter