Adds poker base import

realmasync
Laurent 3 years ago
parent d852d62c93
commit d122f3fd53
  1. 4
      app/build.gradle
  2. 8
      app/src/main/java/net/pokeranalytics/android/model/realm/TransactionType.kt
  3. 4
      app/src/main/java/net/pokeranalytics/android/model/utils/Seed.kt
  4. 13
      app/src/main/java/net/pokeranalytics/android/ui/activity/ImportActivity.kt
  5. 8
      app/src/main/java/net/pokeranalytics/android/ui/fragment/ImportFragment.kt
  6. 23
      app/src/main/java/net/pokeranalytics/android/util/csv/CSVDescriptor.kt
  7. 86
      app/src/main/java/net/pokeranalytics/android/util/csv/CSVImporter.kt
  8. 12
      app/src/main/java/net/pokeranalytics/android/util/csv/PACSVDescriptor.kt
  9. 18
      app/src/main/java/net/pokeranalytics/android/util/csv/ProductCSVDescriptors.kt
  10. 6
      app/src/main/java/net/pokeranalytics/android/util/csv/SessionCSVDescriptor.kt
  11. 5
      app/src/main/java/net/pokeranalytics/android/util/csv/SessionField.kt
  12. 5
      app/src/main/java/net/pokeranalytics/android/util/csv/SessionTransactionCSVDescriptor.kt
  13. 3
      app/src/main/java/net/pokeranalytics/android/util/csv/TransactionCSVDescriptor.kt
  14. 1
      app/src/main/res/values-de/strings.xml
  15. 1
      app/src/main/res/values-es/strings.xml
  16. 1
      app/src/main/res/values-fr/strings.xml
  17. 1
      app/src/main/res/values-hi/strings.xml
  18. 1
      app/src/main/res/values-it/strings.xml
  19. 1
      app/src/main/res/values-ja/strings.xml
  20. 1
      app/src/main/res/values-pt/strings.xml
  21. 1
      app/src/main/res/values-ru/strings.xml
  22. 1
      app/src/main/res/values-zh/strings.xml
  23. 1
      app/src/main/res/values/strings.xml
  24. 11
      app/src/test/java/net/pokeranalytics/android/BasicUnitTest.kt
  25. 3
      app/src/test/java/net/pokeranalytics/android/HandHistoryTest.kt

@ -35,8 +35,8 @@ android {
applicationId "net.pokeranalytics.android" applicationId "net.pokeranalytics.android"
minSdkVersion 23 minSdkVersion 23
targetSdkVersion 32 targetSdkVersion 32
versionCode 145 versionCode 146
versionName "6.0.2" versionName "6.0.3"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }

@ -31,7 +31,8 @@ open class TransactionType : RealmObject(), RowRepresentable, RowUpdatable, Name
BONUS(2, true), BONUS(2, true),
STACKING_INCOMING(3, true), STACKING_INCOMING(3, true),
STACKING_OUTGOING(4, false), 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<Value> { companion object : IntSearchable<Value> {
@ -49,6 +50,7 @@ open class TransactionType : RealmObject(), RowRepresentable, RowUpdatable, Name
STACKING_INCOMING -> R.string.stacking_incoming STACKING_INCOMING -> R.string.stacking_incoming
STACKING_OUTGOING -> R.string.stacking_outgoing STACKING_OUTGOING -> R.string.stacking_outgoing
TRANSFER -> R.string.transfer 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!") 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 { fun getOrCreate(realm: Realm, name: String, additive: Boolean): TransactionType {
val type = realm.where(TransactionType::class.java).equalTo("name", name).findFirst() val type = realm.where(TransactionType::class.java).equalTo("name", name).findFirst()
return if (type != null) { return if (type != null) {

@ -17,6 +17,8 @@ class Seed(var context:Context) : Realm.Transaction {
fun createDefaultTransactionTypes(values: Array<TransactionType.Value>, context: Context, realm: Realm) { fun createDefaultTransactionTypes(values: Array<TransactionType.Value>, context: Context, realm: Realm) {
values.forEach { value -> values.forEach { value ->
if (value != TransactionType.Value.EXPENSE) {
val existing = realm.where(TransactionType::class.java).equalTo("kind", value.uniqueIdentifier).findAll() val existing = realm.where(TransactionType::class.java).equalTo("kind", value.uniqueIdentifier).findAll()
if (existing.isEmpty()) { if (existing.isEmpty()) {
val type = TransactionType() val type = TransactionType()
@ -27,6 +29,8 @@ class Seed(var context:Context) : Realm.Transaction {
realm.insertOrUpdate(type) realm.insertOrUpdate(type)
} }
} }
}
} }
} }

@ -18,7 +18,6 @@ import net.pokeranalytics.android.ui.extensions.showAlertDialog
import net.pokeranalytics.android.ui.fragment.ImportFragment import net.pokeranalytics.android.ui.fragment.ImportFragment
import net.pokeranalytics.android.util.billing.AppGuard import net.pokeranalytics.android.util.billing.AppGuard
import net.pokeranalytics.android.util.extensions.count import net.pokeranalytics.android.util.extensions.count
import timber.log.Timber
class ImportActivity : BaseActivity() { class ImportActivity : BaseActivity() {
@ -64,11 +63,13 @@ class ImportActivity : BaseActivity() {
val fragmentTransaction = supportFragmentManager.beginTransaction() val fragmentTransaction = supportFragmentManager.beginTransaction()
val fragment = ImportFragment() val fragment = ImportFragment()
val fis = contentResolver.openInputStream(fileURI) fragment.setData(fileURI)
Timber.d("Load fragment data with: $fis")
fis?.let { // val fis = contentResolver.openInputStream(fileURI)
fragment.setData(it) // Timber.d("Load fragment data with: $fis")
} // fis?.let {
// fragment.setData(it)
// }
fragmentTransaction.add(R.id.container, fragment) fragmentTransaction.add(R.id.container, fragment)
fragmentTransaction.commit() fragmentTransaction.commit()

@ -1,5 +1,6 @@
package net.pokeranalytics.android.ui.fragment package net.pokeranalytics.android.ui.fragment
import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@ -24,6 +25,7 @@ class ImportFragment : RealmFragment(), ImportDelegate {
private lateinit var filePath: String private lateinit var filePath: String
private lateinit var inputStream: InputStream private lateinit var inputStream: InputStream
private lateinit var uri: Uri
private lateinit var importer: CSVImporter private lateinit var importer: CSVImporter
private var _binding: FragmentImportBinding? = null private var _binding: FragmentImportBinding? = null
@ -52,6 +54,10 @@ class ImportFragment : RealmFragment(), ImportDelegate {
this.inputStream = inputStream this.inputStream = inputStream
} }
fun setData(uri: Uri) {
this.uri = uri
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
@ -86,7 +92,7 @@ class ImportFragment : RealmFragment(), ImportDelegate {
this.parentActivity?.paApplication?.reportWhistleBlower?.pause() this.parentActivity?.paApplication?.reportWhistleBlower?.pause()
this.importer = CSVImporter(inputStream) this.importer = CSVImporter(uri, requireContext())
this.importer.delegate = this this.importer.delegate = this
CoroutineScope(coroutineContext).launch { CoroutineScope(coroutineContext).launch {

@ -1,5 +1,6 @@
package net.pokeranalytics.android.util.csv package net.pokeranalytics.android.util.csv
import android.content.Context
import io.realm.Realm import io.realm.Realm
import io.realm.kotlin.deleteFromRealm import io.realm.kotlin.deleteFromRealm
import net.pokeranalytics.android.model.interfaces.Identifiable 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.model.realm.Session
import net.pokeranalytics.android.util.extensions.findById import net.pokeranalytics.android.util.extensions.findById
import org.apache.commons.csv.CSVRecord import org.apache.commons.csv.CSVRecord
import timber.log.Timber
/** /**
* The various sources of CSV * The various sources of CSV
@ -18,7 +18,8 @@ enum class DataSource {
POKER_INCOME, POKER_INCOME,
POKER_BANKROLL_TRACKER, POKER_BANKROLL_TRACKER,
RUN_GOOD, RUN_GOOD,
POKER_AGENT; POKER_AGENT,
POKER_BASE;
val availableDateFormats: List<String> val availableDateFormats: List<String>
get() { 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<T : Identifiable>(source: DataSource, vararg el
*/ */
private val realmModelIds = mutableListOf<ObjectIdentifier>() private val realmModelIds = mutableListOf<ObjectIdentifier>()
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 { data?.let {
// Timber.d(">>>>>>> identifier added: ${it.id}") // Timber.d(">>>>>>> identifier added: ${it.id}")
this.realmModelIds.add(it.objectIdentifier) 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 * 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) { 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 } 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 return count >= mandatoryFields.size
} }

@ -1,16 +1,15 @@
package net.pokeranalytics.android.util.csv package net.pokeranalytics.android.util.csv
import android.content.Context
import android.net.Uri
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import io.realm.Realm import io.realm.Realm
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.util.extensions.count
import org.apache.commons.csv.CSVFormat import org.apache.commons.csv.CSVFormat
import org.apache.commons.csv.CSVParser
import org.apache.commons.csv.CSVRecord import org.apache.commons.csv.CSVRecord
import timber.log.Timber import timber.log.Timber
import java.io.FileReader import java.io.FileReader
import java.io.InputStream
import java.io.InputStreamReader import java.io.InputStreamReader
import java.io.Reader 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 * 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 * When starting the parsing of a file, the instance will search for a CSVDescriptor,
* the format of a CSV file. * 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 * When finding a descriptor, the CSVImporter then continue to parse the file and
* to the CSVDescriptor * 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 * The object being notified of the import progress
@ -52,10 +51,11 @@ open class CSVImporter(istream: InputStream) {
* The path of the CSV file * The path of the CSV file
*/ */
private var path: String? = null 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 * The current number of attempts at finding a valid CSVDescriptor
@ -85,36 +85,58 @@ open class CSVImporter(istream: InputStream) {
/** /**
* The CSV parser * 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 * Constructs a CSVParser object and starts parsing the CSV
*/ */
fun start() { fun start() {
Timber.d("Starting import...")
val realm = Realm.getDefaultInstance() val realm = Realm.getDefaultInstance()
realm.beginTransaction()
var reader: Reader? = null val descriptorsByDelimiter = ProductCSVDescriptors.all.groupBy { it.source.delimiter }
if (this.path != null) {
reader = FileReader(this.path) for ((delimiter, descriptors) in descriptorsByDelimiter) {
}
if (this.inputStream != null) { if (this.currentDescriptor != null) {
reader = InputStreamReader(this.inputStream) break
} }
this.parser = CSVFormat.DEFAULT.withAllowMissingColumnNames().parse(reader) Timber.d("====== Trying with delimiter '$delimiter'")
Timber.d("Starting import...") val format = CSVFormat.DEFAULT
.withAllowMissingColumnNames()
.withDelimiter(delimiter)
val parser = format.parse(this.reader)
realm.beginTransaction() Timber.d("parse delim = ${format.delimiter}")
this.parser.forEachIndexed { index, record -> parser.forEachIndexed { index, record ->
// Timber.d("line $index") // Timber.d("line $index")
this.notifyDelegate() this.notifyDelegate()
if (this.currentDescriptor == null) { // find descriptor if (this.currentDescriptor == null) { // find descriptor
this.currentDescriptor = this.findDescriptor(record) this.currentDescriptor = this.findDescriptor(record, descriptors)
this.currentDescriptor?.hasMatched(realm, record) this.currentDescriptor?.hasMatched(realm, record)
@ -149,7 +171,7 @@ open class CSVImporter(istream: InputStream) {
} else { } else {
try { try {
val count = it.parse(realm, record) val count = it.parse(realm, record, this.context)
this.importedRecords += count this.importedRecords += count
this.totalParsedRecords++ this.totalParsedRecords++
@ -166,16 +188,14 @@ open class CSVImporter(istream: InputStream) {
realm.close() realm.close()
throw ImportException("CSVDescriptor should never be null here") throw ImportException("CSVDescriptor should never be null here")
} }
} }
} }
parser.close()
}
Timber.d("Ending import...")
this.notifyDelegate() this.notifyDelegate()
realm.commitTransaction() realm.commitTransaction()
Timber.d("Ending import...")
realm.close() realm.close()
} }
@ -188,9 +208,9 @@ open class CSVImporter(istream: InputStream) {
/** /**
* Search for a descriptor in the list of managed formats * Search for a descriptor in the list of managed formats
*/ */
private fun findDescriptor(record: CSVRecord): CSVDescriptor? { private fun findDescriptor(record: CSVRecord, descriptors: List<CSVDescriptor>): CSVDescriptor? {
ProductCSVDescriptors.all.forEach { descriptor -> descriptors.forEach { descriptor ->
if (descriptor.matches(record)) { if (descriptor.matches(record)) {
this.currentDescriptor = descriptor this.currentDescriptor = descriptor
Timber.d("Identified source: ${descriptor.source}") Timber.d("Identified source: ${descriptor.source}")
@ -201,7 +221,7 @@ open class CSVImporter(istream: InputStream) {
} }
fun save(realm: Realm) { fun save(realm: Realm) {
this.parser.close() // this.parser?.close()
realm.refresh() realm.refresh()
this.currentDescriptor?.save(realm) this.currentDescriptor?.save(realm)
@ -211,7 +231,7 @@ open class CSVImporter(istream: InputStream) {
} }
fun cancel(realm: Realm) { fun cancel(realm: Realm) {
this.parser.close() // this.parser?.close()
realm.refresh() realm.refresh()
this.currentDescriptor?.cancel(realm) this.currentDescriptor?.cancel(realm)

@ -1,5 +1,6 @@
package net.pokeranalytics.android.util.csv package net.pokeranalytics.android.util.csv
import android.content.Context
import io.realm.Realm import io.realm.Realm
import net.pokeranalytics.android.exceptions.PAIllegalStateException import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.model.Limit import net.pokeranalytics.android.model.Limit
@ -42,7 +43,7 @@ abstract class PACSVDescriptor<T : Identifiable>(source: DataSource,
/** /**
* Parses a [record] and return an optional Session * 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 isTournament = isTournament ?: false
val session = Session.newInstance(realm, isTournament, managed = false) val session = Session.newInstance(realm, isTournament, managed = false)
@ -58,6 +59,7 @@ abstract class PACSVDescriptor<T : Identifiable>(source: DataSource,
var stackingIn: Double? = null var stackingIn: Double? = null
var stackingOut: Double? = null var stackingOut: Double? = null
var expense: Double? = null
var sb: Double? = null var sb: Double? = null
var bb: Double? = null var bb: Double? = null
@ -216,6 +218,9 @@ abstract class PACSVDescriptor<T : Identifiable>(source: DataSource,
is SessionField.StackingOut -> { is SessionField.StackingOut -> {
stackingOut = field.parse(value) stackingOut = field.parse(value)
} }
is SessionField.Expense -> {
expense = field.parse(value)
}
is SessionField.ListCustomField -> { is SessionField.ListCustomField -> {
val entry = field.customField.getOrCreateEntry(realm, value) val entry = field.customField.getOrCreateEntry(realm, value)
session.customFieldEntries.add(entry) session.customFieldEntries.add(entry)
@ -275,6 +280,11 @@ abstract class PACSVDescriptor<T : Identifiable>(source: DataSource,
val transaction = Transaction.newInstance(realm, bankroll, startDate, type, stackingOut!!) val transaction = Transaction.newInstance(realm, bankroll, startDate, type, stackingOut!!)
this.addAdditionallyCreatedIdentifiable(transaction) 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 return managedSession
} else { } else {

@ -20,7 +20,8 @@ class ProductCSVDescriptors {
pokerAnalytics6iOS, pokerAnalytics6iOS,
pokerAnalyticsAndroidSessions, pokerAnalyticsAndroidSessions,
pokerAnalyticsAndroid6Sessions, pokerAnalyticsAndroid6Sessions,
pokerAnalyticsAndroidTransactions pokerAnalyticsAndroidTransactions,
pokerBase
) )
private val pokerAgent: CSVDescriptor 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 private val pokerAnalyticsiOS: SessionCSVDescriptor
get() { get() {
return SessionCSVDescriptor( return SessionCSVDescriptor(

@ -1,5 +1,6 @@
package net.pokeranalytics.android.util.csv package net.pokeranalytics.android.util.csv
import android.content.Context
import io.realm.Realm import io.realm.Realm
import net.pokeranalytics.android.exceptions.PAIllegalStateException import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.model.Limit import net.pokeranalytics.android.model.Limit
@ -30,11 +31,10 @@ class SessionCSVDescriptor(source: DataSource, isTournament: Boolean?, vararg el
this.fields.add(f) this.fields.add(f)
} }
realm.close() realm.close()
} }
override fun parseData(realm: Realm, record: CSVRecord): Session? { override fun parseData(realm: Realm, record: CSVRecord, context: Context): Session? {
return this.parseSession(realm, record) return this.parseSession(realm, record, context)
} }
override fun toCSV(data: Session, field: CSVField): String? { override fun toCSV(data: Session, field: CSVField): String? {

@ -174,6 +174,11 @@ sealed class SessionField {
override var callback: ((String) -> Double?)? = null override var callback: ((String) -> Double?)? = null
) : NumberCSVField ) : NumberCSVField
data class Expense(
override var header: String,
override var callback: ((String) -> Double?)? = null
) : NumberCSVField
data class Blind(override var header: String, data class Blind(override var header: String,
override var callback: ((String) -> Pair<Double, Double>?)? = null override var callback: ((String) -> Pair<Double, Double>?)? = null
) : BlindCSVField ) : BlindCSVField

@ -1,5 +1,6 @@
package net.pokeranalytics.android.util.csv package net.pokeranalytics.android.util.csv
import android.content.Context
import io.realm.Realm import io.realm.Realm
import net.pokeranalytics.android.model.interfaces.Identifiable import net.pokeranalytics.android.model.interfaces.Identifiable
import net.pokeranalytics.android.model.realm.Bankroll 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 * 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 var dataType: DataType? = null
val typeField = fields.firstOrNull { it is SessionField.SessionType } val typeField = fields.firstOrNull { it is SessionField.SessionType }
@ -49,7 +50,7 @@ class SessionTransactionCSVDescriptor(source: DataSource, isTournament: Boolean?
return when (dataType) { return when (dataType) {
DataType.TRANSACTION -> parseTransaction(realm, record) DataType.TRANSACTION -> parseTransaction(realm, record)
else -> parseSession(realm, record) else -> parseSession(realm, record, context)
} }
} }

@ -1,5 +1,6 @@
package net.pokeranalytics.android.util.csv package net.pokeranalytics.android.util.csv
import android.content.Context
import io.realm.Realm import io.realm.Realm
import net.pokeranalytics.android.exceptions.PAIllegalStateException import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.model.realm.Bankroll import net.pokeranalytics.android.model.realm.Bankroll
@ -13,7 +14,7 @@ import java.util.*
class TransactionCSVDescriptor(source: DataSource, vararg elements: CSVField) : class TransactionCSVDescriptor(source: DataSource, vararg elements: CSVField) :
DataCSVDescriptor<Transaction>(source, *elements) { DataCSVDescriptor<Transaction>(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 date: Date? = null
var typeName: String? = null var typeName: String? = null

@ -779,5 +779,6 @@
<string name="more_sign"><![CDATA[>]]></string> <string name="more_sign"><![CDATA[>]]></string>
<string name="less_or_equal_sign"><![CDATA[≤]]></string> <string name="less_or_equal_sign"><![CDATA[≤]]></string>
<string name="less_sign"><![CDATA[<]]></string> <string name="less_sign"><![CDATA[<]]></string>
<string name="expense">expense</string>
</resources> </resources>

@ -783,6 +783,7 @@ La aplicación funciona con una suscripción anual para uso ilimitado, pero obti
<string name="more_sign"><![CDATA[>]]></string> <string name="more_sign"><![CDATA[>]]></string>
<string name="less_or_equal_sign"><![CDATA[≤]]></string> <string name="less_or_equal_sign"><![CDATA[≤]]></string>
<string name="less_sign"><![CDATA[<]]></string> <string name="less_sign"><![CDATA[<]]></string>
<string name="expense">expense</string>
</resources> </resources>

@ -788,5 +788,6 @@
<string name="less_or_equal_sign"><![CDATA[≤]]></string> <string name="less_or_equal_sign"><![CDATA[≤]]></string>
<string name="less_sign"><![CDATA[<]]></string> <string name="less_sign"><![CDATA[<]]></string>
<string name="transaction_filter">Filtre de transactions</string> <string name="transaction_filter">Filtre de transactions</string>
<string name="expense">frais</string>
</resources> </resources>

@ -778,5 +778,6 @@
<string name="more_sign"><![CDATA[>]]></string> <string name="more_sign"><![CDATA[>]]></string>
<string name="less_or_equal_sign"><![CDATA[≤]]></string> <string name="less_or_equal_sign"><![CDATA[≤]]></string>
<string name="less_sign"><![CDATA[<]]></string> <string name="less_sign"><![CDATA[<]]></string>
<string name="expense">expense</string>
</resources> </resources>

@ -778,5 +778,6 @@
<string name="more_sign"><![CDATA[>]]></string> <string name="more_sign"><![CDATA[>]]></string>
<string name="less_or_equal_sign"><![CDATA[≤]]></string> <string name="less_or_equal_sign"><![CDATA[≤]]></string>
<string name="less_sign"><![CDATA[<]]></string> <string name="less_sign"><![CDATA[<]]></string>
<string name="expense">expense</string>
</resources> </resources>

@ -782,5 +782,6 @@
<string name="more_sign"><![CDATA[>]]></string> <string name="more_sign"><![CDATA[>]]></string>
<string name="less_or_equal_sign"><![CDATA[≤]]></string> <string name="less_or_equal_sign"><![CDATA[≤]]></string>
<string name="less_sign"><![CDATA[<]]></string> <string name="less_sign"><![CDATA[<]]></string>
<string name="expense">expense</string>
</resources> </resources>

@ -777,5 +777,6 @@
<string name="more_sign"><![CDATA[>]]></string> <string name="more_sign"><![CDATA[>]]></string>
<string name="less_or_equal_sign"><![CDATA[≤]]></string> <string name="less_or_equal_sign"><![CDATA[≤]]></string>
<string name="less_sign"><![CDATA[<]]></string> <string name="less_sign"><![CDATA[<]]></string>
<string name="expense">expense</string>
</resources> </resources>

@ -779,5 +779,6 @@
<string name="more_sign"><![CDATA[>]]></string> <string name="more_sign"><![CDATA[>]]></string>
<string name="less_or_equal_sign"><![CDATA[≤]]></string> <string name="less_or_equal_sign"><![CDATA[≤]]></string>
<string name="less_sign"><![CDATA[<]]></string> <string name="less_sign"><![CDATA[<]]></string>
<string name="expense">expense</string>
</resources> </resources>

@ -772,5 +772,6 @@
<string name="more_sign"><![CDATA[>]]></string> <string name="more_sign"><![CDATA[>]]></string>
<string name="less_or_equal_sign"><![CDATA[≤]]></string> <string name="less_or_equal_sign"><![CDATA[≤]]></string>
<string name="less_sign"><![CDATA[<]]></string> <string name="less_sign"><![CDATA[<]]></string>
<string name="expense">expense</string>
</resources> </resources>

@ -832,5 +832,6 @@
<string name="less_sign"><![CDATA[<]]></string> <string name="less_sign"><![CDATA[<]]></string>
<string name="empty_reports_screen">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.</string> <string name="empty_reports_screen">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.</string>
<string name="transaction_filter">Transaction Filter</string> <string name="transaction_filter">Transaction Filter</string>
<string name="expense">expense</string>
</resources> </resources>

@ -7,6 +7,7 @@ import net.pokeranalytics.android.util.Parser
import net.pokeranalytics.android.util.extensions.kmbFormatted import net.pokeranalytics.android.util.extensions.kmbFormatted
import org.junit.Assert import org.junit.Assert
import org.junit.Test import org.junit.Test
import java.text.SimpleDateFormat
class BasicUnitTest : RealmUnitTest() { 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)
}
} }

@ -24,8 +24,7 @@ class HandHistoryTest {
private fun handHistoryInstance(players: Int): HandHistory { private fun handHistoryInstance(players: Int): HandHistory {
val hh = HandHistory() val hh = HandHistory()
val hs = HandSetup() val hs = HandSetup()
hs.smallBlind = 1.0 hs.blinds = "1/2"
hs.bigBlind = 2.0
hs.tableSize = players hs.tableSize = players
hh.configure(hs) hh.configure(hs)

Loading…
Cancel
Save