CSV import improvements

dev
Laurent 7 years ago
parent 3b65082794
commit dca9a7a8f6
  1. 6
      app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt
  2. 2
      app/src/main/java/net/pokeranalytics/android/api/CurrencyConverterApi.kt
  3. 2
      app/src/main/java/net/pokeranalytics/android/model/Limit.kt
  4. 13
      app/src/main/java/net/pokeranalytics/android/model/TableSize.kt
  5. 8
      app/src/main/java/net/pokeranalytics/android/model/TournamentType.kt
  6. 21
      app/src/main/java/net/pokeranalytics/android/model/realm/Bankroll.kt
  7. 15
      app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt
  8. 2
      app/src/main/java/net/pokeranalytics/android/model/retrofit/ConvertResult.kt
  9. 2
      app/src/main/java/net/pokeranalytics/android/model/utils/Seed.kt
  10. 2
      app/src/main/java/net/pokeranalytics/android/ui/activity/HomeActivity.kt
  11. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/data/BankrollDataFragment.kt
  12. 2
      app/src/main/java/net/pokeranalytics/android/util/URL.kt
  13. 17
      app/src/main/java/net/pokeranalytics/android/util/csv/CSVDescriptor.kt
  14. 3
      app/src/main/java/net/pokeranalytics/android/util/csv/CSVImporter.kt
  15. 213
      app/src/main/java/net/pokeranalytics/android/util/csv/SessionCSVDescriptor.kt
  16. 28
      app/src/main/java/net/pokeranalytics/android/util/csv/TypedField.kt
  17. 4
      app/src/main/java/net/pokeranalytics/android/util/extensions/DateExtension.kt

@ -40,6 +40,12 @@ class PokerAnalyticsApplication : Application() {
.build() .build()
Realm.setDefaultConfiguration(realmConfiguration) Realm.setDefaultConfiguration(realmConfiguration)
// val realm = Realm.getDefaultInstance()
// realm.executeTransaction {
// realm.where(Session::class.java).findAll().deleteAllFromRealm()
// }
// realm.close()
// Set up Crashlytics, disabled for debug builds // Set up Crashlytics, disabled for debug builds
val crashlyticsKit = Crashlytics.Builder() val crashlyticsKit = Crashlytics.Builder()
.core(CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build()) .core(CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build())

@ -16,7 +16,7 @@ import retrofit2.http.Query
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
/** /**
* Currency Converter API * CurrencyCode Converter API
*/ */
interface CurrencyConverterApi { interface CurrencyConverterApi {

@ -16,7 +16,7 @@ enum class Limit : RowRepresentable {
return when (value) { return when (value) {
"No Limit" -> NO "No Limit" -> NO
"Pot Limit" -> POT "Pot Limit" -> POT
"Fixed Limit" -> FIXED "Fixed Limit", "Limit" -> FIXED
"Mixed Limit" -> MIXED "Mixed Limit" -> MIXED
"Spread Limit" -> SPREAD "Spread Limit" -> SPREAD
else -> null else -> null

@ -6,12 +6,23 @@ import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.RowViewType
class TableSize(var numberOfPlayer: Int, var rowViewType: Int = RowViewType.TITLE_GRID.ordinal) : RowRepresentable { class TableSize(var numberOfPlayer: Int, var rowViewType: Int = RowViewType.TITLE_GRID.ordinal) : RowRepresentable {
companion object { companion object {
val all : List<TableSize>
val all: List<TableSize>
get() { get() {
return Array(9, init = return Array(9, init =
{ index -> TableSize(index + 2) }).toList() { index -> TableSize(index + 2) }).toList()
} }
fun valueForLabel(label: String) : Int? {
return when (label) {
"Full Ring", "Full-Ring" -> 10
"Short-Handed", "Short Handed" -> 6
"Heads-Up", "Heads Up" -> 2
else -> null
}
}
} }
override fun getDisplayName(context: Context): String { override fun getDisplayName(context: Context): String {

@ -14,6 +14,14 @@ enum class TournamentType : RowRepresentable {
get() { get() {
return TournamentType.values() as List<TournamentType> return TournamentType.values() as List<TournamentType>
} }
fun getValueForLabel(label: String) : TournamentType? {
return when (label) {
"Single-Table" -> SNG
"Multi-Table" -> MTT
else -> null
}
}
} }
override val resId: Int? override val resId: Int?

@ -96,4 +96,25 @@ open class Bankroll : RealmObject(), NameManageable, RowRepresentable {
else -> super.getFailedSaveMessage(status) else -> super.getFailedSaveMessage(status)
} }
} }
companion object {
fun getOrCreate(realm: Realm, name: String, live: Boolean = true, currencyCode: String? = null, currencyRate: Double? = null) : Bankroll {
val bankroll = realm.where<Bankroll>().equalTo("name", name).findFirst()
return if (bankroll != null) {
bankroll
} else {
val bankroll = Bankroll()
bankroll.name = name
val currency = Currency()
currency.code = currencyCode
currency.rate = currencyRate
bankroll.currency = currency
realm.copyToRealm(bankroll)
}
}
}
} }

@ -50,7 +50,20 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat
enum class Type { enum class Type {
CASH_GAME, CASH_GAME,
TOURNAMENT TOURNAMENT;
companion object {
fun getValueFromString(string: String): Type? {
return when (string) {
"Cash", "Cash Game" -> CASH_GAME
"Tournament" -> TOURNAMENT
else -> null
}
}
}
} }
companion object { companion object {

@ -3,7 +3,7 @@ package net.pokeranalytics.android.model.retrofit
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
/** /**
* Currency Converter mapping class * CurrencyCode Converter mapping class
*/ */
class CurrencyConverterValue { class CurrencyConverterValue {
@SerializedName("val") @SerializedName("val")

@ -30,7 +30,7 @@ class Seed(var context:Context) : Realm.Transaction {
private fun createDefaultCurrencyAndBankroll(realm: Realm) { private fun createDefaultCurrencyAndBankroll(realm: Realm) {
// Currency // CurrencyCode
val localeCurrency = UserDefaults.getLocaleCurrency() val localeCurrency = UserDefaults.getLocaleCurrency()
val defaultCurrency = Currency() val defaultCurrency = Currency()
defaultCurrency.code = localeCurrency.currencyCode defaultCurrency.code = localeCurrency.currencyCode

@ -80,7 +80,7 @@ class HomeActivity : PokerAnalyticsActivity() {
fun csv() { fun csv() {
val path = "sdcard/Download/AllCashGames.csv" val path = "sdcard/Download/RunGoodSessions1.csv"
val csv = CSVImporter(path) val csv = CSVImporter(path)
csv.start() csv.start()

@ -203,7 +203,7 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
} }
/** /**
* Refresh the rate with the Currency Converter API * Refresh the rate with the CurrencyCode Converter API
*/ */
private fun refreshRate() { private fun refreshRate() {

@ -18,7 +18,7 @@ enum class URL(var value: String) {
// Support // Support
SUPPORT_EMAIL("support@pokeranalytics.net"), SUPPORT_EMAIL("support@pokeranalytics.net"),
// Currency Converter API // CurrencyCode Converter API
API_CURRENCY_CONVERTER("https://free.currencyconverterapi.com/api/v5/") API_CURRENCY_CONVERTER("https://free.currencyconverterapi.com/api/v5/")
} }

@ -5,11 +5,17 @@ import io.realm.RealmModel
import org.apache.commons.csv.CSVRecord import org.apache.commons.csv.CSVRecord
abstract class DataCSVDescriptor<T : RealmModel>(vararg elements: Field) : CSVDescriptor(*elements) { enum class DataSource {
POKER_INCOME,
POKER_BANKROLL_TRACKER,
RUNGOOD
}
abstract class DataCSVDescriptor<T : RealmModel>(source: DataSource, vararg elements: Field) : CSVDescriptor(source, *elements) {
val realmModels = mutableListOf<RealmModel>() val realmModels = mutableListOf<RealmModel>()
abstract fun parseData(realm: Realm, record: CSVRecord) : T? abstract fun parseData(realm: Realm, record: CSVRecord): T?
override fun parse(realm: Realm, record: CSVRecord) { override fun parse(realm: Realm, record: CSVRecord) {
@ -22,7 +28,7 @@ abstract class DataCSVDescriptor<T : RealmModel>(vararg elements: Field) : CSVDe
} }
open class CSVDescriptor(vararg elements: Field) { open class CSVDescriptor(var source: DataSource, vararg elements: Field) {
protected var fields: List<Field> = listOf() protected var fields: List<Field> = listOf()
protected var fieldMapping: MutableMap<Field, Int> = mutableMapOf() protected var fieldMapping: MutableMap<Field, Int> = mutableMapOf()
@ -34,10 +40,11 @@ open class CSVDescriptor(vararg elements: Field) {
} }
companion object { companion object {
val all: List<CSVDescriptor> = listOf(SessionCSVDescriptor.pokerIncomeCash) val all: List<CSVDescriptor> =
listOf(SessionCSVDescriptor.pokerIncomeCash, SessionCSVDescriptor.pokerBankrollTracker, SessionCSVDescriptor.runGoodCashGames, SessionCSVDescriptor.runGoodTournaments)
} }
fun matches(record: CSVRecord) : Boolean { fun matches(record: CSVRecord): Boolean {
var count = 0 var count = 0
val headers = record.toSet() val headers = record.toSet()

@ -17,7 +17,7 @@ open class CSVImporter(var path: String) {
val reader = FileReader(this.path) val reader = FileReader(this.path)
val parser = CSVFormat.DEFAULT.withFirstRecordAsHeader().parse(reader) val parser = CSVFormat.DEFAULT.withAllowMissingColumnNames().parse(reader)
Timber.d("Starting import...") Timber.d("Starting import...")
@ -58,6 +58,7 @@ open class CSVImporter(var path: String) {
CSVDescriptor.all.forEach { descriptor -> CSVDescriptor.all.forEach { descriptor ->
if (descriptor.matches(record)) { if (descriptor.matches(record)) {
this.currentDescriptor = descriptor this.currentDescriptor = descriptor
Timber.d("Identified source: ${descriptor.source}")
return return
} }
} }

@ -2,63 +2,122 @@ package net.pokeranalytics.android.util.csv
import io.realm.Realm import io.realm.Realm
import net.pokeranalytics.android.model.Limit import net.pokeranalytics.android.model.Limit
import net.pokeranalytics.android.model.TableSize
import net.pokeranalytics.android.model.TournamentType
import net.pokeranalytics.android.model.realm.Bankroll
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.model.utils.SessionUtils import net.pokeranalytics.android.model.utils.SessionUtils
import net.pokeranalytics.android.util.extensions.getOrCreate import net.pokeranalytics.android.util.extensions.getOrCreate
import net.pokeranalytics.android.util.extensions.setHourMinutes
import org.apache.commons.csv.CSVRecord import org.apache.commons.csv.CSVRecord
import timber.log.Timber import timber.log.Timber
import java.util.*
sealed class SessionField { sealed class SessionField {
data class Start( data class Start(
override var header: String, override var header: String,
override var callback: (() -> Unit)? = null, override var callback: ((String) -> Date?)? = null,
override val dateFormat: String? = null
) : DateField
data class StartTime(
override var header: String,
override var callback: ((String) -> Date?)? = null,
override val dateFormat: String? = null override val dateFormat: String? = null
) : DateField ) : DateField
data class End( data class End(
override var header: String, override var header: String,
override var callback: (() -> Unit)? = null, override var callback: ((String) -> Date?)? = null,
override val dateFormat: String? = null
) : DateField
data class EndTime(
override var header: String,
override var callback: ((String) -> Date?)? = null,
override val dateFormat: String? = null override val dateFormat: String? = null
) : DateField ) : DateField
data class Buyin( data class Buyin(
override var header: String, override var header: String,
override var callback: (() -> Unit)? = null, override var callback: ((String) -> Double?)? = null,
override val numberFormat: String? = null
) : NumberField
data class NetResult(
override var header: String,
override var callback: ((String) -> Double?)? = null,
override val numberFormat: String? = null override val numberFormat: String? = null
) : NumberField ) : NumberField
data class CashedOut( data class CashedOut(
override var header: String, override var header: String,
override var callback: (() -> Unit)? = null, override var callback: ((String) -> Double?)? = null,
override val numberFormat: String? = null override val numberFormat: String? = null
) : NumberField ) : NumberField
data class Break( data class Break(
override var header: String, override var header: String,
override var callback: (() -> Unit)? = null, override var callback: ((String) -> Double?)? = null,
override val numberFormat: String? = null override val numberFormat: String? = null
) : NumberField ) : NumberField
data class Tips( data class Tips(
override var header: String, override var header: String,
override var callback: (() -> Unit)? = null, override var callback: ((String) -> Double?)? = null,
override val numberFormat: String? = null override val numberFormat: String? = null
) : NumberField ) : NumberField
data class Blind(override var header: String, override var callback: (() -> Unit)? = null) : BlindField data class SmallBlind(
data class Game(override var header: String, override var callback: (() -> Unit)? = null) : Field override var header: String,
data class Location(override var header: String, override var callback: (() -> Unit)? = null) : Field override var callback: ((String) -> Double?)? = null,
data class Bankroll(override var header: String, override var callback: (() -> Unit)? = null) : Field override val numberFormat: String? = null
data class LimitType(override var header: String, override var callback: (() -> Unit)? = null) : Field ) : NumberField
data class Comment(override var header: String, override var callback: (() -> Unit)? = null) : Field
data class BigBlind(
override var header: String,
override var callback: ((String) -> Double?)? = null,
override val numberFormat: String? = null
) : NumberField
data class Blind(override var header: String, override var callback: ((String) -> Pair<Double, Double>?)? = null) : BlindField
data class Game(override var header: String) : Field
data class Location(override var header: String) : Field
data class LocationType(override var header: String) : Field
data class Bankroll(override var header: String) : Field
data class LimitType(override var header: String) : Field
data class Comment(override var header: String) : Field
data class SessionType(override var header: String) : Field
data class TableSize(override var header: String) : Field
data class CurrencyCode(override var header: String) : Field
data class TournamentName(override var header: String) : Field
data class TournamentType(override var header: String) : Field
data class CurrencyRate(
override var header: String,
override var callback: ((String) -> Double?)? = null,
override val numberFormat: String? = null
) : NumberField
data class TournamentPosition(
override var header: String,
override var callback: ((String) -> Double?)? = null,
override val numberFormat: String? = null
) : NumberField
data class TournamentNumberOfPlayers(
override var header: String,
override var callback: ((String) -> Double?)? = null,
override val numberFormat: String? = null
) : NumberField
} }
class SessionCSVDescriptor(var isTournament: Boolean, vararg elements: Field) : DataCSVDescriptor<Session>(*elements) { class SessionCSVDescriptor(source: DataSource, private var isTournament: Boolean, vararg elements: Field) : DataCSVDescriptor<Session>(source, *elements) {
companion object { companion object {
val pokerIncomeCash: CSVDescriptor = SessionCSVDescriptor( val pokerIncomeCash: CSVDescriptor = SessionCSVDescriptor(
DataSource.POKER_INCOME,
false, false,
SessionField.Start("Start Time"), SessionField.Start("Start Time"),
SessionField.End("End Time"), SessionField.End("End Time"),
@ -69,40 +128,129 @@ class SessionCSVDescriptor(var isTournament: Boolean, vararg elements: Field) :
SessionField.Game("Game"), SessionField.Game("Game"),
SessionField.Bankroll("Bankroll"), SessionField.Bankroll("Bankroll"),
SessionField.Location("Location"), SessionField.Location("Location"),
SessionField.Location("Location Type"),
SessionField.Comment("Note"), SessionField.Comment("Note"),
SessionField.Tips("Tips"), SessionField.Tips("Tips"),
SessionField.Blind("Stake") SessionField.Blind("Stake")
) )
val pokerBankrollTracker: CSVDescriptor = SessionCSVDescriptor(
DataSource.POKER_BANKROLL_TRACKER,
true,
SessionField.Start("starttime", dateFormat = "MM/dd/yyyy HH:mm"),
SessionField.End("endtime", dateFormat = "MM/dd/yyyy HH:mm"),
SessionField.SessionType("variant"),
SessionField.Buyin("buyin"),
SessionField.CashedOut("cashout"),
SessionField.Break("breakminutes"),
SessionField.LimitType("limit"),
SessionField.Game("game"),
SessionField.Bankroll("currency"), // same as currency code
SessionField.Location("location"),
SessionField.Comment("sessionnote"),
SessionField.Tips("expensesfromstack"),
SessionField.SmallBlind("smallblind"),
SessionField.BigBlind("bigblind"),
SessionField.TournamentNumberOfPlayers("player"),
SessionField.TournamentPosition("place"),
SessionField.TournamentName("mttname"),
SessionField.CurrencyCode("currency"),
SessionField.CurrencyRate("exchangerate"),
SessionField.TableSize("tablesize")
)
val runGoodTournaments: CSVDescriptor = SessionCSVDescriptor(
DataSource.RUNGOOD,
true,
SessionField.Start("Start Date", dateFormat = "dd/MM/yyyy"),
SessionField.StartTime("Start Time"),
SessionField.End("End Date"),
SessionField.EndTime("End Time"),
SessionField.Buyin("Total Buy-In"),
SessionField.CashedOut("Winnings"),
SessionField.NetResult("Profit"),
SessionField.Break("Break"),
SessionField.LimitType("Limit Type"),
SessionField.Game("Game"),
SessionField.Bankroll("Bankroll"),
SessionField.TableSize("Table Type"),
SessionField.Location("Location"),
SessionField.LocationType("Location Type"),
SessionField.Comment("Notes"),
SessionField.CurrencyCode("Currency"),
SessionField.TournamentName("Event Name"),
SessionField.TournamentNumberOfPlayers("Total Players"),
SessionField.TournamentPosition("Finished Place"),
SessionField.TournamentType("Single-Table/Multi-Table")
)
val runGoodCashGames: CSVDescriptor = SessionCSVDescriptor(
DataSource.RUNGOOD,
false,
SessionField.Start("Start Date", dateFormat = "dd/MM/yyyy"),
SessionField.StartTime("Start Time", dateFormat = "HH:mm"),
SessionField.End("End Date", dateFormat = "dd/MM/yyyy"),
SessionField.EndTime("End Time", dateFormat = "HH:mm"),
SessionField.Buyin("Total Buy-In"),
SessionField.CashedOut("Cashed Out"),
SessionField.NetResult("Profit"),
SessionField.Break("Break"),
SessionField.LimitType("Limit Type"),
SessionField.Game("Game"),
SessionField.Bankroll("Bankroll"),
SessionField.TableSize("Table Type"),
SessionField.Location("Location"),
SessionField.LocationType("Location Type"),
SessionField.Comment("Notes"),
SessionField.CurrencyCode("Currency"),
SessionField.Blind("Stakes", callback = { value -> // $10/20
value.drop(1)
val blinds = value.split("/")
if (blinds.size == 2) {
return@Blind Pair(blinds.first().toDouble(), blinds.last().toDouble())
} else {
return@Blind null
}
})
)
} }
override fun parseData(realm: Realm, record: CSVRecord): Session? { override fun parseData(realm: Realm, record: CSVRecord): Session? {
val session = Session.newInstance(realm, this.isTournament) val session = Session.newInstance(realm, this.isTournament)
fields.forEach { var isLive = true
var bankrollName: String? = null
var currencyCode: String? = null
var currencyRate: Double? = null
this.fieldMapping[it]?.let { index -> fields.forEach { field ->
this.fieldMapping[field]?.let { index ->
val value = record.get(index) val value = record.get(index)
when (it) { when (field) {
is SessionField.Start -> { is SessionField.Start -> {
session.startDate = it.parse(value) session.startDate = field.parse(value)
} }
is SessionField.End -> { is SessionField.End -> {
session.endDate = it.parse(value) session.endDate = field.parse(value)
} }
is SessionField.Buyin -> session.result?.buyin = it.parse(value) is SessionField.StartTime -> { session.startDate?.setHourMinutes(value) }
is SessionField.CashedOut -> session.result?.cashout = it.parse(value) is SessionField.EndTime -> { session.endDate?.setHourMinutes(value) }
is SessionField.Tips -> session.result?.tips = it.parse(value) is SessionField.Buyin -> session.result?.buyin = field.parse(value)
is SessionField.CashedOut -> session.result?.cashout = field.parse(value)
is SessionField.Tips -> session.result?.tips = field.parse(value)
is SessionField.Break -> { is SessionField.Break -> {
it.parse(value)?.let { field.parse(value)?.let {
session.breakDuration = it.toLong() session.breakDuration = it.toLong() * 60 * 1000
} }
} }
is SessionField.Game -> session.game = realm.getOrCreate(value) is SessionField.Game -> session.game = realm.getOrCreate(value)
is SessionField.Location -> session.location = realm.getOrCreate(value) is SessionField.Location -> session.location = realm.getOrCreate(value)
is SessionField.Bankroll -> session.bankroll = realm.getOrCreate(value) is SessionField.Bankroll -> bankrollName = value
is SessionField.LimitType -> session.limit = Limit.getInstance(value)?.ordinal is SessionField.LimitType -> session.limit = Limit.getInstance(value)?.ordinal
is SessionField.Comment -> session.comment = value is SessionField.Comment -> session.comment = value
is SessionField.Blind -> { // 1/2 is SessionField.Blind -> { // 1/2
@ -114,13 +262,28 @@ class SessionCSVDescriptor(var isTournament: Boolean, vararg elements: Field) :
Timber.d("Blinds could not be parsed: $value") Timber.d("Blinds could not be parsed: $value")
} }
} }
else -> { is SessionField.SmallBlind -> session.cgSmallBlind = field.parse(value)
is SessionField.BigBlind -> session.cgBigBlind = field.parse(value)
is SessionField.TableSize -> session.tableSize = TableSize.valueForLabel(value)
is SessionField.SessionType -> {
Session.Type.getValueFromString(value)?.let { type ->
session.type = type.ordinal
}
} }
is SessionField.TournamentPosition -> session.result?.tournamentFinalPosition = field.parse(value)?.toInt()
is SessionField.TournamentName -> session.tournamentName = realm.getOrCreate(value)
is SessionField.TournamentType -> session.tournamentType = TournamentType.getValueForLabel(value)?.ordinal
is SessionField.TournamentNumberOfPlayers -> session.tournamentNumberOfPlayers = field.parse(value)?.toInt()
is SessionField.CurrencyCode -> currencyCode = value
is SessionField.CurrencyRate -> currencyRate = field.parse(value)
else -> { }
} }
} }
} }
session.bankroll = Bankroll.getOrCreate(realm, bankrollName ?: "Import", isLive, currencyCode, currencyRate)
val startDate = session.startDate val startDate = session.startDate
val endDate = session.endDate val endDate = session.endDate
val net = session.result?.net val net = session.result?.net

@ -1,8 +1,5 @@
package net.pokeranalytics.android.util.csv package net.pokeranalytics.android.util.csv
import io.realm.Realm
import net.pokeranalytics.android.model.interfaces.NameManageable
import net.pokeranalytics.android.util.extensions.getOrCreate
import timber.log.Timber import timber.log.Timber
import java.text.DateFormat import java.text.DateFormat
import java.text.NumberFormat import java.text.NumberFormat
@ -12,9 +9,15 @@ import java.util.*
interface NumberField: TypedField<Double> { interface NumberField: TypedField<Double> {
val numberFormat: String? val numberFormat: String?
override fun parse(value: String) : Double? { override fun parse(value: String) : Double? {
if (value.isEmpty()) {
return null
}
val formatter = NumberFormat.getInstance() val formatter = NumberFormat.getInstance()
return try { return try {
@ -27,6 +30,7 @@ interface NumberField: TypedField<Double> {
} }
interface DateField : TypedField<Date> { interface DateField : TypedField<Date> {
val dateFormat: String? val dateFormat: String?
override fun parse(value: String) : Date? { override fun parse(value: String) : Date? {
@ -42,9 +46,13 @@ interface DateField : TypedField<Date> {
} }
interface BlindField : TypedField<Double> { interface BlindField : TypedField<Pair<Double, Double>> {
override fun parse(value: String) : Double? { override fun parse(value: String) : Pair<Double, Double>? {
this.callback?.let { cb ->
return cb(value)
}
return null return null
} }
@ -52,17 +60,9 @@ interface BlindField : TypedField<Double> {
interface TypedField<T> : Field { interface TypedField<T> : Field {
fun parse(value: String) : T? fun parse(value: String) : T?
} var callback: ((String) -> T?)?
interface NamedDataField : Field {
fun <T : NameManageable> getOrCreate(realm: Realm, clazz: Class<T>, name: String) : T {
return realm.getOrCreate(clazz, name)
}
} }
interface Field { interface Field {
val header: String val header: String
var callback: (() -> Unit)?
} }

@ -161,3 +161,7 @@ fun Date.getNextMinuteInMilliseconds() : Long {
calendar.set(Calendar.MILLISECOND, 0) calendar.set(Calendar.MILLISECOND, 0)
return calendar.time.time - this.time return calendar.time.time - this.time
} }
fun Date.setHourMinutes(value: String) {
}

Loading…
Cancel
Save