Added iOS CSV import + custom field creation

csv
Laurent 6 years ago
parent e36b08aee3
commit 9dca2eb647
  1. 2
      app/src/main/java/net/pokeranalytics/android/model/migrations/PokerAnalyticsMigration.kt
  2. 25
      app/src/main/java/net/pokeranalytics/android/model/realm/CustomField.kt
  3. 5
      app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt
  4. 20
      app/src/main/java/net/pokeranalytics/android/util/csv/CSVDescriptor.kt
  5. 30
      app/src/main/java/net/pokeranalytics/android/util/csv/CSVField.kt
  6. 44
      app/src/main/java/net/pokeranalytics/android/util/csv/ProductCSVDescriptors.kt
  7. 8
      app/src/main/java/net/pokeranalytics/android/util/csv/SessionCSVDescriptor.kt
  8. 19
      app/src/main/java/net/pokeranalytics/android/util/csv/SessionField.kt
  9. 8
      app/src/main/java/net/pokeranalytics/android/util/extensions/RealmExtensions.kt

@ -167,6 +167,8 @@ class PokerAnalyticsMigration : RealmMigration {
}
}
schema.get("Session")?.addField("tournamentPrizepool", Double::class.java)?.setNullable("tournamentPrizepool", true)
currentVersion++
}
}

@ -23,12 +23,29 @@ import net.pokeranalytics.android.ui.view.rowrepresentable.CustomFieldRow
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import net.pokeranalytics.android.util.enumerations.IntIdentifiable
import net.pokeranalytics.android.util.enumerations.IntSearchable
import net.pokeranalytics.android.util.extensions.findByName
import java.util.*
import kotlin.collections.ArrayList
open class CustomField : RealmObject(), NameManageable, StaticRowRepresentableDataSource, RowRepresentable {
companion object {
fun getOrCreate(realm: Realm, name: String, type: Type) : CustomField {
val cf = realm.findByName(CustomField::class.java, name)
cf?.let {
return it
}
val customField = CustomField()
customField.name = name
customField.type = type.uniqueIdentifier
return realm.copyToRealm(customField)
}
}
@Ignore
override val realmObjectClass: Class<out Identifiable> = CustomField::class.java
@ -39,7 +56,13 @@ open class CustomField : RealmObject(), NameManageable, StaticRowRepresentableDa
IntIdentifiable {
LIST(0, R.string.enum_custom_field_type),
NUMBER(1, R.string.number),
AMOUNT(2, R.string.amount)
AMOUNT(2, R.string.amount);
companion object : IntSearchable<Type> {
override fun valuesInternal(): Array<Type> {
return values()
}
}
}
/**

@ -314,6 +314,11 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat
// The features of the tournament, like Knockout, Shootout, Turbo...
var tournamentFeatures: RealmList<TournamentFeature> = RealmList()
/**
* the prizepool of the tournament
*/
var tournamentPrizepool: Double? = null
// The custom fields values
var customFieldEntries: RealmList<CustomFieldEntry> = RealmList()

@ -135,14 +135,28 @@ abstract class CSVDescriptor(var source: DataSource, vararg elements: CSVField)
fun mapCustomField(record: CSVRecord, realm: Realm) {
val customFields = realm.where(CustomField::class.java).findAll()
val headers = record.toSet()
headers.forEach { header ->
headers.forEach { header ->
// automatically creates custom field if necessary
if (source == DataSource.POKER_ANALYTICS) {
val splitter = "|"
if (header.contains(splitter)) {
val info = header.split(splitter)
val typeIdentifier = header.last().toInt()
val type = CustomField.Type.valueByIdentifier(typeIdentifier)
CustomField.getOrCreate(realm, info.first(), type)
}
}
// maps header with custom fields
val customField = customFields.firstOrNull { it.name == header }
customField?.let {
if (it.isListType) {
val f = MappedCustomCSVField.List(header, null, it)
fields.add(f)
} else {
val f = MappedCustomCVSField.Number(header, null, "", it)
val f = MappedCustomCSVField.Number(header, null, "", it)
fields.add(f)
}

@ -16,21 +16,33 @@ interface NumberCSVField: TypedCSVField<Double> {
val numberFormat: String?
override fun parse(value: String) : Double? {
companion object {
fun defaultParse(value: String) : Double? {
if (value.isEmpty()) {
return null
}
val formatter = NumberFormat.getInstance()
if (value.isEmpty()) {
return null
return try {
formatter.parse(value).toDouble()
} catch (e: ParseException) {
Timber.d("Field > Unparseable number: $value")
null
}
}
}
val formatter = NumberFormat.getInstance()
override fun parse(value: String) : Double? {
return try {
formatter.parse(value).toDouble()
} catch (e: ParseException) {
Timber.d("Field ${header} > Unparseable number: $value")
null
this.callback?.let { cb ->
return cb(value)
}
return defaultParse(value)
}
}
interface DataCSVField<T> : TypedCSVField<T> {

@ -12,7 +12,9 @@ class ProductCSVDescriptors {
ProductCSVDescriptors.pokerIncomeCash,
ProductCSVDescriptors.pokerBankrollTracker,
ProductCSVDescriptors.runGoodCashGames,
ProductCSVDescriptors.runGoodTournaments
ProductCSVDescriptors.runGoodTournaments,
ProductCSVDescriptors.iOSPokerAnalytics
)
val pokerIncomeCash: CSVDescriptor = SessionCSVDescriptor(
@ -65,27 +67,33 @@ class ProductCSVDescriptors {
val iOSPokerAnalytics: CSVDescriptor = SessionCSVDescriptor(
DataSource.POKER_ANALYTICS,
true,
SessionField.Start("Start date", dateFormat = "MM/dd/yy HH:mm"),
SessionField.End("End date", dateFormat = "MM/dd/yy HH:mm"),
SessionField.Start("Start date", dateFormat = "MM/dd/yy HH:mm:ss"),
SessionField.End("End date", dateFormat = "MM/dd/yy HH:mm:ss"),
SessionField.Break("Break", callback = { string ->
val number = NumberCSVField.defaultParse(string)
return@Break number?.times(1000.0)
}),
SessionField.SessionType("Type"),
SessionField.Stakes("Stakes"),
SessionField.Live("Live"),
SessionField.Buyin("Buy-in"),
SessionField.CashedOut("Cashed Out"),
SessionField.NetResult("Net Result"),
SessionField.Tips("Tips"),
SessionField.LimitType("Limit"),
SessionField.Game("Game"),
SessionField.Live("Live/Room"),
SessionField.Location("Location"),
SessionField.NumberOfTables("Number of tables"),
SessionField.TableSize("Table size"),
SessionField.Location("Location"),
SessionField.NumberOfTables("Tables"),
SessionField.Bankroll("Bankroll"),
SessionField.CurrencyCode("Currency"),
SessionField.CurrencyRate("Rate"),
SessionField.Comment("Comment"),
SessionField.Buyin("Buy-in"),
SessionField.CashedOut("Net result"),
SessionField.Break("breakminutes"),
SessionField.LimitType("limit"),
SessionField.Tips("expensesfromstack"),
SessionField.TournamentNumberOfPlayers("player"),
SessionField.TournamentPosition("place")
SessionField.CurrencyCode("Currency Code"),
SessionField.SmallBlind("Small Blind"),
SessionField.BigBlind("Big Blind"),
SessionField.TournamentType("Tournament Type"),
SessionField.TournamentEntryFee("Entry fee"),
SessionField.TournamentNumberOfPlayers("Number of players"),
SessionField.TournamentPrizePool("Prize Pool"),
SessionField.TournamentPosition("Position"),
SessionField.Comment("Comment")
)
val runGoodTournaments: CSVDescriptor = SessionCSVDescriptor(

@ -155,6 +155,9 @@ class SessionCSVDescriptor(source: DataSource, private var isTournament: Boolean
is SessionField.EndTime -> {
endDate?.setHourMinutes(value)
}
is SessionField.Live -> {
isLive = field.parse(value) ?: true
}
is SessionField.Buyin -> {
val buyin = field.parse(value)
session.result?.buyin = buyin
@ -212,6 +215,7 @@ class SessionCSVDescriptor(source: DataSource, private var isTournament: Boolean
TournamentType.getValueForLabel(value)?.ordinal
is SessionField.TournamentNumberOfPlayers -> session.tournamentNumberOfPlayers =
field.parse(value)?.toInt()
is SessionField.TournamentPrizePool -> session.tournamentPrizepool = field.parse(value)
is SessionField.CurrencyCode -> currencyCode = value
is SessionField.CurrencyRate -> currencyRate = field.parse(value)
is SessionField.StackingIn -> {
@ -220,12 +224,12 @@ class SessionCSVDescriptor(source: DataSource, private var isTournament: Boolean
is SessionField.StackingOut -> {
stackingOut = field.parse(value)
}
is MappedCustomCVSField.Number -> {
is MappedCustomCSVField.Number -> {
field.parse(value)?.let {
session.customFieldEntries.add(it)
}
}
is MappedCustomCVSField.List -> {
is MappedCustomCSVField.List -> {
field.parse(value)?.let {
session.customFieldEntries.add(it)
}

@ -4,7 +4,7 @@ import net.pokeranalytics.android.model.realm.CustomField
import net.pokeranalytics.android.model.realm.CustomFieldEntry
import java.util.*
sealed class MappedCustomCVSField {
sealed class MappedCustomCSVField {
data class Number(
override var header: String,
@ -149,7 +149,10 @@ sealed class SessionField {
override var callback: ((String) -> Boolean?)? = null) : TypedCSVField<Boolean> {
override fun parse(value: String): Boolean? {
return true
return when (value) {
"Live", "1" -> true
else -> false
}
}
}
@ -165,10 +168,22 @@ sealed class SessionField {
override val numberFormat: String? = null
) : NumberCSVField
data class TournamentEntryFee(
override var header: String,
override var callback: ((String) -> Double?)? = null,
override val numberFormat: String? = null
) : NumberCSVField
data class TournamentNumberOfPlayers(
override var header: String,
override var callback: ((String) -> Double?)? = null,
override val numberFormat: String? = null
) : NumberCSVField
data class TournamentPrizePool(
override var header: String,
override var callback: ((String) -> Double?)? = null,
override val numberFormat: String? = null
) : NumberCSVField
}

@ -24,6 +24,14 @@ inline fun <reified T: Identifiable> Realm.findById(id: String) : T? {
return this.findById(T::class.java, id)
}
fun <T : NameManageable> Realm.findByName(clazz: Class<T>, name: String) : T? {
return this.where(clazz).equalTo("name", name).findFirst()
}
inline fun <reified T: NameManageable> Realm.findByName(name: String) : T? {
return this.findByName(T::class.java, name)
}
fun <T: NameManageable> Realm.getOrCreate(clazz: Class<T>, name: String) : T {
val instance = this.where(clazz).equalTo("name", name).findFirst()
return if (instance != null) {

Loading…
Cancel
Save