From d122f3fd5351f9788a3bd95e2048431314632831 Mon Sep 17 00:00:00 2001 From: Laurent Date: Mon, 23 Jan 2023 15:34:10 +0100 Subject: [PATCH] Adds poker base import --- app/build.gradle | 4 +- .../android/model/realm/TransactionType.kt | 8 +- .../android/model/utils/Seed.kt | 20 ++- .../android/ui/activity/ImportActivity.kt | 13 +- .../android/ui/fragment/ImportFragment.kt | 8 +- .../android/util/csv/CSVDescriptor.kt | 23 ++- .../android/util/csv/CSVImporter.kt | 164 ++++++++++-------- .../android/util/csv/PACSVDescriptor.kt | 12 +- .../android/util/csv/ProductCSVDescriptors.kt | 18 +- .../android/util/csv/SessionCSVDescriptor.kt | 6 +- .../android/util/csv/SessionField.kt | 5 + .../csv/SessionTransactionCSVDescriptor.kt | 5 +- .../util/csv/TransactionCSVDescriptor.kt | 3 +- app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values-es/strings.xml | 1 + app/src/main/res/values-fr/strings.xml | 1 + app/src/main/res/values-hi/strings.xml | 1 + app/src/main/res/values-it/strings.xml | 1 + app/src/main/res/values-ja/strings.xml | 1 + app/src/main/res/values-pt/strings.xml | 1 + app/src/main/res/values-ru/strings.xml | 1 + app/src/main/res/values-zh/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + .../pokeranalytics/android/BasicUnitTest.kt | 11 ++ .../pokeranalytics/android/HandHistoryTest.kt | 3 +- 25 files changed, 206 insertions(+), 107 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index b0bcd84f..4540e1c7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -35,8 +35,8 @@ android { applicationId "net.pokeranalytics.android" minSdkVersion 23 targetSdkVersion 32 - versionCode 145 - versionName "6.0.2" + versionCode 146 + versionName "6.0.3" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/TransactionType.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/TransactionType.kt index 3378b003..5d64a305 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/TransactionType.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/TransactionType.kt @@ -31,7 +31,8 @@ open class TransactionType : RealmObject(), RowRepresentable, RowUpdatable, Name BONUS(2, true), STACKING_INCOMING(3, true), STACKING_OUTGOING(4, false), - TRANSFER(5, false); + TRANSFER(5, false), + EXPENSE(6, false); // not created by default, only used for poker base import atm companion object : IntSearchable { @@ -49,6 +50,7 @@ open class TransactionType : RealmObject(), RowRepresentable, RowUpdatable, Name STACKING_INCOMING -> R.string.stacking_incoming STACKING_OUTGOING -> R.string.stacking_outgoing TRANSFER -> R.string.transfer + EXPENSE -> R.string.expense } } @@ -70,6 +72,10 @@ open class TransactionType : RealmObject(), RowRepresentable, RowUpdatable, Name throw PAIllegalStateException("Transaction type ${value.name} should exist in database!") } + fun getOrCreate(realm: Realm, value: Value, context: Context): TransactionType { + return getOrCreate(realm, value.localizedTitle(context), value.additive) + } + fun getOrCreate(realm: Realm, name: String, additive: Boolean): TransactionType { val type = realm.where(TransactionType::class.java).equalTo("name", name).findFirst() return if (type != null) { diff --git a/app/src/main/java/net/pokeranalytics/android/model/utils/Seed.kt b/app/src/main/java/net/pokeranalytics/android/model/utils/Seed.kt index 72afe28a..20ca78b1 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/utils/Seed.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/utils/Seed.kt @@ -17,15 +17,19 @@ class Seed(var context:Context) : Realm.Transaction { fun createDefaultTransactionTypes(values: Array, context: Context, realm: Realm) { values.forEach { value -> - val existing = realm.where(TransactionType::class.java).equalTo("kind", value.uniqueIdentifier).findAll() - if (existing.isEmpty()) { - val type = TransactionType() - type.name = value.localizedTitle(context) - type.additive = value.additive - type.kind = value.uniqueIdentifier - type.lock = true - realm.insertOrUpdate(type) + if (value != TransactionType.Value.EXPENSE) { + + val existing = realm.where(TransactionType::class.java).equalTo("kind", value.uniqueIdentifier).findAll() + if (existing.isEmpty()) { + val type = TransactionType() + type.name = value.localizedTitle(context) + type.additive = value.additive + type.kind = value.uniqueIdentifier + type.lock = true + realm.insertOrUpdate(type) + } } + } } } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/activity/ImportActivity.kt b/app/src/main/java/net/pokeranalytics/android/ui/activity/ImportActivity.kt index feeab09d..e406e7dc 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 @@ -18,7 +18,6 @@ import net.pokeranalytics.android.ui.extensions.showAlertDialog import net.pokeranalytics.android.ui.fragment.ImportFragment import net.pokeranalytics.android.util.billing.AppGuard import net.pokeranalytics.android.util.extensions.count -import timber.log.Timber class ImportActivity : BaseActivity() { @@ -64,11 +63,13 @@ class ImportActivity : BaseActivity() { val fragmentTransaction = supportFragmentManager.beginTransaction() val fragment = ImportFragment() - val fis = contentResolver.openInputStream(fileURI) - Timber.d("Load fragment data with: $fis") - fis?.let { - fragment.setData(it) - } + fragment.setData(fileURI) + +// val fis = contentResolver.openInputStream(fileURI) +// Timber.d("Load fragment data with: $fis") +// fis?.let { +// fragment.setData(it) +// } fragmentTransaction.add(R.id.container, fragment) fragmentTransaction.commit() 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 89bb5374..748f9c49 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 @@ -1,5 +1,6 @@ package net.pokeranalytics.android.ui.fragment +import android.net.Uri import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -24,6 +25,7 @@ class ImportFragment : RealmFragment(), ImportDelegate { private lateinit var filePath: String private lateinit var inputStream: InputStream + private lateinit var uri: Uri private lateinit var importer: CSVImporter private var _binding: FragmentImportBinding? = null @@ -52,6 +54,10 @@ class ImportFragment : RealmFragment(), ImportDelegate { this.inputStream = inputStream } + fun setData(uri: Uri) { + this.uri = uri + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -86,7 +92,7 @@ class ImportFragment : RealmFragment(), ImportDelegate { this.parentActivity?.paApplication?.reportWhistleBlower?.pause() - this.importer = CSVImporter(inputStream) + this.importer = CSVImporter(uri, requireContext()) this.importer.delegate = this CoroutineScope(coroutineContext).launch { diff --git a/app/src/main/java/net/pokeranalytics/android/util/csv/CSVDescriptor.kt b/app/src/main/java/net/pokeranalytics/android/util/csv/CSVDescriptor.kt index 774cc807..aad81d12 100644 --- a/app/src/main/java/net/pokeranalytics/android/util/csv/CSVDescriptor.kt +++ b/app/src/main/java/net/pokeranalytics/android/util/csv/CSVDescriptor.kt @@ -1,5 +1,6 @@ package net.pokeranalytics.android.util.csv +import android.content.Context import io.realm.Realm import io.realm.kotlin.deleteFromRealm import net.pokeranalytics.android.model.interfaces.Identifiable @@ -7,7 +8,6 @@ import net.pokeranalytics.android.model.interfaces.ObjectIdentifier import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.util.extensions.findById import org.apache.commons.csv.CSVRecord -import timber.log.Timber /** * The various sources of CSV @@ -18,7 +18,8 @@ enum class DataSource { POKER_INCOME, POKER_BANKROLL_TRACKER, RUN_GOOD, - POKER_AGENT; + POKER_AGENT, + POKER_BASE; val availableDateFormats: List get() { @@ -28,6 +29,14 @@ enum class DataSource { } } + val delimiter: Char + get() { + return when (this) { + POKER_BASE -> ';' + else -> ',' + } + } + } /** @@ -40,11 +49,11 @@ abstract class DataCSVDescriptor(source: DataSource, vararg el */ private val realmModelIds = mutableListOf() - abstract fun parseData(realm: Realm, record: CSVRecord): T? + abstract fun parseData(realm: Realm, record: CSVRecord, context: Context): T? - override fun parse(realm: Realm, record: CSVRecord): Int { + override fun parse(realm: Realm, record: CSVRecord, context: Context): Int { - val data = this.parseData(realm, record) + val data = this.parseData(realm, record, context) data?.let { // Timber.d(">>>>>>> identifier added: ${it.id}") this.realmModelIds.add(it.objectIdentifier) @@ -144,7 +153,7 @@ abstract class CSVDescriptor(var source: DataSource, vararg elements: CSVField) /** * Method called when iterating on a CSVRecord */ - abstract fun parse(realm: Realm, record: CSVRecord): Int + abstract fun parse(realm: Realm, record: CSVRecord, context: Context): Int open fun save(realm: Realm) { @@ -171,7 +180,7 @@ abstract class CSVDescriptor(var source: DataSource, vararg elements: CSVField) } } val mandatoryFields = this.fields.filter { !it.optional } - Timber.d("source= ${this.source.name} > total fields = ${this.fields.size}, identified = $count") +// Timber.d("source= ${this.source.name} > total fields = ${this.fields.size}, identified = $count") return count >= mandatoryFields.size } 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 23d98e31..613706b4 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 @@ -1,16 +1,15 @@ package net.pokeranalytics.android.util.csv +import android.content.Context +import android.net.Uri import android.os.Handler import android.os.Looper import io.realm.Realm -import net.pokeranalytics.android.model.realm.Session -import net.pokeranalytics.android.util.extensions.count +import net.pokeranalytics.android.exceptions.PAIllegalStateException import org.apache.commons.csv.CSVFormat -import org.apache.commons.csv.CSVParser import org.apache.commons.csv.CSVRecord import timber.log.Timber import java.io.FileReader -import java.io.InputStream import java.io.InputStreamReader import java.io.Reader @@ -23,12 +22,12 @@ interface ImportDelegate { /** * A CSVImporter is a class in charge of parsing a CSV file and processing it - * When starting the parsing of a file, the instance will search for a CSVDescriptor, which describes - * the format of a CSV file. - * When finding a descriptor, the CSVImporter then continue to parse the file and delegates the parsing of each row - * to the CSVDescriptor + * When starting the parsing of a file, the instance will search for a CSVDescriptor, + * which describes the format of a CSV file. + * When finding a descriptor, the CSVImporter then continue to parse the file and + * delegates the parsing of each row to the CSVDescriptor */ -open class CSVImporter(istream: InputStream) { +open class CSVImporter(uri: Uri, var context: Context) { /** * The object being notified of the import progress @@ -52,10 +51,11 @@ open class CSVImporter(istream: InputStream) { * The path of the CSV file */ private var path: String? = null + /** - * The InputStream containing a file content + * The Uri of the file to import */ - private var inputStream: InputStream? = istream + private var uri: Uri? = uri /** * The current number of attempts at finding a valid CSVDescriptor @@ -85,97 +85,117 @@ open class CSVImporter(istream: InputStream) { /** * The CSV parser */ - private lateinit var parser: CSVParser +// private var parser: CSVParser? = null + + val reader: Reader + get() { + + this.uri?.let { uri -> + // it's required to open the stream each time we start a new parser + val inputStream = context.contentResolver.openInputStream(uri) + return InputStreamReader(inputStream) + } + + return if (this.path != null) { + FileReader(this.path) + } else { + throw PAIllegalStateException("No data source") + } + + } /** * Constructs a CSVParser object and starts parsing the CSV */ fun start() { + Timber.d("Starting import...") val realm = Realm.getDefaultInstance() + realm.beginTransaction() - var reader: Reader? = null - if (this.path != null) { - reader = FileReader(this.path) - } - if (this.inputStream != null) { - reader = InputStreamReader(this.inputStream) - } + val descriptorsByDelimiter = ProductCSVDescriptors.all.groupBy { it.source.delimiter } - this.parser = CSVFormat.DEFAULT.withAllowMissingColumnNames().parse(reader) + for ((delimiter, descriptors) in descriptorsByDelimiter) { - Timber.d("Starting import...") + if (this.currentDescriptor != null) { + break + } - realm.beginTransaction() + Timber.d("====== Trying with delimiter '$delimiter'") + + val format = CSVFormat.DEFAULT + .withAllowMissingColumnNames() + .withDelimiter(delimiter) + val parser = format.parse(this.reader) - this.parser.forEachIndexed { index, record -> + Timber.d("parse delim = ${format.delimiter}") + + parser.forEachIndexed { index, record -> // Timber.d("line $index") - this.notifyDelegate() + this.notifyDelegate() - if (this.currentDescriptor == null) { // find descriptor - this.currentDescriptor = this.findDescriptor(record) + if (this.currentDescriptor == null) { // find descriptor + this.currentDescriptor = this.findDescriptor(record, descriptors) - this.currentDescriptor?.hasMatched(realm, record) + this.currentDescriptor?.hasMatched(realm, record) - if (this.currentDescriptor == null) { + if (this.currentDescriptor == null) { - if (record.size() >= VALID_RECORD_COLUMNS) { - this.descriptorFindingAttempts++ - } - if (this.descriptorFindingAttempts >= VALID_RECORD_ATTEMPTS_BEFORE_THROWING_EXCEPTION) { - realm.cancelTransaction() - realm.close() - throw ImportException("This type of file is not supported") + if (record.size() >= VALID_RECORD_COLUMNS) { + this.descriptorFindingAttempts++ + } + if (this.descriptorFindingAttempts >= VALID_RECORD_ATTEMPTS_BEFORE_THROWING_EXCEPTION) { + realm.cancelTransaction() + realm.close() + throw ImportException("This type of file is not supported") + } } - } - } else { // parse + } else { // parse - // batch commit - val parsingIndex = index + 1 - if (parsingIndex % COMMIT_FREQUENCY == 0) { - Timber.d("****** committing at $parsingIndex sessions...") - realm.commitTransaction() - realm.beginTransaction() - } + // batch commit + val parsingIndex = index + 1 + if (parsingIndex % COMMIT_FREQUENCY == 0) { + Timber.d("****** committing at $parsingIndex sessions...") + realm.commitTransaction() + realm.beginTransaction() + } - this.currentDescriptor?.let { - if (record.size() == 0) { - this.usedDescriptors.add(it) - this.currentDescriptor = - null // reset descriptor when encountering an empty line (multiple descriptors can be found in a single file) - this.descriptorFindingAttempts = 0 - } else { + this.currentDescriptor?.let { + if (record.size() == 0) { + this.usedDescriptors.add(it) + this.currentDescriptor = + null // reset descriptor when encountering an empty line (multiple descriptors can be found in a single file) + this.descriptorFindingAttempts = 0 + } else { - try { - val count = it.parse(realm, record) + try { + val count = it.parse(realm, record, this.context) - this.importedRecords += count - this.totalParsedRecords++ + this.importedRecords += count + this.totalParsedRecords++ - this.notifyDelegate() + this.notifyDelegate() - } catch (e: Exception) { - this.delegate?.exceptionCaught(e) - } + } catch (e: Exception) { + this.delegate?.exceptionCaught(e) + } + } + } ?: run { + realm.cancelTransaction() + realm.close() + throw ImportException("CSVDescriptor should never be null here") } - } ?: run { - realm.cancelTransaction() - realm.close() - throw ImportException("CSVDescriptor should never be null here") } - } + parser.close() } + Timber.d("Ending import...") this.notifyDelegate() - realm.commitTransaction() - - Timber.d("Ending import...") - realm.close() } @@ -188,9 +208,9 @@ open class CSVImporter(istream: InputStream) { /** * Search for a descriptor in the list of managed formats */ - private fun findDescriptor(record: CSVRecord): CSVDescriptor? { + private fun findDescriptor(record: CSVRecord, descriptors: List): CSVDescriptor? { - ProductCSVDescriptors.all.forEach { descriptor -> + descriptors.forEach { descriptor -> if (descriptor.matches(record)) { this.currentDescriptor = descriptor Timber.d("Identified source: ${descriptor.source}") @@ -201,7 +221,7 @@ open class CSVImporter(istream: InputStream) { } fun save(realm: Realm) { - this.parser.close() +// this.parser?.close() realm.refresh() this.currentDescriptor?.save(realm) @@ -211,7 +231,7 @@ open class CSVImporter(istream: InputStream) { } fun cancel(realm: Realm) { - this.parser.close() +// this.parser?.close() realm.refresh() this.currentDescriptor?.cancel(realm) diff --git a/app/src/main/java/net/pokeranalytics/android/util/csv/PACSVDescriptor.kt b/app/src/main/java/net/pokeranalytics/android/util/csv/PACSVDescriptor.kt index 5d36f9b3..63adcb5a 100644 --- a/app/src/main/java/net/pokeranalytics/android/util/csv/PACSVDescriptor.kt +++ b/app/src/main/java/net/pokeranalytics/android/util/csv/PACSVDescriptor.kt @@ -1,5 +1,6 @@ package net.pokeranalytics.android.util.csv +import android.content.Context import io.realm.Realm import net.pokeranalytics.android.exceptions.PAIllegalStateException import net.pokeranalytics.android.model.Limit @@ -42,7 +43,7 @@ abstract class PACSVDescriptor(source: DataSource, /** * Parses a [record] and return an optional Session */ - protected fun parseSession(realm: Realm, record: CSVRecord): Session? { + protected fun parseSession(realm: Realm, record: CSVRecord, context: Context): Session? { val isTournament = isTournament ?: false val session = Session.newInstance(realm, isTournament, managed = false) @@ -58,6 +59,7 @@ abstract class PACSVDescriptor(source: DataSource, var stackingIn: Double? = null var stackingOut: Double? = null + var expense: Double? = null var sb: Double? = null var bb: Double? = null @@ -216,6 +218,9 @@ abstract class PACSVDescriptor(source: DataSource, is SessionField.StackingOut -> { stackingOut = field.parse(value) } + is SessionField.Expense -> { + expense = field.parse(value) + } is SessionField.ListCustomField -> { val entry = field.customField.getOrCreateEntry(realm, value) session.customFieldEntries.add(entry) @@ -275,6 +280,11 @@ abstract class PACSVDescriptor(source: DataSource, val transaction = Transaction.newInstance(realm, bankroll, startDate, type, stackingOut!!) this.addAdditionallyCreatedIdentifiable(transaction) } + if (expense != null && expense != 0.0) { + val type = TransactionType.getOrCreate(realm, TransactionType.Value.EXPENSE, context) + val transaction = Transaction.newInstance(realm, bankroll, startDate, type, expense!!) + this.addAdditionallyCreatedIdentifiable(transaction) + } return managedSession } else { diff --git a/app/src/main/java/net/pokeranalytics/android/util/csv/ProductCSVDescriptors.kt b/app/src/main/java/net/pokeranalytics/android/util/csv/ProductCSVDescriptors.kt index 29a8cd7b..4bedbf36 100644 --- a/app/src/main/java/net/pokeranalytics/android/util/csv/ProductCSVDescriptors.kt +++ b/app/src/main/java/net/pokeranalytics/android/util/csv/ProductCSVDescriptors.kt @@ -20,7 +20,8 @@ class ProductCSVDescriptors { pokerAnalytics6iOS, pokerAnalyticsAndroidSessions, pokerAnalyticsAndroid6Sessions, - pokerAnalyticsAndroidTransactions + pokerAnalyticsAndroidTransactions, + pokerBase ) private val pokerAgent: CSVDescriptor @@ -159,6 +160,21 @@ class ProductCSVDescriptors { ) } + private val pokerBase: CSVDescriptor + get() { + return SessionCSVDescriptor( + DataSource.POKER_BASE, + null, + SessionField.Start("start", dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"), + SessionField.End("end", dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"), + SessionField.Location("location"), + SessionField.Bankroll("currency"), + SessionField.CurrencyCode("currency"), + SessionField.Expense("expenses"), + SessionField.NetResult("profit"), + ) + } + private val pokerAnalyticsiOS: SessionCSVDescriptor get() { return SessionCSVDescriptor( diff --git a/app/src/main/java/net/pokeranalytics/android/util/csv/SessionCSVDescriptor.kt b/app/src/main/java/net/pokeranalytics/android/util/csv/SessionCSVDescriptor.kt index 982e0cb5..4f617718 100644 --- a/app/src/main/java/net/pokeranalytics/android/util/csv/SessionCSVDescriptor.kt +++ b/app/src/main/java/net/pokeranalytics/android/util/csv/SessionCSVDescriptor.kt @@ -1,5 +1,6 @@ package net.pokeranalytics.android.util.csv +import android.content.Context import io.realm.Realm import net.pokeranalytics.android.exceptions.PAIllegalStateException import net.pokeranalytics.android.model.Limit @@ -30,11 +31,10 @@ class SessionCSVDescriptor(source: DataSource, isTournament: Boolean?, vararg el this.fields.add(f) } realm.close() - } - override fun parseData(realm: Realm, record: CSVRecord): Session? { - return this.parseSession(realm, record) + override fun parseData(realm: Realm, record: CSVRecord, context: Context): Session? { + return this.parseSession(realm, record, context) } override fun toCSV(data: Session, field: CSVField): String? { diff --git a/app/src/main/java/net/pokeranalytics/android/util/csv/SessionField.kt b/app/src/main/java/net/pokeranalytics/android/util/csv/SessionField.kt index f92db5c5..971c54e1 100644 --- a/app/src/main/java/net/pokeranalytics/android/util/csv/SessionField.kt +++ b/app/src/main/java/net/pokeranalytics/android/util/csv/SessionField.kt @@ -174,6 +174,11 @@ sealed class SessionField { override var callback: ((String) -> Double?)? = null ) : NumberCSVField + data class Expense( + override var header: String, + override var callback: ((String) -> Double?)? = null + ) : NumberCSVField + data class Blind(override var header: String, override var callback: ((String) -> Pair?)? = null ) : BlindCSVField diff --git a/app/src/main/java/net/pokeranalytics/android/util/csv/SessionTransactionCSVDescriptor.kt b/app/src/main/java/net/pokeranalytics/android/util/csv/SessionTransactionCSVDescriptor.kt index 97f13169..0a2a4bf8 100644 --- a/app/src/main/java/net/pokeranalytics/android/util/csv/SessionTransactionCSVDescriptor.kt +++ b/app/src/main/java/net/pokeranalytics/android/util/csv/SessionTransactionCSVDescriptor.kt @@ -1,5 +1,6 @@ package net.pokeranalytics.android.util.csv +import android.content.Context import io.realm.Realm import net.pokeranalytics.android.model.interfaces.Identifiable import net.pokeranalytics.android.model.realm.Bankroll @@ -36,7 +37,7 @@ class SessionTransactionCSVDescriptor(source: DataSource, isTournament: Boolean? /** * Parses a [record] and return an optional Session */ - override fun parseData(realm: Realm, record: CSVRecord): Identifiable? { + override fun parseData(realm: Realm, record: CSVRecord, context: Context): Identifiable? { var dataType: DataType? = null val typeField = fields.firstOrNull { it is SessionField.SessionType } @@ -49,7 +50,7 @@ class SessionTransactionCSVDescriptor(source: DataSource, isTournament: Boolean? return when (dataType) { DataType.TRANSACTION -> parseTransaction(realm, record) - else -> parseSession(realm, record) + else -> parseSession(realm, record, context) } } diff --git a/app/src/main/java/net/pokeranalytics/android/util/csv/TransactionCSVDescriptor.kt b/app/src/main/java/net/pokeranalytics/android/util/csv/TransactionCSVDescriptor.kt index c0de0819..78d48699 100644 --- a/app/src/main/java/net/pokeranalytics/android/util/csv/TransactionCSVDescriptor.kt +++ b/app/src/main/java/net/pokeranalytics/android/util/csv/TransactionCSVDescriptor.kt @@ -1,5 +1,6 @@ package net.pokeranalytics.android.util.csv +import android.content.Context import io.realm.Realm import net.pokeranalytics.android.exceptions.PAIllegalStateException import net.pokeranalytics.android.model.realm.Bankroll @@ -13,7 +14,7 @@ import java.util.* class TransactionCSVDescriptor(source: DataSource, vararg elements: CSVField) : DataCSVDescriptor(source, *elements) { - override fun parseData(realm: Realm, record: CSVRecord): Transaction? { + override fun parseData(realm: Realm, record: CSVRecord, context: Context): Transaction? { var date: Date? = null var typeName: String? = null diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 25f4b348..aa31e9fa 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -779,5 +779,6 @@ ]]> + expense diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 50e46cd8..788f0034 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -783,6 +783,7 @@ La aplicación funciona con una suscripción anual para uso ilimitado, pero obti ]]> + expense diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 6771e517..11c65a8e 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -788,5 +788,6 @@ Filtre de transactions + frais diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index bb7c66d9..e3a79af2 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -778,5 +778,6 @@ ]]> + expense diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index a1102ee6..794c114a 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -778,5 +778,6 @@ ]]> + expense diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index a0570aee..ace50d8d 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -782,5 +782,6 @@ ]]> + expense diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index e28b9979..a662b946 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -777,5 +777,6 @@ ]]> + expense diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 3edac9b4..80489d4f 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -779,5 +779,6 @@ ]]> + expense diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index 5a5be629..0fac0397 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -772,5 +772,6 @@ ]]> + expense diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e71cbbd6..f88f0887 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -832,5 +832,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 + expense diff --git a/app/src/test/java/net/pokeranalytics/android/BasicUnitTest.kt b/app/src/test/java/net/pokeranalytics/android/BasicUnitTest.kt index c2255f56..bb555cd0 100644 --- a/app/src/test/java/net/pokeranalytics/android/BasicUnitTest.kt +++ b/app/src/test/java/net/pokeranalytics/android/BasicUnitTest.kt @@ -7,6 +7,7 @@ import net.pokeranalytics.android.util.Parser import net.pokeranalytics.android.util.extensions.kmbFormatted import org.junit.Assert import org.junit.Test +import java.text.SimpleDateFormat class BasicUnitTest : RealmUnitTest() { @@ -92,4 +93,14 @@ class BasicUnitTest : RealmUnitTest() { } + @Test + fun testDateFormat() { + val dateString = "2019-01-01T02:00:00.000Z" + val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") + + val date = dateFormat.parse(dateString) + + Assert.assertNotNull(date) + } + } diff --git a/app/src/test/java/net/pokeranalytics/android/HandHistoryTest.kt b/app/src/test/java/net/pokeranalytics/android/HandHistoryTest.kt index 6d47164e..217212d1 100644 --- a/app/src/test/java/net/pokeranalytics/android/HandHistoryTest.kt +++ b/app/src/test/java/net/pokeranalytics/android/HandHistoryTest.kt @@ -24,8 +24,7 @@ class HandHistoryTest { private fun handHistoryInstance(players: Int): HandHistory { val hh = HandHistory() val hs = HandSetup() - hs.smallBlind = 1.0 - hs.bigBlind = 2.0 + hs.blinds = "1/2" hs.tableSize = players hh.configure(hs)