diff --git a/app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt b/app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt index 300616c1..8ec3a204 100644 --- a/app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt +++ b/app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt @@ -11,9 +11,7 @@ import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import net.pokeranalytics.android.model.migrations.Patcher import net.pokeranalytics.android.model.migrations.PokerAnalyticsMigration -import net.pokeranalytics.android.model.realm.ComputableResult import net.pokeranalytics.android.model.realm.Session -import net.pokeranalytics.android.model.realm.SessionSet import net.pokeranalytics.android.model.utils.Seed import net.pokeranalytics.android.util.FakeDataManager import net.pokeranalytics.android.util.PokerAnalyticsLogs @@ -42,13 +40,11 @@ class PokerAnalyticsApplication : Application() { .build() Realm.setDefaultConfiguration(realmConfiguration) - val realm = Realm.getDefaultInstance() - realm.executeTransaction { - realm.where(Session::class.java).findAll().deleteAllFromRealm() - realm.where(ComputableResult::class.java).findAll().deleteAllFromRealm() - realm.where(SessionSet::class.java).findAll().deleteAllFromRealm() - } - realm.close() +// val realm = Realm.getDefaultInstance() +// realm.executeTransaction { +// realm.where(Session::class.java).findAll().deleteAllFromRealm() +// } +// realm.close() // Set up Crashlytics, disabled for debug builds val crashlyticsKit = Crashlytics.Builder() @@ -65,7 +61,7 @@ class PokerAnalyticsApplication : Application() { if (BuildConfig.DEBUG) { Timber.d("UserPreferences.defaultCurrency: ${UserDefaults.currency.symbol}") - this.createFakeSessions() +// this.createFakeSessions() } 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 6cb157d2..8e64dc1f 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 @@ -4,6 +4,7 @@ import android.content.Context import io.realm.RealmQuery import io.realm.kotlin.where import net.pokeranalytics.android.R +import net.pokeranalytics.android.util.NULL_TEXT fun List.mapFirstCondition() : List { return this.map { it.conditions.first() } @@ -41,6 +42,14 @@ class Query { this._conditions.addAll(queryConditions) } + val defaultName: String + get() { + return when (this._conditions.size) { + 0 -> NULL_TEXT + else -> this._conditions.joinToString("") { it.id.joinToString("") } + } + } + fun getName(context: Context): String { return when (this._conditions.size) { 0 -> context.getString(R.string.all_sessions) // @todo should be dependant of the underlying type, ie. Session, Transaction... 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 39f13fe0..bb59dd3c 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 @@ -11,129 +11,132 @@ class PokerAnalyticsMigration : RealmMigration { override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) { - // DynamicRealm exposes an editable schema - val schema = realm.schema - - var currentVersion = oldVersion.toInt() - Timber.d("*** migrate from $oldVersion to $newVersion") - - // Migrate to version 1 - if (currentVersion == 0) { - Timber.d("*** Running migration 1") - - schema.get("Filter")?.addField("entityType", Int::class.java)?.setNullable("entityType", true) - schema.get("FilterElement")?.let { - it.setNullable("filterName", true) - it.setNullable("sectionName", true) - } - schema.get("FilterElementBlind")?.renameField("code", "currencyCode") - currentVersion++ - } - - // Migrate to version 2 - if (currentVersion == 1) { - Timber.d("*** Running migration ${currentVersion + 1}") - schema.rename("FilterElement", "FilterCondition") - - schema.get("Filter")?.renameField("filterElements", "filterConditions") - - schema.get("SessionSet")?.let { - it.addField("id", String::class.java).setRequired("id", true) - it.addPrimaryKey("id") - } - currentVersion++ - } - - // Migrate to version 3 - if (currentVersion == 2) { - Timber.d("*** Running migration ${currentVersion + 1}") - schema.rename("Report", "ReportSetup") - - schema.get("Filter")?.removeField("entityType") - - schema.get("Session")?.let { - it.addField("blinds", String::class.java).transform { - - } - } - - schema.get("FilterCondition")?.let { - it.removeField("blindValues") - it.removeField("numericValues") - - it.addField("operator", Integer::class.java) - it.addField("intValue", Integer::class.java) - it.addRealmListField("intValues", Integer::class.java) - it.addField("doubleValue", Double::class.java).setNullable("doubleValue", true) - it.addRealmListField("doubleValues", Double::class.java) - if (it.isRequired("doubleValues")) { - it.setRequired("doubleValues", false) - } - it.addField("stringValue", String::class.java) - } - - schema.get("ComputableResult")?.removeField("sessionSet") - - schema.get("Bankroll")?.addField("initialValue", Double::class.java) - - currentVersion++ - } - - // Migrate to version 4 - if (currentVersion == 3) { - Timber.d("*** Running migration ${currentVersion + 1}") - - schema.get("Result")?.addField("numberOfRebuy", Double::class.java)?.setNullable("numberOfRebuy", true) - currentVersion++ - } - - // Migrate to version 5 - if (currentVersion == 4) { - Timber.d("*** Running migration ${currentVersion + 1}") - schema.get("Bankroll")?.removeField("transactions") - currentVersion++ - } - - // Migrate to version 6 - if (currentVersion == 5) { - Timber.d("*** Running migration ${currentVersion + 1}") - schema.get("Transaction")?.let { - it.addField("dayOfWeek", Integer::class.java) - it.addField("month", Integer::class.java) - it.addField("year", Integer::class.java) - it.addField("dayOfMonth", Integer::class.java) - } - schema.create("CustomFieldEntry")?.let { - it.addField("id", String::class.java).setRequired("id", true) - it.addField("value", String::class.java).setNullable("value", false) - it.addField("order", Integer::class.java).setNullable("order", false) - it.addField("customField", CustomField::class.java).setNullable("customField", false) - } - schema.get("CustomField")?.let { - it.addField("type", Integer::class.java).setNullable("type", false) - it.addField("duplicateValue", Boolean::class.java) - it.addField("sortCondition", Integer::class.java) - it.addRealmListField("entries", CustomFieldEntry::class.java) - } - schema.get("ReportSetup")?.let { - it.addRealmListField("statIds", Int::class.java) - it.addRealmListField("criteriaIds", Int::class.java) - it.removeField("filters") - schema.get("Filter")?.let { filterSchema -> - it.addRealmObjectField("filter", filterSchema) - } - } + // DynamicRealm exposes an editable schema + val schema = realm.schema + + var currentVersion = oldVersion.toInt() + Timber.d("*** migrate from $oldVersion to $newVersion") + + // Migrate to version 1 + if (currentVersion == 0) { + Timber.d("*** Running migration 1") + + schema.get("Filter")?.addField("entityType", Int::class.java)?.setNullable("entityType", true) + schema.get("FilterElement")?.let { + it.setNullable("filterName", true) + it.setNullable("sectionName", true) + } + schema.get("FilterElementBlind")?.renameField("code", "currencyCode") + currentVersion++ + } + + // Migrate to version 2 + if (currentVersion == 1) { + Timber.d("*** Running migration ${currentVersion + 1}") + schema.rename("FilterElement", "FilterCondition") + + schema.get("Filter")?.renameField("filterElements", "filterConditions") + + schema.get("SessionSet")?.let { + it.addField("id", String::class.java).setRequired("id", true) + it.addPrimaryKey("id") + } + currentVersion++ + } + + // Migrate to version 3 + if (currentVersion == 2) { + Timber.d("*** Running migration ${currentVersion + 1}") + schema.rename("Report", "ReportSetup") + + schema.get("Filter")?.removeField("entityType") + schema.get("Session")?.let { - it.addField("startDateHourMinuteComponent", Double::class.java).setNullable("startDateHourMinuteComponent", true) - it.addField("endDateHourMinuteComponent", Double::class.java).setNullable("endDateHourMinuteComponent", true) - it.addRealmListField("customFieldEntries", CustomFieldEntry::class.java) + it.addField("blinds", String::class.java).transform { + + } } - schema.get("Filter")?.addField("filterableTypeOrdinal", Integer::class.java) + schema.get("FilterCondition")?.let { + it.removeField("blindValues") + it.removeField("numericValues") + + it.addField("operator", Integer::class.java) + it.addField("intValue", Integer::class.java) + it.addRealmListField("intValues", Integer::class.java) + it.addField("doubleValue", Double::class.java).setNullable("doubleValue", true) + it.addRealmListField("doubleValues", Double::class.java) + if (it.isRequired("doubleValues")) { + it.setRequired("doubleValues", false) + } + it.addField("stringValue", String::class.java) + } + + schema.get("ComputableResult")?.removeField("sessionSet") + + schema.get("Bankroll")?.addField("initialValue", Double::class.java) currentVersion++ - } - } + } + + // Migrate to version 4 + if (currentVersion == 3) { + Timber.d("*** Running migration ${currentVersion + 1}") + + schema.get("Result")?.addField("numberOfRebuy", Double::class.java)?.setNullable("numberOfRebuy", true) + currentVersion++ + } + + // Migrate to version 5 + if (currentVersion == 4) { + Timber.d("*** Running migration ${currentVersion + 1}") + schema.get("Bankroll")?.removeField("transactions") + currentVersion++ + } + + // Migrate to version 6 + if (currentVersion == 5) { + Timber.d("*** Running migration ${currentVersion + 1}") + schema.get("Transaction")?.let { + it.addField("dayOfWeek", Integer::class.java) + it.addField("month", Integer::class.java) + it.addField("year", Integer::class.java) + it.addField("dayOfMonth", Integer::class.java) + } + schema.create("CustomFieldEntry")?.let { + it.addField("id", String::class.java).setRequired("id", true) + it.addField("value", String::class.java).setNullable("value", false) + it.addField("order", Integer::class.java).setNullable("order", false) + it.addField("customField", CustomField::class.java).setNullable("customField", false) + } + schema.get("CustomField")?.let { + it.addField("type", Integer::class.java).setNullable("type", false) + it.addField("duplicateValue", Boolean::class.java) + it.addField("sortCondition", Integer::class.java) + it.addRealmListField("entries", CustomFieldEntry::class.java) + } + schema.get("ReportSetup")?.let { + it.addRealmListField("statIds", Int::class.java) + it.addRealmListField("criteriaIds", Int::class.java) + it.removeField("filters") + schema.get("Filter")?.let { filterSchema -> + it.addRealmObjectField("filter", filterSchema) + } + } + schema.get("Session")?.let { + it.addField("startDateHourMinuteComponent", Double::class.java) + .setNullable("startDateHourMinuteComponent", true) + it.addField("endDateHourMinuteComponent", Double::class.java) + .setNullable("endDateHourMinuteComponent", true) + it.addRealmListField("customFieldEntries", CustomFieldEntry::class.java) + } + + schema.get("Filter")?.addField("filterableTypeOrdinal", Integer::class.java) + schema.get("Filter")?.addField("useCount", Int::class.java) + schema.get("Filter")?.removeField("usageCount") + currentVersion++ + } + } override fun equals(other: Any?): Boolean { return other is RealmMigration diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/Filter.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/Filter.kt index 02d35349..a4b7e84b 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/Filter.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/Filter.kt @@ -8,15 +8,14 @@ import net.pokeranalytics.android.R import net.pokeranalytics.android.model.filter.Filterable import net.pokeranalytics.android.model.filter.Query import net.pokeranalytics.android.model.filter.QueryCondition +import net.pokeranalytics.android.model.interfaces.CountableUsage import net.pokeranalytics.android.model.interfaces.Deletable import net.pokeranalytics.android.model.interfaces.DeleteValidityStatus import net.pokeranalytics.android.model.interfaces.Identifiable import net.pokeranalytics.android.ui.interfaces.FilterableType import net.pokeranalytics.android.ui.view.ImageDecorator 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.util.Preferences import java.util.* /** @@ -24,14 +23,14 @@ import java.util.* * It contains a list of [FilterCondition] describing the complete query to launch * The [Filter] is working closely with a [Filterable] interface providing the entity we want the query being launched on */ -open class Filter : RealmObject(), RowRepresentable, Identifiable, Deletable, ImageDecorator { +open class Filter : RealmObject(), RowRepresentable, Identifiable, Deletable, CountableUsage, ImageDecorator { companion object { // Create a new instance - fun newInstance(realm: Realm, filterableType: Int): Filter { + fun newInstance(realm: Realm, filterableType:Int): Filter { val filter = Filter() - filter.filterableTypeOrdinal = filterableType + filter.filterableTypeOrdinal = filterableType return filter //return realm.copyToRealm(filter) } @@ -41,149 +40,144 @@ open class Filter : RealmObject(), RowRepresentable, Identifiable, Deletable, Im return realm.where().equalTo("id", filterId).findFirst() } - inline fun queryOn(realm: Realm, query: Query, sortField: String? = null): RealmResults { - val realmQuery = realm.where() - sortField?.let { - return query.queryWith(realmQuery).sort(it).findAll() - } ?: run { - return query.queryWith(realmQuery).findAll() - } - } + inline fun queryOn(realm: Realm, query: Query, sortField: String? = null): RealmResults { + val realmQuery = realm.where() + sortField?.let { + return query.queryWith(realmQuery).sort(it).findAll() + } ?: run { + return query.queryWith(realmQuery).findAll() + } + } fun sortedByUsage(realm: Realm): RealmResults { return realm.where(Filter::class.java).findAll().sort("usageCount") } - } + } @PrimaryKey - override var id = UUID.randomUUID().toString() + override var id = UUID.randomUUID().toString() // the queryWith name var name: String = "" + get() { + if (field.isEmpty()) { + return this.query.defaultName + } + return field + } - // the number of use of the queryWith, - // for MutableRealmInteger, see https://realm.io/docs/java/latest/#counters - val usageCount: MutableRealmInteger = MutableRealmInteger.valueOf(0) + override var useCount: Int = 0 var filterConditions: RealmList = RealmList() private set - private var filterableTypeOrdinal: Int? = null - - override val viewType: Int - get() = RowViewType.TITLE_VALUE_ACTION.ordinal - override val imageRes: Int? - get() = R.drawable.ic_outline_settings - override val imageTint: Int? - get() = R.color.green - override val imageClickable: Boolean? - get() = true - - val filterableType: FilterableType - get() { - this.filterableTypeOrdinal?.let { - return FilterableType.values()[it] - } - return FilterableType.ALL - } + private var filterableTypeOrdinal: Int? = null + + val filterableType: FilterableType + get() { + this.filterableTypeOrdinal?.let { + return FilterableType.values()[it] + } + return FilterableType.ALL + } fun createOrUpdateFilterConditions(filterConditionRows: ArrayList) { - println("list of querys saving: ${filterConditionRows.map { it.id }}") - println("list of querys previous: ${this.filterConditions.map { it.queryCondition.id }}") - filterConditionRows + println("list of querys saving: ${filterConditionRows.map { it.id }}") + println("list of querys previous: ${this.filterConditions.map { it.queryCondition.id }}") + filterConditionRows .map { it.groupId } .distinct() - .forEach { groupId -> + .forEach { groupId-> filterConditionRows .filter { it.groupId == groupId } .apply { - println("list of querys: ${this.map { it.id }}") - val casted = arrayListOf() - casted.addAll(this) - val newFilterCondition = FilterCondition(casted) - val previousCondition = filterConditions.filter { - it.filterName == newFilterCondition.filterName && it.operator == newFilterCondition.operator - } - filterConditions.removeAll(previousCondition) - filterConditions.add(newFilterCondition) - } + println("list of querys: ${this.map { it.id }}") + val casted = arrayListOf() + casted.addAll(this) + val newFilterCondition = FilterCondition(casted) + val previousCondition = filterConditions.filter { + it.filterName == newFilterCondition.filterName && it.operator == newFilterCondition.operator + } + filterConditions.removeAll(previousCondition) + filterConditions.add(newFilterCondition) + } } } - fun remove(filterCategoryRow: FilterCategoryRow) { - val sections = filterCategoryRow.filterSectionRows.map { it.name } - val savedSections = filterConditions.filter { sections.contains(it.sectionName) } - this.filterConditions.removeAll(savedSections) - } + fun remove(filterCategoryRow: FilterCategoryRow) { + val sections = filterCategoryRow.filterSectionRows.map { it.name } + val savedSections = filterConditions.filter { sections.contains(it.sectionName) } + this.filterConditions.removeAll(savedSections) + } fun countBy(filterCategoryRow: FilterCategoryRow): Int { val sections = filterCategoryRow.filterSectionRows.map { it.name } - println("list of sections $sections") - val savedSections = filterConditions.filter { sections.contains(it.sectionName) }.flatMap { it.queryCondition.id } - println("list of savedSections $savedSections") - return savedSections.size + println("list of sections $sections") + val savedSections = filterConditions.filter { sections.contains(it.sectionName) }.flatMap { it.queryCondition.id } + println("list of savedSections $savedSections") + return savedSections.size } fun contains(filterElementRow: QueryCondition): Boolean { - println("list of saved queries ${filterConditions.map { it.queryCondition.id }}") - println("list of contains ${filterElementRow.id}") - val contained = filterConditions.flatMap { it.queryCondition.id }.contains(filterElementRow.id.first()) - println("list of : $contained") - return contained + println("list of saved queries ${filterConditions.map { it.queryCondition.id }}") + println("list of contains ${filterElementRow.id}") + val contained = filterConditions.flatMap{ it.queryCondition.id }.contains(filterElementRow.id.first()) + println("list of : $contained") + return contained } /** * Get the saved value for the given [filterElementRow] */ - fun loadValueForElement(filterElementRow: QueryCondition) { + fun loadValueForElement(filterElementRow: QueryCondition) { val filtered = filterConditions.filter { it.queryCondition.id == filterElementRow.id } if (filtered.isNotEmpty()) { - return filterElementRow.updateValueBy(filtered.first()) + return filterElementRow.updateValueBy(filtered.first()) } } inline fun results(firstField: String? = null, secondField: String? = null): RealmResults { - val realmQuery = realm.where() + val realmQuery = realm.where() - if (firstField != null && secondField != null) { - return this.query.queryWith(realmQuery).distinct(firstField, secondField).findAll() - } + if (firstField != null && secondField != null) { + return this.query.queryWith(realmQuery).distinct(firstField, secondField).findAll() + } - if (firstField != null) { - return this.query.queryWith(realmQuery).distinct(firstField).findAll() - } + if (firstField != null) { + return this.query.queryWith(realmQuery).distinct(firstField).findAll() + } - return this.query.queryWith(realmQuery).findAll() - } + return this.query.queryWith(realmQuery).findAll() + } - val query: Query - get() { - val query = Query() - this.filterConditions.forEach { - query.add(it.queryCondition) - } - return query - } + val query: Query + get() { + val query = Query() + this.filterConditions.forEach { + query.add(it.queryCondition) + } + return query + } - override fun getDisplayName(context: Context): String { - if (name.isNotEmpty()) return name - return this.query.getName(context) - } + override fun getDisplayName(context: Context): String { + if (name.isNotEmpty()) return name + return this.query.getName(context) + } - override fun isValidForDelete(context: Context, realm: Realm): Boolean { - return id != Preferences.getActiveFilterId(context) + override fun isValidForDelete(context: Context, realm: Realm): Boolean { + return true } override fun getFailedDeleteMessage(status: DeleteValidityStatus): Int { - return R.string.filter_currently_selected + return R.string.relationship_error } } diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/TimeFrame.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/TimeFrame.kt index f6970a25..f9fe2236 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/TimeFrame.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/TimeFrame.kt @@ -174,7 +174,7 @@ // } // // fun createSessionSet(owner: Session) { -// val set: SessionSet = SessionSet.newInstance(this.realm) +// val set: SessionSet = SessionSet.newInstanceForResult(this.realm) // set.timeFrame?.let { // it.startDate = this.startDate // it.endDate = this.endDate @@ -269,7 +269,7 @@ // sessionSets.deleteAllFromRealm() // // // Create a new sets -// val set: SessionSet = SessionSet.newInstance(this.realm) +// val set: SessionSet = SessionSet.newInstanceForResult(this.realm) // set.timeFrame?.let { // it.setDate(startDate, endDate) // } ?: run { diff --git a/app/src/main/java/net/pokeranalytics/android/ui/activity/HomeActivity.kt b/app/src/main/java/net/pokeranalytics/android/ui/activity/HomeActivity.kt index d58ad551..e9a540db 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/activity/HomeActivity.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/activity/HomeActivity.kt @@ -13,6 +13,8 @@ import net.pokeranalytics.android.BuildConfig import net.pokeranalytics.android.R import net.pokeranalytics.android.model.realm.Currency import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity +import net.pokeranalytics.android.ui.activity.components.RequestCode +import net.pokeranalytics.android.ui.activity.components.ResultCode import net.pokeranalytics.android.ui.adapter.HomePagerAdapter import net.pokeranalytics.android.ui.extensions.showAlertDialog import net.pokeranalytics.android.util.billing.AppGuard @@ -96,10 +98,20 @@ class HomeActivity : PokerAnalyticsActivity() { Timber.d("Intent ${intent.action} unmanaged") } } - } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + when (requestCode) { + RequestCode.IMPORT.value -> { + if (resultCode == ResultCode.IMPORT_UNRECOGNIZED_FORMAT.value) { + showAlertDialog(context = this, message = R.string.unknown_import_format_popup_message) + } + } + } } private fun observeRealmObjects() { @@ -154,10 +166,10 @@ class HomeActivity : PokerAnalyticsActivity() { // Import - fun requestImportConfirmation(uri: Uri) { + private fun requestImportConfirmation(uri: Uri) { - showAlertDialog(this, R.string.import_confirmation, showCancelButton = true, positiveAction = { - ImportActivity.newInstance(this, uri) + showAlertDialog(context = this, title = R.string.import_confirmation, showCancelButton = true, positiveAction = { + ImportActivity.newInstanceForResult(this, uri) }) } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/activity/ImportActivity.kt b/app/src/main/java/net/pokeranalytics/android/ui/activity/ImportActivity.kt index 55b8f7f9..fd9fef8c 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/activity/ImportActivity.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/activity/ImportActivity.kt @@ -4,9 +4,11 @@ import android.content.Context import android.content.Intent import android.net.Uri import android.os.Bundle +import androidx.fragment.app.FragmentActivity import io.realm.Realm import net.pokeranalytics.android.R import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity +import net.pokeranalytics.android.ui.activity.components.RequestCode import net.pokeranalytics.android.ui.fragment.ImportFragment import timber.log.Timber @@ -23,11 +25,11 @@ class ImportActivity : PokerAnalyticsActivity() { /** * Create a new instance for result */ - fun newInstance(context: Context, uri: Uri) { - context.startActivity(getIntent(context, uri)) + fun newInstanceForResult(context: FragmentActivity, uri: Uri) { + context.startActivityForResult(getIntent(context, uri), RequestCode.IMPORT.value) } - private fun getIntent(context: Context, uri: Uri) : Intent { + private fun getIntent(context: Context, uri: Uri): Intent { val intent = Intent(context, ImportActivity::class.java) intent.putExtra(ImportActivity.IntentKey.URI.keyName, uri) return intent @@ -41,6 +43,7 @@ class ImportActivity : PokerAnalyticsActivity() { setContentView(R.layout.activity_import) initUI() + } override fun onStop() { diff --git a/app/src/main/java/net/pokeranalytics/android/ui/activity/ProgressReportActivity.kt b/app/src/main/java/net/pokeranalytics/android/ui/activity/ProgressReportActivity.kt index d11984a4..c6ce7ee1 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/activity/ProgressReportActivity.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/activity/ProgressReportActivity.kt @@ -9,6 +9,7 @@ import net.pokeranalytics.android.calculus.Report import net.pokeranalytics.android.calculus.Stat import net.pokeranalytics.android.ui.activity.components.ReportActivity import net.pokeranalytics.android.ui.activity.components.ReportParameters +import net.pokeranalytics.android.ui.activity.components.RequestCode import net.pokeranalytics.android.ui.fragment.report.ProgressReportFragment class ProgressReportActivity : ReportActivity() { @@ -29,7 +30,7 @@ class ProgressReportActivity : ReportActivity() { fun newInstanceForResult(fragment: Fragment, report: Report, title: String, stat: Stat? = null, displayAggregationChoices: Boolean = true) { parameters = ReportParameters(report, title, stat, showAggregationChoices = displayAggregationChoices) val intent = Intent(fragment.context, ProgressReportActivity::class.java) - fragment.startActivityForResult(intent, DEFAULT_REQUEST_CODE) + fragment.startActivityForResult(intent, RequestCode.DEFAULT.value) } } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/activity/ReportCreationActivity.kt b/app/src/main/java/net/pokeranalytics/android/ui/activity/ReportCreationActivity.kt index 359b2a28..3dce1fd9 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/activity/ReportCreationActivity.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/activity/ReportCreationActivity.kt @@ -7,13 +7,10 @@ import androidx.fragment.app.Fragment import net.pokeranalytics.android.R import net.pokeranalytics.android.calculus.Calculator import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity +import net.pokeranalytics.android.ui.activity.components.RequestCode class ReportCreationActivity : PokerAnalyticsActivity() { - enum class RequestCode { - NEW_REPORT - } - companion object { var options: Calculator.Options? = null diff --git a/app/src/main/java/net/pokeranalytics/android/ui/activity/components/Codes.kt b/app/src/main/java/net/pokeranalytics/android/ui/activity/components/Codes.kt new file mode 100644 index 00000000..9d46a61c --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/ui/activity/components/Codes.kt @@ -0,0 +1,11 @@ +package net.pokeranalytics.android.ui.activity.components + +enum class RequestCode(var value: Int) { + DEFAULT(1), + NEW_REPORT(800), + IMPORT(900) +} + +enum class ResultCode(var value: Int) { + IMPORT_UNRECOGNIZED_FORMAT(901) +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/activity/components/ReportActivity.kt b/app/src/main/java/net/pokeranalytics/android/ui/activity/components/ReportActivity.kt index 6d2ea1be..e3c8e51c 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/activity/components/ReportActivity.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/activity/components/ReportActivity.kt @@ -12,8 +12,6 @@ abstract class ReportActivity : PokerAnalyticsActivity() { companion object { - const val DEFAULT_REQUEST_CODE = 999 - // Unparcel fails when setting a custom Parcelable object on Entry so we use a static reference to passe objects var parameters: ReportParameters? = null @@ -31,7 +29,7 @@ abstract class ReportActivity : PokerAnalyticsActivity() { val options = report.options this.parameters = ReportParameters(report, reportTitle, stat) val intent = Intent(fragment.requireContext(), options.display.activityClass) - fragment.startActivityForResult(intent, DEFAULT_REQUEST_CODE) + fragment.startActivityForResult(intent, RequestCode.DEFAULT.value) } } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/extensions/UIExtensions.kt b/app/src/main/java/net/pokeranalytics/android/ui/extensions/UIExtensions.kt index 6d58bb5c..525741b6 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/extensions/UIExtensions.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/extensions/UIExtensions.kt @@ -16,10 +16,10 @@ import androidx.core.content.FileProvider import androidx.core.view.isVisible import net.pokeranalytics.android.BuildConfig import net.pokeranalytics.android.R -import net.pokeranalytics.android.util.TextFormat import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment import net.pokeranalytics.android.util.DeviceUtils +import net.pokeranalytics.android.util.TextFormat import net.pokeranalytics.android.util.URL import net.pokeranalytics.android.util.billing.AppGuard import java.io.File @@ -114,7 +114,7 @@ fun PokerAnalyticsFragment.showAlertDialog(title: Int? = null, message: Int? = n * Create and show an alert dialog */ fun showAlertDialog( - context: Context, title: Int? = null, message: Int? = null, showCancelButton: Boolean = false, + context: Context, title: Int? = null, message: Int? = null, cancelButtonTitle: Int? = null, showCancelButton: Boolean = false, positiveAction: (() -> Unit)? = null, negativeAction: (() -> Unit)? = null ) { val builder = AlertDialog.Builder(context) @@ -127,7 +127,12 @@ fun showAlertDialog( builder.setPositiveButton(net.pokeranalytics.android.R.string.ok) { _, _ -> positiveAction?.invoke() } - if (showCancelButton) { + + if (cancelButtonTitle != null) { + builder.setNegativeButton(cancelButtonTitle) { _, _ -> + negativeAction?.invoke() + } + } else if (showCancelButton) { builder.setNegativeButton(R.string.cancel) { _, _ -> negativeAction?.invoke() } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/DataListFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/DataListFragment.kt index 794dee0c..eb7b5edf 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/DataListFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/DataListFragment.kt @@ -107,17 +107,10 @@ class DataListFragment : DeletableItemFragment(), LiveRowRepresentableDataSource when (this.dataType) { LiveData.FILTER -> { - if (fromAction) { - // Open filter params - val filter = row as Filter - FiltersActivity.newInstanceForResult(fragment = this, filterId = filter.id, currentFilterable = filter.filterableType) - } else { - // Select filter - val intent = Intent() - intent.putExtra(FiltersActivity.IntentKey.FILTER_ID.keyName, (row as Filter).id) - activity?.setResult(Activity.RESULT_OK, intent) - activity?.finish() - } + val intent = Intent() + intent.putExtra(FiltersActivity.IntentKey.FILTER_ID.keyName, (row as Filter).id) + activity?.setResult(Activity.RESULT_OK, intent) + activity?.finish() } else -> { val identifier = (row as Identifiable).id diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/FeedFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/FeedFragment.kt index ce23386b..5e92b790 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/FeedFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/FeedFragment.kt @@ -195,14 +195,16 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate { } // Sessions - this.realmSessions = sessionFilter?.results() ?: run { getRealm().where().findAll() }.sort("startDate", Sort.DESCENDING) + this.realmSessions = sessionFilter?.results() ?: run { getRealm().where().findAll() } + this.realmSessions = this.realmSessions.sort("startDate", Sort.DESCENDING) this.realmSessions.addChangeListener { _, _ -> this.feedSessionAdapter.refreshData() this.feedSessionAdapter.notifyDataSetChanged() } val pendingSessions = sessionFilter?.let { getRealm().where().alwaysFalse().findAll() } ?: run { getRealm().where().isNull("year").isNull("month").findAll().sort("startDate", Sort.DESCENDING) } - val distinctDateSessions = sessionFilter?.results("year", "month") ?: run { getRealm().where().distinct("year", "month").findAll() }.sort("startDate", Sort.DESCENDING) + var distinctDateSessions = sessionFilter?.results("year", "month") ?: run { getRealm().where().distinct("year", "month").findAll() } + distinctDateSessions = distinctDateSessions.sort("startDate", Sort.DESCENDING) this.feedSessionAdapter = FeedSessionRowRepresentableAdapter(this, realmSessions, pendingSessions, distinctDateSessions) } @@ -216,13 +218,15 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate { } // Transactions - this.realmTransactions = transactionFilter?.results() ?: run { getRealm().where().findAll()}.sort("date", Sort.DESCENDING) + this.realmTransactions = transactionFilter?.results() ?: run { getRealm().where().findAll()} + this.realmTransactions = this.realmTransactions.sort("date", Sort.DESCENDING) this.realmTransactions.addChangeListener { _, _ -> this.feedTransactionAdapter.refreshData() this.feedTransactionAdapter.notifyDataSetChanged() } - val distinctDateTransactions = transactionFilter?.results("year", "month") ?: run { getRealm().where().distinct("year", "month").findAll() }.sort("date", Sort.DESCENDING) + var distinctDateTransactions = transactionFilter?.results("year", "month") ?: run { getRealm().where().distinct("year", "month").findAll() } + distinctDateTransactions = distinctDateTransactions.sort("date", Sort.DESCENDING) this.feedTransactionAdapter = FeedTransactionRowRepresentableAdapter(this, realmTransactions, distinctDateTransactions) } @@ -235,7 +239,7 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate { // val sessionCount = this.feedSessionAdapter.realmResults.size // if (!AppGuard.isProUser && sessionCount >= AppGuard.MAX_SESSIONS_BEFORE_REQUESTING_SUBSCRIPTION) { // && !BuildConfig.DEBUG // Toast.makeText(context, "Please subscribe!", Toast.LENGTH_LONG).show() -// BillingActivity.newInstance(requireContext()) +// BillingActivity.newInstanceForResult(requireContext()) // return // } 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 index 3fbbb256..58b16f2d 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/FiltersFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/FiltersFragment.kt @@ -176,7 +176,7 @@ open class FiltersFragment : RealmFragment(), StaticRowRepresentableDataSource, isUpdating = true } ?: run { realm.beginTransaction() - currentFilter = Filter.newInstance(realm, this.filterableType.ordinal) //realm.copyFromRealm(Filter.newInstance(realm, this.filterableType.ordinal)) + currentFilter = Filter.newInstance(realm, this.filterableType.ordinal) //realm.copyFromRealm(Filter.newInstanceForResult(realm, this.filterableType.ordinal)) realm.commitTransaction() } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/ImportFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/ImportFragment.kt index 177cd9e9..0727dd0d 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/ImportFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/ImportFragment.kt @@ -9,8 +9,10 @@ import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.async import kotlinx.coroutines.launch import net.pokeranalytics.android.R +import net.pokeranalytics.android.ui.activity.components.ResultCode import net.pokeranalytics.android.ui.fragment.components.RealmFragment import net.pokeranalytics.android.util.csv.CSVImporter +import net.pokeranalytics.android.util.csv.ImportException import timber.log.Timber import java.io.InputStream import java.util.* @@ -29,7 +31,6 @@ class ImportFragment : RealmFragment() { } fun setData(inputStream: InputStream) { - Timber.d("> setData with IS...") this.inputStream = inputStream } @@ -41,28 +42,43 @@ class ImportFragment : RealmFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - Timber.d("> onViewCreated...") this.startImport() } fun startImport() { + var shouldDismissActivity = false + GlobalScope.launch(coroutineContext) { val test = GlobalScope.async { val s = Date() Timber.d(">>> Start Import...") - val csv = CSVImporter(inputStream) - csv.start() - + try { + val csv = CSVImporter(inputStream) + csv.start() + } catch (e: ImportException) { + shouldDismissActivity = true + } val e = Date() val duration = (e.time - s.time) / 1000.0 Timber.d(">>> Import ended in $duration seconds") } test.await() + + if (shouldDismissActivity) { + + activity?.let { + it.setResult(ResultCode.IMPORT_UNRECOGNIZED_FORMAT.value) + it.finish() + } + + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/ReportsFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/ReportsFragment.kt index 9759ec4e..263a1dee 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/ReportsFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/ReportsFragment.kt @@ -25,6 +25,7 @@ import net.pokeranalytics.android.model.realm.ReportSetup import net.pokeranalytics.android.ui.activity.DataListActivity import net.pokeranalytics.android.ui.activity.ReportCreationActivity import net.pokeranalytics.android.ui.activity.components.ReportActivity +import net.pokeranalytics.android.ui.activity.components.RequestCode import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource @@ -38,7 +39,6 @@ import java.util.* class ReportsFragment : DeletableItemFragment(), StaticRowRepresentableDataSource, RowRepresentableDelegate { - // private lateinit var dataListAdapter: RowRepresentableAdapter private lateinit var reportSetups: RealmResults private var adapterRows = mutableListOf() @@ -77,12 +77,12 @@ class ReportsFragment : DeletableItemFragment(), StaticRowRepresentableDataSourc override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) - if (requestCode == ReportCreationActivity.RequestCode.NEW_REPORT.ordinal && resultCode == Activity.RESULT_OK) { + if (requestCode == RequestCode.NEW_REPORT.ordinal && resultCode == Activity.RESULT_OK) { ReportCreationActivity.options?.let { options -> this.launchReportWithOptions(options, options.getName(requireContext())) } ReportCreationActivity.options = null - } else if (requestCode == ReportActivity.DEFAULT_REQUEST_CODE && resultCode == Activity.RESULT_OK) { + } else if (requestCode == RequestCode.DEFAULT.value && resultCode == Activity.RESULT_OK) { val itemToDeleteId = data?.getStringExtra(DataListActivity.IntentKey.ITEM_DELETED.keyName) itemToDeleteId?.let { id -> GlobalScope.launch(Dispatchers.Main) { diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/report/ComposableTableReportFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/report/ComposableTableReportFragment.kt index 7bcfa1c3..04036972 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/report/ComposableTableReportFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/report/ComposableTableReportFragment.kt @@ -217,7 +217,7 @@ open class ComposableTableReportFragment : RealmFragment(), StaticRowRepresentab ReportActivity.newInstance(requireContext(), it, title, stat) -// ProgressReportActivity.newInstance(requireContext(), stat, it, title = title) +// ProgressReportActivity.newInstanceForResult(requireContext(), stat, it, title = title) } } } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/interfaces/FilterHandler.kt b/app/src/main/java/net/pokeranalytics/android/ui/interfaces/FilterHandler.kt index 85b301d5..9868520c 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/interfaces/FilterHandler.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/interfaces/FilterHandler.kt @@ -36,6 +36,18 @@ interface FilterHandler { fun saveFilter(context: Context, filterId:String) { Preferences.setActiveFilterId(filterId, context) + + println("<<<< save filter") + val realm = Realm.getDefaultInstance() + realm.beginTransaction() + currentFilter(context, realm)?.let { + println("<<<< old ${it.useCount}") + it.useCount++ + println("<<<< new ${it.useCount}") + } + realm.commitTransaction() + realm.close() + // Send broadcast val intent = Intent() intent.action = INTENT_FILTER_UPDATE_FILTER_UI diff --git a/app/src/main/java/net/pokeranalytics/android/util/csv/TypedCSVField.kt b/app/src/main/java/net/pokeranalytics/android/util/csv/CSVField.kt similarity index 100% rename from app/src/main/java/net/pokeranalytics/android/util/csv/TypedCSVField.kt rename to app/src/main/java/net/pokeranalytics/android/util/csv/CSVField.kt diff --git a/app/src/main/java/net/pokeranalytics/android/util/csv/CSVImporter.kt b/app/src/main/java/net/pokeranalytics/android/util/csv/CSVImporter.kt index 1ac91e55..7a1bfb90 100644 --- a/app/src/main/java/net/pokeranalytics/android/util/csv/CSVImporter.kt +++ b/app/src/main/java/net/pokeranalytics/android/util/csv/CSVImporter.kt @@ -31,7 +31,7 @@ open class CSVImporter(istream: InputStream) { /** * The number of valid record to test for descriptor before throwing a File Format Exception */ - private val VALID_RECORD_ATTEMPTS_BEFORE_THROWING_EXCEPTION = 5 + private val VALID_RECORD_ATTEMPTS_BEFORE_THROWING_EXCEPTION = 4 /** * The path of the CSV file @@ -85,9 +85,12 @@ open class CSVImporter(istream: InputStream) { this.currentDescriptor = this.findDescriptor(record) if (this.currentDescriptor == null) { - this.descriptorFindingAttempts++ - if (record.size() > VALID_RECORD_COLUMNS && this.descriptorFindingAttempts > VALID_RECORD_ATTEMPTS_BEFORE_THROWING_EXCEPTION) { + if (record.size() >= VALID_RECORD_COLUMNS) { + this.descriptorFindingAttempts++ + } + if (this.descriptorFindingAttempts >= VALID_RECORD_ATTEMPTS_BEFORE_THROWING_EXCEPTION) { + realm.cancelTransaction() throw ImportException("This type of file is not supported") } } @@ -110,6 +113,7 @@ open class CSVImporter(istream: InputStream) { it.parse(realm, record) } } ?: run { + realm.cancelTransaction() throw IllegalStateException("CSVDescriptor should never be null here") } diff --git a/app/src/main/java/net/pokeranalytics/android/util/extensions/RealmExtensions.kt b/app/src/main/java/net/pokeranalytics/android/util/extensions/RealmExtensions.kt index 6585d0c8..15b84375 100644 --- a/app/src/main/java/net/pokeranalytics/android/util/extensions/RealmExtensions.kt +++ b/app/src/main/java/net/pokeranalytics/android/util/extensions/RealmExtensions.kt @@ -7,6 +7,7 @@ import io.realm.Sort import io.realm.kotlin.where import net.pokeranalytics.android.model.interfaces.CountableUsage import net.pokeranalytics.android.model.interfaces.NameManageable +import net.pokeranalytics.android.model.realm.Filter import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.TournamentFeature import net.pokeranalytics.android.model.realm.Transaction @@ -29,24 +30,30 @@ inline fun Realm.getOrCreate(name: String) : T { /** * Returns all entities of the [clazz] sorted with their default sorting */ -fun Realm.sorted(clazz: Class) : RealmResults { +fun < T : RealmModel> Realm.sorted(clazz: Class) : RealmResults { + val items = this.where(clazz).findAll() + var sortField = arrayOf("name") + var resultSort = arrayOf(Sort.ASCENDING) - if (clazz is CountableUsage) { - this.updateUsageCount(clazz) - } - - val sortField = when (clazz) { - is CountableUsage -> "useCount" - is Transaction -> "date" - else -> "name" - } - val resultSort = when (clazz) { - is CountableUsage -> Sort.DESCENDING - is Transaction -> Sort.DESCENDING - else -> Sort.ASCENDING - } - - return this.where(clazz).findAll().sort(sortField, resultSort) + when (items.firstOrNull()) { + is Transaction -> { + println("<<<< is transaction") + sortField = arrayOf("date") + resultSort = arrayOf(Sort.DESCENDING) + } + is Filter -> { + println("<<<< is filter") + sortField = arrayOf("useCount", "name") + resultSort = arrayOf(Sort.DESCENDING, Sort.ASCENDING) + } + is CountableUsage -> { + println("<<<< is countable") + this.updateUsageCount(clazz) + sortField = arrayOf("useCount") + resultSort = arrayOf(Sort.DESCENDING) + } + } + return items.sort(sortField, resultSort) } /**